[PATCH 0/5] [WOK] Set new structure to Wok plugins.
From: Paulo Vital <pvital@linux.vnet.ibm.com> This patch-set moves the plugins structure to a new path inside src/wok, and fix and modify all necessary build, config and code files to use the new structure. In addition, fix all bugs related to build and install Wok and Kimchi in the system and generate the necessary RPM and DEB files. Paulo Vital (5): Move plugins directory to src/wok structure. Change relative to absolute imports in Kimchi. Update build and config files to new plugins path. Make dynamic the state_dir path in Kimchi. Adding COPYING and CONTRIBUTE files into Kimchi. Makefile.am | 20 +- configure.ac | 16 +- plugins/Makefile.am | 25 - plugins/__init__.py | 18 - plugins/kimchi/.gitignore | 37 - plugins/kimchi/API.json | 836 ------- plugins/kimchi/INSTALL | 369 --- plugins/kimchi/Makefile.am | 161 -- plugins/kimchi/README.md | 1 - plugins/kimchi/VERSION | 1 - plugins/kimchi/__init__.py | 21 - plugins/kimchi/autogen.sh | 21 - plugins/kimchi/build-aux/config.rpath | 672 ------ plugins/kimchi/build-aux/genChangelog | 25 - plugins/kimchi/build-aux/pkg-version | 59 - plugins/kimchi/config.py.in | 144 -- plugins/kimchi/config.rpath | 672 ------ plugins/kimchi/configure.ac | 119 - plugins/kimchi/contrib/DEBIAN/Makefile.am | 17 - plugins/kimchi/contrib/DEBIAN/control.in | 30 - plugins/kimchi/contrib/Makefile.am | 34 - plugins/kimchi/contrib/check_i18n.py | 82 - plugins/kimchi/contrib/kimchi.spec.fedora.in | 119 - plugins/kimchi/contrib/kimchi.spec.suse.in | 107 - plugins/kimchi/contrib/make-deb.sh.in | 15 - plugins/kimchi/control/Makefile.am | 27 - plugins/kimchi/control/__init__.py | 26 - plugins/kimchi/control/config.py | 57 - plugins/kimchi/control/cpuinfo.py | 37 - plugins/kimchi/control/debugreports.py | 61 - plugins/kimchi/control/groups.py | 28 - plugins/kimchi/control/host.py | 157 -- plugins/kimchi/control/interfaces.py | 46 - plugins/kimchi/control/networks.py | 54 - plugins/kimchi/control/peers.py | 29 - plugins/kimchi/control/storagepools.py | 116 - plugins/kimchi/control/storageservers.py | 60 - plugins/kimchi/control/storagevolumes.py | 83 - plugins/kimchi/control/templates.py | 58 - plugins/kimchi/control/users.py | 35 - plugins/kimchi/control/vm/Makefile.am | 26 - plugins/kimchi/control/vm/__init__.py | 26 - plugins/kimchi/control/vm/hostdevs.py | 43 - plugins/kimchi/control/vm/ifaces.py | 45 - plugins/kimchi/control/vm/snapshots.py | 58 - plugins/kimchi/control/vm/storages.py | 45 - plugins/kimchi/control/vms.py | 67 - plugins/kimchi/disks.py | 196 -- plugins/kimchi/distroloader.py | 67 - plugins/kimchi/distros.d/Makefile.am | 22 - plugins/kimchi/distros.d/debian.json | 9 - plugins/kimchi/distros.d/fedora.json | 30 - plugins/kimchi/distros.d/gentoo.json | 9 - plugins/kimchi/distros.d/opensuse.json | 23 - plugins/kimchi/distros.d/ubuntu.json | 37 - plugins/kimchi/docs/API.md | 1116 --------- plugins/kimchi/docs/Makefile.am | 28 - plugins/kimchi/docs/README-federation.md | 60 - plugins/kimchi/docs/README.md | 247 -- plugins/kimchi/docs/kimchi-guest.png | Bin 192281 -> 0 bytes plugins/kimchi/docs/kimchi-login.png | Bin 318041 -> 0 bytes plugins/kimchi/docs/kimchi-templates.png | Bin 329678 -> 0 bytes plugins/kimchi/i18n.py | 335 --- plugins/kimchi/imageinfo.py | 72 - plugins/kimchi/iscsi.py | 88 - plugins/kimchi/isoinfo.py | 506 ----- plugins/kimchi/kimchi.conf | 37 - plugins/kimchi/kvmusertests.py | 79 - plugins/kimchi/m4/ac_python_module.m4 | 30 - plugins/kimchi/m4/gettext.m4 | 383 ---- plugins/kimchi/m4/iconv.m4 | 214 -- plugins/kimchi/m4/intlmacosx.m4 | 51 - plugins/kimchi/m4/lib-ld.m4 | 110 - plugins/kimchi/m4/lib-link.m4 | 774 ------- plugins/kimchi/m4/lib-prefix.m4 | 224 -- plugins/kimchi/m4/nls.m4 | 32 - plugins/kimchi/m4/po.m4 | 449 ---- plugins/kimchi/m4/progtest.m4 | 92 - plugins/kimchi/mockmodel.py | 627 ------ plugins/kimchi/model/Makefile.am | 25 - plugins/kimchi/model/__init__.py | 18 - plugins/kimchi/model/config.py | 176 -- plugins/kimchi/model/cpuinfo.py | 126 -- plugins/kimchi/model/debugreports.py | 213 -- plugins/kimchi/model/diskutils.py | 75 - plugins/kimchi/model/featuretests.py | 259 --- plugins/kimchi/model/groups.py | 67 - plugins/kimchi/model/host.py | 476 ---- plugins/kimchi/model/hostdev.py | 324 --- plugins/kimchi/model/interfaces.py | 44 - plugins/kimchi/model/libvirtconnection.py | 136 -- plugins/kimchi/model/libvirtstoragepool.py | 264 --- plugins/kimchi/model/model.py | 52 - plugins/kimchi/model/networks.py | 382 ---- plugins/kimchi/model/peers.py | 72 - plugins/kimchi/model/storagepools.py | 490 ---- plugins/kimchi/model/storageservers.py | 81 - plugins/kimchi/model/storagetargets.py | 122 - plugins/kimchi/model/storagevolumes.py | 542 ----- plugins/kimchi/model/templates.py | 303 --- plugins/kimchi/model/users.py | 90 - plugins/kimchi/model/utils.py | 161 -- plugins/kimchi/model/vmhostdevs.py | 336 --- plugins/kimchi/model/vmifaces.py | 186 -- plugins/kimchi/model/vms.py | 1307 ----------- plugins/kimchi/model/vmsnapshots.py | 204 -- plugins/kimchi/model/vmstorages.py | 252 --- plugins/kimchi/netinfo.py | 216 -- plugins/kimchi/network.py | 62 - plugins/kimchi/osinfo.py | 213 -- plugins/kimchi/po/LINGUAS | 11 - plugins/kimchi/po/Makefile.in.in | 398 ---- plugins/kimchi/po/Makevars | 41 - plugins/kimchi/po/POTFILES.in | 3 - plugins/kimchi/po/de_DE.po | 2288 ------------------- plugins/kimchi/po/en_US.po | 2075 ----------------- plugins/kimchi/po/es_ES.po | 2305 ------------------- plugins/kimchi/po/fr_FR.po | 2338 ------------------- plugins/kimchi/po/gen-pot.in | 9 - plugins/kimchi/po/it_IT.po | 2274 ------------------- plugins/kimchi/po/ja_JP.po | 2269 ------------------- plugins/kimchi/po/kimchi.pot | 2074 ----------------- plugins/kimchi/po/ko_KR.po | 2197 ------------------ plugins/kimchi/po/pt_BR.po | 2369 -------------------- plugins/kimchi/po/ru_RU.po | 2198 ------------------ plugins/kimchi/po/zh_CN.po | 2186 ------------------ plugins/kimchi/po/zh_TW.po | 2138 ------------------ plugins/kimchi/repositories.py | 529 ----- plugins/kimchi/root.py | 69 - plugins/kimchi/scan.py | 89 - plugins/kimchi/screenshot.py | 184 -- plugins/kimchi/swupdate.py | 263 --- plugins/kimchi/template.conf | 47 - plugins/kimchi/tests/Makefile.am | 50 - plugins/kimchi/tests/iso_gen.py | 212 -- plugins/kimchi/tests/run_tests.sh.in | 55 - plugins/kimchi/tests/test_authorization.py | 178 -- plugins/kimchi/tests/test_config.py.in | 267 --- plugins/kimchi/tests/test_host.py | 206 -- plugins/kimchi/tests/test_mock_network.py | 73 - plugins/kimchi/tests/test_mock_storagepool.py | 147 -- plugins/kimchi/tests/test_mock_storagevolume.py | 98 - plugins/kimchi/tests/test_mockmodel.py | 141 -- plugins/kimchi/tests/test_model.py | 1248 ----------- plugins/kimchi/tests/test_model_network.py | 149 -- plugins/kimchi/tests/test_model_storagepool.py | 123 - plugins/kimchi/tests/test_model_storagevolume.py | 280 --- plugins/kimchi/tests/test_networkxml.py | 172 -- plugins/kimchi/tests/test_osinfo.py | 69 - plugins/kimchi/tests/test_rest.py | 1327 ----------- plugins/kimchi/tests/test_storagepoolxml.py | 171 -- plugins/kimchi/tests/test_template.py | 387 ---- plugins/kimchi/tests/test_vmtemplate.py | 116 - plugins/kimchi/tests/test_yumparser.py | 162 -- plugins/kimchi/tests/utils.py | 260 --- plugins/kimchi/ui/Makefile.am | 20 - plugins/kimchi/ui/config/Makefile.am | 22 - plugins/kimchi/ui/config/tab-ext.xml | 38 - plugins/kimchi/ui/css/Makefile.am | 26 - plugins/kimchi/ui/css/theme-default/guest-edit.css | 424 ---- .../ui/css/theme-default/guest-storage-add.css | 81 - plugins/kimchi/ui/css/theme-default/host.css | 287 --- plugins/kimchi/ui/css/theme-default/icon.css | 106 - plugins/kimchi/ui/css/theme-default/list.css | 326 --- plugins/kimchi/ui/css/theme-default/network.css | 267 --- plugins/kimchi/ui/css/theme-default/report-add.css | 37 - .../kimchi/ui/css/theme-default/report-rename.css | 39 - .../kimchi/ui/css/theme-default/repository-add.css | 42 - .../ui/css/theme-default/repository-edit.css | 88 - plugins/kimchi/ui/css/theme-default/storage.css | 550 ----- .../css/theme-default/storagepool-add-volume.css | 36 - .../kimchi/ui/css/theme-default/template-edit.css | 175 -- plugins/kimchi/ui/css/theme-default/template.css | 85 - .../kimchi/ui/css/theme-default/template_add.css | 317 --- .../kimchi/ui/css/theme-default/template_list.css | 267 --- plugins/kimchi/ui/images/Makefile.am | 22 - plugins/kimchi/ui/images/icon-centos.png | Bin 4734 -> 0 bytes plugins/kimchi/ui/images/icon-debian.png | Bin 4239 -> 0 bytes plugins/kimchi/ui/images/icon-fedora.png | Bin 4449 -> 0 bytes plugins/kimchi/ui/images/icon-gentoo.png | Bin 15307 -> 0 bytes plugins/kimchi/ui/images/icon-opensuse.png | Bin 3046 -> 0 bytes plugins/kimchi/ui/images/icon-ubuntu.png | Bin 4818 -> 0 bytes plugins/kimchi/ui/images/icon-vm.png | Bin 2976 -> 0 bytes plugins/kimchi/ui/images/theme-default/Makefile.am | 20 - .../kimchi/ui/images/theme-default/ac22_pause.png | Bin 1219 -> 0 bytes .../ui/images/theme-default/ac22_pause_grey.png | Bin 1175 -> 0 bytes .../kimchi/ui/images/theme-default/ac24_resume.png | Bin 1341 -> 0 bytes .../ui/images/theme-default/ac24_resume_grey.png | Bin 1282 -> 0 bytes .../ui/images/theme-default/arrow-down-black.png | Bin 2942 -> 0 bytes .../ui/images/theme-default/arrow-down-disable.png | Bin 472 -> 0 bytes .../kimchi/ui/images/theme-default/arrow-down.png | Bin 537 -> 0 bytes .../kimchi/ui/images/theme-default/arrow-up.png | Bin 510 -> 0 bytes .../kimchi/ui/images/theme-default/arrow_out.png | Bin 3048 -> 0 bytes plugins/kimchi/ui/images/theme-default/group.png | Bin 1703 -> 0 bytes .../ui/images/theme-default/host-icon-sprite.png | Bin 1034 -> 0 bytes .../kimchi/ui/images/theme-default/icon-back.png | Bin 244 -> 0 bytes .../kimchi/ui/images/theme-default/icon-camera.png | Bin 4860 -> 0 bytes .../kimchi/ui/images/theme-default/icon-design.png | Bin 4562 -> 0 bytes .../kimchi/ui/images/theme-default/icon-detail.png | Bin 3079 -> 0 bytes .../kimchi/ui/images/theme-default/icon-iso.png | Bin 4188 -> 0 bytes .../kimchi/ui/images/theme-default/icon-list.png | Bin 2983 -> 0 bytes .../kimchi/ui/images/theme-default/icon-load.png | Bin 3678 -> 0 bytes .../kimchi/ui/images/theme-default/icon-local.png | Bin 425 -> 0 bytes .../ui/images/theme-default/icon-power-down.png | Bin 4372 -> 0 bytes .../ui/images/theme-default/icon-power-up.png | Bin 4367 -> 0 bytes .../kimchi/ui/images/theme-default/icon-qcow2.png | Bin 4684 -> 0 bytes .../kimchi/ui/images/theme-default/icon-raw.png | Bin 4679 -> 0 bytes .../kimchi/ui/images/theme-default/icon-remote.png | Bin 1005 -> 0 bytes .../kimchi/ui/images/theme-default/icon-reset.png | Bin 4576 -> 0 bytes .../kimchi/ui/images/theme-default/icon-search.png | Bin 4197 -> 0 bytes .../kimchi/ui/images/theme-default/icon-sort.png | Bin 3421 -> 0 bytes .../kimchi/ui/images/theme-default/icon-tree.png | Bin 3526 -> 0 bytes .../kimchi/ui/images/theme-default/icon-user.png | Bin 5366 -> 0 bytes .../images/theme-default/icon-volume-default.png | Bin 4265 -> 0 bytes .../images/theme-default/kimchi-loading15x15.gif | Bin 1653 -> 0 bytes plugins/kimchi/ui/images/theme-default/loading.gif | Bin 2190 -> 0 bytes plugins/kimchi/ui/images/theme-default/user.png | Bin 1322 -> 0 bytes plugins/kimchi/ui/js/Makefile.am | 27 - plugins/kimchi/ui/js/src/kimchi.api.js | 1355 ----------- plugins/kimchi/ui/js/src/kimchi.guest_add_main.js | 86 - plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js | 759 ------- plugins/kimchi/ui/js/src/kimchi.guest_main.js | 511 ----- .../kimchi/ui/js/src/kimchi.guest_media_main.js | 56 - .../ui/js/src/kimchi.guest_storage_add.main.js | 199 -- plugins/kimchi/ui/js/src/kimchi.host.js | 858 ------- plugins/kimchi/ui/js/src/kimchi.main.js | 26 - plugins/kimchi/ui/js/src/kimchi.network.js | 442 ---- plugins/kimchi/ui/js/src/kimchi.report_add_main.js | 72 - .../kimchi/ui/js/src/kimchi.report_rename_main.js | 66 - .../kimchi/ui/js/src/kimchi.repository_add_main.js | 96 - .../ui/js/src/kimchi.repository_edit_main.js | 74 - plugins/kimchi/ui/js/src/kimchi.storage_main.js | 428 ---- .../ui/js/src/kimchi.storagepool_add_main.js | 414 ---- .../js/src/kimchi.storagepool_add_volume_main.js | 179 -- .../kimchi/ui/js/src/kimchi.template_add_main.js | 441 ---- .../kimchi/ui/js/src/kimchi.template_edit_main.js | 343 --- plugins/kimchi/ui/js/src/kimchi.template_main.js | 111 - plugins/kimchi/ui/pages/Makefile.am | 22 - plugins/kimchi/ui/pages/guest-add.html.tmpl | 98 - plugins/kimchi/ui/pages/guest-edit.html.tmpl | 311 --- .../kimchi/ui/pages/guest-storage-add.html.tmpl | 103 - plugins/kimchi/ui/pages/guest.html.tmpl | 77 - plugins/kimchi/ui/pages/guests.html.tmpl | 65 - plugins/kimchi/ui/pages/help/Makefile.am | 34 - plugins/kimchi/ui/pages/help/de_DE/Makefile.am | 23 - plugins/kimchi/ui/pages/help/de_DE/guests.dita | 127 -- plugins/kimchi/ui/pages/help/de_DE/host.dita | 49 - plugins/kimchi/ui/pages/help/de_DE/network.dita | 62 - plugins/kimchi/ui/pages/help/de_DE/storage.dita | 86 - plugins/kimchi/ui/pages/help/de_DE/templates.dita | 112 - plugins/kimchi/ui/pages/help/dita-help.xsl | 26 - plugins/kimchi/ui/pages/help/en_US/Makefile.am | 23 - plugins/kimchi/ui/pages/help/en_US/guests.dita | 136 -- plugins/kimchi/ui/pages/help/en_US/host.dita | 70 - plugins/kimchi/ui/pages/help/en_US/network.dita | 68 - plugins/kimchi/ui/pages/help/en_US/storage.dita | 99 - plugins/kimchi/ui/pages/help/en_US/templates.dita | 123 - plugins/kimchi/ui/pages/help/es_ES/Makefile.am | 23 - plugins/kimchi/ui/pages/help/es_ES/guests.dita | 120 - plugins/kimchi/ui/pages/help/es_ES/host.dita | 49 - plugins/kimchi/ui/pages/help/es_ES/network.dita | 61 - plugins/kimchi/ui/pages/help/es_ES/storage.dita | 86 - plugins/kimchi/ui/pages/help/es_ES/templates.dita | 111 - plugins/kimchi/ui/pages/help/fr_FR/Makefile.am | 23 - plugins/kimchi/ui/pages/help/fr_FR/guests.dita | 130 -- plugins/kimchi/ui/pages/help/fr_FR/host.dita | 68 - plugins/kimchi/ui/pages/help/fr_FR/network.dita | 67 - plugins/kimchi/ui/pages/help/fr_FR/storage.dita | 93 - plugins/kimchi/ui/pages/help/fr_FR/templates.dita | 120 - plugins/kimchi/ui/pages/help/it_IT/Makefile.am | 23 - plugins/kimchi/ui/pages/help/it_IT/guests.dita | 123 - plugins/kimchi/ui/pages/help/it_IT/host.dita | 51 - plugins/kimchi/ui/pages/help/it_IT/network.dita | 63 - plugins/kimchi/ui/pages/help/it_IT/storage.dita | 91 - plugins/kimchi/ui/pages/help/it_IT/templates.dita | 115 - plugins/kimchi/ui/pages/help/ja_JP/Makefile.am | 23 - plugins/kimchi/ui/pages/help/ja_JP/guests.dita | 172 -- plugins/kimchi/ui/pages/help/ja_JP/host.dita | 70 - plugins/kimchi/ui/pages/help/ja_JP/network.dita | 83 - plugins/kimchi/ui/pages/help/ja_JP/storage.dita | 120 - plugins/kimchi/ui/pages/help/ja_JP/templates.dita | 150 -- plugins/kimchi/ui/pages/help/kimchi.css | 208 -- plugins/kimchi/ui/pages/help/ko_KR/Makefile.am | 23 - plugins/kimchi/ui/pages/help/ko_KR/guests.dita | 119 - plugins/kimchi/ui/pages/help/ko_KR/host.dita | 47 - plugins/kimchi/ui/pages/help/ko_KR/network.dita | 61 - plugins/kimchi/ui/pages/help/ko_KR/storage.dita | 86 - plugins/kimchi/ui/pages/help/ko_KR/templates.dita | 111 - plugins/kimchi/ui/pages/help/pt_BR/Makefile.am | 23 - plugins/kimchi/ui/pages/help/pt_BR/guests.dita | 137 -- plugins/kimchi/ui/pages/help/pt_BR/host.dita | 74 - plugins/kimchi/ui/pages/help/pt_BR/network.dita | 72 - plugins/kimchi/ui/pages/help/pt_BR/storage.dita | 102 - plugins/kimchi/ui/pages/help/pt_BR/templates.dita | 127 -- plugins/kimchi/ui/pages/help/ru_RU/Makefile.am | 23 - plugins/kimchi/ui/pages/help/ru_RU/guests.dita | 122 - plugins/kimchi/ui/pages/help/ru_RU/host.dita | 48 - plugins/kimchi/ui/pages/help/ru_RU/network.dita | 61 - plugins/kimchi/ui/pages/help/ru_RU/storage.dita | 88 - plugins/kimchi/ui/pages/help/ru_RU/templates.dita | 111 - plugins/kimchi/ui/pages/help/zh_CN/Makefile.am | 23 - plugins/kimchi/ui/pages/help/zh_CN/guests.dita | 118 - plugins/kimchi/ui/pages/help/zh_CN/host.dita | 45 - plugins/kimchi/ui/pages/help/zh_CN/network.dita | 61 - plugins/kimchi/ui/pages/help/zh_CN/storage.dita | 84 - plugins/kimchi/ui/pages/help/zh_CN/templates.dita | 111 - plugins/kimchi/ui/pages/help/zh_TW/Makefile.am | 23 - plugins/kimchi/ui/pages/help/zh_TW/guests.dita | 120 - plugins/kimchi/ui/pages/help/zh_TW/host.dita | 50 - plugins/kimchi/ui/pages/help/zh_TW/network.dita | 61 - plugins/kimchi/ui/pages/help/zh_TW/storage.dita | 88 - plugins/kimchi/ui/pages/help/zh_TW/templates.dita | 112 - plugins/kimchi/ui/pages/host.html.tmpl | 177 -- plugins/kimchi/ui/pages/i18n.json.tmpl | 187 -- plugins/kimchi/ui/pages/network.html.tmpl | 133 -- plugins/kimchi/ui/pages/report-add.html.tmpl | 56 - plugins/kimchi/ui/pages/report-rename.html.tmpl | 56 - plugins/kimchi/ui/pages/repository-add.html.tmpl | 113 - plugins/kimchi/ui/pages/repository-edit.html.tmpl | 117 - plugins/kimchi/ui/pages/storage.html.tmpl | 143 -- .../ui/pages/storagepool-add-volume.html.tmpl | 79 - plugins/kimchi/ui/pages/storagepool-add.html.tmpl | 186 -- plugins/kimchi/ui/pages/template-add.html.tmpl | 233 -- plugins/kimchi/ui/pages/template-edit.html.tmpl | 193 -- plugins/kimchi/ui/pages/templates.html.tmpl | 77 - plugins/kimchi/ui/robots.txt | 2 - plugins/kimchi/ui/spice-html5/Makefile.am | 25 - plugins/kimchi/ui/spice-html5/atKeynames.js | 183 -- plugins/kimchi/ui/spice-html5/bitmap.js | 51 - plugins/kimchi/ui/spice-html5/css/Makefile.am | 20 - plugins/kimchi/ui/spice-html5/css/spice.css | 118 - plugins/kimchi/ui/spice-html5/cursor.js | 110 - plugins/kimchi/ui/spice-html5/display.js | 823 ------- plugins/kimchi/ui/spice-html5/enums.js | 324 --- plugins/kimchi/ui/spice-html5/inputs.js | 280 --- plugins/kimchi/ui/spice-html5/lz.js | 166 -- plugins/kimchi/ui/spice-html5/main.js | 231 -- plugins/kimchi/ui/spice-html5/pages/Makefile.am | 20 - .../kimchi/ui/spice-html5/pages/spice_auto.html | 200 -- plugins/kimchi/ui/spice-html5/playback.js | 278 --- plugins/kimchi/ui/spice-html5/png.js | 256 --- plugins/kimchi/ui/spice-html5/quic.js | 1335 ----------- plugins/kimchi/ui/spice-html5/resize.js | 70 - plugins/kimchi/ui/spice-html5/simulatecursor.js | 202 -- plugins/kimchi/ui/spice-html5/spicearraybuffer.js | 58 - plugins/kimchi/ui/spice-html5/spiceconn.js | 460 ---- plugins/kimchi/ui/spice-html5/spicedataview.js | 120 - plugins/kimchi/ui/spice-html5/spicemsg.js | 1047 --------- plugins/kimchi/ui/spice-html5/spicetype.js | 473 ---- .../kimchi/ui/spice-html5/thirdparty/Makefile.am | 20 - plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js | 589 ----- plugins/kimchi/ui/spice-html5/thirdparty/prng4.js | 79 - plugins/kimchi/ui/spice-html5/thirdparty/rng.js | 102 - plugins/kimchi/ui/spice-html5/thirdparty/rsa.js | 146 -- plugins/kimchi/ui/spice-html5/thirdparty/sha1.js | 346 --- plugins/kimchi/ui/spice-html5/ticket.js | 250 --- plugins/kimchi/ui/spice-html5/utils.js | 265 --- plugins/kimchi/ui/spice-html5/webm.js | 553 ----- plugins/kimchi/ui/spice-html5/wire.js | 123 - plugins/kimchi/utils.py | 39 - plugins/kimchi/vmtemplate.py | 431 ---- plugins/kimchi/vnc.py | 77 - plugins/kimchi/xmlutils/Makefile.am | 25 - plugins/kimchi/xmlutils/__init__.py | 18 - plugins/kimchi/xmlutils/cpu.py | 60 - plugins/kimchi/xmlutils/disk.py | 164 -- plugins/kimchi/xmlutils/graphics.py | 45 - plugins/kimchi/xmlutils/interface.py | 61 - plugins/kimchi/xmlutils/network.py | 122 - plugins/kimchi/xmlutils/qemucmdline.py | 45 - plugins/kimchi/yumparser.py | 283 --- plugins/sample/API.json | 56 - plugins/sample/Makefile.am | 29 - plugins/sample/__init__.py | 97 - plugins/sample/config.status | 1 - plugins/sample/i18n.py | 40 - plugins/sample/model.py | 131 -- plugins/sample/po/LINGUAS | 3 - plugins/sample/po/Makefile.in.in | 400 ---- plugins/sample/po/Makevars | 41 - plugins/sample/po/POTFILES.in | 2 - plugins/sample/po/en_US.po | 21 - plugins/sample/po/gen-pot | 9 - plugins/sample/po/pt_BR.po | 24 - plugins/sample/po/sample.pot | 21 - plugins/sample/po/zh_CN.po | 24 - plugins/sample/sample.conf.in | 27 - plugins/sample/ui/Makefile.am | 22 - plugins/sample/ui/config/Makefile.am | 21 - plugins/sample/ui/config/tab-ext.xml | 17 - plugins/sample/ui/css/.gitignore | 0 plugins/sample/ui/images/.gitignore | 0 plugins/sample/ui/js/.gitignore | 0 plugins/sample/ui/js/Makefile.am | 20 - plugins/sample/ui/js/util.js | 33 - plugins/sample/ui/libs/.gitignore | 0 plugins/sample/ui/pages/Makefile.am | 20 - .../sample/ui/pages/help/en_US/sample-tab1.html | 1 - .../sample/ui/pages/help/en_US/sample-tab2.html | 1 - plugins/sample/ui/pages/i18n.json.tmpl | 26 - plugins/sample/ui/pages/sample-tab1.html.tmpl | 30 - plugins/sample/ui/pages/sample-tab2.html.tmpl | 30 - src/wok/Makefile.am | 2 +- src/wok/config.py.in | 7 +- src/wok/plugins/Makefile.am | 25 + src/wok/plugins/__init__.py | 18 + src/wok/plugins/kimchi/.gitignore | 37 + src/wok/plugins/kimchi/API.json | 836 +++++++ src/wok/plugins/kimchi/CONTRIBUTE.md | 16 + src/wok/plugins/kimchi/COPYING | 19 + src/wok/plugins/kimchi/COPYING.ASL2 | 202 ++ src/wok/plugins/kimchi/COPYING.LGPL | 165 ++ src/wok/plugins/kimchi/ChangeLog | 2155 ++++++++++++++++++ src/wok/plugins/kimchi/INSTALL | 369 +++ src/wok/plugins/kimchi/Makefile.am | 165 ++ src/wok/plugins/kimchi/README.md | 1 + src/wok/plugins/kimchi/VERSION | 1 + src/wok/plugins/kimchi/__init__.py | 21 + src/wok/plugins/kimchi/autogen.sh | 21 + src/wok/plugins/kimchi/build-aux/config.rpath | 672 ++++++ src/wok/plugins/kimchi/build-aux/genChangelog | 25 + src/wok/plugins/kimchi/build-aux/pkg-version | 59 + src/wok/plugins/kimchi/config.py.in | 144 ++ src/wok/plugins/kimchi/config.rpath | 672 ++++++ src/wok/plugins/kimchi/configure.ac | 119 + src/wok/plugins/kimchi/contrib/DEBIAN/Makefile.am | 17 + src/wok/plugins/kimchi/contrib/DEBIAN/control.in | 30 + src/wok/plugins/kimchi/contrib/Makefile.am | 34 + src/wok/plugins/kimchi/contrib/check_i18n.py | 82 + .../plugins/kimchi/contrib/kimchi.spec.fedora.in | 120 + src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in | 108 + src/wok/plugins/kimchi/contrib/make-deb.sh.in | 15 + src/wok/plugins/kimchi/control/Makefile.am | 27 + src/wok/plugins/kimchi/control/__init__.py | 26 + src/wok/plugins/kimchi/control/config.py | 57 + src/wok/plugins/kimchi/control/cpuinfo.py | 37 + src/wok/plugins/kimchi/control/debugreports.py | 61 + src/wok/plugins/kimchi/control/groups.py | 28 + src/wok/plugins/kimchi/control/host.py | 157 ++ src/wok/plugins/kimchi/control/interfaces.py | 46 + src/wok/plugins/kimchi/control/networks.py | 54 + src/wok/plugins/kimchi/control/peers.py | 29 + src/wok/plugins/kimchi/control/storagepools.py | 116 + src/wok/plugins/kimchi/control/storageservers.py | 60 + src/wok/plugins/kimchi/control/storagevolumes.py | 83 + src/wok/plugins/kimchi/control/templates.py | 58 + src/wok/plugins/kimchi/control/users.py | 35 + src/wok/plugins/kimchi/control/vm/Makefile.am | 26 + src/wok/plugins/kimchi/control/vm/__init__.py | 26 + src/wok/plugins/kimchi/control/vm/hostdevs.py | 43 + src/wok/plugins/kimchi/control/vm/ifaces.py | 45 + src/wok/plugins/kimchi/control/vm/snapshots.py | 58 + src/wok/plugins/kimchi/control/vm/storages.py | 45 + src/wok/plugins/kimchi/control/vms.py | 67 + src/wok/plugins/kimchi/disks.py | 196 ++ src/wok/plugins/kimchi/distroloader.py | 67 + src/wok/plugins/kimchi/distros.d/Makefile.am | 22 + src/wok/plugins/kimchi/distros.d/debian.json | 9 + src/wok/plugins/kimchi/distros.d/fedora.json | 30 + src/wok/plugins/kimchi/distros.d/gentoo.json | 9 + src/wok/plugins/kimchi/distros.d/opensuse.json | 23 + src/wok/plugins/kimchi/distros.d/ubuntu.json | 37 + src/wok/plugins/kimchi/docs/API.md | 1116 +++++++++ src/wok/plugins/kimchi/docs/Makefile.am | 28 + src/wok/plugins/kimchi/docs/README-federation.md | 60 + src/wok/plugins/kimchi/docs/README.md | 247 ++ src/wok/plugins/kimchi/docs/kimchi-guest.png | Bin 0 -> 192281 bytes src/wok/plugins/kimchi/docs/kimchi-login.png | Bin 0 -> 318041 bytes src/wok/plugins/kimchi/docs/kimchi-templates.png | Bin 0 -> 329678 bytes src/wok/plugins/kimchi/i18n.py | 335 +++ src/wok/plugins/kimchi/imageinfo.py | 72 + src/wok/plugins/kimchi/iscsi.py | 88 + src/wok/plugins/kimchi/isoinfo.py | 506 +++++ src/wok/plugins/kimchi/kimchi.conf | 37 + src/wok/plugins/kimchi/kvmusertests.py | 79 + src/wok/plugins/kimchi/m4/ac_python_module.m4 | 30 + src/wok/plugins/kimchi/m4/gettext.m4 | 383 ++++ src/wok/plugins/kimchi/m4/iconv.m4 | 214 ++ src/wok/plugins/kimchi/m4/intlmacosx.m4 | 51 + src/wok/plugins/kimchi/m4/lib-ld.m4 | 110 + src/wok/plugins/kimchi/m4/lib-link.m4 | 774 +++++++ src/wok/plugins/kimchi/m4/lib-prefix.m4 | 224 ++ src/wok/plugins/kimchi/m4/nls.m4 | 32 + src/wok/plugins/kimchi/m4/po.m4 | 449 ++++ src/wok/plugins/kimchi/m4/progtest.m4 | 92 + src/wok/plugins/kimchi/mockmodel.py | 627 ++++++ src/wok/plugins/kimchi/model/Makefile.am | 25 + src/wok/plugins/kimchi/model/__init__.py | 18 + src/wok/plugins/kimchi/model/config.py | 176 ++ src/wok/plugins/kimchi/model/cpuinfo.py | 126 ++ src/wok/plugins/kimchi/model/debugreports.py | 213 ++ src/wok/plugins/kimchi/model/diskutils.py | 75 + src/wok/plugins/kimchi/model/featuretests.py | 259 +++ src/wok/plugins/kimchi/model/groups.py | 67 + src/wok/plugins/kimchi/model/host.py | 476 ++++ src/wok/plugins/kimchi/model/hostdev.py | 324 +++ src/wok/plugins/kimchi/model/interfaces.py | 44 + src/wok/plugins/kimchi/model/libvirtconnection.py | 136 ++ src/wok/plugins/kimchi/model/libvirtstoragepool.py | 266 +++ src/wok/plugins/kimchi/model/model.py | 52 + src/wok/plugins/kimchi/model/networks.py | 382 ++++ src/wok/plugins/kimchi/model/peers.py | 72 + src/wok/plugins/kimchi/model/storagepools.py | 490 ++++ src/wok/plugins/kimchi/model/storageservers.py | 81 + src/wok/plugins/kimchi/model/storagetargets.py | 122 + src/wok/plugins/kimchi/model/storagevolumes.py | 542 +++++ src/wok/plugins/kimchi/model/templates.py | 303 +++ src/wok/plugins/kimchi/model/users.py | 90 + src/wok/plugins/kimchi/model/utils.py | 161 ++ src/wok/plugins/kimchi/model/vmhostdevs.py | 336 +++ src/wok/plugins/kimchi/model/vmifaces.py | 186 ++ src/wok/plugins/kimchi/model/vms.py | 1307 +++++++++++ src/wok/plugins/kimchi/model/vmsnapshots.py | 204 ++ src/wok/plugins/kimchi/model/vmstorages.py | 252 +++ src/wok/plugins/kimchi/netinfo.py | 216 ++ src/wok/plugins/kimchi/network.py | 62 + src/wok/plugins/kimchi/osinfo.py | 213 ++ src/wok/plugins/kimchi/po/LINGUAS | 11 + src/wok/plugins/kimchi/po/Makefile.in.in | 398 ++++ src/wok/plugins/kimchi/po/Makevars | 41 + src/wok/plugins/kimchi/po/POTFILES.in | 3 + src/wok/plugins/kimchi/po/de_DE.po | 2288 +++++++++++++++++++ src/wok/plugins/kimchi/po/en_US.po | 2075 +++++++++++++++++ src/wok/plugins/kimchi/po/es_ES.po | 2305 +++++++++++++++++++ src/wok/plugins/kimchi/po/fr_FR.po | 2338 +++++++++++++++++++ src/wok/plugins/kimchi/po/gen-pot.in | 9 + src/wok/plugins/kimchi/po/it_IT.po | 2274 +++++++++++++++++++ src/wok/plugins/kimchi/po/ja_JP.po | 2269 +++++++++++++++++++ src/wok/plugins/kimchi/po/kimchi.pot | 2074 +++++++++++++++++ src/wok/plugins/kimchi/po/ko_KR.po | 2197 ++++++++++++++++++ src/wok/plugins/kimchi/po/pt_BR.po | 2369 ++++++++++++++++++++ src/wok/plugins/kimchi/po/ru_RU.po | 2198 ++++++++++++++++++ src/wok/plugins/kimchi/po/zh_CN.po | 2186 ++++++++++++++++++ src/wok/plugins/kimchi/po/zh_TW.po | 2138 ++++++++++++++++++ src/wok/plugins/kimchi/repositories.py | 529 +++++ src/wok/plugins/kimchi/root.py | 69 + src/wok/plugins/kimchi/scan.py | 89 + src/wok/plugins/kimchi/screenshot.py | 184 ++ src/wok/plugins/kimchi/swupdate.py | 263 +++ src/wok/plugins/kimchi/template.conf | 47 + src/wok/plugins/kimchi/tests/Makefile.am | 50 + src/wok/plugins/kimchi/tests/iso_gen.py | 212 ++ src/wok/plugins/kimchi/tests/run_tests.sh.in | 55 + src/wok/plugins/kimchi/tests/test_authorization.py | 178 ++ src/wok/plugins/kimchi/tests/test_config.py.in | 267 +++ src/wok/plugins/kimchi/tests/test_host.py | 206 ++ src/wok/plugins/kimchi/tests/test_mock_network.py | 73 + .../plugins/kimchi/tests/test_mock_storagepool.py | 147 ++ .../kimchi/tests/test_mock_storagevolume.py | 98 + src/wok/plugins/kimchi/tests/test_mockmodel.py | 141 ++ src/wok/plugins/kimchi/tests/test_model.py | 1248 +++++++++++ src/wok/plugins/kimchi/tests/test_model_network.py | 149 ++ .../plugins/kimchi/tests/test_model_storagepool.py | 123 + .../kimchi/tests/test_model_storagevolume.py | 280 +++ src/wok/plugins/kimchi/tests/test_networkxml.py | 172 ++ src/wok/plugins/kimchi/tests/test_osinfo.py | 69 + src/wok/plugins/kimchi/tests/test_rest.py | 1327 +++++++++++ .../plugins/kimchi/tests/test_storagepoolxml.py | 171 ++ src/wok/plugins/kimchi/tests/test_template.py | 387 ++++ src/wok/plugins/kimchi/tests/test_vmtemplate.py | 116 + src/wok/plugins/kimchi/tests/test_yumparser.py | 162 ++ src/wok/plugins/kimchi/tests/utils.py | 260 +++ src/wok/plugins/kimchi/ui/Makefile.am | 20 + src/wok/plugins/kimchi/ui/config/Makefile.am | 22 + src/wok/plugins/kimchi/ui/config/tab-ext.xml | 38 + src/wok/plugins/kimchi/ui/css/Makefile.am | 26 + .../kimchi/ui/css/theme-default/guest-edit.css | 424 ++++ .../ui/css/theme-default/guest-storage-add.css | 81 + .../plugins/kimchi/ui/css/theme-default/host.css | 287 +++ .../plugins/kimchi/ui/css/theme-default/icon.css | 106 + .../plugins/kimchi/ui/css/theme-default/list.css | 326 +++ .../kimchi/ui/css/theme-default/network.css | 267 +++ .../kimchi/ui/css/theme-default/report-add.css | 37 + .../kimchi/ui/css/theme-default/report-rename.css | 39 + .../kimchi/ui/css/theme-default/repository-add.css | 42 + .../ui/css/theme-default/repository-edit.css | 88 + .../kimchi/ui/css/theme-default/storage.css | 550 +++++ .../css/theme-default/storagepool-add-volume.css | 36 + .../kimchi/ui/css/theme-default/template-edit.css | 175 ++ .../kimchi/ui/css/theme-default/template.css | 85 + .../kimchi/ui/css/theme-default/template_add.css | 317 +++ .../kimchi/ui/css/theme-default/template_list.css | 267 +++ src/wok/plugins/kimchi/ui/images/Makefile.am | 22 + src/wok/plugins/kimchi/ui/images/icon-centos.png | Bin 0 -> 4734 bytes src/wok/plugins/kimchi/ui/images/icon-debian.png | Bin 0 -> 4239 bytes src/wok/plugins/kimchi/ui/images/icon-fedora.png | Bin 0 -> 4449 bytes src/wok/plugins/kimchi/ui/images/icon-gentoo.png | Bin 0 -> 15307 bytes src/wok/plugins/kimchi/ui/images/icon-opensuse.png | Bin 0 -> 3046 bytes src/wok/plugins/kimchi/ui/images/icon-ubuntu.png | Bin 0 -> 4818 bytes src/wok/plugins/kimchi/ui/images/icon-vm.png | Bin 0 -> 2976 bytes .../kimchi/ui/images/theme-default/Makefile.am | 20 + .../kimchi/ui/images/theme-default/ac22_pause.png | Bin 0 -> 1219 bytes .../ui/images/theme-default/ac22_pause_grey.png | Bin 0 -> 1175 bytes .../kimchi/ui/images/theme-default/ac24_resume.png | Bin 0 -> 1341 bytes .../ui/images/theme-default/ac24_resume_grey.png | Bin 0 -> 1282 bytes .../ui/images/theme-default/arrow-down-black.png | Bin 0 -> 2942 bytes .../ui/images/theme-default/arrow-down-disable.png | Bin 0 -> 472 bytes .../kimchi/ui/images/theme-default/arrow-down.png | Bin 0 -> 537 bytes .../kimchi/ui/images/theme-default/arrow-up.png | Bin 0 -> 510 bytes .../kimchi/ui/images/theme-default/arrow_out.png | Bin 0 -> 3048 bytes .../kimchi/ui/images/theme-default/group.png | Bin 0 -> 1703 bytes .../ui/images/theme-default/host-icon-sprite.png | Bin 0 -> 1034 bytes .../kimchi/ui/images/theme-default/icon-back.png | Bin 0 -> 244 bytes .../kimchi/ui/images/theme-default/icon-camera.png | Bin 0 -> 4860 bytes .../kimchi/ui/images/theme-default/icon-design.png | Bin 0 -> 4562 bytes .../kimchi/ui/images/theme-default/icon-detail.png | Bin 0 -> 3079 bytes .../kimchi/ui/images/theme-default/icon-iso.png | Bin 0 -> 4188 bytes .../kimchi/ui/images/theme-default/icon-list.png | Bin 0 -> 2983 bytes .../kimchi/ui/images/theme-default/icon-load.png | Bin 0 -> 3678 bytes .../kimchi/ui/images/theme-default/icon-local.png | Bin 0 -> 425 bytes .../ui/images/theme-default/icon-power-down.png | Bin 0 -> 4372 bytes .../ui/images/theme-default/icon-power-up.png | Bin 0 -> 4367 bytes .../kimchi/ui/images/theme-default/icon-qcow2.png | Bin 0 -> 4684 bytes .../kimchi/ui/images/theme-default/icon-raw.png | Bin 0 -> 4679 bytes .../kimchi/ui/images/theme-default/icon-remote.png | Bin 0 -> 1005 bytes .../kimchi/ui/images/theme-default/icon-reset.png | Bin 0 -> 4576 bytes .../kimchi/ui/images/theme-default/icon-search.png | Bin 0 -> 4197 bytes .../kimchi/ui/images/theme-default/icon-sort.png | Bin 0 -> 3421 bytes .../kimchi/ui/images/theme-default/icon-tree.png | Bin 0 -> 3526 bytes .../kimchi/ui/images/theme-default/icon-user.png | Bin 0 -> 5366 bytes .../images/theme-default/icon-volume-default.png | Bin 0 -> 4265 bytes .../images/theme-default/kimchi-loading15x15.gif | Bin 0 -> 1653 bytes .../kimchi/ui/images/theme-default/loading.gif | Bin 0 -> 2190 bytes .../kimchi/ui/images/theme-default/user.png | Bin 0 -> 1322 bytes src/wok/plugins/kimchi/ui/js/Makefile.am | 27 + src/wok/plugins/kimchi/ui/js/src/kimchi.api.js | 1355 +++++++++++ .../kimchi/ui/js/src/kimchi.guest_add_main.js | 86 + .../kimchi/ui/js/src/kimchi.guest_edit_main.js | 759 +++++++ .../plugins/kimchi/ui/js/src/kimchi.guest_main.js | 511 +++++ .../kimchi/ui/js/src/kimchi.guest_media_main.js | 56 + .../ui/js/src/kimchi.guest_storage_add.main.js | 199 ++ src/wok/plugins/kimchi/ui/js/src/kimchi.host.js | 858 +++++++ src/wok/plugins/kimchi/ui/js/src/kimchi.main.js | 26 + src/wok/plugins/kimchi/ui/js/src/kimchi.network.js | 442 ++++ .../kimchi/ui/js/src/kimchi.report_add_main.js | 72 + .../kimchi/ui/js/src/kimchi.report_rename_main.js | 66 + .../kimchi/ui/js/src/kimchi.repository_add_main.js | 96 + .../ui/js/src/kimchi.repository_edit_main.js | 74 + .../kimchi/ui/js/src/kimchi.storage_main.js | 428 ++++ .../ui/js/src/kimchi.storagepool_add_main.js | 414 ++++ .../js/src/kimchi.storagepool_add_volume_main.js | 179 ++ .../kimchi/ui/js/src/kimchi.template_add_main.js | 441 ++++ .../kimchi/ui/js/src/kimchi.template_edit_main.js | 343 +++ .../kimchi/ui/js/src/kimchi.template_main.js | 111 + src/wok/plugins/kimchi/ui/pages/Makefile.am | 22 + .../plugins/kimchi/ui/pages/guest-add.html.tmpl | 98 + .../plugins/kimchi/ui/pages/guest-edit.html.tmpl | 311 +++ .../kimchi/ui/pages/guest-storage-add.html.tmpl | 103 + src/wok/plugins/kimchi/ui/pages/guest.html.tmpl | 77 + src/wok/plugins/kimchi/ui/pages/guests.html.tmpl | 65 + src/wok/plugins/kimchi/ui/pages/help/Makefile.am | 34 + .../plugins/kimchi/ui/pages/help/de_DE/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/de_DE/guests.dita | 127 ++ .../plugins/kimchi/ui/pages/help/de_DE/host.dita | 49 + .../kimchi/ui/pages/help/de_DE/network.dita | 62 + .../kimchi/ui/pages/help/de_DE/storage.dita | 86 + .../kimchi/ui/pages/help/de_DE/templates.dita | 112 + src/wok/plugins/kimchi/ui/pages/help/dita-help.xsl | 26 + .../plugins/kimchi/ui/pages/help/en_US/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/en_US/guests.dita | 136 ++ .../plugins/kimchi/ui/pages/help/en_US/host.dita | 70 + .../kimchi/ui/pages/help/en_US/network.dita | 68 + .../kimchi/ui/pages/help/en_US/storage.dita | 99 + .../kimchi/ui/pages/help/en_US/templates.dita | 123 + .../plugins/kimchi/ui/pages/help/es_ES/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/es_ES/guests.dita | 120 + .../plugins/kimchi/ui/pages/help/es_ES/host.dita | 49 + .../kimchi/ui/pages/help/es_ES/network.dita | 61 + .../kimchi/ui/pages/help/es_ES/storage.dita | 86 + .../kimchi/ui/pages/help/es_ES/templates.dita | 111 + .../plugins/kimchi/ui/pages/help/fr_FR/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/fr_FR/guests.dita | 130 ++ .../plugins/kimchi/ui/pages/help/fr_FR/host.dita | 68 + .../kimchi/ui/pages/help/fr_FR/network.dita | 67 + .../kimchi/ui/pages/help/fr_FR/storage.dita | 93 + .../kimchi/ui/pages/help/fr_FR/templates.dita | 120 + .../plugins/kimchi/ui/pages/help/it_IT/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/it_IT/guests.dita | 123 + .../plugins/kimchi/ui/pages/help/it_IT/host.dita | 51 + .../kimchi/ui/pages/help/it_IT/network.dita | 63 + .../kimchi/ui/pages/help/it_IT/storage.dita | 91 + .../kimchi/ui/pages/help/it_IT/templates.dita | 115 + .../plugins/kimchi/ui/pages/help/ja_JP/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/ja_JP/guests.dita | 172 ++ .../plugins/kimchi/ui/pages/help/ja_JP/host.dita | 70 + .../kimchi/ui/pages/help/ja_JP/network.dita | 83 + .../kimchi/ui/pages/help/ja_JP/storage.dita | 120 + .../kimchi/ui/pages/help/ja_JP/templates.dita | 150 ++ src/wok/plugins/kimchi/ui/pages/help/kimchi.css | 208 ++ .../plugins/kimchi/ui/pages/help/ko_KR/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/ko_KR/guests.dita | 119 + .../plugins/kimchi/ui/pages/help/ko_KR/host.dita | 47 + .../kimchi/ui/pages/help/ko_KR/network.dita | 61 + .../kimchi/ui/pages/help/ko_KR/storage.dita | 86 + .../kimchi/ui/pages/help/ko_KR/templates.dita | 111 + .../plugins/kimchi/ui/pages/help/pt_BR/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/pt_BR/guests.dita | 137 ++ .../plugins/kimchi/ui/pages/help/pt_BR/host.dita | 74 + .../kimchi/ui/pages/help/pt_BR/network.dita | 72 + .../kimchi/ui/pages/help/pt_BR/storage.dita | 102 + .../kimchi/ui/pages/help/pt_BR/templates.dita | 127 ++ .../plugins/kimchi/ui/pages/help/ru_RU/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/ru_RU/guests.dita | 122 + .../plugins/kimchi/ui/pages/help/ru_RU/host.dita | 48 + .../kimchi/ui/pages/help/ru_RU/network.dita | 61 + .../kimchi/ui/pages/help/ru_RU/storage.dita | 88 + .../kimchi/ui/pages/help/ru_RU/templates.dita | 111 + .../plugins/kimchi/ui/pages/help/zh_CN/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/zh_CN/guests.dita | 118 + .../plugins/kimchi/ui/pages/help/zh_CN/host.dita | 45 + .../kimchi/ui/pages/help/zh_CN/network.dita | 61 + .../kimchi/ui/pages/help/zh_CN/storage.dita | 84 + .../kimchi/ui/pages/help/zh_CN/templates.dita | 111 + .../plugins/kimchi/ui/pages/help/zh_TW/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/zh_TW/guests.dita | 120 + .../plugins/kimchi/ui/pages/help/zh_TW/host.dita | 50 + .../kimchi/ui/pages/help/zh_TW/network.dita | 61 + .../kimchi/ui/pages/help/zh_TW/storage.dita | 88 + .../kimchi/ui/pages/help/zh_TW/templates.dita | 112 + src/wok/plugins/kimchi/ui/pages/host.html.tmpl | 177 ++ src/wok/plugins/kimchi/ui/pages/i18n.json.tmpl | 187 ++ src/wok/plugins/kimchi/ui/pages/network.html.tmpl | 133 ++ .../plugins/kimchi/ui/pages/report-add.html.tmpl | 56 + .../kimchi/ui/pages/report-rename.html.tmpl | 56 + .../kimchi/ui/pages/repository-add.html.tmpl | 113 + .../kimchi/ui/pages/repository-edit.html.tmpl | 117 + src/wok/plugins/kimchi/ui/pages/storage.html.tmpl | 143 ++ .../ui/pages/storagepool-add-volume.html.tmpl | 79 + .../kimchi/ui/pages/storagepool-add.html.tmpl | 186 ++ .../plugins/kimchi/ui/pages/template-add.html.tmpl | 233 ++ .../kimchi/ui/pages/template-edit.html.tmpl | 193 ++ .../plugins/kimchi/ui/pages/templates.html.tmpl | 77 + src/wok/plugins/kimchi/ui/robots.txt | 2 + src/wok/plugins/kimchi/ui/spice-html5/Makefile.am | 25 + .../plugins/kimchi/ui/spice-html5/atKeynames.js | 183 ++ src/wok/plugins/kimchi/ui/spice-html5/bitmap.js | 51 + .../plugins/kimchi/ui/spice-html5/css/Makefile.am | 20 + .../plugins/kimchi/ui/spice-html5/css/spice.css | 118 + src/wok/plugins/kimchi/ui/spice-html5/cursor.js | 110 + src/wok/plugins/kimchi/ui/spice-html5/display.js | 823 +++++++ src/wok/plugins/kimchi/ui/spice-html5/enums.js | 324 +++ src/wok/plugins/kimchi/ui/spice-html5/inputs.js | 280 +++ src/wok/plugins/kimchi/ui/spice-html5/lz.js | 166 ++ src/wok/plugins/kimchi/ui/spice-html5/main.js | 231 ++ .../kimchi/ui/spice-html5/pages/Makefile.am | 20 + .../kimchi/ui/spice-html5/pages/spice_auto.html | 200 ++ src/wok/plugins/kimchi/ui/spice-html5/playback.js | 278 +++ src/wok/plugins/kimchi/ui/spice-html5/png.js | 256 +++ src/wok/plugins/kimchi/ui/spice-html5/quic.js | 1335 +++++++++++ src/wok/plugins/kimchi/ui/spice-html5/resize.js | 70 + .../kimchi/ui/spice-html5/simulatecursor.js | 202 ++ .../kimchi/ui/spice-html5/spicearraybuffer.js | 58 + src/wok/plugins/kimchi/ui/spice-html5/spiceconn.js | 460 ++++ .../plugins/kimchi/ui/spice-html5/spicedataview.js | 120 + src/wok/plugins/kimchi/ui/spice-html5/spicemsg.js | 1047 +++++++++ src/wok/plugins/kimchi/ui/spice-html5/spicetype.js | 473 ++++ .../kimchi/ui/spice-html5/thirdparty/Makefile.am | 20 + .../kimchi/ui/spice-html5/thirdparty/jsbn.js | 589 +++++ .../kimchi/ui/spice-html5/thirdparty/prng4.js | 79 + .../kimchi/ui/spice-html5/thirdparty/rng.js | 102 + .../kimchi/ui/spice-html5/thirdparty/rsa.js | 146 ++ .../kimchi/ui/spice-html5/thirdparty/sha1.js | 346 +++ src/wok/plugins/kimchi/ui/spice-html5/ticket.js | 250 +++ src/wok/plugins/kimchi/ui/spice-html5/utils.js | 265 +++ src/wok/plugins/kimchi/ui/spice-html5/webm.js | 553 +++++ src/wok/plugins/kimchi/ui/spice-html5/wire.js | 123 + src/wok/plugins/kimchi/utils.py | 39 + src/wok/plugins/kimchi/vmtemplate.py | 431 ++++ src/wok/plugins/kimchi/vnc.py | 77 + src/wok/plugins/kimchi/xmlutils/Makefile.am | 25 + src/wok/plugins/kimchi/xmlutils/__init__.py | 18 + src/wok/plugins/kimchi/xmlutils/cpu.py | 60 + src/wok/plugins/kimchi/xmlutils/disk.py | 164 ++ src/wok/plugins/kimchi/xmlutils/graphics.py | 45 + src/wok/plugins/kimchi/xmlutils/interface.py | 61 + src/wok/plugins/kimchi/xmlutils/network.py | 122 + src/wok/plugins/kimchi/xmlutils/qemucmdline.py | 45 + src/wok/plugins/kimchi/yumparser.py | 283 +++ src/wok/plugins/sample/API.json | 56 + src/wok/plugins/sample/Makefile.am | 29 + src/wok/plugins/sample/__init__.py | 97 + src/wok/plugins/sample/config.status | 1 + src/wok/plugins/sample/i18n.py | 40 + src/wok/plugins/sample/model.py | 131 ++ src/wok/plugins/sample/po/LINGUAS | 3 + src/wok/plugins/sample/po/Makefile.in.in | 400 ++++ src/wok/plugins/sample/po/Makevars | 41 + src/wok/plugins/sample/po/POTFILES.in | 2 + src/wok/plugins/sample/po/en_US.po | 21 + src/wok/plugins/sample/po/gen-pot | 9 + src/wok/plugins/sample/po/pt_BR.po | 24 + src/wok/plugins/sample/po/sample.pot | 21 + src/wok/plugins/sample/po/zh_CN.po | 24 + src/wok/plugins/sample/sample.conf.in | 27 + src/wok/plugins/sample/ui/Makefile.am | 22 + src/wok/plugins/sample/ui/config/Makefile.am | 21 + src/wok/plugins/sample/ui/config/tab-ext.xml | 17 + src/wok/plugins/sample/ui/css/.gitignore | 0 src/wok/plugins/sample/ui/images/.gitignore | 0 src/wok/plugins/sample/ui/js/.gitignore | 0 src/wok/plugins/sample/ui/js/Makefile.am | 20 + src/wok/plugins/sample/ui/js/util.js | 33 + src/wok/plugins/sample/ui/libs/.gitignore | 0 src/wok/plugins/sample/ui/pages/Makefile.am | 20 + .../sample/ui/pages/help/en_US/sample-tab1.html | 1 + .../sample/ui/pages/help/en_US/sample-tab2.html | 1 + src/wok/plugins/sample/ui/pages/i18n.json.tmpl | 26 + .../plugins/sample/ui/pages/sample-tab1.html.tmpl | 30 + .../plugins/sample/ui/pages/sample-tab2.html.tmpl | 30 + 809 files changed, 84521 insertions(+), 81955 deletions(-) delete mode 100644 plugins/Makefile.am delete mode 100644 plugins/__init__.py delete mode 100644 plugins/kimchi/.gitignore delete mode 100644 plugins/kimchi/API.json delete mode 100644 plugins/kimchi/INSTALL delete mode 100644 plugins/kimchi/Makefile.am delete mode 120000 plugins/kimchi/README.md delete mode 100644 plugins/kimchi/VERSION delete mode 100644 plugins/kimchi/__init__.py delete mode 100755 plugins/kimchi/autogen.sh delete mode 100644 plugins/kimchi/build-aux/config.rpath delete mode 100755 plugins/kimchi/build-aux/genChangelog delete mode 100755 plugins/kimchi/build-aux/pkg-version delete mode 100644 plugins/kimchi/config.py.in delete mode 100644 plugins/kimchi/config.rpath delete mode 100644 plugins/kimchi/configure.ac delete mode 100644 plugins/kimchi/contrib/DEBIAN/Makefile.am delete mode 100644 plugins/kimchi/contrib/DEBIAN/control.in delete mode 100644 plugins/kimchi/contrib/Makefile.am delete mode 100755 plugins/kimchi/contrib/check_i18n.py delete mode 100644 plugins/kimchi/contrib/kimchi.spec.fedora.in delete mode 100644 plugins/kimchi/contrib/kimchi.spec.suse.in delete mode 100644 plugins/kimchi/contrib/make-deb.sh.in delete mode 100644 plugins/kimchi/control/Makefile.am delete mode 100644 plugins/kimchi/control/__init__.py delete mode 100644 plugins/kimchi/control/config.py delete mode 100644 plugins/kimchi/control/cpuinfo.py delete mode 100644 plugins/kimchi/control/debugreports.py delete mode 100644 plugins/kimchi/control/groups.py delete mode 100644 plugins/kimchi/control/host.py delete mode 100644 plugins/kimchi/control/interfaces.py delete mode 100644 plugins/kimchi/control/networks.py delete mode 100644 plugins/kimchi/control/peers.py delete mode 100644 plugins/kimchi/control/storagepools.py delete mode 100644 plugins/kimchi/control/storageservers.py delete mode 100644 plugins/kimchi/control/storagevolumes.py delete mode 100644 plugins/kimchi/control/templates.py delete mode 100644 plugins/kimchi/control/users.py delete mode 100644 plugins/kimchi/control/vm/Makefile.am delete mode 100644 plugins/kimchi/control/vm/__init__.py delete mode 100644 plugins/kimchi/control/vm/hostdevs.py delete mode 100644 plugins/kimchi/control/vm/ifaces.py delete mode 100644 plugins/kimchi/control/vm/snapshots.py delete mode 100644 plugins/kimchi/control/vm/storages.py delete mode 100644 plugins/kimchi/control/vms.py delete mode 100644 plugins/kimchi/disks.py delete mode 100644 plugins/kimchi/distroloader.py delete mode 100644 plugins/kimchi/distros.d/Makefile.am delete mode 100644 plugins/kimchi/distros.d/debian.json delete mode 100644 plugins/kimchi/distros.d/fedora.json delete mode 100644 plugins/kimchi/distros.d/gentoo.json delete mode 100644 plugins/kimchi/distros.d/opensuse.json delete mode 100644 plugins/kimchi/distros.d/ubuntu.json delete mode 100644 plugins/kimchi/docs/API.md delete mode 100644 plugins/kimchi/docs/Makefile.am delete mode 100644 plugins/kimchi/docs/README-federation.md delete mode 100644 plugins/kimchi/docs/README.md delete mode 100644 plugins/kimchi/docs/kimchi-guest.png delete mode 100644 plugins/kimchi/docs/kimchi-login.png delete mode 100644 plugins/kimchi/docs/kimchi-templates.png delete mode 100644 plugins/kimchi/i18n.py delete mode 100644 plugins/kimchi/imageinfo.py delete mode 100644 plugins/kimchi/iscsi.py delete mode 100644 plugins/kimchi/isoinfo.py delete mode 100644 plugins/kimchi/kimchi.conf delete mode 100644 plugins/kimchi/kvmusertests.py delete mode 100644 plugins/kimchi/m4/ac_python_module.m4 delete mode 100644 plugins/kimchi/m4/gettext.m4 delete mode 100644 plugins/kimchi/m4/iconv.m4 delete mode 100644 plugins/kimchi/m4/intlmacosx.m4 delete mode 100644 plugins/kimchi/m4/lib-ld.m4 delete mode 100644 plugins/kimchi/m4/lib-link.m4 delete mode 100644 plugins/kimchi/m4/lib-prefix.m4 delete mode 100644 plugins/kimchi/m4/nls.m4 delete mode 100644 plugins/kimchi/m4/po.m4 delete mode 100644 plugins/kimchi/m4/progtest.m4 delete mode 100644 plugins/kimchi/mockmodel.py delete mode 100644 plugins/kimchi/model/Makefile.am delete mode 100644 plugins/kimchi/model/__init__.py delete mode 100644 plugins/kimchi/model/config.py delete mode 100644 plugins/kimchi/model/cpuinfo.py delete mode 100644 plugins/kimchi/model/debugreports.py delete mode 100644 plugins/kimchi/model/diskutils.py delete mode 100644 plugins/kimchi/model/featuretests.py delete mode 100644 plugins/kimchi/model/groups.py delete mode 100644 plugins/kimchi/model/host.py delete mode 100644 plugins/kimchi/model/hostdev.py delete mode 100644 plugins/kimchi/model/interfaces.py delete mode 100644 plugins/kimchi/model/libvirtconnection.py delete mode 100644 plugins/kimchi/model/libvirtstoragepool.py delete mode 100644 plugins/kimchi/model/model.py delete mode 100644 plugins/kimchi/model/networks.py delete mode 100644 plugins/kimchi/model/peers.py delete mode 100644 plugins/kimchi/model/storagepools.py delete mode 100644 plugins/kimchi/model/storageservers.py delete mode 100644 plugins/kimchi/model/storagetargets.py delete mode 100644 plugins/kimchi/model/storagevolumes.py delete mode 100644 plugins/kimchi/model/templates.py delete mode 100644 plugins/kimchi/model/users.py delete mode 100644 plugins/kimchi/model/utils.py delete mode 100644 plugins/kimchi/model/vmhostdevs.py delete mode 100644 plugins/kimchi/model/vmifaces.py delete mode 100644 plugins/kimchi/model/vms.py delete mode 100644 plugins/kimchi/model/vmsnapshots.py delete mode 100644 plugins/kimchi/model/vmstorages.py delete mode 100644 plugins/kimchi/netinfo.py delete mode 100644 plugins/kimchi/network.py delete mode 100644 plugins/kimchi/osinfo.py delete mode 100644 plugins/kimchi/po/LINGUAS delete mode 100644 plugins/kimchi/po/Makefile.in.in delete mode 100644 plugins/kimchi/po/Makevars delete mode 100644 plugins/kimchi/po/POTFILES.in delete mode 100644 plugins/kimchi/po/de_DE.po delete mode 100644 plugins/kimchi/po/en_US.po delete mode 100644 plugins/kimchi/po/es_ES.po delete mode 100644 plugins/kimchi/po/fr_FR.po delete mode 100644 plugins/kimchi/po/gen-pot.in delete mode 100644 plugins/kimchi/po/it_IT.po delete mode 100644 plugins/kimchi/po/ja_JP.po delete mode 100755 plugins/kimchi/po/kimchi.pot delete mode 100644 plugins/kimchi/po/ko_KR.po delete mode 100644 plugins/kimchi/po/pt_BR.po delete mode 100644 plugins/kimchi/po/ru_RU.po delete mode 100644 plugins/kimchi/po/zh_CN.po delete mode 100644 plugins/kimchi/po/zh_TW.po delete mode 100644 plugins/kimchi/repositories.py delete mode 100644 plugins/kimchi/root.py delete mode 100644 plugins/kimchi/scan.py delete mode 100644 plugins/kimchi/screenshot.py delete mode 100644 plugins/kimchi/swupdate.py delete mode 100644 plugins/kimchi/template.conf delete mode 100644 plugins/kimchi/tests/Makefile.am delete mode 100644 plugins/kimchi/tests/iso_gen.py delete mode 100644 plugins/kimchi/tests/run_tests.sh.in delete mode 100644 plugins/kimchi/tests/test_authorization.py delete mode 100644 plugins/kimchi/tests/test_config.py.in delete mode 100644 plugins/kimchi/tests/test_host.py delete mode 100644 plugins/kimchi/tests/test_mock_network.py delete mode 100644 plugins/kimchi/tests/test_mock_storagepool.py delete mode 100644 plugins/kimchi/tests/test_mock_storagevolume.py delete mode 100644 plugins/kimchi/tests/test_mockmodel.py delete mode 100644 plugins/kimchi/tests/test_model.py delete mode 100644 plugins/kimchi/tests/test_model_network.py delete mode 100644 plugins/kimchi/tests/test_model_storagepool.py delete mode 100644 plugins/kimchi/tests/test_model_storagevolume.py delete mode 100644 plugins/kimchi/tests/test_networkxml.py delete mode 100644 plugins/kimchi/tests/test_osinfo.py delete mode 100644 plugins/kimchi/tests/test_rest.py delete mode 100644 plugins/kimchi/tests/test_storagepoolxml.py delete mode 100644 plugins/kimchi/tests/test_template.py delete mode 100644 plugins/kimchi/tests/test_vmtemplate.py delete mode 100644 plugins/kimchi/tests/test_yumparser.py delete mode 100644 plugins/kimchi/tests/utils.py delete mode 100644 plugins/kimchi/ui/Makefile.am delete mode 100644 plugins/kimchi/ui/config/Makefile.am delete mode 100644 plugins/kimchi/ui/config/tab-ext.xml delete mode 100644 plugins/kimchi/ui/css/Makefile.am delete mode 100644 plugins/kimchi/ui/css/theme-default/guest-edit.css delete mode 100644 plugins/kimchi/ui/css/theme-default/guest-storage-add.css delete mode 100644 plugins/kimchi/ui/css/theme-default/host.css delete mode 100644 plugins/kimchi/ui/css/theme-default/icon.css delete mode 100644 plugins/kimchi/ui/css/theme-default/list.css delete mode 100644 plugins/kimchi/ui/css/theme-default/network.css delete mode 100644 plugins/kimchi/ui/css/theme-default/report-add.css delete mode 100644 plugins/kimchi/ui/css/theme-default/report-rename.css delete mode 100644 plugins/kimchi/ui/css/theme-default/repository-add.css delete mode 100644 plugins/kimchi/ui/css/theme-default/repository-edit.css delete mode 100644 plugins/kimchi/ui/css/theme-default/storage.css delete mode 100644 plugins/kimchi/ui/css/theme-default/storagepool-add-volume.css delete mode 100644 plugins/kimchi/ui/css/theme-default/template-edit.css delete mode 100644 plugins/kimchi/ui/css/theme-default/template.css delete mode 100644 plugins/kimchi/ui/css/theme-default/template_add.css delete mode 100644 plugins/kimchi/ui/css/theme-default/template_list.css delete mode 100644 plugins/kimchi/ui/images/Makefile.am delete mode 100644 plugins/kimchi/ui/images/icon-centos.png delete mode 100644 plugins/kimchi/ui/images/icon-debian.png delete mode 100644 plugins/kimchi/ui/images/icon-fedora.png delete mode 100644 plugins/kimchi/ui/images/icon-gentoo.png delete mode 100644 plugins/kimchi/ui/images/icon-opensuse.png delete mode 100644 plugins/kimchi/ui/images/icon-ubuntu.png delete mode 100644 plugins/kimchi/ui/images/icon-vm.png delete mode 100644 plugins/kimchi/ui/images/theme-default/Makefile.am delete mode 100644 plugins/kimchi/ui/images/theme-default/ac22_pause.png delete mode 100644 plugins/kimchi/ui/images/theme-default/ac22_pause_grey.png delete mode 100644 plugins/kimchi/ui/images/theme-default/ac24_resume.png delete mode 100644 plugins/kimchi/ui/images/theme-default/ac24_resume_grey.png delete mode 100644 plugins/kimchi/ui/images/theme-default/arrow-down-black.png delete mode 100644 plugins/kimchi/ui/images/theme-default/arrow-down-disable.png delete mode 100644 plugins/kimchi/ui/images/theme-default/arrow-down.png delete mode 100644 plugins/kimchi/ui/images/theme-default/arrow-up.png delete mode 100644 plugins/kimchi/ui/images/theme-default/arrow_out.png delete mode 100644 plugins/kimchi/ui/images/theme-default/group.png delete mode 100644 plugins/kimchi/ui/images/theme-default/host-icon-sprite.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-back.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-camera.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-design.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-detail.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-iso.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-list.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-load.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-local.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-power-down.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-power-up.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-qcow2.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-raw.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-remote.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-reset.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-search.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-sort.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-tree.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-user.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-volume-default.png delete mode 100644 plugins/kimchi/ui/images/theme-default/kimchi-loading15x15.gif delete mode 100644 plugins/kimchi/ui/images/theme-default/loading.gif delete mode 100644 plugins/kimchi/ui/images/theme-default/user.png delete mode 100644 plugins/kimchi/ui/js/Makefile.am delete mode 100644 plugins/kimchi/ui/js/src/kimchi.api.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.guest_add_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.guest_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.guest_media_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.guest_storage_add.main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.host.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.network.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.report_add_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.report_rename_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.repository_add_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.storage_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.storagepool_add_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.storagepool_add_volume_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.template_add_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.template_edit_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.template_main.js delete mode 100644 plugins/kimchi/ui/pages/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/guest-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/guest-edit.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/guest-storage-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/guest.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/guests.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/help/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/dita-help.xsl delete mode 100644 plugins/kimchi/ui/pages/help/en_US/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/en_US/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/en_US/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/en_US/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/en_US/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/en_US/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/kimchi.css delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/templates.dita delete mode 100644 plugins/kimchi/ui/pages/host.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/i18n.json.tmpl delete mode 100644 plugins/kimchi/ui/pages/network.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/report-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/report-rename.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/repository-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/repository-edit.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/storage.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/storagepool-add-volume.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/storagepool-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/template-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/template-edit.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/templates.html.tmpl delete mode 100644 plugins/kimchi/ui/robots.txt delete mode 100644 plugins/kimchi/ui/spice-html5/Makefile.am delete mode 100644 plugins/kimchi/ui/spice-html5/atKeynames.js delete mode 100644 plugins/kimchi/ui/spice-html5/bitmap.js delete mode 100644 plugins/kimchi/ui/spice-html5/css/Makefile.am delete mode 100644 plugins/kimchi/ui/spice-html5/css/spice.css delete mode 100644 plugins/kimchi/ui/spice-html5/cursor.js delete mode 100644 plugins/kimchi/ui/spice-html5/display.js delete mode 100644 plugins/kimchi/ui/spice-html5/enums.js delete mode 100644 plugins/kimchi/ui/spice-html5/inputs.js delete mode 100644 plugins/kimchi/ui/spice-html5/lz.js delete mode 100644 plugins/kimchi/ui/spice-html5/main.js delete mode 100644 plugins/kimchi/ui/spice-html5/pages/Makefile.am delete mode 100644 plugins/kimchi/ui/spice-html5/pages/spice_auto.html delete mode 100644 plugins/kimchi/ui/spice-html5/playback.js delete mode 100644 plugins/kimchi/ui/spice-html5/png.js delete mode 100644 plugins/kimchi/ui/spice-html5/quic.js delete mode 100644 plugins/kimchi/ui/spice-html5/resize.js delete mode 100644 plugins/kimchi/ui/spice-html5/simulatecursor.js delete mode 100644 plugins/kimchi/ui/spice-html5/spicearraybuffer.js delete mode 100644 plugins/kimchi/ui/spice-html5/spiceconn.js delete mode 100644 plugins/kimchi/ui/spice-html5/spicedataview.js delete mode 100644 plugins/kimchi/ui/spice-html5/spicemsg.js delete mode 100644 plugins/kimchi/ui/spice-html5/spicetype.js delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/Makefile.am delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/prng4.js delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/rng.js delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/rsa.js delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/sha1.js delete mode 100644 plugins/kimchi/ui/spice-html5/ticket.js delete mode 100644 plugins/kimchi/ui/spice-html5/utils.js delete mode 100644 plugins/kimchi/ui/spice-html5/webm.js delete mode 100644 plugins/kimchi/ui/spice-html5/wire.js delete mode 100644 plugins/kimchi/utils.py delete mode 100644 plugins/kimchi/vmtemplate.py delete mode 100644 plugins/kimchi/vnc.py delete mode 100644 plugins/kimchi/xmlutils/Makefile.am delete mode 100644 plugins/kimchi/xmlutils/__init__.py delete mode 100644 plugins/kimchi/xmlutils/cpu.py delete mode 100644 plugins/kimchi/xmlutils/disk.py delete mode 100644 plugins/kimchi/xmlutils/graphics.py delete mode 100644 plugins/kimchi/xmlutils/interface.py delete mode 100644 plugins/kimchi/xmlutils/network.py delete mode 100644 plugins/kimchi/xmlutils/qemucmdline.py delete mode 100644 plugins/kimchi/yumparser.py delete mode 100644 plugins/sample/API.json delete mode 100644 plugins/sample/Makefile.am delete mode 100644 plugins/sample/__init__.py delete mode 120000 plugins/sample/config.status delete mode 100644 plugins/sample/i18n.py delete mode 100644 plugins/sample/model.py delete mode 100644 plugins/sample/po/LINGUAS delete mode 100644 plugins/sample/po/Makefile.in.in delete mode 100644 plugins/sample/po/Makevars delete mode 100644 plugins/sample/po/POTFILES.in delete mode 100644 plugins/sample/po/en_US.po delete mode 100755 plugins/sample/po/gen-pot delete mode 100644 plugins/sample/po/pt_BR.po delete mode 100644 plugins/sample/po/sample.pot delete mode 100644 plugins/sample/po/zh_CN.po delete mode 100644 plugins/sample/sample.conf.in delete mode 100644 plugins/sample/ui/Makefile.am delete mode 100644 plugins/sample/ui/config/Makefile.am delete mode 100644 plugins/sample/ui/config/tab-ext.xml delete mode 100644 plugins/sample/ui/css/.gitignore delete mode 100644 plugins/sample/ui/images/.gitignore delete mode 100644 plugins/sample/ui/js/.gitignore delete mode 100644 plugins/sample/ui/js/Makefile.am delete mode 100644 plugins/sample/ui/js/util.js delete mode 100644 plugins/sample/ui/libs/.gitignore delete mode 100644 plugins/sample/ui/pages/Makefile.am delete mode 100644 plugins/sample/ui/pages/help/en_US/sample-tab1.html delete mode 100644 plugins/sample/ui/pages/help/en_US/sample-tab2.html delete mode 100644 plugins/sample/ui/pages/i18n.json.tmpl delete mode 100644 plugins/sample/ui/pages/sample-tab1.html.tmpl delete mode 100644 plugins/sample/ui/pages/sample-tab2.html.tmpl create mode 100644 src/wok/plugins/Makefile.am create mode 100644 src/wok/plugins/__init__.py create mode 100644 src/wok/plugins/kimchi/.gitignore create mode 100644 src/wok/plugins/kimchi/API.json create mode 100644 src/wok/plugins/kimchi/CONTRIBUTE.md create mode 100644 src/wok/plugins/kimchi/COPYING create mode 100644 src/wok/plugins/kimchi/COPYING.ASL2 create mode 100644 src/wok/plugins/kimchi/COPYING.LGPL create mode 100644 src/wok/plugins/kimchi/ChangeLog create mode 100644 src/wok/plugins/kimchi/INSTALL create mode 100644 src/wok/plugins/kimchi/Makefile.am create mode 120000 src/wok/plugins/kimchi/README.md create mode 100644 src/wok/plugins/kimchi/VERSION create mode 100644 src/wok/plugins/kimchi/__init__.py create mode 100755 src/wok/plugins/kimchi/autogen.sh create mode 100644 src/wok/plugins/kimchi/build-aux/config.rpath create mode 100755 src/wok/plugins/kimchi/build-aux/genChangelog create mode 100755 src/wok/plugins/kimchi/build-aux/pkg-version create mode 100644 src/wok/plugins/kimchi/config.py.in create mode 100644 src/wok/plugins/kimchi/config.rpath create mode 100644 src/wok/plugins/kimchi/configure.ac create mode 100644 src/wok/plugins/kimchi/contrib/DEBIAN/Makefile.am create mode 100644 src/wok/plugins/kimchi/contrib/DEBIAN/control.in create mode 100644 src/wok/plugins/kimchi/contrib/Makefile.am create mode 100755 src/wok/plugins/kimchi/contrib/check_i18n.py create mode 100644 src/wok/plugins/kimchi/contrib/kimchi.spec.fedora.in create mode 100644 src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in create mode 100644 src/wok/plugins/kimchi/contrib/make-deb.sh.in create mode 100644 src/wok/plugins/kimchi/control/Makefile.am create mode 100644 src/wok/plugins/kimchi/control/__init__.py create mode 100644 src/wok/plugins/kimchi/control/config.py create mode 100644 src/wok/plugins/kimchi/control/cpuinfo.py create mode 100644 src/wok/plugins/kimchi/control/debugreports.py create mode 100644 src/wok/plugins/kimchi/control/groups.py create mode 100644 src/wok/plugins/kimchi/control/host.py create mode 100644 src/wok/plugins/kimchi/control/interfaces.py create mode 100644 src/wok/plugins/kimchi/control/networks.py create mode 100644 src/wok/plugins/kimchi/control/peers.py create mode 100644 src/wok/plugins/kimchi/control/storagepools.py create mode 100644 src/wok/plugins/kimchi/control/storageservers.py create mode 100644 src/wok/plugins/kimchi/control/storagevolumes.py create mode 100644 src/wok/plugins/kimchi/control/templates.py create mode 100644 src/wok/plugins/kimchi/control/users.py create mode 100644 src/wok/plugins/kimchi/control/vm/Makefile.am create mode 100644 src/wok/plugins/kimchi/control/vm/__init__.py create mode 100644 src/wok/plugins/kimchi/control/vm/hostdevs.py create mode 100644 src/wok/plugins/kimchi/control/vm/ifaces.py create mode 100644 src/wok/plugins/kimchi/control/vm/snapshots.py create mode 100644 src/wok/plugins/kimchi/control/vm/storages.py create mode 100644 src/wok/plugins/kimchi/control/vms.py create mode 100644 src/wok/plugins/kimchi/disks.py create mode 100644 src/wok/plugins/kimchi/distroloader.py create mode 100644 src/wok/plugins/kimchi/distros.d/Makefile.am create mode 100644 src/wok/plugins/kimchi/distros.d/debian.json create mode 100644 src/wok/plugins/kimchi/distros.d/fedora.json create mode 100644 src/wok/plugins/kimchi/distros.d/gentoo.json create mode 100644 src/wok/plugins/kimchi/distros.d/opensuse.json create mode 100644 src/wok/plugins/kimchi/distros.d/ubuntu.json create mode 100644 src/wok/plugins/kimchi/docs/API.md create mode 100644 src/wok/plugins/kimchi/docs/Makefile.am create mode 100644 src/wok/plugins/kimchi/docs/README-federation.md create mode 100644 src/wok/plugins/kimchi/docs/README.md create mode 100644 src/wok/plugins/kimchi/docs/kimchi-guest.png create mode 100644 src/wok/plugins/kimchi/docs/kimchi-login.png create mode 100644 src/wok/plugins/kimchi/docs/kimchi-templates.png create mode 100644 src/wok/plugins/kimchi/i18n.py create mode 100644 src/wok/plugins/kimchi/imageinfo.py create mode 100644 src/wok/plugins/kimchi/iscsi.py create mode 100644 src/wok/plugins/kimchi/isoinfo.py create mode 100644 src/wok/plugins/kimchi/kimchi.conf create mode 100644 src/wok/plugins/kimchi/kvmusertests.py create mode 100644 src/wok/plugins/kimchi/m4/ac_python_module.m4 create mode 100644 src/wok/plugins/kimchi/m4/gettext.m4 create mode 100644 src/wok/plugins/kimchi/m4/iconv.m4 create mode 100644 src/wok/plugins/kimchi/m4/intlmacosx.m4 create mode 100644 src/wok/plugins/kimchi/m4/lib-ld.m4 create mode 100644 src/wok/plugins/kimchi/m4/lib-link.m4 create mode 100644 src/wok/plugins/kimchi/m4/lib-prefix.m4 create mode 100644 src/wok/plugins/kimchi/m4/nls.m4 create mode 100644 src/wok/plugins/kimchi/m4/po.m4 create mode 100644 src/wok/plugins/kimchi/m4/progtest.m4 create mode 100644 src/wok/plugins/kimchi/mockmodel.py create mode 100644 src/wok/plugins/kimchi/model/Makefile.am create mode 100644 src/wok/plugins/kimchi/model/__init__.py create mode 100644 src/wok/plugins/kimchi/model/config.py create mode 100644 src/wok/plugins/kimchi/model/cpuinfo.py create mode 100644 src/wok/plugins/kimchi/model/debugreports.py create mode 100644 src/wok/plugins/kimchi/model/diskutils.py create mode 100644 src/wok/plugins/kimchi/model/featuretests.py create mode 100644 src/wok/plugins/kimchi/model/groups.py create mode 100644 src/wok/plugins/kimchi/model/host.py create mode 100644 src/wok/plugins/kimchi/model/hostdev.py create mode 100644 src/wok/plugins/kimchi/model/interfaces.py create mode 100644 src/wok/plugins/kimchi/model/libvirtconnection.py create mode 100644 src/wok/plugins/kimchi/model/libvirtstoragepool.py create mode 100644 src/wok/plugins/kimchi/model/model.py create mode 100644 src/wok/plugins/kimchi/model/networks.py create mode 100644 src/wok/plugins/kimchi/model/peers.py create mode 100644 src/wok/plugins/kimchi/model/storagepools.py create mode 100644 src/wok/plugins/kimchi/model/storageservers.py create mode 100644 src/wok/plugins/kimchi/model/storagetargets.py create mode 100644 src/wok/plugins/kimchi/model/storagevolumes.py create mode 100644 src/wok/plugins/kimchi/model/templates.py create mode 100644 src/wok/plugins/kimchi/model/users.py create mode 100644 src/wok/plugins/kimchi/model/utils.py create mode 100644 src/wok/plugins/kimchi/model/vmhostdevs.py create mode 100644 src/wok/plugins/kimchi/model/vmifaces.py create mode 100644 src/wok/plugins/kimchi/model/vms.py create mode 100644 src/wok/plugins/kimchi/model/vmsnapshots.py create mode 100644 src/wok/plugins/kimchi/model/vmstorages.py create mode 100644 src/wok/plugins/kimchi/netinfo.py create mode 100644 src/wok/plugins/kimchi/network.py create mode 100644 src/wok/plugins/kimchi/osinfo.py create mode 100644 src/wok/plugins/kimchi/po/LINGUAS create mode 100644 src/wok/plugins/kimchi/po/Makefile.in.in create mode 100644 src/wok/plugins/kimchi/po/Makevars create mode 100644 src/wok/plugins/kimchi/po/POTFILES.in create mode 100644 src/wok/plugins/kimchi/po/de_DE.po create mode 100644 src/wok/plugins/kimchi/po/en_US.po create mode 100644 src/wok/plugins/kimchi/po/es_ES.po create mode 100644 src/wok/plugins/kimchi/po/fr_FR.po create mode 100644 src/wok/plugins/kimchi/po/gen-pot.in create mode 100644 src/wok/plugins/kimchi/po/it_IT.po create mode 100644 src/wok/plugins/kimchi/po/ja_JP.po create mode 100755 src/wok/plugins/kimchi/po/kimchi.pot create mode 100644 src/wok/plugins/kimchi/po/ko_KR.po create mode 100644 src/wok/plugins/kimchi/po/pt_BR.po create mode 100644 src/wok/plugins/kimchi/po/ru_RU.po create mode 100644 src/wok/plugins/kimchi/po/zh_CN.po create mode 100644 src/wok/plugins/kimchi/po/zh_TW.po create mode 100644 src/wok/plugins/kimchi/repositories.py create mode 100644 src/wok/plugins/kimchi/root.py create mode 100644 src/wok/plugins/kimchi/scan.py create mode 100644 src/wok/plugins/kimchi/screenshot.py create mode 100644 src/wok/plugins/kimchi/swupdate.py create mode 100644 src/wok/plugins/kimchi/template.conf create mode 100644 src/wok/plugins/kimchi/tests/Makefile.am create mode 100644 src/wok/plugins/kimchi/tests/iso_gen.py create mode 100644 src/wok/plugins/kimchi/tests/run_tests.sh.in create mode 100644 src/wok/plugins/kimchi/tests/test_authorization.py create mode 100644 src/wok/plugins/kimchi/tests/test_config.py.in create mode 100644 src/wok/plugins/kimchi/tests/test_host.py create mode 100644 src/wok/plugins/kimchi/tests/test_mock_network.py create mode 100644 src/wok/plugins/kimchi/tests/test_mock_storagepool.py create mode 100644 src/wok/plugins/kimchi/tests/test_mock_storagevolume.py create mode 100644 src/wok/plugins/kimchi/tests/test_mockmodel.py create mode 100644 src/wok/plugins/kimchi/tests/test_model.py create mode 100644 src/wok/plugins/kimchi/tests/test_model_network.py create mode 100644 src/wok/plugins/kimchi/tests/test_model_storagepool.py create mode 100644 src/wok/plugins/kimchi/tests/test_model_storagevolume.py create mode 100644 src/wok/plugins/kimchi/tests/test_networkxml.py create mode 100644 src/wok/plugins/kimchi/tests/test_osinfo.py create mode 100644 src/wok/plugins/kimchi/tests/test_rest.py create mode 100644 src/wok/plugins/kimchi/tests/test_storagepoolxml.py create mode 100644 src/wok/plugins/kimchi/tests/test_template.py create mode 100644 src/wok/plugins/kimchi/tests/test_vmtemplate.py create mode 100644 src/wok/plugins/kimchi/tests/test_yumparser.py create mode 100644 src/wok/plugins/kimchi/tests/utils.py create mode 100644 src/wok/plugins/kimchi/ui/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/config/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/config/tab-ext.xml create mode 100644 src/wok/plugins/kimchi/ui/css/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/guest-edit.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/guest-storage-add.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/host.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/icon.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/list.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/network.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/report-add.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/report-rename.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/repository-add.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/repository-edit.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/storage.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/storagepool-add-volume.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/template-edit.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/template.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/template_add.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/template_list.css create mode 100644 src/wok/plugins/kimchi/ui/images/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/images/icon-centos.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-debian.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-fedora.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-gentoo.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-opensuse.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-ubuntu.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-vm.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/ac22_pause.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/ac22_pause_grey.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/ac24_resume.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/ac24_resume_grey.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/arrow-down-black.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/arrow-down-disable.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/arrow-down.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/arrow-up.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/arrow_out.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/group.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/host-icon-sprite.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-back.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-camera.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-design.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-detail.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-iso.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-list.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-load.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-local.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-power-down.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-power-up.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-qcow2.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-raw.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-remote.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-reset.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-search.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-sort.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-tree.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-user.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-volume-default.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/kimchi-loading15x15.gif create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/loading.gif create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/user.png create mode 100644 src/wok/plugins/kimchi/ui/js/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.api.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.guest_add_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.guest_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.guest_media_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.guest_storage_add.main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.host.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.network.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.report_add_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.storage_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.storagepool_add_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.storagepool_add_volume_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.template_add_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.template_main.js create mode 100644 src/wok/plugins/kimchi/ui/pages/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/guest-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/guest-edit.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/guest-storage-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/guest.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/guests.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/help/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/dita-help.xsl create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/kimchi.css create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/host.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/i18n.json.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/network.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/report-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/report-rename.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/repository-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/repository-edit.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/storage.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/storagepool-add-volume.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/storagepool-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/template-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/template-edit.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/templates.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/robots.txt create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/atKeynames.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/bitmap.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/css/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/css/spice.css create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/cursor.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/display.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/enums.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/inputs.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/lz.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/main.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/pages/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/pages/spice_auto.html create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/playback.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/png.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/quic.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/resize.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/simulatecursor.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/spicearraybuffer.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/spiceconn.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/spicedataview.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/spicemsg.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/spicetype.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/prng4.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/rng.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/rsa.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/sha1.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/ticket.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/utils.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/webm.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/wire.js create mode 100644 src/wok/plugins/kimchi/utils.py create mode 100644 src/wok/plugins/kimchi/vmtemplate.py create mode 100644 src/wok/plugins/kimchi/vnc.py create mode 100644 src/wok/plugins/kimchi/xmlutils/Makefile.am create mode 100644 src/wok/plugins/kimchi/xmlutils/__init__.py create mode 100644 src/wok/plugins/kimchi/xmlutils/cpu.py create mode 100644 src/wok/plugins/kimchi/xmlutils/disk.py create mode 100644 src/wok/plugins/kimchi/xmlutils/graphics.py create mode 100644 src/wok/plugins/kimchi/xmlutils/interface.py create mode 100644 src/wok/plugins/kimchi/xmlutils/network.py create mode 100644 src/wok/plugins/kimchi/xmlutils/qemucmdline.py create mode 100644 src/wok/plugins/kimchi/yumparser.py create mode 100644 src/wok/plugins/sample/API.json create mode 100644 src/wok/plugins/sample/Makefile.am create mode 100644 src/wok/plugins/sample/__init__.py create mode 120000 src/wok/plugins/sample/config.status create mode 100644 src/wok/plugins/sample/i18n.py create mode 100644 src/wok/plugins/sample/model.py create mode 100644 src/wok/plugins/sample/po/LINGUAS create mode 100644 src/wok/plugins/sample/po/Makefile.in.in create mode 100644 src/wok/plugins/sample/po/Makevars create mode 100644 src/wok/plugins/sample/po/POTFILES.in create mode 100644 src/wok/plugins/sample/po/en_US.po create mode 100755 src/wok/plugins/sample/po/gen-pot create mode 100644 src/wok/plugins/sample/po/pt_BR.po create mode 100644 src/wok/plugins/sample/po/sample.pot create mode 100644 src/wok/plugins/sample/po/zh_CN.po create mode 100644 src/wok/plugins/sample/sample.conf.in create mode 100644 src/wok/plugins/sample/ui/Makefile.am create mode 100644 src/wok/plugins/sample/ui/config/Makefile.am create mode 100644 src/wok/plugins/sample/ui/config/tab-ext.xml create mode 100644 src/wok/plugins/sample/ui/css/.gitignore create mode 100644 src/wok/plugins/sample/ui/images/.gitignore create mode 100644 src/wok/plugins/sample/ui/js/.gitignore create mode 100644 src/wok/plugins/sample/ui/js/Makefile.am create mode 100644 src/wok/plugins/sample/ui/js/util.js create mode 100644 src/wok/plugins/sample/ui/libs/.gitignore create mode 100644 src/wok/plugins/sample/ui/pages/Makefile.am create mode 100644 src/wok/plugins/sample/ui/pages/help/en_US/sample-tab1.html create mode 100644 src/wok/plugins/sample/ui/pages/help/en_US/sample-tab2.html create mode 100644 src/wok/plugins/sample/ui/pages/i18n.json.tmpl create mode 100644 src/wok/plugins/sample/ui/pages/sample-tab1.html.tmpl create mode 100644 src/wok/plugins/sample/ui/pages/sample-tab2.html.tmpl -- 2.4.3
From: Paulo Vital <pvital@linux.vnet.ibm.com> Moving plugins directory to be part of src/wok development structure to make easy develop, build, execute and test all plugins integrated with wok. Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- plugins/Makefile.am | 25 - plugins/__init__.py | 18 - plugins/kimchi/.gitignore | 37 - plugins/kimchi/API.json | 836 ------- plugins/kimchi/INSTALL | 369 --- plugins/kimchi/Makefile.am | 161 -- plugins/kimchi/README.md | 1 - plugins/kimchi/VERSION | 1 - plugins/kimchi/__init__.py | 21 - plugins/kimchi/autogen.sh | 21 - plugins/kimchi/build-aux/config.rpath | 672 ------ plugins/kimchi/build-aux/genChangelog | 25 - plugins/kimchi/build-aux/pkg-version | 59 - plugins/kimchi/config.py.in | 144 -- plugins/kimchi/config.rpath | 672 ------ plugins/kimchi/configure.ac | 119 - plugins/kimchi/contrib/DEBIAN/Makefile.am | 17 - plugins/kimchi/contrib/DEBIAN/control.in | 30 - plugins/kimchi/contrib/Makefile.am | 34 - plugins/kimchi/contrib/check_i18n.py | 82 - plugins/kimchi/contrib/kimchi.spec.fedora.in | 119 - plugins/kimchi/contrib/kimchi.spec.suse.in | 107 - plugins/kimchi/contrib/make-deb.sh.in | 15 - plugins/kimchi/control/Makefile.am | 27 - plugins/kimchi/control/__init__.py | 26 - plugins/kimchi/control/config.py | 57 - plugins/kimchi/control/cpuinfo.py | 37 - plugins/kimchi/control/debugreports.py | 61 - plugins/kimchi/control/groups.py | 28 - plugins/kimchi/control/host.py | 157 -- plugins/kimchi/control/interfaces.py | 46 - plugins/kimchi/control/networks.py | 54 - plugins/kimchi/control/peers.py | 29 - plugins/kimchi/control/storagepools.py | 116 - plugins/kimchi/control/storageservers.py | 60 - plugins/kimchi/control/storagevolumes.py | 83 - plugins/kimchi/control/templates.py | 58 - plugins/kimchi/control/users.py | 35 - plugins/kimchi/control/vm/Makefile.am | 26 - plugins/kimchi/control/vm/__init__.py | 26 - plugins/kimchi/control/vm/hostdevs.py | 43 - plugins/kimchi/control/vm/ifaces.py | 45 - plugins/kimchi/control/vm/snapshots.py | 58 - plugins/kimchi/control/vm/storages.py | 45 - plugins/kimchi/control/vms.py | 67 - plugins/kimchi/disks.py | 196 -- plugins/kimchi/distroloader.py | 67 - plugins/kimchi/distros.d/Makefile.am | 22 - plugins/kimchi/distros.d/debian.json | 9 - plugins/kimchi/distros.d/fedora.json | 30 - plugins/kimchi/distros.d/gentoo.json | 9 - plugins/kimchi/distros.d/opensuse.json | 23 - plugins/kimchi/distros.d/ubuntu.json | 37 - plugins/kimchi/docs/API.md | 1116 --------- plugins/kimchi/docs/Makefile.am | 28 - plugins/kimchi/docs/README-federation.md | 60 - plugins/kimchi/docs/README.md | 247 -- plugins/kimchi/docs/kimchi-guest.png | Bin 192281 -> 0 bytes plugins/kimchi/docs/kimchi-login.png | Bin 318041 -> 0 bytes plugins/kimchi/docs/kimchi-templates.png | Bin 329678 -> 0 bytes plugins/kimchi/i18n.py | 335 --- plugins/kimchi/imageinfo.py | 72 - plugins/kimchi/iscsi.py | 88 - plugins/kimchi/isoinfo.py | 506 ----- plugins/kimchi/kimchi.conf | 37 - plugins/kimchi/kvmusertests.py | 79 - plugins/kimchi/m4/ac_python_module.m4 | 30 - plugins/kimchi/m4/gettext.m4 | 383 ---- plugins/kimchi/m4/iconv.m4 | 214 -- plugins/kimchi/m4/intlmacosx.m4 | 51 - plugins/kimchi/m4/lib-ld.m4 | 110 - plugins/kimchi/m4/lib-link.m4 | 774 ------- plugins/kimchi/m4/lib-prefix.m4 | 224 -- plugins/kimchi/m4/nls.m4 | 32 - plugins/kimchi/m4/po.m4 | 449 ---- plugins/kimchi/m4/progtest.m4 | 92 - plugins/kimchi/mockmodel.py | 627 ------ plugins/kimchi/model/Makefile.am | 25 - plugins/kimchi/model/__init__.py | 18 - plugins/kimchi/model/config.py | 176 -- plugins/kimchi/model/cpuinfo.py | 126 -- plugins/kimchi/model/debugreports.py | 213 -- plugins/kimchi/model/diskutils.py | 75 - plugins/kimchi/model/featuretests.py | 259 --- plugins/kimchi/model/groups.py | 67 - plugins/kimchi/model/host.py | 476 ---- plugins/kimchi/model/hostdev.py | 324 --- plugins/kimchi/model/interfaces.py | 44 - plugins/kimchi/model/libvirtconnection.py | 136 -- plugins/kimchi/model/libvirtstoragepool.py | 264 --- plugins/kimchi/model/model.py | 52 - plugins/kimchi/model/networks.py | 382 ---- plugins/kimchi/model/peers.py | 72 - plugins/kimchi/model/storagepools.py | 490 ---- plugins/kimchi/model/storageservers.py | 81 - plugins/kimchi/model/storagetargets.py | 122 - plugins/kimchi/model/storagevolumes.py | 542 ----- plugins/kimchi/model/templates.py | 303 --- plugins/kimchi/model/users.py | 90 - plugins/kimchi/model/utils.py | 161 -- plugins/kimchi/model/vmhostdevs.py | 336 --- plugins/kimchi/model/vmifaces.py | 186 -- plugins/kimchi/model/vms.py | 1307 ----------- plugins/kimchi/model/vmsnapshots.py | 204 -- plugins/kimchi/model/vmstorages.py | 252 --- plugins/kimchi/netinfo.py | 216 -- plugins/kimchi/network.py | 62 - plugins/kimchi/osinfo.py | 213 -- plugins/kimchi/po/LINGUAS | 11 - plugins/kimchi/po/Makefile.in.in | 398 ---- plugins/kimchi/po/Makevars | 41 - plugins/kimchi/po/POTFILES.in | 3 - plugins/kimchi/po/de_DE.po | 2288 ------------------- plugins/kimchi/po/en_US.po | 2075 ----------------- plugins/kimchi/po/es_ES.po | 2305 ------------------- plugins/kimchi/po/fr_FR.po | 2338 ------------------- plugins/kimchi/po/gen-pot.in | 9 - plugins/kimchi/po/it_IT.po | 2274 ------------------- plugins/kimchi/po/ja_JP.po | 2269 ------------------- plugins/kimchi/po/kimchi.pot | 2074 ----------------- plugins/kimchi/po/ko_KR.po | 2197 ------------------ plugins/kimchi/po/pt_BR.po | 2369 -------------------- plugins/kimchi/po/ru_RU.po | 2198 ------------------ plugins/kimchi/po/zh_CN.po | 2186 ------------------ plugins/kimchi/po/zh_TW.po | 2138 ------------------ plugins/kimchi/repositories.py | 529 ----- plugins/kimchi/root.py | 69 - plugins/kimchi/scan.py | 89 - plugins/kimchi/screenshot.py | 184 -- plugins/kimchi/swupdate.py | 263 --- plugins/kimchi/template.conf | 47 - plugins/kimchi/tests/Makefile.am | 50 - plugins/kimchi/tests/iso_gen.py | 212 -- plugins/kimchi/tests/run_tests.sh.in | 55 - plugins/kimchi/tests/test_authorization.py | 178 -- plugins/kimchi/tests/test_config.py.in | 267 --- plugins/kimchi/tests/test_exception.py | 123 - plugins/kimchi/tests/test_host.py | 206 -- plugins/kimchi/tests/test_mock_network.py | 73 - plugins/kimchi/tests/test_mock_storagepool.py | 147 -- plugins/kimchi/tests/test_mock_storagevolume.py | 98 - plugins/kimchi/tests/test_mockmodel.py | 141 -- plugins/kimchi/tests/test_model.py | 1248 ----------- plugins/kimchi/tests/test_model_network.py | 149 -- plugins/kimchi/tests/test_model_storagepool.py | 123 - plugins/kimchi/tests/test_model_storagevolume.py | 280 --- plugins/kimchi/tests/test_networkxml.py | 172 -- plugins/kimchi/tests/test_objectstore.py | 97 - plugins/kimchi/tests/test_osinfo.py | 69 - plugins/kimchi/tests/test_plugin.py | 126 -- plugins/kimchi/tests/test_rest.py | 1327 ----------- plugins/kimchi/tests/test_rollbackcontext.py | 99 - plugins/kimchi/tests/test_server.py | 289 --- plugins/kimchi/tests/test_storagepoolxml.py | 171 -- plugins/kimchi/tests/test_template.py | 387 ---- plugins/kimchi/tests/test_utils.py | 69 - plugins/kimchi/tests/test_vmtemplate.py | 116 - plugins/kimchi/tests/test_yumparser.py | 162 -- plugins/kimchi/tests/utils.py | 260 --- plugins/kimchi/ui/Makefile.am | 20 - plugins/kimchi/ui/config/Makefile.am | 22 - plugins/kimchi/ui/config/tab-ext.xml | 38 - plugins/kimchi/ui/css/Makefile.am | 26 - plugins/kimchi/ui/css/theme-default/guest-edit.css | 424 ---- .../ui/css/theme-default/guest-storage-add.css | 81 - plugins/kimchi/ui/css/theme-default/host.css | 287 --- plugins/kimchi/ui/css/theme-default/icon.css | 106 - plugins/kimchi/ui/css/theme-default/list.css | 326 --- plugins/kimchi/ui/css/theme-default/network.css | 267 --- plugins/kimchi/ui/css/theme-default/report-add.css | 37 - .../kimchi/ui/css/theme-default/report-rename.css | 39 - .../kimchi/ui/css/theme-default/repository-add.css | 42 - .../ui/css/theme-default/repository-edit.css | 88 - plugins/kimchi/ui/css/theme-default/storage.css | 550 ----- .../css/theme-default/storagepool-add-volume.css | 36 - .../kimchi/ui/css/theme-default/template-edit.css | 175 -- plugins/kimchi/ui/css/theme-default/template.css | 85 - .../kimchi/ui/css/theme-default/template_add.css | 317 --- .../kimchi/ui/css/theme-default/template_list.css | 267 --- plugins/kimchi/ui/images/Makefile.am | 22 - plugins/kimchi/ui/images/icon-centos.png | Bin 4734 -> 0 bytes plugins/kimchi/ui/images/icon-debian.png | Bin 4239 -> 0 bytes plugins/kimchi/ui/images/icon-fedora.png | Bin 4449 -> 0 bytes plugins/kimchi/ui/images/icon-gentoo.png | Bin 15307 -> 0 bytes plugins/kimchi/ui/images/icon-opensuse.png | Bin 3046 -> 0 bytes plugins/kimchi/ui/images/icon-ubuntu.png | Bin 4818 -> 0 bytes plugins/kimchi/ui/images/icon-vm.png | Bin 2976 -> 0 bytes plugins/kimchi/ui/images/theme-default/Makefile.am | 20 - .../kimchi/ui/images/theme-default/ac22_pause.png | Bin 1219 -> 0 bytes .../ui/images/theme-default/ac22_pause_grey.png | Bin 1175 -> 0 bytes .../kimchi/ui/images/theme-default/ac24_resume.png | Bin 1341 -> 0 bytes .../ui/images/theme-default/ac24_resume_grey.png | Bin 1282 -> 0 bytes .../ui/images/theme-default/arrow-down-black.png | Bin 2942 -> 0 bytes .../ui/images/theme-default/arrow-down-disable.png | Bin 472 -> 0 bytes .../kimchi/ui/images/theme-default/arrow-down.png | Bin 537 -> 0 bytes .../kimchi/ui/images/theme-default/arrow-up.png | Bin 510 -> 0 bytes .../kimchi/ui/images/theme-default/arrow_out.png | Bin 3048 -> 0 bytes plugins/kimchi/ui/images/theme-default/group.png | Bin 1703 -> 0 bytes .../ui/images/theme-default/host-icon-sprite.png | Bin 1034 -> 0 bytes .../kimchi/ui/images/theme-default/icon-back.png | Bin 244 -> 0 bytes .../kimchi/ui/images/theme-default/icon-camera.png | Bin 4860 -> 0 bytes .../kimchi/ui/images/theme-default/icon-design.png | Bin 4562 -> 0 bytes .../kimchi/ui/images/theme-default/icon-detail.png | Bin 3079 -> 0 bytes .../kimchi/ui/images/theme-default/icon-iso.png | Bin 4188 -> 0 bytes .../kimchi/ui/images/theme-default/icon-list.png | Bin 2983 -> 0 bytes .../kimchi/ui/images/theme-default/icon-load.png | Bin 3678 -> 0 bytes .../kimchi/ui/images/theme-default/icon-local.png | Bin 425 -> 0 bytes .../ui/images/theme-default/icon-power-down.png | Bin 4372 -> 0 bytes .../ui/images/theme-default/icon-power-up.png | Bin 4367 -> 0 bytes .../kimchi/ui/images/theme-default/icon-qcow2.png | Bin 4684 -> 0 bytes .../kimchi/ui/images/theme-default/icon-raw.png | Bin 4679 -> 0 bytes .../kimchi/ui/images/theme-default/icon-remote.png | Bin 1005 -> 0 bytes .../kimchi/ui/images/theme-default/icon-reset.png | Bin 4576 -> 0 bytes .../kimchi/ui/images/theme-default/icon-search.png | Bin 4197 -> 0 bytes .../kimchi/ui/images/theme-default/icon-sort.png | Bin 3421 -> 0 bytes .../kimchi/ui/images/theme-default/icon-tree.png | Bin 3526 -> 0 bytes .../kimchi/ui/images/theme-default/icon-user.png | Bin 5366 -> 0 bytes .../images/theme-default/icon-volume-default.png | Bin 4265 -> 0 bytes .../images/theme-default/kimchi-loading15x15.gif | Bin 1653 -> 0 bytes plugins/kimchi/ui/images/theme-default/loading.gif | Bin 2190 -> 0 bytes plugins/kimchi/ui/images/theme-default/user.png | Bin 1322 -> 0 bytes plugins/kimchi/ui/js/Makefile.am | 27 - plugins/kimchi/ui/js/src/kimchi.api.js | 1355 ----------- plugins/kimchi/ui/js/src/kimchi.guest_add_main.js | 86 - plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js | 759 ------- plugins/kimchi/ui/js/src/kimchi.guest_main.js | 511 ----- .../kimchi/ui/js/src/kimchi.guest_media_main.js | 56 - .../ui/js/src/kimchi.guest_storage_add.main.js | 199 -- plugins/kimchi/ui/js/src/kimchi.host.js | 858 ------- plugins/kimchi/ui/js/src/kimchi.main.js | 26 - plugins/kimchi/ui/js/src/kimchi.network.js | 442 ---- plugins/kimchi/ui/js/src/kimchi.report_add_main.js | 72 - .../kimchi/ui/js/src/kimchi.report_rename_main.js | 66 - .../kimchi/ui/js/src/kimchi.repository_add_main.js | 96 - .../ui/js/src/kimchi.repository_edit_main.js | 74 - plugins/kimchi/ui/js/src/kimchi.storage_main.js | 428 ---- .../ui/js/src/kimchi.storagepool_add_main.js | 414 ---- .../js/src/kimchi.storagepool_add_volume_main.js | 179 -- .../kimchi/ui/js/src/kimchi.template_add_main.js | 441 ---- .../kimchi/ui/js/src/kimchi.template_edit_main.js | 343 --- plugins/kimchi/ui/js/src/kimchi.template_main.js | 111 - plugins/kimchi/ui/pages/Makefile.am | 22 - plugins/kimchi/ui/pages/guest-add.html.tmpl | 98 - plugins/kimchi/ui/pages/guest-edit.html.tmpl | 311 --- .../kimchi/ui/pages/guest-storage-add.html.tmpl | 103 - plugins/kimchi/ui/pages/guest.html.tmpl | 77 - plugins/kimchi/ui/pages/guests.html.tmpl | 65 - plugins/kimchi/ui/pages/help/Makefile.am | 34 - plugins/kimchi/ui/pages/help/de_DE/Makefile.am | 23 - plugins/kimchi/ui/pages/help/de_DE/guests.dita | 127 -- plugins/kimchi/ui/pages/help/de_DE/host.dita | 49 - plugins/kimchi/ui/pages/help/de_DE/network.dita | 62 - plugins/kimchi/ui/pages/help/de_DE/storage.dita | 86 - plugins/kimchi/ui/pages/help/de_DE/templates.dita | 112 - plugins/kimchi/ui/pages/help/dita-help.xsl | 26 - plugins/kimchi/ui/pages/help/en_US/Makefile.am | 23 - plugins/kimchi/ui/pages/help/en_US/guests.dita | 136 -- plugins/kimchi/ui/pages/help/en_US/host.dita | 70 - plugins/kimchi/ui/pages/help/en_US/network.dita | 68 - plugins/kimchi/ui/pages/help/en_US/storage.dita | 99 - plugins/kimchi/ui/pages/help/en_US/templates.dita | 123 - plugins/kimchi/ui/pages/help/es_ES/Makefile.am | 23 - plugins/kimchi/ui/pages/help/es_ES/guests.dita | 120 - plugins/kimchi/ui/pages/help/es_ES/host.dita | 49 - plugins/kimchi/ui/pages/help/es_ES/network.dita | 61 - plugins/kimchi/ui/pages/help/es_ES/storage.dita | 86 - plugins/kimchi/ui/pages/help/es_ES/templates.dita | 111 - plugins/kimchi/ui/pages/help/fr_FR/Makefile.am | 23 - plugins/kimchi/ui/pages/help/fr_FR/guests.dita | 130 -- plugins/kimchi/ui/pages/help/fr_FR/host.dita | 68 - plugins/kimchi/ui/pages/help/fr_FR/network.dita | 67 - plugins/kimchi/ui/pages/help/fr_FR/storage.dita | 93 - plugins/kimchi/ui/pages/help/fr_FR/templates.dita | 120 - plugins/kimchi/ui/pages/help/it_IT/Makefile.am | 23 - plugins/kimchi/ui/pages/help/it_IT/guests.dita | 123 - plugins/kimchi/ui/pages/help/it_IT/host.dita | 51 - plugins/kimchi/ui/pages/help/it_IT/network.dita | 63 - plugins/kimchi/ui/pages/help/it_IT/storage.dita | 91 - plugins/kimchi/ui/pages/help/it_IT/templates.dita | 115 - plugins/kimchi/ui/pages/help/ja_JP/Makefile.am | 23 - plugins/kimchi/ui/pages/help/ja_JP/guests.dita | 172 -- plugins/kimchi/ui/pages/help/ja_JP/host.dita | 70 - plugins/kimchi/ui/pages/help/ja_JP/network.dita | 83 - plugins/kimchi/ui/pages/help/ja_JP/storage.dita | 120 - plugins/kimchi/ui/pages/help/ja_JP/templates.dita | 150 -- plugins/kimchi/ui/pages/help/kimchi.css | 208 -- plugins/kimchi/ui/pages/help/ko_KR/Makefile.am | 23 - plugins/kimchi/ui/pages/help/ko_KR/guests.dita | 119 - plugins/kimchi/ui/pages/help/ko_KR/host.dita | 47 - plugins/kimchi/ui/pages/help/ko_KR/network.dita | 61 - plugins/kimchi/ui/pages/help/ko_KR/storage.dita | 86 - plugins/kimchi/ui/pages/help/ko_KR/templates.dita | 111 - plugins/kimchi/ui/pages/help/pt_BR/Makefile.am | 23 - plugins/kimchi/ui/pages/help/pt_BR/guests.dita | 137 -- plugins/kimchi/ui/pages/help/pt_BR/host.dita | 74 - plugins/kimchi/ui/pages/help/pt_BR/network.dita | 72 - plugins/kimchi/ui/pages/help/pt_BR/storage.dita | 102 - plugins/kimchi/ui/pages/help/pt_BR/templates.dita | 127 -- plugins/kimchi/ui/pages/help/ru_RU/Makefile.am | 23 - plugins/kimchi/ui/pages/help/ru_RU/guests.dita | 122 - plugins/kimchi/ui/pages/help/ru_RU/host.dita | 48 - plugins/kimchi/ui/pages/help/ru_RU/network.dita | 61 - plugins/kimchi/ui/pages/help/ru_RU/storage.dita | 88 - plugins/kimchi/ui/pages/help/ru_RU/templates.dita | 111 - plugins/kimchi/ui/pages/help/zh_CN/Makefile.am | 23 - plugins/kimchi/ui/pages/help/zh_CN/guests.dita | 118 - plugins/kimchi/ui/pages/help/zh_CN/host.dita | 45 - plugins/kimchi/ui/pages/help/zh_CN/network.dita | 61 - plugins/kimchi/ui/pages/help/zh_CN/storage.dita | 84 - plugins/kimchi/ui/pages/help/zh_CN/templates.dita | 111 - plugins/kimchi/ui/pages/help/zh_TW/Makefile.am | 23 - plugins/kimchi/ui/pages/help/zh_TW/guests.dita | 120 - plugins/kimchi/ui/pages/help/zh_TW/host.dita | 50 - plugins/kimchi/ui/pages/help/zh_TW/network.dita | 61 - plugins/kimchi/ui/pages/help/zh_TW/storage.dita | 88 - plugins/kimchi/ui/pages/help/zh_TW/templates.dita | 112 - plugins/kimchi/ui/pages/host.html.tmpl | 177 -- plugins/kimchi/ui/pages/i18n.json.tmpl | 187 -- plugins/kimchi/ui/pages/network.html.tmpl | 133 -- plugins/kimchi/ui/pages/report-add.html.tmpl | 56 - plugins/kimchi/ui/pages/report-rename.html.tmpl | 56 - plugins/kimchi/ui/pages/repository-add.html.tmpl | 113 - plugins/kimchi/ui/pages/repository-edit.html.tmpl | 117 - plugins/kimchi/ui/pages/storage.html.tmpl | 143 -- .../ui/pages/storagepool-add-volume.html.tmpl | 79 - plugins/kimchi/ui/pages/storagepool-add.html.tmpl | 186 -- plugins/kimchi/ui/pages/template-add.html.tmpl | 233 -- plugins/kimchi/ui/pages/template-edit.html.tmpl | 193 -- plugins/kimchi/ui/pages/templates.html.tmpl | 77 - plugins/kimchi/ui/robots.txt | 2 - plugins/kimchi/ui/spice-html5/Makefile.am | 25 - plugins/kimchi/ui/spice-html5/atKeynames.js | 183 -- plugins/kimchi/ui/spice-html5/bitmap.js | 51 - plugins/kimchi/ui/spice-html5/css/Makefile.am | 20 - plugins/kimchi/ui/spice-html5/css/spice.css | 118 - plugins/kimchi/ui/spice-html5/cursor.js | 110 - plugins/kimchi/ui/spice-html5/display.js | 823 ------- plugins/kimchi/ui/spice-html5/enums.js | 324 --- plugins/kimchi/ui/spice-html5/inputs.js | 280 --- plugins/kimchi/ui/spice-html5/lz.js | 166 -- plugins/kimchi/ui/spice-html5/main.js | 231 -- plugins/kimchi/ui/spice-html5/pages/Makefile.am | 20 - .../kimchi/ui/spice-html5/pages/spice_auto.html | 200 -- plugins/kimchi/ui/spice-html5/playback.js | 278 --- plugins/kimchi/ui/spice-html5/png.js | 256 --- plugins/kimchi/ui/spice-html5/quic.js | 1335 ----------- plugins/kimchi/ui/spice-html5/resize.js | 70 - plugins/kimchi/ui/spice-html5/simulatecursor.js | 202 -- plugins/kimchi/ui/spice-html5/spicearraybuffer.js | 58 - plugins/kimchi/ui/spice-html5/spiceconn.js | 460 ---- plugins/kimchi/ui/spice-html5/spicedataview.js | 120 - plugins/kimchi/ui/spice-html5/spicemsg.js | 1047 --------- plugins/kimchi/ui/spice-html5/spicetype.js | 473 ---- .../kimchi/ui/spice-html5/thirdparty/Makefile.am | 20 - plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js | 589 ----- plugins/kimchi/ui/spice-html5/thirdparty/prng4.js | 79 - plugins/kimchi/ui/spice-html5/thirdparty/rng.js | 102 - plugins/kimchi/ui/spice-html5/thirdparty/rsa.js | 146 -- plugins/kimchi/ui/spice-html5/thirdparty/sha1.js | 346 --- plugins/kimchi/ui/spice-html5/ticket.js | 250 --- plugins/kimchi/ui/spice-html5/utils.js | 265 --- plugins/kimchi/ui/spice-html5/webm.js | 553 ----- plugins/kimchi/ui/spice-html5/wire.js | 123 - plugins/kimchi/utils.py | 39 - plugins/kimchi/vmtemplate.py | 431 ---- plugins/kimchi/vnc.py | 77 - plugins/kimchi/xmlutils/Makefile.am | 25 - plugins/kimchi/xmlutils/__init__.py | 18 - plugins/kimchi/xmlutils/cpu.py | 60 - plugins/kimchi/xmlutils/disk.py | 164 -- plugins/kimchi/xmlutils/graphics.py | 45 - plugins/kimchi/xmlutils/interface.py | 61 - plugins/kimchi/xmlutils/network.py | 122 - plugins/kimchi/xmlutils/qemucmdline.py | 45 - plugins/kimchi/yumparser.py | 283 --- plugins/sample/API.json | 56 - plugins/sample/Makefile.am | 29 - plugins/sample/__init__.py | 97 - plugins/sample/config.status | 1 - plugins/sample/i18n.py | 40 - plugins/sample/model.py | 131 -- plugins/sample/po/LINGUAS | 3 - plugins/sample/po/Makefile.in.in | 400 ---- plugins/sample/po/Makevars | 41 - plugins/sample/po/POTFILES.in | 2 - plugins/sample/po/en_US.po | 21 - plugins/sample/po/gen-pot | 9 - plugins/sample/po/pt_BR.po | 24 - plugins/sample/po/sample.pot | 21 - plugins/sample/po/zh_CN.po | 24 - plugins/sample/sample.conf.in | 27 - plugins/sample/ui/Makefile.am | 22 - plugins/sample/ui/config/Makefile.am | 21 - plugins/sample/ui/config/tab-ext.xml | 17 - plugins/sample/ui/css/.gitignore | 0 plugins/sample/ui/images/.gitignore | 0 plugins/sample/ui/js/.gitignore | 0 plugins/sample/ui/js/Makefile.am | 20 - plugins/sample/ui/js/util.js | 33 - plugins/sample/ui/libs/.gitignore | 0 plugins/sample/ui/pages/Makefile.am | 20 - .../sample/ui/pages/help/en_US/sample-tab1.html | 1 - .../sample/ui/pages/help/en_US/sample-tab2.html | 1 - plugins/sample/ui/pages/i18n.json.tmpl | 26 - plugins/sample/ui/pages/sample-tab1.html.tmpl | 30 - plugins/sample/ui/pages/sample-tab2.html.tmpl | 30 - src/wok/plugins/Makefile.am | 25 + src/wok/plugins/__init__.py | 18 + src/wok/plugins/kimchi/.gitignore | 37 + src/wok/plugins/kimchi/API.json | 836 +++++++ src/wok/plugins/kimchi/INSTALL | 369 +++ src/wok/plugins/kimchi/Makefile.am | 161 ++ src/wok/plugins/kimchi/README.md | 1 + src/wok/plugins/kimchi/VERSION | 1 + src/wok/plugins/kimchi/__init__.py | 21 + src/wok/plugins/kimchi/autogen.sh | 21 + src/wok/plugins/kimchi/build-aux/config.rpath | 672 ++++++ src/wok/plugins/kimchi/build-aux/genChangelog | 25 + src/wok/plugins/kimchi/build-aux/pkg-version | 59 + src/wok/plugins/kimchi/config.py.in | 144 ++ src/wok/plugins/kimchi/config.rpath | 672 ++++++ src/wok/plugins/kimchi/configure.ac | 119 + src/wok/plugins/kimchi/contrib/DEBIAN/Makefile.am | 17 + src/wok/plugins/kimchi/contrib/DEBIAN/control.in | 30 + src/wok/plugins/kimchi/contrib/Makefile.am | 34 + src/wok/plugins/kimchi/contrib/check_i18n.py | 82 + .../plugins/kimchi/contrib/kimchi.spec.fedora.in | 119 + src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in | 107 + src/wok/plugins/kimchi/contrib/make-deb.sh.in | 15 + src/wok/plugins/kimchi/control/Makefile.am | 27 + src/wok/plugins/kimchi/control/__init__.py | 26 + src/wok/plugins/kimchi/control/config.py | 57 + src/wok/plugins/kimchi/control/cpuinfo.py | 37 + src/wok/plugins/kimchi/control/debugreports.py | 61 + src/wok/plugins/kimchi/control/groups.py | 28 + src/wok/plugins/kimchi/control/host.py | 157 ++ src/wok/plugins/kimchi/control/interfaces.py | 46 + src/wok/plugins/kimchi/control/networks.py | 54 + src/wok/plugins/kimchi/control/peers.py | 29 + src/wok/plugins/kimchi/control/storagepools.py | 116 + src/wok/plugins/kimchi/control/storageservers.py | 60 + src/wok/plugins/kimchi/control/storagevolumes.py | 83 + src/wok/plugins/kimchi/control/templates.py | 58 + src/wok/plugins/kimchi/control/users.py | 35 + src/wok/plugins/kimchi/control/vm/Makefile.am | 26 + src/wok/plugins/kimchi/control/vm/__init__.py | 26 + src/wok/plugins/kimchi/control/vm/hostdevs.py | 43 + src/wok/plugins/kimchi/control/vm/ifaces.py | 45 + src/wok/plugins/kimchi/control/vm/snapshots.py | 58 + src/wok/plugins/kimchi/control/vm/storages.py | 45 + src/wok/plugins/kimchi/control/vms.py | 67 + src/wok/plugins/kimchi/disks.py | 196 ++ src/wok/plugins/kimchi/distroloader.py | 67 + src/wok/plugins/kimchi/distros.d/Makefile.am | 22 + src/wok/plugins/kimchi/distros.d/debian.json | 9 + src/wok/plugins/kimchi/distros.d/fedora.json | 30 + src/wok/plugins/kimchi/distros.d/gentoo.json | 9 + src/wok/plugins/kimchi/distros.d/opensuse.json | 23 + src/wok/plugins/kimchi/distros.d/ubuntu.json | 37 + src/wok/plugins/kimchi/docs/API.md | 1116 +++++++++ src/wok/plugins/kimchi/docs/Makefile.am | 28 + src/wok/plugins/kimchi/docs/README-federation.md | 60 + src/wok/plugins/kimchi/docs/README.md | 247 ++ src/wok/plugins/kimchi/docs/kimchi-guest.png | Bin 0 -> 192281 bytes src/wok/plugins/kimchi/docs/kimchi-login.png | Bin 0 -> 318041 bytes src/wok/plugins/kimchi/docs/kimchi-templates.png | Bin 0 -> 329678 bytes src/wok/plugins/kimchi/i18n.py | 335 +++ src/wok/plugins/kimchi/imageinfo.py | 72 + src/wok/plugins/kimchi/iscsi.py | 88 + src/wok/plugins/kimchi/isoinfo.py | 506 +++++ src/wok/plugins/kimchi/kimchi.conf | 37 + src/wok/plugins/kimchi/kvmusertests.py | 79 + src/wok/plugins/kimchi/m4/ac_python_module.m4 | 30 + src/wok/plugins/kimchi/m4/gettext.m4 | 383 ++++ src/wok/plugins/kimchi/m4/iconv.m4 | 214 ++ src/wok/plugins/kimchi/m4/intlmacosx.m4 | 51 + src/wok/plugins/kimchi/m4/lib-ld.m4 | 110 + src/wok/plugins/kimchi/m4/lib-link.m4 | 774 +++++++ src/wok/plugins/kimchi/m4/lib-prefix.m4 | 224 ++ src/wok/plugins/kimchi/m4/nls.m4 | 32 + src/wok/plugins/kimchi/m4/po.m4 | 449 ++++ src/wok/plugins/kimchi/m4/progtest.m4 | 92 + src/wok/plugins/kimchi/mockmodel.py | 627 ++++++ src/wok/plugins/kimchi/model/Makefile.am | 25 + src/wok/plugins/kimchi/model/__init__.py | 18 + src/wok/plugins/kimchi/model/config.py | 176 ++ src/wok/plugins/kimchi/model/cpuinfo.py | 126 ++ src/wok/plugins/kimchi/model/debugreports.py | 213 ++ src/wok/plugins/kimchi/model/diskutils.py | 75 + src/wok/plugins/kimchi/model/featuretests.py | 259 +++ src/wok/plugins/kimchi/model/groups.py | 67 + src/wok/plugins/kimchi/model/host.py | 476 ++++ src/wok/plugins/kimchi/model/hostdev.py | 324 +++ src/wok/plugins/kimchi/model/interfaces.py | 44 + src/wok/plugins/kimchi/model/libvirtconnection.py | 136 ++ src/wok/plugins/kimchi/model/libvirtstoragepool.py | 264 +++ src/wok/plugins/kimchi/model/model.py | 52 + src/wok/plugins/kimchi/model/networks.py | 382 ++++ src/wok/plugins/kimchi/model/peers.py | 72 + src/wok/plugins/kimchi/model/storagepools.py | 490 ++++ src/wok/plugins/kimchi/model/storageservers.py | 81 + src/wok/plugins/kimchi/model/storagetargets.py | 122 + src/wok/plugins/kimchi/model/storagevolumes.py | 542 +++++ src/wok/plugins/kimchi/model/templates.py | 303 +++ src/wok/plugins/kimchi/model/users.py | 90 + src/wok/plugins/kimchi/model/utils.py | 161 ++ src/wok/plugins/kimchi/model/vmhostdevs.py | 336 +++ src/wok/plugins/kimchi/model/vmifaces.py | 186 ++ src/wok/plugins/kimchi/model/vms.py | 1307 +++++++++++ src/wok/plugins/kimchi/model/vmsnapshots.py | 204 ++ src/wok/plugins/kimchi/model/vmstorages.py | 252 +++ src/wok/plugins/kimchi/netinfo.py | 216 ++ src/wok/plugins/kimchi/network.py | 62 + src/wok/plugins/kimchi/osinfo.py | 213 ++ src/wok/plugins/kimchi/po/LINGUAS | 11 + src/wok/plugins/kimchi/po/Makefile.in.in | 398 ++++ src/wok/plugins/kimchi/po/Makevars | 41 + src/wok/plugins/kimchi/po/POTFILES.in | 3 + src/wok/plugins/kimchi/po/de_DE.po | 2288 +++++++++++++++++++ src/wok/plugins/kimchi/po/en_US.po | 2075 +++++++++++++++++ src/wok/plugins/kimchi/po/es_ES.po | 2305 +++++++++++++++++++ src/wok/plugins/kimchi/po/fr_FR.po | 2338 +++++++++++++++++++ src/wok/plugins/kimchi/po/gen-pot.in | 9 + src/wok/plugins/kimchi/po/it_IT.po | 2274 +++++++++++++++++++ src/wok/plugins/kimchi/po/ja_JP.po | 2269 +++++++++++++++++++ src/wok/plugins/kimchi/po/kimchi.pot | 2074 +++++++++++++++++ src/wok/plugins/kimchi/po/ko_KR.po | 2197 ++++++++++++++++++ src/wok/plugins/kimchi/po/pt_BR.po | 2369 ++++++++++++++++++++ src/wok/plugins/kimchi/po/ru_RU.po | 2198 ++++++++++++++++++ src/wok/plugins/kimchi/po/zh_CN.po | 2186 ++++++++++++++++++ src/wok/plugins/kimchi/po/zh_TW.po | 2138 ++++++++++++++++++ src/wok/plugins/kimchi/repositories.py | 529 +++++ src/wok/plugins/kimchi/root.py | 69 + src/wok/plugins/kimchi/scan.py | 89 + src/wok/plugins/kimchi/screenshot.py | 184 ++ src/wok/plugins/kimchi/swupdate.py | 263 +++ src/wok/plugins/kimchi/template.conf | 47 + src/wok/plugins/kimchi/tests/Makefile.am | 50 + src/wok/plugins/kimchi/tests/iso_gen.py | 212 ++ src/wok/plugins/kimchi/tests/run_tests.sh.in | 55 + src/wok/plugins/kimchi/tests/test_authorization.py | 178 ++ src/wok/plugins/kimchi/tests/test_config.py.in | 267 +++ src/wok/plugins/kimchi/tests/test_exception.py | 123 + src/wok/plugins/kimchi/tests/test_host.py | 206 ++ src/wok/plugins/kimchi/tests/test_mock_network.py | 73 + .../plugins/kimchi/tests/test_mock_storagepool.py | 147 ++ .../kimchi/tests/test_mock_storagevolume.py | 98 + src/wok/plugins/kimchi/tests/test_mockmodel.py | 141 ++ src/wok/plugins/kimchi/tests/test_model.py | 1248 +++++++++++ src/wok/plugins/kimchi/tests/test_model_network.py | 149 ++ .../plugins/kimchi/tests/test_model_storagepool.py | 123 + .../kimchi/tests/test_model_storagevolume.py | 280 +++ src/wok/plugins/kimchi/tests/test_networkxml.py | 172 ++ src/wok/plugins/kimchi/tests/test_objectstore.py | 97 + src/wok/plugins/kimchi/tests/test_osinfo.py | 69 + src/wok/plugins/kimchi/tests/test_plugin.py | 126 ++ src/wok/plugins/kimchi/tests/test_rest.py | 1327 +++++++++++ .../plugins/kimchi/tests/test_rollbackcontext.py | 99 + src/wok/plugins/kimchi/tests/test_server.py | 289 +++ .../plugins/kimchi/tests/test_storagepoolxml.py | 171 ++ src/wok/plugins/kimchi/tests/test_template.py | 387 ++++ src/wok/plugins/kimchi/tests/test_utils.py | 69 + src/wok/plugins/kimchi/tests/test_vmtemplate.py | 116 + src/wok/plugins/kimchi/tests/test_yumparser.py | 162 ++ src/wok/plugins/kimchi/tests/utils.py | 260 +++ src/wok/plugins/kimchi/ui/Makefile.am | 20 + src/wok/plugins/kimchi/ui/config/Makefile.am | 22 + src/wok/plugins/kimchi/ui/config/tab-ext.xml | 38 + src/wok/plugins/kimchi/ui/css/Makefile.am | 26 + .../kimchi/ui/css/theme-default/guest-edit.css | 424 ++++ .../ui/css/theme-default/guest-storage-add.css | 81 + .../plugins/kimchi/ui/css/theme-default/host.css | 287 +++ .../plugins/kimchi/ui/css/theme-default/icon.css | 106 + .../plugins/kimchi/ui/css/theme-default/list.css | 326 +++ .../kimchi/ui/css/theme-default/network.css | 267 +++ .../kimchi/ui/css/theme-default/report-add.css | 37 + .../kimchi/ui/css/theme-default/report-rename.css | 39 + .../kimchi/ui/css/theme-default/repository-add.css | 42 + .../ui/css/theme-default/repository-edit.css | 88 + .../kimchi/ui/css/theme-default/storage.css | 550 +++++ .../css/theme-default/storagepool-add-volume.css | 36 + .../kimchi/ui/css/theme-default/template-edit.css | 175 ++ .../kimchi/ui/css/theme-default/template.css | 85 + .../kimchi/ui/css/theme-default/template_add.css | 317 +++ .../kimchi/ui/css/theme-default/template_list.css | 267 +++ src/wok/plugins/kimchi/ui/images/Makefile.am | 22 + src/wok/plugins/kimchi/ui/images/icon-centos.png | Bin 0 -> 4734 bytes src/wok/plugins/kimchi/ui/images/icon-debian.png | Bin 0 -> 4239 bytes src/wok/plugins/kimchi/ui/images/icon-fedora.png | Bin 0 -> 4449 bytes src/wok/plugins/kimchi/ui/images/icon-gentoo.png | Bin 0 -> 15307 bytes src/wok/plugins/kimchi/ui/images/icon-opensuse.png | Bin 0 -> 3046 bytes src/wok/plugins/kimchi/ui/images/icon-ubuntu.png | Bin 0 -> 4818 bytes src/wok/plugins/kimchi/ui/images/icon-vm.png | Bin 0 -> 2976 bytes .../kimchi/ui/images/theme-default/Makefile.am | 20 + .../kimchi/ui/images/theme-default/ac22_pause.png | Bin 0 -> 1219 bytes .../ui/images/theme-default/ac22_pause_grey.png | Bin 0 -> 1175 bytes .../kimchi/ui/images/theme-default/ac24_resume.png | Bin 0 -> 1341 bytes .../ui/images/theme-default/ac24_resume_grey.png | Bin 0 -> 1282 bytes .../ui/images/theme-default/arrow-down-black.png | Bin 0 -> 2942 bytes .../ui/images/theme-default/arrow-down-disable.png | Bin 0 -> 472 bytes .../kimchi/ui/images/theme-default/arrow-down.png | Bin 0 -> 537 bytes .../kimchi/ui/images/theme-default/arrow-up.png | Bin 0 -> 510 bytes .../kimchi/ui/images/theme-default/arrow_out.png | Bin 0 -> 3048 bytes .../kimchi/ui/images/theme-default/group.png | Bin 0 -> 1703 bytes .../ui/images/theme-default/host-icon-sprite.png | Bin 0 -> 1034 bytes .../kimchi/ui/images/theme-default/icon-back.png | Bin 0 -> 244 bytes .../kimchi/ui/images/theme-default/icon-camera.png | Bin 0 -> 4860 bytes .../kimchi/ui/images/theme-default/icon-design.png | Bin 0 -> 4562 bytes .../kimchi/ui/images/theme-default/icon-detail.png | Bin 0 -> 3079 bytes .../kimchi/ui/images/theme-default/icon-iso.png | Bin 0 -> 4188 bytes .../kimchi/ui/images/theme-default/icon-list.png | Bin 0 -> 2983 bytes .../kimchi/ui/images/theme-default/icon-load.png | Bin 0 -> 3678 bytes .../kimchi/ui/images/theme-default/icon-local.png | Bin 0 -> 425 bytes .../ui/images/theme-default/icon-power-down.png | Bin 0 -> 4372 bytes .../ui/images/theme-default/icon-power-up.png | Bin 0 -> 4367 bytes .../kimchi/ui/images/theme-default/icon-qcow2.png | Bin 0 -> 4684 bytes .../kimchi/ui/images/theme-default/icon-raw.png | Bin 0 -> 4679 bytes .../kimchi/ui/images/theme-default/icon-remote.png | Bin 0 -> 1005 bytes .../kimchi/ui/images/theme-default/icon-reset.png | Bin 0 -> 4576 bytes .../kimchi/ui/images/theme-default/icon-search.png | Bin 0 -> 4197 bytes .../kimchi/ui/images/theme-default/icon-sort.png | Bin 0 -> 3421 bytes .../kimchi/ui/images/theme-default/icon-tree.png | Bin 0 -> 3526 bytes .../kimchi/ui/images/theme-default/icon-user.png | Bin 0 -> 5366 bytes .../images/theme-default/icon-volume-default.png | Bin 0 -> 4265 bytes .../images/theme-default/kimchi-loading15x15.gif | Bin 0 -> 1653 bytes .../kimchi/ui/images/theme-default/loading.gif | Bin 0 -> 2190 bytes .../kimchi/ui/images/theme-default/user.png | Bin 0 -> 1322 bytes src/wok/plugins/kimchi/ui/js/Makefile.am | 27 + src/wok/plugins/kimchi/ui/js/src/kimchi.api.js | 1355 +++++++++++ .../kimchi/ui/js/src/kimchi.guest_add_main.js | 86 + .../kimchi/ui/js/src/kimchi.guest_edit_main.js | 759 +++++++ .../plugins/kimchi/ui/js/src/kimchi.guest_main.js | 511 +++++ .../kimchi/ui/js/src/kimchi.guest_media_main.js | 56 + .../ui/js/src/kimchi.guest_storage_add.main.js | 199 ++ src/wok/plugins/kimchi/ui/js/src/kimchi.host.js | 858 +++++++ src/wok/plugins/kimchi/ui/js/src/kimchi.main.js | 26 + src/wok/plugins/kimchi/ui/js/src/kimchi.network.js | 442 ++++ .../kimchi/ui/js/src/kimchi.report_add_main.js | 72 + .../kimchi/ui/js/src/kimchi.report_rename_main.js | 66 + .../kimchi/ui/js/src/kimchi.repository_add_main.js | 96 + .../ui/js/src/kimchi.repository_edit_main.js | 74 + .../kimchi/ui/js/src/kimchi.storage_main.js | 428 ++++ .../ui/js/src/kimchi.storagepool_add_main.js | 414 ++++ .../js/src/kimchi.storagepool_add_volume_main.js | 179 ++ .../kimchi/ui/js/src/kimchi.template_add_main.js | 441 ++++ .../kimchi/ui/js/src/kimchi.template_edit_main.js | 343 +++ .../kimchi/ui/js/src/kimchi.template_main.js | 111 + src/wok/plugins/kimchi/ui/pages/Makefile.am | 22 + .../plugins/kimchi/ui/pages/guest-add.html.tmpl | 98 + .../plugins/kimchi/ui/pages/guest-edit.html.tmpl | 311 +++ .../kimchi/ui/pages/guest-storage-add.html.tmpl | 103 + src/wok/plugins/kimchi/ui/pages/guest.html.tmpl | 77 + src/wok/plugins/kimchi/ui/pages/guests.html.tmpl | 65 + src/wok/plugins/kimchi/ui/pages/help/Makefile.am | 34 + .../plugins/kimchi/ui/pages/help/de_DE/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/de_DE/guests.dita | 127 ++ .../plugins/kimchi/ui/pages/help/de_DE/host.dita | 49 + .../kimchi/ui/pages/help/de_DE/network.dita | 62 + .../kimchi/ui/pages/help/de_DE/storage.dita | 86 + .../kimchi/ui/pages/help/de_DE/templates.dita | 112 + src/wok/plugins/kimchi/ui/pages/help/dita-help.xsl | 26 + .../plugins/kimchi/ui/pages/help/en_US/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/en_US/guests.dita | 136 ++ .../plugins/kimchi/ui/pages/help/en_US/host.dita | 70 + .../kimchi/ui/pages/help/en_US/network.dita | 68 + .../kimchi/ui/pages/help/en_US/storage.dita | 99 + .../kimchi/ui/pages/help/en_US/templates.dita | 123 + .../plugins/kimchi/ui/pages/help/es_ES/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/es_ES/guests.dita | 120 + .../plugins/kimchi/ui/pages/help/es_ES/host.dita | 49 + .../kimchi/ui/pages/help/es_ES/network.dita | 61 + .../kimchi/ui/pages/help/es_ES/storage.dita | 86 + .../kimchi/ui/pages/help/es_ES/templates.dita | 111 + .../plugins/kimchi/ui/pages/help/fr_FR/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/fr_FR/guests.dita | 130 ++ .../plugins/kimchi/ui/pages/help/fr_FR/host.dita | 68 + .../kimchi/ui/pages/help/fr_FR/network.dita | 67 + .../kimchi/ui/pages/help/fr_FR/storage.dita | 93 + .../kimchi/ui/pages/help/fr_FR/templates.dita | 120 + .../plugins/kimchi/ui/pages/help/it_IT/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/it_IT/guests.dita | 123 + .../plugins/kimchi/ui/pages/help/it_IT/host.dita | 51 + .../kimchi/ui/pages/help/it_IT/network.dita | 63 + .../kimchi/ui/pages/help/it_IT/storage.dita | 91 + .../kimchi/ui/pages/help/it_IT/templates.dita | 115 + .../plugins/kimchi/ui/pages/help/ja_JP/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/ja_JP/guests.dita | 172 ++ .../plugins/kimchi/ui/pages/help/ja_JP/host.dita | 70 + .../kimchi/ui/pages/help/ja_JP/network.dita | 83 + .../kimchi/ui/pages/help/ja_JP/storage.dita | 120 + .../kimchi/ui/pages/help/ja_JP/templates.dita | 150 ++ src/wok/plugins/kimchi/ui/pages/help/kimchi.css | 208 ++ .../plugins/kimchi/ui/pages/help/ko_KR/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/ko_KR/guests.dita | 119 + .../plugins/kimchi/ui/pages/help/ko_KR/host.dita | 47 + .../kimchi/ui/pages/help/ko_KR/network.dita | 61 + .../kimchi/ui/pages/help/ko_KR/storage.dita | 86 + .../kimchi/ui/pages/help/ko_KR/templates.dita | 111 + .../plugins/kimchi/ui/pages/help/pt_BR/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/pt_BR/guests.dita | 137 ++ .../plugins/kimchi/ui/pages/help/pt_BR/host.dita | 74 + .../kimchi/ui/pages/help/pt_BR/network.dita | 72 + .../kimchi/ui/pages/help/pt_BR/storage.dita | 102 + .../kimchi/ui/pages/help/pt_BR/templates.dita | 127 ++ .../plugins/kimchi/ui/pages/help/ru_RU/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/ru_RU/guests.dita | 122 + .../plugins/kimchi/ui/pages/help/ru_RU/host.dita | 48 + .../kimchi/ui/pages/help/ru_RU/network.dita | 61 + .../kimchi/ui/pages/help/ru_RU/storage.dita | 88 + .../kimchi/ui/pages/help/ru_RU/templates.dita | 111 + .../plugins/kimchi/ui/pages/help/zh_CN/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/zh_CN/guests.dita | 118 + .../plugins/kimchi/ui/pages/help/zh_CN/host.dita | 45 + .../kimchi/ui/pages/help/zh_CN/network.dita | 61 + .../kimchi/ui/pages/help/zh_CN/storage.dita | 84 + .../kimchi/ui/pages/help/zh_CN/templates.dita | 111 + .../plugins/kimchi/ui/pages/help/zh_TW/Makefile.am | 23 + .../plugins/kimchi/ui/pages/help/zh_TW/guests.dita | 120 + .../plugins/kimchi/ui/pages/help/zh_TW/host.dita | 50 + .../kimchi/ui/pages/help/zh_TW/network.dita | 61 + .../kimchi/ui/pages/help/zh_TW/storage.dita | 88 + .../kimchi/ui/pages/help/zh_TW/templates.dita | 112 + src/wok/plugins/kimchi/ui/pages/host.html.tmpl | 177 ++ src/wok/plugins/kimchi/ui/pages/i18n.json.tmpl | 187 ++ src/wok/plugins/kimchi/ui/pages/network.html.tmpl | 133 ++ .../plugins/kimchi/ui/pages/report-add.html.tmpl | 56 + .../kimchi/ui/pages/report-rename.html.tmpl | 56 + .../kimchi/ui/pages/repository-add.html.tmpl | 113 + .../kimchi/ui/pages/repository-edit.html.tmpl | 117 + src/wok/plugins/kimchi/ui/pages/storage.html.tmpl | 143 ++ .../ui/pages/storagepool-add-volume.html.tmpl | 79 + .../kimchi/ui/pages/storagepool-add.html.tmpl | 186 ++ .../plugins/kimchi/ui/pages/template-add.html.tmpl | 233 ++ .../kimchi/ui/pages/template-edit.html.tmpl | 193 ++ .../plugins/kimchi/ui/pages/templates.html.tmpl | 77 + src/wok/plugins/kimchi/ui/robots.txt | 2 + src/wok/plugins/kimchi/ui/spice-html5/Makefile.am | 25 + .../plugins/kimchi/ui/spice-html5/atKeynames.js | 183 ++ src/wok/plugins/kimchi/ui/spice-html5/bitmap.js | 51 + .../plugins/kimchi/ui/spice-html5/css/Makefile.am | 20 + .../plugins/kimchi/ui/spice-html5/css/spice.css | 118 + src/wok/plugins/kimchi/ui/spice-html5/cursor.js | 110 + src/wok/plugins/kimchi/ui/spice-html5/display.js | 823 +++++++ src/wok/plugins/kimchi/ui/spice-html5/enums.js | 324 +++ src/wok/plugins/kimchi/ui/spice-html5/inputs.js | 280 +++ src/wok/plugins/kimchi/ui/spice-html5/lz.js | 166 ++ src/wok/plugins/kimchi/ui/spice-html5/main.js | 231 ++ .../kimchi/ui/spice-html5/pages/Makefile.am | 20 + .../kimchi/ui/spice-html5/pages/spice_auto.html | 200 ++ src/wok/plugins/kimchi/ui/spice-html5/playback.js | 278 +++ src/wok/plugins/kimchi/ui/spice-html5/png.js | 256 +++ src/wok/plugins/kimchi/ui/spice-html5/quic.js | 1335 +++++++++++ src/wok/plugins/kimchi/ui/spice-html5/resize.js | 70 + .../kimchi/ui/spice-html5/simulatecursor.js | 202 ++ .../kimchi/ui/spice-html5/spicearraybuffer.js | 58 + src/wok/plugins/kimchi/ui/spice-html5/spiceconn.js | 460 ++++ .../plugins/kimchi/ui/spice-html5/spicedataview.js | 120 + src/wok/plugins/kimchi/ui/spice-html5/spicemsg.js | 1047 +++++++++ src/wok/plugins/kimchi/ui/spice-html5/spicetype.js | 473 ++++ .../kimchi/ui/spice-html5/thirdparty/Makefile.am | 20 + .../kimchi/ui/spice-html5/thirdparty/jsbn.js | 589 +++++ .../kimchi/ui/spice-html5/thirdparty/prng4.js | 79 + .../kimchi/ui/spice-html5/thirdparty/rng.js | 102 + .../kimchi/ui/spice-html5/thirdparty/rsa.js | 146 ++ .../kimchi/ui/spice-html5/thirdparty/sha1.js | 346 +++ src/wok/plugins/kimchi/ui/spice-html5/ticket.js | 250 +++ src/wok/plugins/kimchi/ui/spice-html5/utils.js | 265 +++ src/wok/plugins/kimchi/ui/spice-html5/webm.js | 553 +++++ src/wok/plugins/kimchi/ui/spice-html5/wire.js | 123 + src/wok/plugins/kimchi/utils.py | 39 + src/wok/plugins/kimchi/vmtemplate.py | 431 ++++ src/wok/plugins/kimchi/vnc.py | 77 + src/wok/plugins/kimchi/xmlutils/Makefile.am | 25 + src/wok/plugins/kimchi/xmlutils/__init__.py | 18 + src/wok/plugins/kimchi/xmlutils/cpu.py | 60 + src/wok/plugins/kimchi/xmlutils/disk.py | 164 ++ src/wok/plugins/kimchi/xmlutils/graphics.py | 45 + src/wok/plugins/kimchi/xmlutils/interface.py | 61 + src/wok/plugins/kimchi/xmlutils/network.py | 122 + src/wok/plugins/kimchi/xmlutils/qemucmdline.py | 45 + src/wok/plugins/kimchi/yumparser.py | 283 +++ src/wok/plugins/sample/API.json | 56 + src/wok/plugins/sample/Makefile.am | 29 + src/wok/plugins/sample/__init__.py | 97 + src/wok/plugins/sample/config.status | 1 + src/wok/plugins/sample/i18n.py | 40 + src/wok/plugins/sample/model.py | 131 ++ src/wok/plugins/sample/po/LINGUAS | 3 + src/wok/plugins/sample/po/Makefile.in.in | 400 ++++ src/wok/plugins/sample/po/Makevars | 41 + src/wok/plugins/sample/po/POTFILES.in | 2 + src/wok/plugins/sample/po/en_US.po | 21 + src/wok/plugins/sample/po/gen-pot | 9 + src/wok/plugins/sample/po/pt_BR.po | 24 + src/wok/plugins/sample/po/sample.pot | 21 + src/wok/plugins/sample/po/zh_CN.po | 24 + src/wok/plugins/sample/sample.conf.in | 27 + src/wok/plugins/sample/ui/Makefile.am | 22 + src/wok/plugins/sample/ui/config/Makefile.am | 21 + src/wok/plugins/sample/ui/config/tab-ext.xml | 17 + src/wok/plugins/sample/ui/css/.gitignore | 0 src/wok/plugins/sample/ui/images/.gitignore | 0 src/wok/plugins/sample/ui/js/.gitignore | 0 src/wok/plugins/sample/ui/js/Makefile.am | 20 + src/wok/plugins/sample/ui/js/util.js | 33 + src/wok/plugins/sample/ui/libs/.gitignore | 0 src/wok/plugins/sample/ui/pages/Makefile.am | 20 + .../sample/ui/pages/help/en_US/sample-tab1.html | 1 + .../sample/ui/pages/help/en_US/sample-tab2.html | 1 + src/wok/plugins/sample/ui/pages/i18n.json.tmpl | 26 + .../plugins/sample/ui/pages/sample-tab1.html.tmpl | 30 + .../plugins/sample/ui/pages/sample-tab2.html.tmpl | 30 + 812 files changed, 82736 insertions(+), 82736 deletions(-) delete mode 100644 plugins/Makefile.am delete mode 100644 plugins/__init__.py delete mode 100644 plugins/kimchi/.gitignore delete mode 100644 plugins/kimchi/API.json delete mode 100644 plugins/kimchi/INSTALL delete mode 100644 plugins/kimchi/Makefile.am delete mode 120000 plugins/kimchi/README.md delete mode 100644 plugins/kimchi/VERSION delete mode 100644 plugins/kimchi/__init__.py delete mode 100755 plugins/kimchi/autogen.sh delete mode 100644 plugins/kimchi/build-aux/config.rpath delete mode 100755 plugins/kimchi/build-aux/genChangelog delete mode 100755 plugins/kimchi/build-aux/pkg-version delete mode 100644 plugins/kimchi/config.py.in delete mode 100644 plugins/kimchi/config.rpath delete mode 100644 plugins/kimchi/configure.ac delete mode 100644 plugins/kimchi/contrib/DEBIAN/Makefile.am delete mode 100644 plugins/kimchi/contrib/DEBIAN/control.in delete mode 100644 plugins/kimchi/contrib/Makefile.am delete mode 100755 plugins/kimchi/contrib/check_i18n.py delete mode 100644 plugins/kimchi/contrib/kimchi.spec.fedora.in delete mode 100644 plugins/kimchi/contrib/kimchi.spec.suse.in delete mode 100644 plugins/kimchi/contrib/make-deb.sh.in delete mode 100644 plugins/kimchi/control/Makefile.am delete mode 100644 plugins/kimchi/control/__init__.py delete mode 100644 plugins/kimchi/control/config.py delete mode 100644 plugins/kimchi/control/cpuinfo.py delete mode 100644 plugins/kimchi/control/debugreports.py delete mode 100644 plugins/kimchi/control/groups.py delete mode 100644 plugins/kimchi/control/host.py delete mode 100644 plugins/kimchi/control/interfaces.py delete mode 100644 plugins/kimchi/control/networks.py delete mode 100644 plugins/kimchi/control/peers.py delete mode 100644 plugins/kimchi/control/storagepools.py delete mode 100644 plugins/kimchi/control/storageservers.py delete mode 100644 plugins/kimchi/control/storagevolumes.py delete mode 100644 plugins/kimchi/control/templates.py delete mode 100644 plugins/kimchi/control/users.py delete mode 100644 plugins/kimchi/control/vm/Makefile.am delete mode 100644 plugins/kimchi/control/vm/__init__.py delete mode 100644 plugins/kimchi/control/vm/hostdevs.py delete mode 100644 plugins/kimchi/control/vm/ifaces.py delete mode 100644 plugins/kimchi/control/vm/snapshots.py delete mode 100644 plugins/kimchi/control/vm/storages.py delete mode 100644 plugins/kimchi/control/vms.py delete mode 100644 plugins/kimchi/disks.py delete mode 100644 plugins/kimchi/distroloader.py delete mode 100644 plugins/kimchi/distros.d/Makefile.am delete mode 100644 plugins/kimchi/distros.d/debian.json delete mode 100644 plugins/kimchi/distros.d/fedora.json delete mode 100644 plugins/kimchi/distros.d/gentoo.json delete mode 100644 plugins/kimchi/distros.d/opensuse.json delete mode 100644 plugins/kimchi/distros.d/ubuntu.json delete mode 100644 plugins/kimchi/docs/API.md delete mode 100644 plugins/kimchi/docs/Makefile.am delete mode 100644 plugins/kimchi/docs/README-federation.md delete mode 100644 plugins/kimchi/docs/README.md delete mode 100644 plugins/kimchi/docs/kimchi-guest.png delete mode 100644 plugins/kimchi/docs/kimchi-login.png delete mode 100644 plugins/kimchi/docs/kimchi-templates.png delete mode 100644 plugins/kimchi/i18n.py delete mode 100644 plugins/kimchi/imageinfo.py delete mode 100644 plugins/kimchi/iscsi.py delete mode 100644 plugins/kimchi/isoinfo.py delete mode 100644 plugins/kimchi/kimchi.conf delete mode 100644 plugins/kimchi/kvmusertests.py delete mode 100644 plugins/kimchi/m4/ac_python_module.m4 delete mode 100644 plugins/kimchi/m4/gettext.m4 delete mode 100644 plugins/kimchi/m4/iconv.m4 delete mode 100644 plugins/kimchi/m4/intlmacosx.m4 delete mode 100644 plugins/kimchi/m4/lib-ld.m4 delete mode 100644 plugins/kimchi/m4/lib-link.m4 delete mode 100644 plugins/kimchi/m4/lib-prefix.m4 delete mode 100644 plugins/kimchi/m4/nls.m4 delete mode 100644 plugins/kimchi/m4/po.m4 delete mode 100644 plugins/kimchi/m4/progtest.m4 delete mode 100644 plugins/kimchi/mockmodel.py delete mode 100644 plugins/kimchi/model/Makefile.am delete mode 100644 plugins/kimchi/model/__init__.py delete mode 100644 plugins/kimchi/model/config.py delete mode 100644 plugins/kimchi/model/cpuinfo.py delete mode 100644 plugins/kimchi/model/debugreports.py delete mode 100644 plugins/kimchi/model/diskutils.py delete mode 100644 plugins/kimchi/model/featuretests.py delete mode 100644 plugins/kimchi/model/groups.py delete mode 100644 plugins/kimchi/model/host.py delete mode 100644 plugins/kimchi/model/hostdev.py delete mode 100644 plugins/kimchi/model/interfaces.py delete mode 100644 plugins/kimchi/model/libvirtconnection.py delete mode 100644 plugins/kimchi/model/libvirtstoragepool.py delete mode 100644 plugins/kimchi/model/model.py delete mode 100644 plugins/kimchi/model/networks.py delete mode 100644 plugins/kimchi/model/peers.py delete mode 100644 plugins/kimchi/model/storagepools.py delete mode 100644 plugins/kimchi/model/storageservers.py delete mode 100644 plugins/kimchi/model/storagetargets.py delete mode 100644 plugins/kimchi/model/storagevolumes.py delete mode 100644 plugins/kimchi/model/templates.py delete mode 100644 plugins/kimchi/model/users.py delete mode 100644 plugins/kimchi/model/utils.py delete mode 100644 plugins/kimchi/model/vmhostdevs.py delete mode 100644 plugins/kimchi/model/vmifaces.py delete mode 100644 plugins/kimchi/model/vms.py delete mode 100644 plugins/kimchi/model/vmsnapshots.py delete mode 100644 plugins/kimchi/model/vmstorages.py delete mode 100644 plugins/kimchi/netinfo.py delete mode 100644 plugins/kimchi/network.py delete mode 100644 plugins/kimchi/osinfo.py delete mode 100644 plugins/kimchi/po/LINGUAS delete mode 100644 plugins/kimchi/po/Makefile.in.in delete mode 100644 plugins/kimchi/po/Makevars delete mode 100644 plugins/kimchi/po/POTFILES.in delete mode 100644 plugins/kimchi/po/de_DE.po delete mode 100644 plugins/kimchi/po/en_US.po delete mode 100644 plugins/kimchi/po/es_ES.po delete mode 100644 plugins/kimchi/po/fr_FR.po delete mode 100644 plugins/kimchi/po/gen-pot.in delete mode 100644 plugins/kimchi/po/it_IT.po delete mode 100644 plugins/kimchi/po/ja_JP.po delete mode 100755 plugins/kimchi/po/kimchi.pot delete mode 100644 plugins/kimchi/po/ko_KR.po delete mode 100644 plugins/kimchi/po/pt_BR.po delete mode 100644 plugins/kimchi/po/ru_RU.po delete mode 100644 plugins/kimchi/po/zh_CN.po delete mode 100644 plugins/kimchi/po/zh_TW.po delete mode 100644 plugins/kimchi/repositories.py delete mode 100644 plugins/kimchi/root.py delete mode 100644 plugins/kimchi/scan.py delete mode 100644 plugins/kimchi/screenshot.py delete mode 100644 plugins/kimchi/swupdate.py delete mode 100644 plugins/kimchi/template.conf delete mode 100644 plugins/kimchi/tests/Makefile.am delete mode 100644 plugins/kimchi/tests/iso_gen.py delete mode 100644 plugins/kimchi/tests/run_tests.sh.in delete mode 100644 plugins/kimchi/tests/test_authorization.py delete mode 100644 plugins/kimchi/tests/test_config.py.in delete mode 100644 plugins/kimchi/tests/test_exception.py delete mode 100644 plugins/kimchi/tests/test_host.py delete mode 100644 plugins/kimchi/tests/test_mock_network.py delete mode 100644 plugins/kimchi/tests/test_mock_storagepool.py delete mode 100644 plugins/kimchi/tests/test_mock_storagevolume.py delete mode 100644 plugins/kimchi/tests/test_mockmodel.py delete mode 100644 plugins/kimchi/tests/test_model.py delete mode 100644 plugins/kimchi/tests/test_model_network.py delete mode 100644 plugins/kimchi/tests/test_model_storagepool.py delete mode 100644 plugins/kimchi/tests/test_model_storagevolume.py delete mode 100644 plugins/kimchi/tests/test_networkxml.py delete mode 100644 plugins/kimchi/tests/test_objectstore.py delete mode 100644 plugins/kimchi/tests/test_osinfo.py delete mode 100644 plugins/kimchi/tests/test_plugin.py delete mode 100644 plugins/kimchi/tests/test_rest.py delete mode 100644 plugins/kimchi/tests/test_rollbackcontext.py delete mode 100644 plugins/kimchi/tests/test_server.py delete mode 100644 plugins/kimchi/tests/test_storagepoolxml.py delete mode 100644 plugins/kimchi/tests/test_template.py delete mode 100644 plugins/kimchi/tests/test_utils.py delete mode 100644 plugins/kimchi/tests/test_vmtemplate.py delete mode 100644 plugins/kimchi/tests/test_yumparser.py delete mode 100644 plugins/kimchi/tests/utils.py delete mode 100644 plugins/kimchi/ui/Makefile.am delete mode 100644 plugins/kimchi/ui/config/Makefile.am delete mode 100644 plugins/kimchi/ui/config/tab-ext.xml delete mode 100644 plugins/kimchi/ui/css/Makefile.am delete mode 100644 plugins/kimchi/ui/css/theme-default/guest-edit.css delete mode 100644 plugins/kimchi/ui/css/theme-default/guest-storage-add.css delete mode 100644 plugins/kimchi/ui/css/theme-default/host.css delete mode 100644 plugins/kimchi/ui/css/theme-default/icon.css delete mode 100644 plugins/kimchi/ui/css/theme-default/list.css delete mode 100644 plugins/kimchi/ui/css/theme-default/network.css delete mode 100644 plugins/kimchi/ui/css/theme-default/report-add.css delete mode 100644 plugins/kimchi/ui/css/theme-default/report-rename.css delete mode 100644 plugins/kimchi/ui/css/theme-default/repository-add.css delete mode 100644 plugins/kimchi/ui/css/theme-default/repository-edit.css delete mode 100644 plugins/kimchi/ui/css/theme-default/storage.css delete mode 100644 plugins/kimchi/ui/css/theme-default/storagepool-add-volume.css delete mode 100644 plugins/kimchi/ui/css/theme-default/template-edit.css delete mode 100644 plugins/kimchi/ui/css/theme-default/template.css delete mode 100644 plugins/kimchi/ui/css/theme-default/template_add.css delete mode 100644 plugins/kimchi/ui/css/theme-default/template_list.css delete mode 100644 plugins/kimchi/ui/images/Makefile.am delete mode 100644 plugins/kimchi/ui/images/icon-centos.png delete mode 100644 plugins/kimchi/ui/images/icon-debian.png delete mode 100644 plugins/kimchi/ui/images/icon-fedora.png delete mode 100644 plugins/kimchi/ui/images/icon-gentoo.png delete mode 100644 plugins/kimchi/ui/images/icon-opensuse.png delete mode 100644 plugins/kimchi/ui/images/icon-ubuntu.png delete mode 100644 plugins/kimchi/ui/images/icon-vm.png delete mode 100644 plugins/kimchi/ui/images/theme-default/Makefile.am delete mode 100644 plugins/kimchi/ui/images/theme-default/ac22_pause.png delete mode 100644 plugins/kimchi/ui/images/theme-default/ac22_pause_grey.png delete mode 100644 plugins/kimchi/ui/images/theme-default/ac24_resume.png delete mode 100644 plugins/kimchi/ui/images/theme-default/ac24_resume_grey.png delete mode 100644 plugins/kimchi/ui/images/theme-default/arrow-down-black.png delete mode 100644 plugins/kimchi/ui/images/theme-default/arrow-down-disable.png delete mode 100644 plugins/kimchi/ui/images/theme-default/arrow-down.png delete mode 100644 plugins/kimchi/ui/images/theme-default/arrow-up.png delete mode 100644 plugins/kimchi/ui/images/theme-default/arrow_out.png delete mode 100644 plugins/kimchi/ui/images/theme-default/group.png delete mode 100644 plugins/kimchi/ui/images/theme-default/host-icon-sprite.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-back.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-camera.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-design.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-detail.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-iso.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-list.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-load.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-local.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-power-down.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-power-up.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-qcow2.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-raw.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-remote.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-reset.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-search.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-sort.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-tree.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-user.png delete mode 100644 plugins/kimchi/ui/images/theme-default/icon-volume-default.png delete mode 100644 plugins/kimchi/ui/images/theme-default/kimchi-loading15x15.gif delete mode 100644 plugins/kimchi/ui/images/theme-default/loading.gif delete mode 100644 plugins/kimchi/ui/images/theme-default/user.png delete mode 100644 plugins/kimchi/ui/js/Makefile.am delete mode 100644 plugins/kimchi/ui/js/src/kimchi.api.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.guest_add_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.guest_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.guest_media_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.guest_storage_add.main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.host.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.network.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.report_add_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.report_rename_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.repository_add_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.storage_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.storagepool_add_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.storagepool_add_volume_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.template_add_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.template_edit_main.js delete mode 100644 plugins/kimchi/ui/js/src/kimchi.template_main.js delete mode 100644 plugins/kimchi/ui/pages/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/guest-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/guest-edit.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/guest-storage-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/guest.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/guests.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/help/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/de_DE/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/dita-help.xsl delete mode 100644 plugins/kimchi/ui/pages/help/en_US/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/en_US/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/en_US/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/en_US/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/en_US/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/en_US/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/es_ES/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/fr_FR/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/it_IT/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/ja_JP/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/kimchi.css delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/ko_KR/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/pt_BR/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/ru_RU/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_CN/templates.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/Makefile.am delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/guests.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/host.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/network.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/storage.dita delete mode 100644 plugins/kimchi/ui/pages/help/zh_TW/templates.dita delete mode 100644 plugins/kimchi/ui/pages/host.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/i18n.json.tmpl delete mode 100644 plugins/kimchi/ui/pages/network.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/report-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/report-rename.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/repository-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/repository-edit.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/storage.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/storagepool-add-volume.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/storagepool-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/template-add.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/template-edit.html.tmpl delete mode 100644 plugins/kimchi/ui/pages/templates.html.tmpl delete mode 100644 plugins/kimchi/ui/robots.txt delete mode 100644 plugins/kimchi/ui/spice-html5/Makefile.am delete mode 100644 plugins/kimchi/ui/spice-html5/atKeynames.js delete mode 100644 plugins/kimchi/ui/spice-html5/bitmap.js delete mode 100644 plugins/kimchi/ui/spice-html5/css/Makefile.am delete mode 100644 plugins/kimchi/ui/spice-html5/css/spice.css delete mode 100644 plugins/kimchi/ui/spice-html5/cursor.js delete mode 100644 plugins/kimchi/ui/spice-html5/display.js delete mode 100644 plugins/kimchi/ui/spice-html5/enums.js delete mode 100644 plugins/kimchi/ui/spice-html5/inputs.js delete mode 100644 plugins/kimchi/ui/spice-html5/lz.js delete mode 100644 plugins/kimchi/ui/spice-html5/main.js delete mode 100644 plugins/kimchi/ui/spice-html5/pages/Makefile.am delete mode 100644 plugins/kimchi/ui/spice-html5/pages/spice_auto.html delete mode 100644 plugins/kimchi/ui/spice-html5/playback.js delete mode 100644 plugins/kimchi/ui/spice-html5/png.js delete mode 100644 plugins/kimchi/ui/spice-html5/quic.js delete mode 100644 plugins/kimchi/ui/spice-html5/resize.js delete mode 100644 plugins/kimchi/ui/spice-html5/simulatecursor.js delete mode 100644 plugins/kimchi/ui/spice-html5/spicearraybuffer.js delete mode 100644 plugins/kimchi/ui/spice-html5/spiceconn.js delete mode 100644 plugins/kimchi/ui/spice-html5/spicedataview.js delete mode 100644 plugins/kimchi/ui/spice-html5/spicemsg.js delete mode 100644 plugins/kimchi/ui/spice-html5/spicetype.js delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/Makefile.am delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/prng4.js delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/rng.js delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/rsa.js delete mode 100644 plugins/kimchi/ui/spice-html5/thirdparty/sha1.js delete mode 100644 plugins/kimchi/ui/spice-html5/ticket.js delete mode 100644 plugins/kimchi/ui/spice-html5/utils.js delete mode 100644 plugins/kimchi/ui/spice-html5/webm.js delete mode 100644 plugins/kimchi/ui/spice-html5/wire.js delete mode 100644 plugins/kimchi/utils.py delete mode 100644 plugins/kimchi/vmtemplate.py delete mode 100644 plugins/kimchi/vnc.py delete mode 100644 plugins/kimchi/xmlutils/Makefile.am delete mode 100644 plugins/kimchi/xmlutils/__init__.py delete mode 100644 plugins/kimchi/xmlutils/cpu.py delete mode 100644 plugins/kimchi/xmlutils/disk.py delete mode 100644 plugins/kimchi/xmlutils/graphics.py delete mode 100644 plugins/kimchi/xmlutils/interface.py delete mode 100644 plugins/kimchi/xmlutils/network.py delete mode 100644 plugins/kimchi/xmlutils/qemucmdline.py delete mode 100644 plugins/kimchi/yumparser.py delete mode 100644 plugins/sample/API.json delete mode 100644 plugins/sample/Makefile.am delete mode 100644 plugins/sample/__init__.py delete mode 120000 plugins/sample/config.status delete mode 100644 plugins/sample/i18n.py delete mode 100644 plugins/sample/model.py delete mode 100644 plugins/sample/po/LINGUAS delete mode 100644 plugins/sample/po/Makefile.in.in delete mode 100644 plugins/sample/po/Makevars delete mode 100644 plugins/sample/po/POTFILES.in delete mode 100644 plugins/sample/po/en_US.po delete mode 100755 plugins/sample/po/gen-pot delete mode 100644 plugins/sample/po/pt_BR.po delete mode 100644 plugins/sample/po/sample.pot delete mode 100644 plugins/sample/po/zh_CN.po delete mode 100644 plugins/sample/sample.conf.in delete mode 100644 plugins/sample/ui/Makefile.am delete mode 100644 plugins/sample/ui/config/Makefile.am delete mode 100644 plugins/sample/ui/config/tab-ext.xml delete mode 100644 plugins/sample/ui/css/.gitignore delete mode 100644 plugins/sample/ui/images/.gitignore delete mode 100644 plugins/sample/ui/js/.gitignore delete mode 100644 plugins/sample/ui/js/Makefile.am delete mode 100644 plugins/sample/ui/js/util.js delete mode 100644 plugins/sample/ui/libs/.gitignore delete mode 100644 plugins/sample/ui/pages/Makefile.am delete mode 100644 plugins/sample/ui/pages/help/en_US/sample-tab1.html delete mode 100644 plugins/sample/ui/pages/help/en_US/sample-tab2.html delete mode 100644 plugins/sample/ui/pages/i18n.json.tmpl delete mode 100644 plugins/sample/ui/pages/sample-tab1.html.tmpl delete mode 100644 plugins/sample/ui/pages/sample-tab2.html.tmpl create mode 100644 src/wok/plugins/Makefile.am create mode 100644 src/wok/plugins/__init__.py create mode 100644 src/wok/plugins/kimchi/.gitignore create mode 100644 src/wok/plugins/kimchi/API.json create mode 100644 src/wok/plugins/kimchi/INSTALL create mode 100644 src/wok/plugins/kimchi/Makefile.am create mode 120000 src/wok/plugins/kimchi/README.md create mode 100644 src/wok/plugins/kimchi/VERSION create mode 100644 src/wok/plugins/kimchi/__init__.py create mode 100755 src/wok/plugins/kimchi/autogen.sh create mode 100644 src/wok/plugins/kimchi/build-aux/config.rpath create mode 100755 src/wok/plugins/kimchi/build-aux/genChangelog create mode 100755 src/wok/plugins/kimchi/build-aux/pkg-version create mode 100644 src/wok/plugins/kimchi/config.py.in create mode 100644 src/wok/plugins/kimchi/config.rpath create mode 100644 src/wok/plugins/kimchi/configure.ac create mode 100644 src/wok/plugins/kimchi/contrib/DEBIAN/Makefile.am create mode 100644 src/wok/plugins/kimchi/contrib/DEBIAN/control.in create mode 100644 src/wok/plugins/kimchi/contrib/Makefile.am create mode 100755 src/wok/plugins/kimchi/contrib/check_i18n.py create mode 100644 src/wok/plugins/kimchi/contrib/kimchi.spec.fedora.in create mode 100644 src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in create mode 100644 src/wok/plugins/kimchi/contrib/make-deb.sh.in create mode 100644 src/wok/plugins/kimchi/control/Makefile.am create mode 100644 src/wok/plugins/kimchi/control/__init__.py create mode 100644 src/wok/plugins/kimchi/control/config.py create mode 100644 src/wok/plugins/kimchi/control/cpuinfo.py create mode 100644 src/wok/plugins/kimchi/control/debugreports.py create mode 100644 src/wok/plugins/kimchi/control/groups.py create mode 100644 src/wok/plugins/kimchi/control/host.py create mode 100644 src/wok/plugins/kimchi/control/interfaces.py create mode 100644 src/wok/plugins/kimchi/control/networks.py create mode 100644 src/wok/plugins/kimchi/control/peers.py create mode 100644 src/wok/plugins/kimchi/control/storagepools.py create mode 100644 src/wok/plugins/kimchi/control/storageservers.py create mode 100644 src/wok/plugins/kimchi/control/storagevolumes.py create mode 100644 src/wok/plugins/kimchi/control/templates.py create mode 100644 src/wok/plugins/kimchi/control/users.py create mode 100644 src/wok/plugins/kimchi/control/vm/Makefile.am create mode 100644 src/wok/plugins/kimchi/control/vm/__init__.py create mode 100644 src/wok/plugins/kimchi/control/vm/hostdevs.py create mode 100644 src/wok/plugins/kimchi/control/vm/ifaces.py create mode 100644 src/wok/plugins/kimchi/control/vm/snapshots.py create mode 100644 src/wok/plugins/kimchi/control/vm/storages.py create mode 100644 src/wok/plugins/kimchi/control/vms.py create mode 100644 src/wok/plugins/kimchi/disks.py create mode 100644 src/wok/plugins/kimchi/distroloader.py create mode 100644 src/wok/plugins/kimchi/distros.d/Makefile.am create mode 100644 src/wok/plugins/kimchi/distros.d/debian.json create mode 100644 src/wok/plugins/kimchi/distros.d/fedora.json create mode 100644 src/wok/plugins/kimchi/distros.d/gentoo.json create mode 100644 src/wok/plugins/kimchi/distros.d/opensuse.json create mode 100644 src/wok/plugins/kimchi/distros.d/ubuntu.json create mode 100644 src/wok/plugins/kimchi/docs/API.md create mode 100644 src/wok/plugins/kimchi/docs/Makefile.am create mode 100644 src/wok/plugins/kimchi/docs/README-federation.md create mode 100644 src/wok/plugins/kimchi/docs/README.md create mode 100644 src/wok/plugins/kimchi/docs/kimchi-guest.png create mode 100644 src/wok/plugins/kimchi/docs/kimchi-login.png create mode 100644 src/wok/plugins/kimchi/docs/kimchi-templates.png create mode 100644 src/wok/plugins/kimchi/i18n.py create mode 100644 src/wok/plugins/kimchi/imageinfo.py create mode 100644 src/wok/plugins/kimchi/iscsi.py create mode 100644 src/wok/plugins/kimchi/isoinfo.py create mode 100644 src/wok/plugins/kimchi/kimchi.conf create mode 100644 src/wok/plugins/kimchi/kvmusertests.py create mode 100644 src/wok/plugins/kimchi/m4/ac_python_module.m4 create mode 100644 src/wok/plugins/kimchi/m4/gettext.m4 create mode 100644 src/wok/plugins/kimchi/m4/iconv.m4 create mode 100644 src/wok/plugins/kimchi/m4/intlmacosx.m4 create mode 100644 src/wok/plugins/kimchi/m4/lib-ld.m4 create mode 100644 src/wok/plugins/kimchi/m4/lib-link.m4 create mode 100644 src/wok/plugins/kimchi/m4/lib-prefix.m4 create mode 100644 src/wok/plugins/kimchi/m4/nls.m4 create mode 100644 src/wok/plugins/kimchi/m4/po.m4 create mode 100644 src/wok/plugins/kimchi/m4/progtest.m4 create mode 100644 src/wok/plugins/kimchi/mockmodel.py create mode 100644 src/wok/plugins/kimchi/model/Makefile.am create mode 100644 src/wok/plugins/kimchi/model/__init__.py create mode 100644 src/wok/plugins/kimchi/model/config.py create mode 100644 src/wok/plugins/kimchi/model/cpuinfo.py create mode 100644 src/wok/plugins/kimchi/model/debugreports.py create mode 100644 src/wok/plugins/kimchi/model/diskutils.py create mode 100644 src/wok/plugins/kimchi/model/featuretests.py create mode 100644 src/wok/plugins/kimchi/model/groups.py create mode 100644 src/wok/plugins/kimchi/model/host.py create mode 100644 src/wok/plugins/kimchi/model/hostdev.py create mode 100644 src/wok/plugins/kimchi/model/interfaces.py create mode 100644 src/wok/plugins/kimchi/model/libvirtconnection.py create mode 100644 src/wok/plugins/kimchi/model/libvirtstoragepool.py create mode 100644 src/wok/plugins/kimchi/model/model.py create mode 100644 src/wok/plugins/kimchi/model/networks.py create mode 100644 src/wok/plugins/kimchi/model/peers.py create mode 100644 src/wok/plugins/kimchi/model/storagepools.py create mode 100644 src/wok/plugins/kimchi/model/storageservers.py create mode 100644 src/wok/plugins/kimchi/model/storagetargets.py create mode 100644 src/wok/plugins/kimchi/model/storagevolumes.py create mode 100644 src/wok/plugins/kimchi/model/templates.py create mode 100644 src/wok/plugins/kimchi/model/users.py create mode 100644 src/wok/plugins/kimchi/model/utils.py create mode 100644 src/wok/plugins/kimchi/model/vmhostdevs.py create mode 100644 src/wok/plugins/kimchi/model/vmifaces.py create mode 100644 src/wok/plugins/kimchi/model/vms.py create mode 100644 src/wok/plugins/kimchi/model/vmsnapshots.py create mode 100644 src/wok/plugins/kimchi/model/vmstorages.py create mode 100644 src/wok/plugins/kimchi/netinfo.py create mode 100644 src/wok/plugins/kimchi/network.py create mode 100644 src/wok/plugins/kimchi/osinfo.py create mode 100644 src/wok/plugins/kimchi/po/LINGUAS create mode 100644 src/wok/plugins/kimchi/po/Makefile.in.in create mode 100644 src/wok/plugins/kimchi/po/Makevars create mode 100644 src/wok/plugins/kimchi/po/POTFILES.in create mode 100644 src/wok/plugins/kimchi/po/de_DE.po create mode 100644 src/wok/plugins/kimchi/po/en_US.po create mode 100644 src/wok/plugins/kimchi/po/es_ES.po create mode 100644 src/wok/plugins/kimchi/po/fr_FR.po create mode 100644 src/wok/plugins/kimchi/po/gen-pot.in create mode 100644 src/wok/plugins/kimchi/po/it_IT.po create mode 100644 src/wok/plugins/kimchi/po/ja_JP.po create mode 100755 src/wok/plugins/kimchi/po/kimchi.pot create mode 100644 src/wok/plugins/kimchi/po/ko_KR.po create mode 100644 src/wok/plugins/kimchi/po/pt_BR.po create mode 100644 src/wok/plugins/kimchi/po/ru_RU.po create mode 100644 src/wok/plugins/kimchi/po/zh_CN.po create mode 100644 src/wok/plugins/kimchi/po/zh_TW.po create mode 100644 src/wok/plugins/kimchi/repositories.py create mode 100644 src/wok/plugins/kimchi/root.py create mode 100644 src/wok/plugins/kimchi/scan.py create mode 100644 src/wok/plugins/kimchi/screenshot.py create mode 100644 src/wok/plugins/kimchi/swupdate.py create mode 100644 src/wok/plugins/kimchi/template.conf create mode 100644 src/wok/plugins/kimchi/tests/Makefile.am create mode 100644 src/wok/plugins/kimchi/tests/iso_gen.py create mode 100644 src/wok/plugins/kimchi/tests/run_tests.sh.in create mode 100644 src/wok/plugins/kimchi/tests/test_authorization.py create mode 100644 src/wok/plugins/kimchi/tests/test_config.py.in create mode 100644 src/wok/plugins/kimchi/tests/test_exception.py create mode 100644 src/wok/plugins/kimchi/tests/test_host.py create mode 100644 src/wok/plugins/kimchi/tests/test_mock_network.py create mode 100644 src/wok/plugins/kimchi/tests/test_mock_storagepool.py create mode 100644 src/wok/plugins/kimchi/tests/test_mock_storagevolume.py create mode 100644 src/wok/plugins/kimchi/tests/test_mockmodel.py create mode 100644 src/wok/plugins/kimchi/tests/test_model.py create mode 100644 src/wok/plugins/kimchi/tests/test_model_network.py create mode 100644 src/wok/plugins/kimchi/tests/test_model_storagepool.py create mode 100644 src/wok/plugins/kimchi/tests/test_model_storagevolume.py create mode 100644 src/wok/plugins/kimchi/tests/test_networkxml.py create mode 100644 src/wok/plugins/kimchi/tests/test_objectstore.py create mode 100644 src/wok/plugins/kimchi/tests/test_osinfo.py create mode 100644 src/wok/plugins/kimchi/tests/test_plugin.py create mode 100644 src/wok/plugins/kimchi/tests/test_rest.py create mode 100644 src/wok/plugins/kimchi/tests/test_rollbackcontext.py create mode 100644 src/wok/plugins/kimchi/tests/test_server.py create mode 100644 src/wok/plugins/kimchi/tests/test_storagepoolxml.py create mode 100644 src/wok/plugins/kimchi/tests/test_template.py create mode 100644 src/wok/plugins/kimchi/tests/test_utils.py create mode 100644 src/wok/plugins/kimchi/tests/test_vmtemplate.py create mode 100644 src/wok/plugins/kimchi/tests/test_yumparser.py create mode 100644 src/wok/plugins/kimchi/tests/utils.py create mode 100644 src/wok/plugins/kimchi/ui/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/config/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/config/tab-ext.xml create mode 100644 src/wok/plugins/kimchi/ui/css/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/guest-edit.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/guest-storage-add.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/host.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/icon.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/list.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/network.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/report-add.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/report-rename.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/repository-add.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/repository-edit.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/storage.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/storagepool-add-volume.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/template-edit.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/template.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/template_add.css create mode 100644 src/wok/plugins/kimchi/ui/css/theme-default/template_list.css create mode 100644 src/wok/plugins/kimchi/ui/images/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/images/icon-centos.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-debian.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-fedora.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-gentoo.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-opensuse.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-ubuntu.png create mode 100644 src/wok/plugins/kimchi/ui/images/icon-vm.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/ac22_pause.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/ac22_pause_grey.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/ac24_resume.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/ac24_resume_grey.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/arrow-down-black.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/arrow-down-disable.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/arrow-down.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/arrow-up.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/arrow_out.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/group.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/host-icon-sprite.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-back.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-camera.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-design.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-detail.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-iso.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-list.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-load.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-local.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-power-down.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-power-up.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-qcow2.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-raw.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-remote.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-reset.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-search.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-sort.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-tree.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-user.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/icon-volume-default.png create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/kimchi-loading15x15.gif create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/loading.gif create mode 100644 src/wok/plugins/kimchi/ui/images/theme-default/user.png create mode 100644 src/wok/plugins/kimchi/ui/js/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.api.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.guest_add_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.guest_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.guest_media_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.guest_storage_add.main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.host.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.network.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.report_add_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.storage_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.storagepool_add_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.storagepool_add_volume_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.template_add_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js create mode 100644 src/wok/plugins/kimchi/ui/js/src/kimchi.template_main.js create mode 100644 src/wok/plugins/kimchi/ui/pages/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/guest-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/guest-edit.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/guest-storage-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/guest.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/guests.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/help/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/de_DE/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/dita-help.xsl create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/en_US/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/es_ES/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/fr_FR/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/it_IT/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ja_JP/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/kimchi.css create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ko_KR/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/pt_BR/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/ru_RU/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_CN/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/guests.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/host.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/network.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/storage.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/help/zh_TW/templates.dita create mode 100644 src/wok/plugins/kimchi/ui/pages/host.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/i18n.json.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/network.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/report-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/report-rename.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/repository-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/repository-edit.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/storage.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/storagepool-add-volume.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/storagepool-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/template-add.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/template-edit.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/pages/templates.html.tmpl create mode 100644 src/wok/plugins/kimchi/ui/robots.txt create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/atKeynames.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/bitmap.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/css/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/css/spice.css create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/cursor.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/display.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/enums.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/inputs.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/lz.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/main.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/pages/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/pages/spice_auto.html create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/playback.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/png.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/quic.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/resize.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/simulatecursor.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/spicearraybuffer.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/spiceconn.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/spicedataview.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/spicemsg.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/spicetype.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/Makefile.am create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/prng4.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/rng.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/rsa.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/thirdparty/sha1.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/ticket.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/utils.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/webm.js create mode 100644 src/wok/plugins/kimchi/ui/spice-html5/wire.js create mode 100644 src/wok/plugins/kimchi/utils.py create mode 100644 src/wok/plugins/kimchi/vmtemplate.py create mode 100644 src/wok/plugins/kimchi/vnc.py create mode 100644 src/wok/plugins/kimchi/xmlutils/Makefile.am create mode 100644 src/wok/plugins/kimchi/xmlutils/__init__.py create mode 100644 src/wok/plugins/kimchi/xmlutils/cpu.py create mode 100644 src/wok/plugins/kimchi/xmlutils/disk.py create mode 100644 src/wok/plugins/kimchi/xmlutils/graphics.py create mode 100644 src/wok/plugins/kimchi/xmlutils/interface.py create mode 100644 src/wok/plugins/kimchi/xmlutils/network.py create mode 100644 src/wok/plugins/kimchi/xmlutils/qemucmdline.py create mode 100644 src/wok/plugins/kimchi/yumparser.py create mode 100644 src/wok/plugins/sample/API.json create mode 100644 src/wok/plugins/sample/Makefile.am create mode 100644 src/wok/plugins/sample/__init__.py create mode 120000 src/wok/plugins/sample/config.status create mode 100644 src/wok/plugins/sample/i18n.py create mode 100644 src/wok/plugins/sample/model.py create mode 100644 src/wok/plugins/sample/po/LINGUAS create mode 100644 src/wok/plugins/sample/po/Makefile.in.in create mode 100644 src/wok/plugins/sample/po/Makevars create mode 100644 src/wok/plugins/sample/po/POTFILES.in create mode 100644 src/wok/plugins/sample/po/en_US.po create mode 100755 src/wok/plugins/sample/po/gen-pot create mode 100644 src/wok/plugins/sample/po/pt_BR.po create mode 100644 src/wok/plugins/sample/po/sample.pot create mode 100644 src/wok/plugins/sample/po/zh_CN.po create mode 100644 src/wok/plugins/sample/sample.conf.in create mode 100644 src/wok/plugins/sample/ui/Makefile.am create mode 100644 src/wok/plugins/sample/ui/config/Makefile.am create mode 100644 src/wok/plugins/sample/ui/config/tab-ext.xml create mode 100644 src/wok/plugins/sample/ui/css/.gitignore create mode 100644 src/wok/plugins/sample/ui/images/.gitignore create mode 100644 src/wok/plugins/sample/ui/js/.gitignore create mode 100644 src/wok/plugins/sample/ui/js/Makefile.am create mode 100644 src/wok/plugins/sample/ui/js/util.js create mode 100644 src/wok/plugins/sample/ui/libs/.gitignore create mode 100644 src/wok/plugins/sample/ui/pages/Makefile.am create mode 100644 src/wok/plugins/sample/ui/pages/help/en_US/sample-tab1.html create mode 100644 src/wok/plugins/sample/ui/pages/help/en_US/sample-tab2.html create mode 100644 src/wok/plugins/sample/ui/pages/i18n.json.tmpl create mode 100644 src/wok/plugins/sample/ui/pages/sample-tab1.html.tmpl create mode 100644 src/wok/plugins/sample/ui/pages/sample-tab2.html.tmpl diff --git a/plugins/Makefile.am b/plugins/Makefile.am deleted file mode 100644 index 21a6ece..0000000 --- a/plugins/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -SUBDIRS = sample - -plugins_PYTHON = \ - __init__.py - -pluginsdir = $(pythondir)/wok/plugins diff --git a/plugins/__init__.py b/plugins/__init__.py deleted file mode 100644 index 0539a76..0000000 --- a/plugins/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/plugins/kimchi/.gitignore b/plugins/kimchi/.gitignore deleted file mode 100644 index 1dae610..0000000 --- a/plugins/kimchi/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -*.pyc -*~ -i18n/mo/* -log -data -mo -autom4te.cache -Makefile -Makefile.in -aclocal.m4 -build-aux/compile -build-aux/config.guess -build-aux/config.sub -build-aux/install-sh -build-aux/missing -build-aux/py-compile -configure -config.log -config.py -config.status -contrib/DEBIAN/control -contrib/kimchi.spec.fedora -contrib/kimchi.spec.suse -contrib/make-deb.sh -*.min.css -*.min.js -*.gmo -stamp-po -kimchi-*.tar.gz -tests/run_tests.sh -tests/test_config.py -po/POTFILES -po/gen-pot -*.orig -*.rej -*.pem -ui/pages/help/*/*.html diff --git a/plugins/kimchi/API.json b/plugins/kimchi/API.json deleted file mode 100644 index f1f58ff..0000000 --- a/plugins/kimchi/API.json +++ /dev/null @@ -1,836 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-03/schema#", - "title": "Kimchi API", - "description": "Json schema for Kimchi API", - "type": "object", - "kimchitype": { - "graphics": { - "description": "Configure graphics parameters for the new VM", - "type": "object", - "properties": { - "type": { - "enum": ["spice", "vnc"], - "error": "KCHVM0014E" - }, - "listen": { - "error": "KCHVM0015E", - "type": [ - { - "type": "string", - "format": "ip-address" - }, - { - "type": "string", - "format": "ipv6" - } - ] - } - } - }, - "cpu_info": { - "description": "Configure CPU specifics for a VM.", - "type": "object", - "properties": { - "topology": { - "description": "Configure the guest CPU topology.", - "type": "object", - "properties": { - "sockets": { - "type": "integer", - "required": true, - "minimum": 1, - "error": "KCHTMPL0026E" - }, - "cores": { - "type": "integer", - "required": true, - "minimum": 1, - "error": "KCHTMPL0026E" - }, - "threads": { - "type": "integer", - "required": true, - "minimum": 1, - "error": "KCHTMPL0026E" - } - } - } - } - } - }, - "properties": { - "debugreports_create": { - "type": "object", - "error": "KCHDR0006E", - "properties": { - "name": { - "description": "The name for the debug report file.", - "type": "string", - "pattern": "^[_A-Za-z0-9-]*$", - "error": "KCHDR0007E" - } - } - }, - "debugreport_update": { - "type": "object", - "properties": { - "name": { - "description": "New name of debug report", - "type": "string", - "pattern": "^[_A-Za-z0-9-]*$", - "error": "KCHDR0007E" - } - }, - "additionalProperties": false - }, - "storagepools_create": { - "type": "object", - "error": "KCHPOOL0026E", - "properties": { - "name": { - "description": "The name of the Storage Pool", - "type": "string", - "minLength": 1, - "pattern": "^[^/]*$", - "required": true, - "error": "KCHPOOL0016E" - }, - "type": { - "description": "The type of the defined Storage Pool", - "type": "string", - "pattern": "^dir|netfs|logical|kimchi-iso|iscsi|scsi$", - "required": true, - "error": "KCHPOOL0017E" - }, - "path": { - "description": "The path of the defined Storage Pool", - "type": "string", - "error": "KCHPOOL0018E" - }, - "source": { - "description": "Dictionary containing source information of the pool", - "type": "object", - "properties": { - "host": { - "description": "IP or hostname of server for a pool backed from a remote host", - "type": "string", - "error": "KCHPOOL0019E" - }, - "path": { - "description": "Export path on NFS server for NFS pool", - "type": "string", - "error": "KCHPOOL0018E" - }, - "devices": { - "description": "Array of devices to be used in the Storage Pool", - "type": "array", - "minItems": 1, - "uniqueItems": true, - "error": "KCHPOOL0021E", - "items": { - "description": "Full path of the block device node", - "type": "string", - "error": "KCHPOOL0020E" - } - }, - "target": { - "description": "Target IQN of an iSCSI pool", - "type": "string", - "error": "KCHPOOL0022E" - }, - "port": { - "description": "Listening port of a remote storage server", - "type": "integer", - "minimum": 1, - "maximum": 65535, - "error": "KCHPOOL0023E" - }, - "adapter_name": { - "description": "SCSI host name", - "type": "string", - "error": "KCHPOOL0030E" - }, - "auth": { - "description": "Storage back-end authentication information", - "type": "object", - "properties": { - "username": { - "description": "Login username of the iSCSI target", - "type": "string", - "error": "KCHPOOL0024E" - }, - "password": { - "description": "Login password of the iSCSI target", - "type": "string", - "error": "KCHPOOL0025E" - } - } - } - } - } - } - }, - "storagepool_update": { - "type": "object", - "properties": { - "autostart": { - "description": "Set autostart value of the pool", - "type": "boolean" - }, - "disks": { - "description": "List of disks/partitions to be added", - "type": "array", - "items": { "type": "string" }, - "minItems": 1, - "uniqueItems": true - } - }, - "additionalProperties": false - }, - "storagevolumes_create": { - "type": "object", - "properties": { - "name": { - "description": "The name of the Storage Volume", - "type": "string", - "minLength": 1, - "error": "KCHVOL0013E" - }, - "capacity": { - "description": "The total size (MiB) of the storage volume", - "type": "number", - "minimum": 1, - "error": "KCHVOL0020E" - }, - "upload": { - "description": "When the storage volume will be uploaded", - "type": "boolean", - "error": "KCHVOL0025E" - }, - "allocation": { - "description": "The size(MiB) of allocation when create the storage volume", - "type": "number", - "minimum": 1, - "error": "KCHVOL0014E" - }, - "format": { - "description": "The format of the volume", - "type": "string", - "pattern": "^(|bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", - "error": "KCHVOL0015E" - }, - "url": { - "description": "The remote URL of the storage volume", - "type": "string", - "pattern": "^(http|ftp)[s]?://", - "error": "KCHVOL0021E" - } - } - }, - "storagevolume_update": { - "type": "object", - "properties": { - "chunk": { - "description": "Upload storage volume chunk", - "error": "KCHVOL0024E", - "required": true - }, - "chunk_size": { - "description": "Chunk size of uploaded storage volume", - "type": "string", - "error": "KCHVOL0024E", - "required": true - } - }, - "additionalProperties": false - }, - "vms_create": { - "type": "object", - "error": "KCHVM0016E", - "properties": { - "name": { - "description": "The name of the new VM", - "type": "string", - "pattern": "^[^/]*$", - "error": "KCHVM0011E" - }, - "template": { - "description": "The URI of a template to use when building a VM", - "type": "string", - "pattern": "^/plugins/kimchi/templates/(.*?)/?$", - "required": true, - "error": "KCHVM0012E" - }, - "storagepool": { - "description": "Assign a specefic Storage Pool to the new VM", - "type": "string", - "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", - "error": "KCHVM0013E" - }, - "graphics": { "$ref": "#/kimchitype/graphics" } - } - }, - "vm_update": { - "type": "object", - "properties": { - "name": { - "description": "New name of VM", - "type": "string", - "pattern": "^[^/]*$", - "minLength": 1, - "error": "KCHVM0011E" - }, - "users": { - "description": "Array of users who have permission to the VM", - "type": "array", - "uniqueItems": true, - "error": "KCHVM0023E", - "items": { - "description": "User name", - "type": "string", - "error": "KCHVM0024E" - } - }, - "groups": { - "description": "Array of groups who have permission to the VM", - "type": "array", - "uniqueItems": true, - "error": "KCHVM0025E", - "items": { - "description": "Group name", - "type": "string", - "error": "KCHVM0026E" - } - }, - "graphics": { - "description": "Graphics information from guest", - "type": "object", - "properties": { - "passwd": { - "description": "New graphics password.", - "type": "string", - "error": "KCHVM0031E" - }, - "passwdValidTo": { - "description": "Life time for the graphics password.", - "type": "number", - "error": "KCHVM0032E" - } - } - }, - "cpus": { - "description": "The new number of virtual CPUs for the VM", - "type": "integer", - "minimum": 1, - "error": "KCHTMPL0012E" - }, - "memory": { - "description": "The new amount (MB) of memory for the VM", - "type": "integer", - "minimum": 512, - "error": "KCHTMPL0013E" - } - }, - "additionalProperties": false - }, - "networks_create": { - "type": "object", - "error": "KCHNET0016E", - "properties": { - "name": { - "description": "The name of the new network", - "type": "string", - "minLength": 1, - "pattern": "^[^/\"]*$", - "required": true, - "error": "KCHNET0011E" - }, - "connection": { - "description": "Specifies how this network should be connected to the other networks", - "type": "string", - "pattern": "^isolated|nat|bridge$", - "required": true, - "error": "KCHNET0012E" - }, - "subnet": { - "description": "Network segment in slash-separated format with ip address and prefix or netmask", - "type": "string", - "error": "KCHNET0013E" - }, - "interface": { - "description": "The name of a network interface on the host", - "type": "string", - "error": "KCHNET0014E" - }, - "vlan_id": { - "description": "Network's VLAN ID", - "type": "integer", - "maximum": 4094, - "minimum": 1, - "error": "KCHNET0015E" - } - } - }, - "vmifaces_create": { - "type": "object", - "error": "KCHVMIF0007E", - "properties": { - "type": { - "description": "The type of VM network interface that libvirt supports", - "type": "string", - "pattern": "^network$", - "required": true, - "error": "KCHVMIF0004E" - }, - "network": { - "description": "the name of one available network", - "minLength": 1, - "type": "string", - "error": "KCHVMIF0005E" - }, - "model": { - "description": "model of emulated network interface card", - "type": "string", - "pattern": "^ne2k_pci|i82551|i82557b|i82559er|rtl8139|e1000|pcnet|virtio$", - "error": "KCHVMIF0006E" - }, - "mac": { - "description": "Network Interface Card MAC address", - "type": "string", - "pattern": "(^$)|^(([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$)", - "error": "KCHVMIF0010E" - } - } - }, - "vmiface_update": { - "type": "object", - "error": "KCHVMIF0008E", - "properties": { - "mac": { - "description": "Network Interface Card MAC address", - "type": "string", - "pattern": "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$", - "error": "KCHVMIF0010E" - } - } - }, - "templates_create": { - "type": "object", - "error": "KCHTMPL0016E", - "properties": { - "name": { - "description": "The name of the template", - "type": "string", - "pattern": "^[^ ]+( +[^ ]+)*$", - "minLength": 1, - "error": "KCHTMPL0008E" - }, - "icon": { - "description": "The template icon path", - "type": "string", - "pattern": "^/plugins/kimchi/images/", - "error": "KCHTMPL0009E" - }, - "os_distro": { - "description": "Distribution name of the Operating System", - "type": "string", - "minLength": 1, - "error": "KCHTMPL0010E" - }, - "os_version": { - "description": "Version of the Operating System", - "type": "string", - "minLength": 1, - "error": "KCHTMPL0011E" - }, - "cpus": { - "description": "Number of CPUs for the template", - "type": "integer", - "minimum": 1, - "error": "KCHTMPL0012E" - }, - "memory": { - "description": "Memory (MB) for the template", - "type": "integer", - "minimum": 512, - "error": "KCHTMPL0013E" - }, - "cdrom": { - "description": "Path for cdrom", - "type": "string", - "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", - "error": "KCHTMPL0014E" - }, - "disks": { - "description": "List of disks", - "type": "array", - "items": { - "type": "object", - "properties": { - "index": { - "description": "Index of the disk", - "type": "integer", - "minimum": 0 - }, - "size": { - "description": "Size (GB) of the disk", - "type": "number", - "minimum": 1, - "error": "KCHTMPL0022E" - }, - "base": { - "description": "Base image of the disk", - "type": "string", - "pattern": "^/.+$", - "error": "KCHTMPL0023E" - } - - } - }, - "minItems": 1, - "uniqueItems": true - }, - "storagepool": { - "description": "Location of the storage pool", - "type": "string", - "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", - "error": "KCHTMPL0015E" - }, - "networks": { - "description": "list of which networks will be assigned to the new VM.", - "type": "array", - "items": { "type": "string" }, - "error": "KCHTMPL0017E" - }, - "folder": { - "description": "Folder", - "type": "array", - "items": { "type": "string" } - }, - "graphics": { "$ref": "#/kimchitype/graphics" }, - "cpu_info": { "$ref": "#/kimchitype/cpu_info" } - }, - "additionalProperties": false, - "error": "KCHAPI0001E" - }, - "storageservers_get_list": { - "type": "object", - "properties": { - "_target_type": { - "description": "List storage servers of given type", - "type": "string", - "pattern": "^netfs|iscsi$" - } - }, - "additionalProperties": false, - "error": "KCHAPI0001E" - }, - "storagetargets_get_list": { - "type": "object", - "properties": { - "_target_type": { - "description": "List storage servers of given type", - "type": "string", - "pattern": "^netfs|iscsi$" - }, - "_server_port": { - "description": "the port of iscsi storage servers", - "type": "string", - "pattern": "^[0-9]{1,5}$" - } - }, - "additionalProperties": false, - "error": "KCHAPI0001E" - }, - "vmstorages_create": { - "type": "object", - "error": "KCHVMSTOR0012E", - "properties": { - "type": { - "description": "The storage type", - "type": "string", - "pattern": "^cdrom|disk$", - "required": true, - "error": "KCHVMSTOR0002E" - }, - "pool": { - "description": "Storage pool name disk image locate in", - "type": "string", - "minLength": 1, - "error": "KCHVMSTOR0012E" - }, - "vol": { - "description": "Storage volume name of disk image", - "type": "string", - "minLength": 1, - "error": "KCHVMSTOR0012E" - }, - "path": { - "description": "Path of iso image file or disk mount point", - "type": "string", - "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", - "error": "KCHVMSTOR0003E" - } - } - }, - "vmstorage_update": { - "type": "object", - "error": "KCHVMSTOR0013E", - "properties": { - "path": { - "description": "Path of iso image file or disk mount point", - "type": "string", - "pattern": "^(|(/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", - "required": true, - "error": "KCHVMSTOR0003E" - } - }, - "additionalProperties": false - }, - "template_update": { - "type": "object", - "properties": { - "name": { - "description": "The name of the template", - "type": "string", - "pattern": "^[^ ]+( +[^ ]+)*$", - "minLength": 1, - "error": "KCHTMPL0008E" - }, - "icon": { - "description": "The template icon path", - "type": "string", - "pattern": "^/plugins/kimchi/images/", - "error": "KCHTMPL0009E" - }, - "os_distro": { - "description": "Distribution name of the Operating System", - "type": "string", - "minLength": 1, - "error": "KCHTMPL0010E" - }, - "os_version": { - "description": "Version of the Operating System", - "type": "string", - "minLength": 1, - "error": "KCHTMPL0011E" - }, - "cpus": { - "description": "Number of CPUs for the template", - "type": "integer", - "minimum": 1, - "error": "KCHTMPL0012E" - }, - "memory": { - "description": "Memory (MB) for the template", - "type": "integer", - "minimum": 512, - "error": "KCHTMPL0013E" - }, - "cdrom": { - "description": "Path for cdrom", - "type": "string", - "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", - "error": "KCHTMPL0014E" - }, - "disks": { - "description": "List of disks", - "type": "array", - "items": { - "type": "object", - "properties": { - "index": { - "description": "Index of the disk", - "type": "integer", - "minimum": 0 - }, - "size": { - "description": "Size (GB) of the disk", - "type": "integer", - "minimum": 1, - "error": "KCHTMPL0022E" - }, - "format": { - "description": "Type of the image of the disk", - "type": "string", - "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", - "error": "KCHTMPL0027E" - } - } - }, - "minItems": 1, - "uniqueItems": true - }, - "storagepool": { - "description": "Location of the storage pool", - "type": "string", - "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", - "error": "KCHTMPL0015E" - }, - "networks": { - "description": "list of which networks will be assigned to the new VM.", - "type": "array", - "items": { "type": "string" }, - "error": "KCHTMPL0017E" - }, - "folder": { - "description": "Folder", - "type": "array", - "items": { "type": "string" } - }, - "graphics": { "$ref": "#/kimchitype/graphics" }, - "cpu_info": { "$ref": "#/kimchitype/cpu_info" } - }, - "additionalProperties": false, - "error": "KCHAPI0001E" - }, - "repositories_create": { - "type": "object", - "properties": { - "repo_id": { - "description": "Repository ID used for YUM repository.", - "type": "string", - "error": "KCHREPOS0001E" - }, - "baseurl": { - "description": "URL to the directory where the repodata directory of a repository is located. Can be an http://, ftp:// or file:// URL.", - "type": "string", - "error": "KCHREPOS0002E" - }, - "config": { - "description": "Dictionary containing repository configuration", - "type": "object", - "error": "KCHREPOS0003E", - "properties": { - "dist": { - "description": "Distribution to DEB repository", - "type": "string", - "error": "KCHREPOS0004E" - }, - "comps": { - "description": "List of components to DEB repository", - "type": "array", - "error": "KCHREPOS0005E", - "uniqueItems": true, - "items": { - "description": "Component name", - "type": "string", - "error": "KCHREPOS0006E" - } - }, - "repo_name": { - "description": "YUM repository name", - "type": "string", - "error": "KCHREPOS0023E" - }, - "mirrorlist": { - "description": "URL to a file containing a list of baseurls", - "type": "string", - "error": "KCHREPOS0007E" - }, - "metalink": { - "description": "URL to a metalink file for the repomd.xml", - "type": "string", - "error": "KCHREPOS0029E" - } - } - } - }, - "additionalProperties": false, - "error": "KCHAPI0001E" - }, - "repository_update": { - "type": "object", - "properties": { - "baseurl": { - "description": "URL to the directory where the repodata directory of a repository is located. Can be an http://, ftp:// or file:// URL.", - "type": "string", - "error": "KCHREPOS0002E" - }, - "config": { - "description": "Dictionary containing repository configuration", - "type": "object", - "error": "KCHREPOS0003E", - "properties": { - "dist": { - "description": "Distribution to DEB repository", - "type": "string", - "error": "KCHREPOS0004E" - }, - "comps": { - "description": "List of components to DEB repository", - "type": "array", - "error": "KCHREPOS0005E", - "uniqueItems": true, - "items": { - "description": "Component name", - "type": "string", - "error": "KCHREPOS0006E" - } - }, - "repo_name": { - "description": "Human-readable string describing the YUM repository.", - "type": "string", - "error": "KCHREPOS0008E" - }, - "mirrorlist": { - "description": "URL to a file containing a list of baseurls for YUM repository", - "type": "string", - "error": "KCHREPOS0007E" - }, - "gpgcheck": { - "description": "Indicates if a GPG signature check on the packages gotten from repository should be performed.", - "type": "boolean", - "error": "KCHREPOS0009E" - }, - "gpgkey": { - "description": "URL pointing to the ASCII-armored GPG key file for the repository.", - "type": "string", - "error": "KCHREPOS0010E" - } - } - } - }, - "additionalProperties": false, - "error": "KCHAPI0001E" - }, - "devices_get_list": { - "type": "object", - "properties": { - "_cap": { - "description": "List specific type of device", - "type": "string", - "pattern": "^fc_host|net|pci|scsi|scsi_host|storage|system|usb|usb_device$", - "error": "KCHDEVS0001E" - }, - "_passthrough": { - "description": "List only devices eligible to be assigned to guest", - "type": "string", - "pattern": "^true|false$", - "error": "KCHDEVS0002E" - }, - "_passthrough_affected_by": { - "description": "List the affected devices in the same group of a certain device to be assigned to guest", - "type": "string", - "pattern": "^[_A-Za-z0-9-]+$", - "error": "KCHDEVS0003E" - } - }, - "additionalProperties": false, - "error": "KCHAPI0001E" - }, - "vmhostdevs_create": { - "type": "object", - "properties": { - "name": { - "description": "Then name of the device to assign to VM", - "type": "string", - "pattern": "^[_A-Za-z0-9-]+$", - "required": true, - "error": "KCHVMHDEV0004E" - } - }, - "error": "KCHAPI0001E" - } - } -} diff --git a/plugins/kimchi/INSTALL b/plugins/kimchi/INSTALL deleted file mode 100644 index 63bf076..0000000 --- a/plugins/kimchi/INSTALL +++ /dev/null @@ -1,369 +0,0 @@ -Installation Instructions -************************* - -Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, -Inc. - - Copying and distribution of this file, with or without modification, -are permitted in any medium without royalty provided the copyright -notice and this notice are preserved. This file is offered as-is, -without warranty of any kind. - -Basic Installation -================== - - Briefly, the shell commands `./configure; make; make install' should -configure, build, and install this package. The following -more-detailed instructions are generic; see the `README' file for -instructions specific to this package. Some packages provide this -`INSTALL' file but do not implement all of the features documented -below. The lack of an optional feature in a given package is not -necessarily a bug. More recommendations for GNU packages can be found -in *note Makefile Conventions: (standards)Makefile Conventions. - - The `configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation. It uses -those values to create a `Makefile' in each directory of the package. -It may also create one or more `.h' files containing system-dependent -definitions. Finally, it creates a shell script `config.status' that -you can run in the future to recreate the current configuration, and a -file `config.log' containing compiler output (useful mainly for -debugging `configure'). - - It can also use an optional file (typically called `config.cache' -and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. Caching is -disabled by default to prevent problems with accidental use of stale -cache files. - - If you need to do unusual things to compile the package, please try -to figure out how `configure' could check whether to do them, and mail -diffs or instructions to the address given in the `README' so they can -be considered for the next release. If you are using the cache, and at -some point `config.cache' contains results you don't want to keep, you -may remove or edit it. - - The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You need `configure.ac' if -you want to change it or regenerate `configure' using a newer version -of `autoconf'. - - The simplest way to compile this package is: - - 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. - - Running `configure' might take a while. While running, it prints - some messages telling which features it is checking for. - - 2. Type `make' to compile the package. - - 3. Optionally, type `make check' to run any self-tests that come with - the package, generally using the just-built uninstalled binaries. - - 4. Type `make install' to install the programs and any data files and - documentation. When installing into a prefix owned by root, it is - recommended that the package be configured and built as a regular - user, and only the `make install' phase executed with root - privileges. - - 5. Optionally, type `make installcheck' to repeat any self-tests, but - this time using the binaries in their final installed location. - This target does not install anything. Running this target as a - regular user, particularly if the prior `make install' required - root privileges, verifies that the installation completed - correctly. - - 6. You can remove the program binaries and object files from the - source code directory by typing `make clean'. To also remove the - files that `configure' created (so you can compile the package for - a different kind of computer), type `make distclean'. There is - also a `make maintainer-clean' target, but that is intended mainly - for the package's developers. If you use it, you may have to get - all sorts of other programs in order to regenerate files that came - with the distribution. - - 7. Often, you can also type `make uninstall' to remove the installed - files again. In practice, not all packages have tested that - uninstallation works correctly, even though it is required by the - GNU Coding Standards. - - 8. Some packages, particularly those that use Automake, provide `make - distcheck', which can by used by developers to test that all other - targets like `make install' and `make uninstall' work correctly. - This target is generally not run by end users. - -Compilers and Options -===================== - - Some systems require unusual options for compilation or linking that -the `configure' script does not know about. Run `./configure --help' -for details on some of the pertinent environment variables. - - You can give `configure' initial values for configuration parameters -by setting variables in the command line or in the environment. Here -is an example: - - ./configure CC=c99 CFLAGS=-g LIBS=-lposix - - *Note Defining Variables::, for more details. - -Compiling For Multiple Architectures -==================================== - - You can compile the package for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you can use GNU `make'. `cd' to the -directory where you want the object files and executables to go and run -the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. This -is known as a "VPATH" build. - - With a non-GNU `make', it is safer to compile the package for one -architecture at a time in the source code directory. After you have -installed the package for one architecture, use `make distclean' before -reconfiguring for another architecture. - - On MacOS X 10.5 and later systems, you can create libraries and -executables that work on multiple system types--known as "fat" or -"universal" binaries--by specifying multiple `-arch' options to the -compiler but only a single `-arch' option to the preprocessor. Like -this: - - ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ - CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ - CPP="gcc -E" CXXCPP="g++ -E" - - This is not guaranteed to produce working output in all cases, you -may have to build one architecture at a time and combine the results -using the `lipo' tool if you have problems. - -Installation Names -================== - - By default, `make install' installs the package's commands under -`/usr/local/bin', include files under `/usr/local/include', etc. You -can specify an installation prefix other than `/usr/local' by giving -`configure' the option `--prefix=PREFIX', where PREFIX must be an -absolute file name. - - You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If you -pass the option `--exec-prefix=PREFIX' to `configure', the package uses -PREFIX as the prefix for installing programs and libraries. -Documentation and other data files still use the regular prefix. - - In addition, if you use an unusual directory layout you can give -options like `--bindir=DIR' to specify different values for particular -kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. In general, the -default for these options is expressed in terms of `${prefix}', so that -specifying just `--prefix' will affect all of the other directory -specifications that were not explicitly provided. - - The most portable way to affect installation locations is to pass the -correct locations to `configure'; however, many packages provide one or -both of the following shortcuts of passing variable assignments to the -`make install' command line to change installation locations without -having to reconfigure or recompile. - - The first method involves providing an override variable for each -affected directory. For example, `make install -prefix=/alternate/directory' will choose an alternate location for all -directory configuration variables that were expressed in terms of -`${prefix}'. Any directories that were specified during `configure', -but not in terms of `${prefix}', must each be overridden at install -time for the entire installation to be relocated. The approach of -makefile variable overrides for each directory variable is required by -the GNU Coding Standards, and ideally causes no recompilation. -However, some platforms have known limitations with the semantics of -shared libraries that end up requiring recompilation when using this -method, particularly noticeable in packages that use GNU Libtool. - - The second method involves providing the `DESTDIR' variable. For -example, `make install DESTDIR=/alternate/directory' will prepend -`/alternate/directory' before all installation names. The approach of -`DESTDIR' overrides is not required by the GNU Coding Standards, and -does not work on platforms that have drive letters. On the other hand, -it does better at avoiding recompilation issues, and works well even -when some directory options were not specified in terms of `${prefix}' -at `configure' time. - -Optional Features -================= - - If the package supports it, you can cause programs to be installed -with an extra prefix or suffix on their names by giving `configure' the -option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. - - Some packages pay attention to `--enable-FEATURE' options to -`configure', where FEATURE indicates an optional part of the package. -They may also pay attention to `--with-PACKAGE' options, where PACKAGE -is something like `gnu-as' or `x' (for the X Window System). The -`README' should mention any `--enable-' and `--with-' options that the -package recognizes. - - For packages that use the X Window System, `configure' can usually -find the X include and library files automatically, but if it doesn't, -you can use the `configure' options `--x-includes=DIR' and -`--x-libraries=DIR' to specify their locations. - - Some packages offer the ability to configure how verbose the -execution of `make' will be. For these packages, running `./configure ---enable-silent-rules' sets the default to minimal output, which can be -overridden with `make V=1'; while running `./configure ---disable-silent-rules' sets the default to verbose, which can be -overridden with `make V=0'. - -Particular systems -================== - - On HP-UX, the default C compiler is not ANSI C compatible. If GNU -CC is not installed, it is recommended to use the following options in -order to use an ANSI C compiler: - - ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" - -and if that doesn't work, install pre-built binaries of GCC for HP-UX. - - HP-UX `make' updates targets which have the same time stamps as -their prerequisites, which makes it generally unusable when shipped -generated files such as `configure' are involved. Use GNU `make' -instead. - - On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot -parse its `<wchar.h>' header file. The option `-nodtk' can be used as -a workaround. If GNU CC is not installed, it is therefore recommended -to try - - ./configure CC="cc" - -and if that doesn't work, try - - ./configure CC="cc -nodtk" - - On Solaris, don't put `/usr/ucb' early in your `PATH'. This -directory contains several dysfunctional programs; working variants of -these programs are available in `/usr/bin'. So, if you need `/usr/ucb' -in your `PATH', put it _after_ `/usr/bin'. - - On Haiku, software installed for all users goes in `/boot/common', -not `/usr/local'. It is recommended to use the following options: - - ./configure --prefix=/boot/common - -Specifying the System Type -========================== - - There may be some features `configure' cannot figure out -automatically, but needs to determine by the type of machine the package -will run on. Usually, assuming the package is built to be run on the -_same_ architectures, `configure' can figure that out, but if it prints -a message saying it cannot guess the machine type, give it the -`--build=TYPE' option. TYPE can either be a short name for the system -type, such as `sun4', or a canonical name which has the form: - - CPU-COMPANY-SYSTEM - -where SYSTEM can have one of these forms: - - OS - KERNEL-OS - - See the file `config.sub' for the possible values of each field. If -`config.sub' isn't included in this package, then this package doesn't -need to know the machine type. - - If you are _building_ compiler tools for cross-compiling, you should -use the option `--target=TYPE' to select the type of system they will -produce code for. - - If you want to _use_ a cross compiler, that generates code for a -platform different from the build platform, you should specify the -"host" platform (i.e., that on which the generated programs will -eventually be run) with `--host=TYPE'. - -Sharing Defaults -================ - - If you want to set default values for `configure' scripts to share, -you can create a site shell script called `config.site' that gives -default values for variables like `CC', `cache_file', and `prefix'. -`configure' looks for `PREFIX/share/config.site' if it exists, then -`PREFIX/etc/config.site' if it exists. Or, you can set the -`CONFIG_SITE' environment variable to the location of the site script. -A warning: not all `configure' scripts look for a site script. - -Defining Variables -================== - - Variables not defined in a site shell script can be set in the -environment passed to `configure'. However, some packages may run -configure again during the build, and the customized values of these -variables may be lost. In order to avoid this problem, you should set -them in the `configure' command line, using `VAR=value'. For example: - - ./configure CC=/usr/local2/bin/gcc - -causes the specified `gcc' to be used as the C compiler (unless it is -overridden in the site shell script). - -Unfortunately, this technique does not work for `CONFIG_SHELL' due to -an Autoconf bug. Until the bug is fixed you can use this workaround: - - CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash - -`configure' Invocation -====================== - - `configure' recognizes the following options to control how it -operates. - -`--help' -`-h' - Print a summary of all of the options to `configure', and exit. - -`--help=short' -`--help=recursive' - Print a summary of the options unique to this package's - `configure', and exit. The `short' variant lists options used - only in the top level, while the `recursive' variant lists options - also present in any nested packages. - -`--version' -`-V' - Print the version of Autoconf used to generate the `configure' - script, and exit. - -`--cache-file=FILE' - Enable the cache: use and save the results of the tests in FILE, - traditionally `config.cache'. FILE defaults to `/dev/null' to - disable caching. - -`--config-cache' -`-C' - Alias for `--cache-file=config.cache'. - -`--quiet' -`--silent' -`-q' - Do not print messages saying which checks are being made. To - suppress all normal output, redirect it to `/dev/null' (any error - messages will still be shown). - -`--srcdir=DIR' - Look for the package's source code in directory DIR. Usually - `configure' can determine that directory automatically. - -`--prefix=DIR' - Use DIR as the installation prefix. *note Installation Names:: - for more details, including other options available for fine-tuning - the installation locations. - -`--no-create' -`-n' - Run the configure checks, but stop before creating any output - files. - -`configure' also accepts some other, not widely useful, options. Run -`configure --help' for more details. diff --git a/plugins/kimchi/Makefile.am b/plugins/kimchi/Makefile.am deleted file mode 100644 index 49c835e..0000000 --- a/plugins/kimchi/Makefile.am +++ /dev/null @@ -1,161 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -SUBDIRS = contrib control distros.d docs model po tests ui xmlutils - -kimchi_PYTHON = $(filter-out config.py, $(wildcard *.py)) - -nodist_kimchi_PYTHON = config.py - -if WITH_SPICE -WITH_SPICE=yes -else -WITH_SPICE=no -endif - -wokdir = $(pythondir)/wok -kimchidir = $(pythondir)/wok/plugins/kimchi - -confdir = $(sysconfdir)/wok/plugins.d -dist_conf_DATA = kimchi.conf template.conf - -AUTOMAKE_OPTIONS = foreign - -ACLOCAL_AMFLAGS = --install -I m4 - -EXTRA_DIST = \ - config.rpath \ - API.json \ - autogen.sh \ - COPYING.ASL2 \ - COPYING.LGPL \ - CONTRIBUTE.md \ - VERSION \ - build-aux/pkg-version \ - config.py.in \ - $(NULL) - - -PEP8_BLACKLIST = *config.py,*i18n.py,*tests/test_config.py - -I18N_FILES = ./i18n.py \ - $(NULL) - -check-local: - contrib/check_i18n.py $(I18N_FILES) - find . -path './.git' -prune -type f -o \ - -name '*.py' -o -name '*.py.in' | xargs $(PYFLAKES) | \ - while read LINE; do echo "$$LINE"; false; done - - $(PEP8) --version - $(PEP8) --filename '*.py,*.py.in' --exclude="$(PEP8_BLACKLIST)" . - - -# Link built mo files in the source tree to enable use of translations from -# within the source tree -all-local: - while read L && test -n "$$L"; do \ - dir=mo/$$L/LC_MESSAGES ; \ - $(MKDIR_P) $$dir ; \ - ln -sf ../../../po/$$L.gmo $$dir/kimchi.mo ; \ - done < po/LINGUAS - -do_substitution = \ - sed -e 's,[@]prefix[@],$(prefix),g' \ - -e 's,[@]datadir[@],$(datadir),g' \ - -e 's,[@]sysconfdir[@],$(sysconfdir),g' \ - -e 's,[@]localstatedir[@],$(localstatedir),g' \ - -e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \ - -e 's,[@]wokdir[@],$(wokdir),g' \ - -e 's,[@]kimchidir[@],$(kimchidir),g' \ - -e 's,[@]kimchiversion[@],$(PACKAGE_VERSION),g' \ - -e 's,[@]kimchirelease[@],$(PACKAGE_RELEASE),g' \ - -e 's,[@]withspice[@],$(WITH_SPICE),g' - -config.py: config.py.in Makefile - $(do_substitution) < $(srcdir)/config.py.in > config.py - - -# -# Packaging helpers -# - -install-deb: install - cp -R $(top_srcdir)/contrib/DEBIAN $(DESTDIR)/ - mkdir -p $(DESTDIR)/var/lib/kimchi/vnc-tokens - mkdir -p $(DESTDIR)/var/lib/kimchi/debugreports - mkdir -p $(DESTDIR)/var/lib/kimchi/screenshots - mkdir -p $(DESTDIR)/var/lib/kimchi/isos - - -deb: contrib/make-deb.sh - $(top_srcdir)/contrib/make-deb.sh - -kimchi.spec: contrib/kimchi.spec.fedora contrib/kimchi.spec.suse - @if test -e /etc/redhat-release; then \ - ln -sf contrib/kimchi.spec.fedora $@ ; \ - elif test -e /etc/SuSE-release; then \ - ln -sf contrib/kimchi.spec.suse $@ ; \ - else \ - echo "Unable to select a spec file for RPM build" ; \ - /bin/false ; \ - fi - -rpm: dist kimchi.spec - $(MKDIR_P) rpm/BUILD rpm/RPMS rpm/SOURCES rpm/SPECS rpm/SRPMS - cp $(top_srcdir)/kimchi.spec rpm/SPECS/kimchi.spec - cp $(DIST_ARCHIVES) rpm/SOURCES - rpmbuild -ba --define "_topdir `pwd`/rpm" rpm/SPECS/kimchi.spec - -fedora-rpm: contrib/kimchi.spec.fedora - ln -sf contrib/kimchi.spec.fedora kimchi.spec - $(MAKE) rpm - -suse-rpm: contrib/kimchi.spec.suse - ln -sf contrib/kimchi.spec.suse kimchi.spec - $(MAKE) rpm - -ChangeLog: - @if test -d .git; then \ - $(top_srcdir)/build-aux/genChangelog --release > $@; \ - fi - -install-data-local: - $(MKDIR_P) $(DESTDIR)$(kimchidir) - $(INSTALL_DATA) API.json $(DESTDIR)$(kimchidir)/API.json - mkdir -p $(DESTDIR)/var/lib/kimchi/vnc-tokens - mkdir -p $(DESTDIR)/var/lib/kimchi/{debugreports,isos,screenshots} - -uninstall-local: - $(RM) $(DESTDIR)$(kimchidir)/API.json - $(RM) -rf $(DESTDIR)/var/lib/kimchi - -VERSION: - @if test -d .git; then \ - git describe --abbrev=0 > $@; \ - fi - -.PHONY: deb install-deb rpm fedora-rpm suse-rpm ChangeLog VERSION - - -clean-local: - rm -rf mo rpm - -BUILT_SOURCES = config.py -CLEANFILES = config.py kimchi.spec `find "$(top_srcdir)" -type f -name "*.pyc" -print` diff --git a/plugins/kimchi/README.md b/plugins/kimchi/README.md deleted file mode 120000 index 0e01b43..0000000 --- a/plugins/kimchi/README.md +++ /dev/null @@ -1 +0,0 @@ -docs/README.md \ No newline at end of file diff --git a/plugins/kimchi/VERSION b/plugins/kimchi/VERSION deleted file mode 100644 index bc80560..0000000 --- a/plugins/kimchi/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.5.0 diff --git a/plugins/kimchi/__init__.py b/plugins/kimchi/__init__.py deleted file mode 100644 index 9330044..0000000 --- a/plugins/kimchi/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from root import KimchiRoot -__all__ = [KimchiRoot] diff --git a/plugins/kimchi/autogen.sh b/plugins/kimchi/autogen.sh deleted file mode 100755 index 0f22dba..0000000 --- a/plugins/kimchi/autogen.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -aclocal -automake --add-missing -autoreconf - -if [ ! -f "configure" ]; then - echo "Failed to generate configure script. Check to make sure autoconf, " - echo "automake, and other build dependencies are properly installed." - exit 1 -fi - -if [ "x$1" == "x--system" ]; then - ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var -else - if [ $# -gt 0 ]; then - ./configure $@ - else - ./configure --prefix=/usr/local - fi -fi diff --git a/plugins/kimchi/build-aux/config.rpath b/plugins/kimchi/build-aux/config.rpath deleted file mode 100644 index 17298f2..0000000 --- a/plugins/kimchi/build-aux/config.rpath +++ /dev/null @@ -1,672 +0,0 @@ -#! /bin/sh -# Output a system dependent set of variables, describing how to set the -# run time search path of shared libraries in an executable. -# -# Copyright 1996-2010 Free Software Foundation, Inc. -# Taken from GNU libtool, 2001 -# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 -# -# This file is free software; the Free Software Foundation gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# The first argument passed to this file is the canonical host specification, -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld -# should be set by the caller. -# -# The set of defined variables is at the end of this script. - -# Known limitations: -# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer -# than 256 bytes, otherwise the compiler driver will dump core. The only -# known workaround is to choose shorter directory names for the build -# directory and/or the installation directory. - -# All known linkers require a `.a' archive for static linking (except MSVC, -# which needs '.lib'). -libext=a -shrext=.so - -host="$1" -host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` -host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` -host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` - -# Code taken from libtool.m4's _LT_CC_BASENAME. - -for cc_temp in $CC""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` - -# Code taken from libtool.m4's _LT_COMPILER_PIC. - -wl= -if test "$GCC" = yes; then - wl='-Wl,' -else - case "$host_os" in - aix*) - wl='-Wl,' - ;; - darwin*) - case $cc_basename in - xlc*) - wl='-Wl,' - ;; - esac - ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) - ;; - hpux9* | hpux10* | hpux11*) - wl='-Wl,' - ;; - irix5* | irix6* | nonstopux*) - wl='-Wl,' - ;; - newsos6) - ;; - linux* | k*bsd*-gnu) - case $cc_basename in - ecc*) - wl='-Wl,' - ;; - icc* | ifort*) - wl='-Wl,' - ;; - lf95*) - wl='-Wl,' - ;; - pgcc | pgf77 | pgf90) - wl='-Wl,' - ;; - ccc*) - wl='-Wl,' - ;; - como) - wl='-lopt=' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - wl='-Wl,' - ;; - esac - ;; - esac - ;; - osf3* | osf4* | osf5*) - wl='-Wl,' - ;; - rdos*) - ;; - solaris*) - wl='-Wl,' - ;; - sunos4*) - wl='-Qoption ld ' - ;; - sysv4 | sysv4.2uw2* | sysv4.3*) - wl='-Wl,' - ;; - sysv4*MP*) - ;; - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - wl='-Wl,' - ;; - unicos*) - wl='-Wl,' - ;; - uts4*) - ;; - esac -fi - -# Code taken from libtool.m4's _LT_LINKER_SHLIBS. - -hardcode_libdir_flag_spec= -hardcode_libdir_separator= -hardcode_direct=no -hardcode_minus_L=no - -case "$host_os" in - cygwin* | mingw* | pw32* | cegcc*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$GCC" != yes; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) - with_gnu_ld=yes - ;; - openbsd*) - with_gnu_ld=no - ;; -esac - -ld_shlibs=yes -if test "$with_gnu_ld" = yes; then - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - # Unlike libtool, we use -rpath here, not --rpath, since the documented - # option of GNU ld is called -rpath, not --rpath. - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - case "$host_os" in - aix[3-9]*) - # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then - ld_shlibs=no - fi - ;; - amigaos*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports - # that the semantics of dynamic libraries on AmigaOS, at least up - # to version 4, is to share data among multiple programs linked - # with the same dynamic library. Since this doesn't match the - # behavior of shared libraries on other platforms, we cannot use - # them. - ld_shlibs=no - ;; - beos*) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - : - else - ld_shlibs=no - fi - ;; - cygwin* | mingw* | pw32* | cegcc*) - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then - : - else - ld_shlibs=no - fi - ;; - interix[3-9]*) - hardcode_direct=no - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - ;; - gnu* | linux* | k*bsd*-gnu) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - : - else - ld_shlibs=no - fi - ;; - netbsd*) - ;; - solaris*) - if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - : - else - ld_shlibs=no - fi - ;; - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - ;; - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' - else - ld_shlibs=no - fi - ;; - esac - ;; - sunos4*) - hardcode_direct=yes - ;; - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - : - else - ld_shlibs=no - fi - ;; - esac - if test "$ld_shlibs" = no; then - hardcode_libdir_flag_spec= - fi -else - case "$host_os" in - aix3*) - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test "$GCC" = yes; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - aix[4-9]*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - else - aix_use_runtimelinking=no - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi - done - ;; - esac - fi - hardcode_direct=yes - hardcode_libdir_separator=':' - if test "$GCC" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - fi - # Begin _LT_AC_SYS_LIBPATH_AIX. - echo 'int main () { return 0; }' > conftest.c - ${CC} ${LDFLAGS} conftest.c -o conftest - aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } -}'` - if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } -}'` - fi - if test -z "$aix_libpath"; then - aix_libpath="/usr/lib:/lib" - fi - rm -f conftest.c conftest - # End _LT_AC_SYS_LIBPATH_AIX. - if test "$aix_use_runtimelinking" = yes; then - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' - else - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - fi - fi - ;; - amigaos*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - # see comment about different semantics on the GNU ld section - ld_shlibs=no - ;; - bsdi[45]*) - ;; - cygwin* | mingw* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec=' ' - libext=lib - ;; - darwin* | rhapsody*) - hardcode_direct=no - if test "$GCC" = yes ; then - : - else - case $cc_basename in - xlc*) - ;; - *) - ld_shlibs=no - ;; - esac - fi - ;; - dgux*) - hardcode_libdir_flag_spec='-L$libdir' - ;; - freebsd1*) - ld_shlibs=no - ;; - freebsd2.2*) - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - ;; - freebsd2*) - hardcode_direct=yes - hardcode_minus_L=yes - ;; - freebsd* | dragonfly*) - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - ;; - hpux9*) - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - hpux10*) - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - hpux11*) - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct=no - ;; - *) - hardcode_direct=yes - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - irix5* | irix6* | nonstopux*) - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - netbsd*) - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - ;; - newsos6) - hardcode_direct=yes - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - else - case "$host_os" in - openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) - hardcode_libdir_flag_spec='-R$libdir' - ;; - *) - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - ;; - esac - fi - else - ld_shlibs=no - fi - ;; - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - osf3*) - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - osf4* | osf5*) - if test "$GCC" = yes; then - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - else - # Both cc and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - hardcode_libdir_separator=: - ;; - solaris*) - hardcode_libdir_flag_spec='-R$libdir' - ;; - sunos4*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - ;; - sysv4) - case $host_vendor in - sni) - hardcode_direct=yes # is this really true??? - ;; - siemens) - hardcode_direct=no - ;; - motorola) - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - ;; - sysv4.3*) - ;; - sysv4*MP*) - if test -d /usr/nec; then - ld_shlibs=yes - fi - ;; - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - ;; - sysv5* | sco3.2v5* | sco5v6*) - hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' - hardcode_libdir_separator=':' - ;; - uts4*) - hardcode_libdir_flag_spec='-L$libdir' - ;; - *) - ld_shlibs=no - ;; - esac -fi - -# Check dynamic linker characteristics -# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. -# Unlike libtool.m4, here we don't care about _all_ names of the library, but -# only about the one the linker finds when passed -lNAME. This is the last -# element of library_names_spec in libtool.m4, or possibly two of them if the -# linker has special search rules. -library_names_spec= # the last element of library_names_spec in libtool.m4 -libname_spec='lib$name' -case "$host_os" in - aix3*) - library_names_spec='$libname.a' - ;; - aix[4-9]*) - library_names_spec='$libname$shrext' - ;; - amigaos*) - library_names_spec='$libname.a' - ;; - beos*) - library_names_spec='$libname$shrext' - ;; - bsdi[45]*) - library_names_spec='$libname$shrext' - ;; - cygwin* | mingw* | pw32* | cegcc*) - shrext=.dll - library_names_spec='$libname.dll.a $libname.lib' - ;; - darwin* | rhapsody*) - shrext=.dylib - library_names_spec='$libname$shrext' - ;; - dgux*) - library_names_spec='$libname$shrext' - ;; - freebsd1*) - ;; - freebsd* | dragonfly*) - case "$host_os" in - freebsd[123]*) - library_names_spec='$libname$shrext$versuffix' ;; - *) - library_names_spec='$libname$shrext' ;; - esac - ;; - gnu*) - library_names_spec='$libname$shrext' - ;; - hpux9* | hpux10* | hpux11*) - case $host_cpu in - ia64*) - shrext=.so - ;; - hppa*64*) - shrext=.sl - ;; - *) - shrext=.sl - ;; - esac - library_names_spec='$libname$shrext' - ;; - interix[3-9]*) - library_names_spec='$libname$shrext' - ;; - irix5* | irix6* | nonstopux*) - library_names_spec='$libname$shrext' - case "$host_os" in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; - *) libsuff= shlibsuff= ;; - esac - ;; - esac - ;; - linux*oldld* | linux*aout* | linux*coff*) - ;; - linux* | k*bsd*-gnu) - library_names_spec='$libname$shrext' - ;; - knetbsd*-gnu) - library_names_spec='$libname$shrext' - ;; - netbsd*) - library_names_spec='$libname$shrext' - ;; - newsos6) - library_names_spec='$libname$shrext' - ;; - nto-qnx*) - library_names_spec='$libname$shrext' - ;; - openbsd*) - library_names_spec='$libname$shrext$versuffix' - ;; - os2*) - libname_spec='$name' - shrext=.dll - library_names_spec='$libname.a' - ;; - osf3* | osf4* | osf5*) - library_names_spec='$libname$shrext' - ;; - rdos*) - ;; - solaris*) - library_names_spec='$libname$shrext' - ;; - sunos4*) - library_names_spec='$libname$shrext$versuffix' - ;; - sysv4 | sysv4.3*) - library_names_spec='$libname$shrext' - ;; - sysv4*MP*) - library_names_spec='$libname$shrext' - ;; - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - library_names_spec='$libname$shrext' - ;; - uts4*) - library_names_spec='$libname$shrext' - ;; -esac - -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' -escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` -shlibext=`echo "$shrext" | sed -e 's,^\.,,'` -escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` -escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` -escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` - -LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF - -# How to pass a linker flag through the compiler. -wl="$escaped_wl" - -# Static library suffix (normally "a"). -libext="$libext" - -# Shared library suffix (normally "so"). -shlibext="$shlibext" - -# Format of library name prefix. -libname_spec="$escaped_libname_spec" - -# Library names that the linker finds when passed -lNAME. -library_names_spec="$escaped_library_names_spec" - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec" - -# Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator="$hardcode_libdir_separator" - -# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the -# resulting binary. -hardcode_direct="$hardcode_direct" - -# Set to yes if using the -LDIR flag during linking hardcodes DIR into the -# resulting binary. -hardcode_minus_L="$hardcode_minus_L" - -EOF diff --git a/plugins/kimchi/build-aux/genChangelog b/plugins/kimchi/build-aux/genChangelog deleted file mode 100755 index 803f24e..0000000 --- a/plugins/kimchi/build-aux/genChangelog +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -# This script is based on code from the Kandan project: -# https://github.com/kandanapp/kandan/blob/master/gen-changelog.sh - -echo "CHANGELOG" -echo "=========" -echo -git for-each-ref --sort='*authordate' --format='%(tag)' refs/tags | tac |grep -v '^$' | while read TAG ; do - if [ $NEXT ]; then - echo "#### [$NEXT] ####" - elif [ "$1" != "--release" ]; then - echo "#### [Current] ####" - else - NEXT=$TAG - continue - fi - GIT_PAGER=cat git log --pretty=format:" * [%h] %<(78,trunc)%s (%an)" $TAG..$NEXT - NEXT=$TAG - echo; echo -done -FIRST=$(git for-each-ref --sort='*authordate' --format='%(tag)' refs/tags | head -1) - -echo "#### [$FIRST] ####" -GIT_PAGER=cat git log --pretty=format:" * [%h] %<(78,trunc)%s (%an)" $FIRST diff --git a/plugins/kimchi/build-aux/pkg-version b/plugins/kimchi/build-aux/pkg-version deleted file mode 100755 index 749cf6c..0000000 --- a/plugins/kimchi/build-aux/pkg-version +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/sh -# -# Copyright 2008-2012 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -# tags and output versions: -# - 4.9.0 => 4.9.0 (upstream clean) -# - 4.9.0-1 => 4.9.0 (downstream clean) -# - 4.9.0-2-g34e62f => 4.9.0 (upstream dirty) -# - 4.9.0-1-2-g34e62f => 4.9.0 (downstream dirty) -AWK_VERSION=' - BEGIN { FS="-" } - /^[0-9]/ { - print $1 - }' - -# tags and output releases: -# - 4.9.0 => 0 (upstream clean) -# - 4.9.0-1 => 1 (downstream clean) -# - 4.9.0-2-g34e62f1 => 2.git34e62f1 (upstream dirty) -# - 4.9.0-1-2-g34e62f1 => 1.2.git34e62f1 (downstream dirty) -AWK_RELEASE=' - BEGIN { FS="-"; OFS="." } - /^[0-9]/ { - if (NF == 1) print 0 - else if (NF == 2) print $2 - else if (NF == 3) print $2, "git" substr($3, 2) - else if (NF == 4) print $2, $3, "git" substr($4, 2) - }' - -if [ ! -d .git ]; then - PKG_VERSION=`cat VERSION` -else - PKG_VERSION=`git describe --tags --match "[0-9]*" || cat VERSION` -fi - -if test "x$1" = "x--full"; then - echo $PKG_VERSION | tr -d '[:space:]' -elif test "x$1" = "x--version"; then - echo $PKG_VERSION | awk "$AWK_VERSION" | tr -cd '[:alnum:].' -elif test "x$1" = "x--release"; then - echo $PKG_VERSION | awk "$AWK_RELEASE" | tr -cd '[:alnum:].' -else - echo "usage: $0 [--full|--version|--release]" - exit 1 -fi diff --git a/plugins/kimchi/config.py.in b/plugins/kimchi/config.py.in deleted file mode 100644 index 6ae0ccd..0000000 --- a/plugins/kimchi/config.py.in +++ /dev/null @@ -1,144 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -import libvirt -import os -import platform -import threading - -from wok.config import CACHEEXPIRES, PluginConfig, PluginPaths -from wok.xmlutils.utils import xpath_get_text - -kimchiLock = threading.Lock() - -__with_spice__ = "@withspice@" - -# Storage pool constant for read-only pool types -READONLY_POOL_TYPE = ['iscsi', 'scsi', 'mpath'] - - -def get_distros_store(): - return os.path.join(PluginPaths('kimchi').conf_dir, 'distros.d') - - -def get_debugreports_path(): - return os.path.join(PluginPaths('kimchi').state_dir, 'debugreports') - - -def get_screenshot_path(): - return os.path.join(PluginPaths('kimchi').state_dir, 'screenshots') - - -def find_qemu_binary(find_emulator=False): - try: - connect = libvirt.open(None) - except Exception, e: - raise Exception("Unable to get qemu binary location: %s" % e) - try: - xml = connect.getCapabilities() - - # On Little Endian system, the qemu binary is - # qemu-system-ppc64, not qemu-system-ppc64le as expected - arch = platform.machine() - if arch == "ppc64le": - arch = "ppc64" - - if find_emulator: - expr = "/capabilities/guest/arch[@name='%s']\ - /emulator" % arch - else: - expr = "/capabilities/guest/arch[@name='%s']\ - /domain[@type='kvm']/emulator" % arch - res = xpath_get_text(xml, expr) - location = res[0] - except Exception, e: - raise Exception("Unable to get qemu binary location: %s" % e) - finally: - connect.close() - return location - - -class KimchiPaths(PluginPaths): - - def __init__(self): - super(KimchiPaths, self).__init__('kimchi') - self.spice_file = os.path.join(self.ui_dir, - 'spice-html5/pages/spice_auto.html') - - if __with_spice__ == 'yes': - self.spice_dir = self.add_prefix('ui/spice-html5') - elif os.path.exists('@datadir@/spice-html5'): - self.spice_dir = '@datadir@/spice-html5' - else: - self.spice_dir = '/usr/share/spice-html5' - - if os.path.exists('@datadir@/novnc'): - self.novnc_dir = '@datadir@/novnc' - else: - self.novnc_dir = '/usr/share/novnc' - - if self.installed: - self.spice_css_file = os.path.join(self.spice_dir, 'spice.css') - else: - self.spice_css_file = os.path.join(self.spice_dir, 'css/spice.css') - - -kimchiPaths = KimchiPaths() - - -class KimchiConfig(PluginConfig): - def __init__(self): - super(KimchiConfig, self).__init__('kimchi') - - static_config = { - '/novnc': {'type': 'dir', - 'path': kimchiPaths.novnc_dir}, - '/spice-html5': {'type': 'dir', - 'path': kimchiPaths.spice_dir}, - '/spice_auto.html': {'type': 'file', - 'path': kimchiPaths.spice_file}, - '/spice-html5/spice.css': {'type': 'file', - 'path': kimchiPaths.spice_css_file}} - - custom_config = {} - for uri, data in static_config.iteritems(): - custom_config[uri] = {'tools.nocache.on': True, - 'tools.wokauth.on': True} - path = data['path'] - if data['type'] == 'dir': - custom_config[uri].update({'tools.staticdir.on': True, - 'tools.staticdir.dir': path}) - elif data['type'] == 'file': - custom_config[uri].update({'tools.staticfile.on': True, - 'tools.staticfile.filename': path}) - - for dirname in ('css', 'js', 'images'): - custom_config['/' + dirname] = { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': os.path.join(kimchiPaths.ui_dir, - dirname), - 'tools.wokauth.on': False, - 'tools.nocache.on': False} - if dirname != 'images': - custom_config['/' + dirname].update({ - 'tools.expires.on': True, - 'tools.expires.secs': CACHEEXPIRES}) - - self.update(custom_config) diff --git a/plugins/kimchi/config.rpath b/plugins/kimchi/config.rpath deleted file mode 100644 index 17298f2..0000000 --- a/plugins/kimchi/config.rpath +++ /dev/null @@ -1,672 +0,0 @@ -#! /bin/sh -# Output a system dependent set of variables, describing how to set the -# run time search path of shared libraries in an executable. -# -# Copyright 1996-2010 Free Software Foundation, Inc. -# Taken from GNU libtool, 2001 -# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 -# -# This file is free software; the Free Software Foundation gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# The first argument passed to this file is the canonical host specification, -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld -# should be set by the caller. -# -# The set of defined variables is at the end of this script. - -# Known limitations: -# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer -# than 256 bytes, otherwise the compiler driver will dump core. The only -# known workaround is to choose shorter directory names for the build -# directory and/or the installation directory. - -# All known linkers require a `.a' archive for static linking (except MSVC, -# which needs '.lib'). -libext=a -shrext=.so - -host="$1" -host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` -host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` -host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` - -# Code taken from libtool.m4's _LT_CC_BASENAME. - -for cc_temp in $CC""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` - -# Code taken from libtool.m4's _LT_COMPILER_PIC. - -wl= -if test "$GCC" = yes; then - wl='-Wl,' -else - case "$host_os" in - aix*) - wl='-Wl,' - ;; - darwin*) - case $cc_basename in - xlc*) - wl='-Wl,' - ;; - esac - ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) - ;; - hpux9* | hpux10* | hpux11*) - wl='-Wl,' - ;; - irix5* | irix6* | nonstopux*) - wl='-Wl,' - ;; - newsos6) - ;; - linux* | k*bsd*-gnu) - case $cc_basename in - ecc*) - wl='-Wl,' - ;; - icc* | ifort*) - wl='-Wl,' - ;; - lf95*) - wl='-Wl,' - ;; - pgcc | pgf77 | pgf90) - wl='-Wl,' - ;; - ccc*) - wl='-Wl,' - ;; - como) - wl='-lopt=' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - wl='-Wl,' - ;; - esac - ;; - esac - ;; - osf3* | osf4* | osf5*) - wl='-Wl,' - ;; - rdos*) - ;; - solaris*) - wl='-Wl,' - ;; - sunos4*) - wl='-Qoption ld ' - ;; - sysv4 | sysv4.2uw2* | sysv4.3*) - wl='-Wl,' - ;; - sysv4*MP*) - ;; - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - wl='-Wl,' - ;; - unicos*) - wl='-Wl,' - ;; - uts4*) - ;; - esac -fi - -# Code taken from libtool.m4's _LT_LINKER_SHLIBS. - -hardcode_libdir_flag_spec= -hardcode_libdir_separator= -hardcode_direct=no -hardcode_minus_L=no - -case "$host_os" in - cygwin* | mingw* | pw32* | cegcc*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$GCC" != yes; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) - with_gnu_ld=yes - ;; - openbsd*) - with_gnu_ld=no - ;; -esac - -ld_shlibs=yes -if test "$with_gnu_ld" = yes; then - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - # Unlike libtool, we use -rpath here, not --rpath, since the documented - # option of GNU ld is called -rpath, not --rpath. - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - case "$host_os" in - aix[3-9]*) - # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then - ld_shlibs=no - fi - ;; - amigaos*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports - # that the semantics of dynamic libraries on AmigaOS, at least up - # to version 4, is to share data among multiple programs linked - # with the same dynamic library. Since this doesn't match the - # behavior of shared libraries on other platforms, we cannot use - # them. - ld_shlibs=no - ;; - beos*) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - : - else - ld_shlibs=no - fi - ;; - cygwin* | mingw* | pw32* | cegcc*) - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then - : - else - ld_shlibs=no - fi - ;; - interix[3-9]*) - hardcode_direct=no - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - ;; - gnu* | linux* | k*bsd*-gnu) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - : - else - ld_shlibs=no - fi - ;; - netbsd*) - ;; - solaris*) - if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - : - else - ld_shlibs=no - fi - ;; - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - ;; - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' - else - ld_shlibs=no - fi - ;; - esac - ;; - sunos4*) - hardcode_direct=yes - ;; - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - : - else - ld_shlibs=no - fi - ;; - esac - if test "$ld_shlibs" = no; then - hardcode_libdir_flag_spec= - fi -else - case "$host_os" in - aix3*) - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test "$GCC" = yes; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - aix[4-9]*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - else - aix_use_runtimelinking=no - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi - done - ;; - esac - fi - hardcode_direct=yes - hardcode_libdir_separator=':' - if test "$GCC" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - fi - # Begin _LT_AC_SYS_LIBPATH_AIX. - echo 'int main () { return 0; }' > conftest.c - ${CC} ${LDFLAGS} conftest.c -o conftest - aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } -}'` - if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } -}'` - fi - if test -z "$aix_libpath"; then - aix_libpath="/usr/lib:/lib" - fi - rm -f conftest.c conftest - # End _LT_AC_SYS_LIBPATH_AIX. - if test "$aix_use_runtimelinking" = yes; then - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' - else - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - fi - fi - ;; - amigaos*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - # see comment about different semantics on the GNU ld section - ld_shlibs=no - ;; - bsdi[45]*) - ;; - cygwin* | mingw* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec=' ' - libext=lib - ;; - darwin* | rhapsody*) - hardcode_direct=no - if test "$GCC" = yes ; then - : - else - case $cc_basename in - xlc*) - ;; - *) - ld_shlibs=no - ;; - esac - fi - ;; - dgux*) - hardcode_libdir_flag_spec='-L$libdir' - ;; - freebsd1*) - ld_shlibs=no - ;; - freebsd2.2*) - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - ;; - freebsd2*) - hardcode_direct=yes - hardcode_minus_L=yes - ;; - freebsd* | dragonfly*) - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - ;; - hpux9*) - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - hpux10*) - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - hpux11*) - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct=no - ;; - *) - hardcode_direct=yes - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - irix5* | irix6* | nonstopux*) - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - netbsd*) - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - ;; - newsos6) - hardcode_direct=yes - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - else - case "$host_os" in - openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) - hardcode_libdir_flag_spec='-R$libdir' - ;; - *) - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - ;; - esac - fi - else - ld_shlibs=no - fi - ;; - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - osf3*) - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - osf4* | osf5*) - if test "$GCC" = yes; then - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - else - # Both cc and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - hardcode_libdir_separator=: - ;; - solaris*) - hardcode_libdir_flag_spec='-R$libdir' - ;; - sunos4*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - ;; - sysv4) - case $host_vendor in - sni) - hardcode_direct=yes # is this really true??? - ;; - siemens) - hardcode_direct=no - ;; - motorola) - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - ;; - sysv4.3*) - ;; - sysv4*MP*) - if test -d /usr/nec; then - ld_shlibs=yes - fi - ;; - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - ;; - sysv5* | sco3.2v5* | sco5v6*) - hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' - hardcode_libdir_separator=':' - ;; - uts4*) - hardcode_libdir_flag_spec='-L$libdir' - ;; - *) - ld_shlibs=no - ;; - esac -fi - -# Check dynamic linker characteristics -# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. -# Unlike libtool.m4, here we don't care about _all_ names of the library, but -# only about the one the linker finds when passed -lNAME. This is the last -# element of library_names_spec in libtool.m4, or possibly two of them if the -# linker has special search rules. -library_names_spec= # the last element of library_names_spec in libtool.m4 -libname_spec='lib$name' -case "$host_os" in - aix3*) - library_names_spec='$libname.a' - ;; - aix[4-9]*) - library_names_spec='$libname$shrext' - ;; - amigaos*) - library_names_spec='$libname.a' - ;; - beos*) - library_names_spec='$libname$shrext' - ;; - bsdi[45]*) - library_names_spec='$libname$shrext' - ;; - cygwin* | mingw* | pw32* | cegcc*) - shrext=.dll - library_names_spec='$libname.dll.a $libname.lib' - ;; - darwin* | rhapsody*) - shrext=.dylib - library_names_spec='$libname$shrext' - ;; - dgux*) - library_names_spec='$libname$shrext' - ;; - freebsd1*) - ;; - freebsd* | dragonfly*) - case "$host_os" in - freebsd[123]*) - library_names_spec='$libname$shrext$versuffix' ;; - *) - library_names_spec='$libname$shrext' ;; - esac - ;; - gnu*) - library_names_spec='$libname$shrext' - ;; - hpux9* | hpux10* | hpux11*) - case $host_cpu in - ia64*) - shrext=.so - ;; - hppa*64*) - shrext=.sl - ;; - *) - shrext=.sl - ;; - esac - library_names_spec='$libname$shrext' - ;; - interix[3-9]*) - library_names_spec='$libname$shrext' - ;; - irix5* | irix6* | nonstopux*) - library_names_spec='$libname$shrext' - case "$host_os" in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; - *) libsuff= shlibsuff= ;; - esac - ;; - esac - ;; - linux*oldld* | linux*aout* | linux*coff*) - ;; - linux* | k*bsd*-gnu) - library_names_spec='$libname$shrext' - ;; - knetbsd*-gnu) - library_names_spec='$libname$shrext' - ;; - netbsd*) - library_names_spec='$libname$shrext' - ;; - newsos6) - library_names_spec='$libname$shrext' - ;; - nto-qnx*) - library_names_spec='$libname$shrext' - ;; - openbsd*) - library_names_spec='$libname$shrext$versuffix' - ;; - os2*) - libname_spec='$name' - shrext=.dll - library_names_spec='$libname.a' - ;; - osf3* | osf4* | osf5*) - library_names_spec='$libname$shrext' - ;; - rdos*) - ;; - solaris*) - library_names_spec='$libname$shrext' - ;; - sunos4*) - library_names_spec='$libname$shrext$versuffix' - ;; - sysv4 | sysv4.3*) - library_names_spec='$libname$shrext' - ;; - sysv4*MP*) - library_names_spec='$libname$shrext' - ;; - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - library_names_spec='$libname$shrext' - ;; - uts4*) - library_names_spec='$libname$shrext' - ;; -esac - -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' -escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` -shlibext=`echo "$shrext" | sed -e 's,^\.,,'` -escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` -escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` -escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` - -LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF - -# How to pass a linker flag through the compiler. -wl="$escaped_wl" - -# Static library suffix (normally "a"). -libext="$libext" - -# Shared library suffix (normally "so"). -shlibext="$shlibext" - -# Format of library name prefix. -libname_spec="$escaped_libname_spec" - -# Library names that the linker finds when passed -lNAME. -library_names_spec="$escaped_library_names_spec" - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec" - -# Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator="$hardcode_libdir_separator" - -# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the -# resulting binary. -hardcode_direct="$hardcode_direct" - -# Set to yes if using the -LDIR flag during linking hardcodes DIR into the -# resulting binary. -hardcode_minus_L="$hardcode_minus_L" - -EOF diff --git a/plugins/kimchi/configure.ac b/plugins/kimchi/configure.ac deleted file mode 100644 index adab45b..0000000 --- a/plugins/kimchi/configure.ac +++ /dev/null @@ -1,119 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -AC_INIT([kimchi], [m4_esyscmd([./build-aux/pkg-version --version])]) - -AC_SUBST([PACKAGE_VERSION], - [m4_esyscmd([./build-aux/pkg-version --version])]) - -AC_SUBST([PACKAGE_RELEASE], - [m4_esyscmd([./build-aux/pkg-version --release])]) - -# Testing for version and release -AS_IF([test "x$PACKAGE_VERSION" = x], - AC_MSG_ERROR([package version not defined])) -AS_IF([test "x$PACKAGE_RELEASE" = x], - AC_MSG_ERROR([package release not defined])) - -AC_CONFIG_AUX_DIR([build-aux]) -AM_INIT_AUTOMAKE([-Wno-portability]) -AM_PATH_PYTHON([2.6]) -AC_PATH_PROG([PEP8], [pep8], [/usr/bin/pep8]) -AC_PYTHON_MODULE([unittest]) -AC_SUBST([HAVE_PYMOD_UNITTEST]) -AC_SUBST([PYTHON_VERSION]) -AM_GNU_GETTEXT([external]) -AM_GNU_GETTEXT_VERSION([0.10]) -AC_PATH_PROG([CHEETAH], [cheetah], [/usr/bin/cheetah]) - -# Checking for pyflakes -AC_PATH_PROG([PYFLAKES], [pyflakes]) -if test "x$PYFLAKES" = "x"; then - AC_MSG_WARN([pyflakes not found]) -fi - -AC_ARG_ENABLE( - [sample], - [AS_HELP_STRING( - [--enable-sample], - [enable sample plugin @<:@default=no@:>@] - )], - , - [enable_sample="no"] -) - -if test "${enable_sample}" = "yes"; then -AC_SUBST([ENABLE_SAMPLE], [True]) -else -AC_SUBST([ENABLE_SAMPLE], [False]) -fi - -AC_ARG_WITH( - [spice-html5], - [AS_HELP_STRING([--with-spice-html5], - [Build Kimchi with spice-html5 @<:@default=no@:>@])], - , - [with_spice_html5="no"] -) -AM_CONDITIONAL([WITH_SPICE], [test "x$with_spice_html5" = xyes]) - -AC_CONFIG_FILES([ - po/Makefile.in - po/gen-pot - Makefile - docs/Makefile - distros.d/Makefile - control/Makefile - control/vm/Makefile - model/Makefile - ui/Makefile - ui/config/Makefile - ui/css/Makefile - ui/images/Makefile - ui/images/theme-default/Makefile - ui/js/Makefile - ui/spice-html5/Makefile - ui/spice-html5/css/Makefile - ui/spice-html5/pages/Makefile - ui/spice-html5/thirdparty/Makefile - ui/pages/Makefile - ui/pages/help/Makefile - ui/pages/help/en_US/Makefile - ui/pages/help/de_DE/Makefile - ui/pages/help/es_ES/Makefile - ui/pages/help/fr_FR/Makefile - ui/pages/help/it_IT/Makefile - ui/pages/help/ja_JP/Makefile - ui/pages/help/ko_KR/Makefile - ui/pages/help/pt_BR/Makefile - ui/pages/help/ru_RU/Makefile - ui/pages/help/zh_CN/Makefile - ui/pages/help/zh_TW/Makefile - contrib/Makefile - contrib/DEBIAN/Makefile - contrib/DEBIAN/control - contrib/kimchi.spec.fedora - contrib/kimchi.spec.suse - tests/Makefile - xmlutils/Makefile -],[ - chmod +x po/gen-pot -]) - -AC_OUTPUT diff --git a/plugins/kimchi/contrib/DEBIAN/Makefile.am b/plugins/kimchi/contrib/DEBIAN/Makefile.am deleted file mode 100644 index ca89552..0000000 --- a/plugins/kimchi/contrib/DEBIAN/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -CLEANFILES = control diff --git a/plugins/kimchi/contrib/DEBIAN/control.in b/plugins/kimchi/contrib/DEBIAN/control.in deleted file mode 100644 index dc153d8..0000000 --- a/plugins/kimchi/contrib/DEBIAN/control.in +++ /dev/null @@ -1,30 +0,0 @@ -Package: @PACKAGE_NAME@ -Version: @PACKAGE_VERSION@ -Section: base -Priority: optional -Architecture: all -Depends: wok, - python-imaging, - python-configobj, - websockify, - novnc, - python-jsonschema (>= 1.3.0), - python-libvirt, - gettext, - libvirt-bin, - nfs-common, - qemu-kvm, - python-parted, - python-psutil (>= 0.6.0), - python-ethtool, - sosreport, - python-ipaddr, - python-lxml, - open-iscsi, - python-guestfs, - libguestfs-tools, - spice-html5 -Build-Depends: libxslt, - python-lxml -Maintainer: Aline Manera <alinefm@br.ibm.com> -Description: Kimchi web application diff --git a/plugins/kimchi/contrib/Makefile.am b/plugins/kimchi/contrib/Makefile.am deleted file mode 100644 index 5001191..0000000 --- a/plugins/kimchi/contrib/Makefile.am +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -SUBDIRS = DEBIAN - -EXTRA_DIST = \ - check_i18n.py \ - kimchi.spec.fedora.in \ - make-deb.sh.in \ - $(NULL) - -make-deb.sh: make-deb.sh.in $(top_builddir)/config.status - $(AM_V_GEN)sed \ - -e 's|[@]PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \ - -e 's|[@]PACKAGE_RELEASE[@]|$(PACKAGE_RELEASE)|g' \ - < $< > $@-t && \ - chmod a+x $@-t && \ - mv $@-t $@ -BUILT_SOURCES = make-deb.sh - -CLEANFILES = kimchi.spec.fedora kimchi.spec.suse kimchi.spec make-deb.sh diff --git a/plugins/kimchi/contrib/check_i18n.py b/plugins/kimchi/contrib/check_i18n.py deleted file mode 100755 index 6a2603c..0000000 --- a/plugins/kimchi/contrib/check_i18n.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python2 -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import imp -import os -import re -import sys - - -# Match all conversion specifier with mapping key -PATTERN = re.compile(r'''%\([^)]+\) # Mapping key - [#0\-+]? # Conversion flags (optional) - (\d+|\*)? # Minimum field width (optional) - (\.(\d+|\*))? # Precision (optional) - [lLh]? # Length modifier (optional) - [cdeEfFgGioursxX%] # Conversion type''', - re.VERBOSE) -BAD_PATTERN = re.compile(r"%\([^)]*?\)") - - -def load_i18n_module(i18nfile): - path = os.path.dirname(i18nfile) - mname = i18nfile.replace("/", "_").rstrip(".py") - mobj = imp.find_module("i18n", [path]) - return imp.load_module(mname, *mobj) - - -def check_string_formatting(messages): - for k, v in messages.iteritems(): - if BAD_PATTERN.findall(PATTERN.sub(" ", v)): - print "bad i18n string formatting:" - print " %s: %s" % (k, v) - exit(1) - - -def check_obsolete_messages(path, messages): - def find_message_key(path, k): - for root, dirs, files in os.walk(path): - for f in files: - fname = os.path.join(root, f) - if (not fname.endswith("i18n.py") and fname.endswith(".py") or - fname.endswith(".json")): - with open(fname) as f: - string = "".join(f.readlines()) - if k in string: - return True - return False - - for k in messages.iterkeys(): - if not find_message_key(path, k): - print " %s is obsolete, it is no longer in use" % k - exit(1) - - -def main(): - print "Checking for invalid i18n string..." - for f in sys.argv[1:]: - messages = load_i18n_module(f).messages - check_string_formatting(messages) - check_obsolete_messages(os.path.dirname(f), messages) - print "Checking for invalid i18n string successfully" - - -if __name__ == '__main__': - main() diff --git a/plugins/kimchi/contrib/kimchi.spec.fedora.in b/plugins/kimchi/contrib/kimchi.spec.fedora.in deleted file mode 100644 index 0db3d7e..0000000 --- a/plugins/kimchi/contrib/kimchi.spec.fedora.in +++ /dev/null @@ -1,119 +0,0 @@ -Name: kimchi -Version: @PACKAGE_VERSION@ -Release: @PACKAGE_RELEASE@%{?dist} -Summary: Kimchi server application -BuildRoot: %{_topdir}/BUILD/%{name}-%{version}-%{release} -BuildArch: noarch -Group: System Environment/Base -License: LGPL/ASL2 -Source0: %{name}-%{version}.tar.gz -Requires: wok -Requires: qemu-kvm -Requires: gettext -Requires: libvirt -Requires: libvirt-python -Requires: libvirt-daemon-config-network -Requires: python-websockify -Requires: python-configobj -Requires: novnc -Requires: python-imaging -Requires: pyparted -Requires: python-psutil >= 0.6.0 -Requires: python-jsonschema >= 1.3.0 -Requires: python-ethtool -Requires: sos -Requires: python-ipaddr -Requires: python-lxml -Requires: nfs-utils -Requires: iscsi-initiator-utils -Requires: python-libguestfs -Requires: libguestfs-tools -BuildRequires: libxslt -BuildRequires: python-lxml - -%if 0%{?rhel} >= 6 || 0%{?fedora} >= 19 -Requires: spice-html5 -%endif - -%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7 -%global with_systemd 1 -%endif - -%if 0%{?rhel} == 6 -Requires: python-ordereddict -Requires: python-imaging -BuildRequires: python-unittest2 -%endif - -%description -Web application to manage KVM/Qemu virtual machines - - -%prep -%setup - - -%build -%if 0%{?rhel} >= 6 || 0%{?fedora} >= 19 -%configure -%else -%configure --with-spice-html5 -%endif -make - - -%install -rm -rf %{buildroot} -make DESTDIR=%{buildroot} install - - -%clean -rm -rf $RPM_BUILD_ROOT - -%files -%attr(-,root,root) -%{python_sitelib}/wok/plugins/kimchi/*.py* -%{python_sitelib}/wok/plugins/kimchi/control/*.py* -%{python_sitelib}/wok/plugins/kimchi/control/vm/*.py* -%{python_sitelib}/wok/plugins/kimchi/model/*.py* -%{python_sitelib}/wok/plugins/kimchi/API.json -%{python_sitelib}/wok/plugins/kimchi/ -%{_datadir}/kimchi/doc/API.md -%{_datadir}/kimchi/doc/README.md -%{_datadir}/kimchi/doc/README-federation.md -%{_datadir}/kimchi/doc/kimchi-guest.png -%{_datadir}/kimchi/doc/kimchi-templates.png -%{_prefix}/share/locale/*/LC_MESSAGES/kimchi.mo -%{_datadir}/wok/plugins/kimchi/ui/config/*.xml -%{_datadir}/wok/plugins/kimchi/ui/ -%{_datadir}/wok/plugins/kimchi -%{_sysconfdir}/wok/plugins.d/kimchi.conf -%{_sysconfdir}/wok/plugins.d/template.conf -%{_sysconfdir}/kimchi/distros.d/debian.json -%{_sysconfdir}/kimchi/distros.d/fedora.json -%{_sysconfdir}/kimchi/distros.d/opensuse.json -%{_sysconfdir}/kimchi/distros.d/ubuntu.json -%{_sysconfdir}/kimchi/distros.d/gentoo.json -%{_sysconfdir}/kimchi/ -%{_sharedstatedir}/kimchi/debugreports/ -%{_sharedstatedir}/kimchi/isos/ -%{_sharedstatedir}/kimchi/screenshots/ -%{_sharedstatedir}/kimchi/vnc-tokens/ -%{_sharedstatedir}/kimchi/ - - -%changelog -* Thu Jun 18 2015 Lucio Correia <luciojhc@linux.vnet.ibm.com> 1.6 -- Run kimchi as a plugin - -* Thu Feb 26 2015 Fr��d��ric Bonnard <frediz@linux.vnet.ibm.com> 1.4.0 -- Add man page for kimchid - -* Tue Feb 11 2014 Cr��stian Viana <vianac@linux.vnet.ibm.com> 1.1.0 -- Add help pages and XSLT dependency - -* Tue Jul 16 2013 Adam Litke <agl@us.ibm.com> 0.1.0-1 -- Adapted for autotools build - -* Thu Apr 04 2013 Aline Manera <alinefm@br.ibm.com> 0.0-1 -- First build diff --git a/plugins/kimchi/contrib/kimchi.spec.suse.in b/plugins/kimchi/contrib/kimchi.spec.suse.in deleted file mode 100644 index e466961..0000000 --- a/plugins/kimchi/contrib/kimchi.spec.suse.in +++ /dev/null @@ -1,107 +0,0 @@ -Name: kimchi -Version: @PACKAGE_VERSION@ -Release: @PACKAGE_RELEASE@%{?dist} -Summary: Kimchi server application -BuildRoot: %{_topdir}/BUILD/%{name}-%{version}-%{release} -BuildArch: noarch -Group: System Environment/Base -License: LGPL/ASL2 -Source0: %{name}-%{version}.tar.gz -Requires: wok -Requires: kvm -Requires: gettext-tools -Requires: libvirt -Requires: libvirt-python -Requires: libvirt-daemon-config-network -Requires: python-websockify -Requires: python-configobj -Requires: novnc -Requires: python-imaging -Requires: python-parted -Requires: python-psutil >= 0.6.0 -Requires: python-jsonschema >= 1.3.0 -Requires: python-ethtool -Requires: python-ipaddr -Requires: python-lxml -Requires: python-xml -Requires: nfs-client -Requires: open-iscsi -Requires: python-libguestfs -Requires: guestfs-tools -BuildRequires: libxslt-tools -BuildRequires: python-lxml - -%if 0%{?suse_version} == 1100 -Requires: python-ordereddict -%endif - -%if 0%{?suse_version} > 1140 -%global with_systemd 1 -%endif - -%description -Web application to manage KVM/Qemu virtual machines - -%prep -%setup - -%build -%configure --with-spice-html5 -make - -%install -rm -rf %{buildroot} -make DESTDIR=%{buildroot} install - - -%clean -rm -rf $RPM_BUILD_ROOT - -%files -%attr(-,root,root) -%{python_sitelib}/wok/plugins/kimchi/*.py* -%{python_sitelib}/wok/plugins/kimchi/control/*.py* -%{python_sitelib}/wok/plugins/kimchi/control/vm/*.py* -%{python_sitelib}/wok/plugins/kimchi/model/*.py* -%{python_sitelib}/wok/plugins/kimchi/API.json -%{python_sitelib}/wok/plugins/kimchi/ -%{_datadir}/kimchi/doc/API.md -%{_datadir}/kimchi/doc/README.md -%{_datadir}/kimchi/doc/README-federation.md -%{_datadir}/kimchi/doc/kimchi-guest.png -%{_datadir}/kimchi/doc/kimchi-templates.png -%{_prefix}/share/locale/*/LC_MESSAGES/kimchi.mo -%{_datadir}/wok/plugins/kimchi/ui/config/*.xml -%{_datadir}/wok/plugins/kimchi/ui/ -%{_datadir}/wok/plugins/kimchi -%{_sysconfdir}/wok/plugins.d/kimchi.conf -%{_sysconfdir}/wok/plugins.d/template.conf -%{_sysconfdir}/kimchi/distros.d/debian.json -%{_sysconfdir}/kimchi/distros.d/fedora.json -%{_sysconfdir}/kimchi/distros.d/opensuse.json -%{_sysconfdir}/kimchi/distros.d/ubuntu.json -%{_sysconfdir}/kimchi/distros.d/gentoo.json -%{_sysconfdir}/kimchi/ -%{_var}/lib/kimchi/debugreports/ -%{_var}/lib/kimchi/isos/ -%{_var}/lib/kimchi/screenshots/ -%{_var}/lib/kimchi/vnc-tokens/ -%{_var}/lib/kimchi/ - - -%changelog -* Thu Jun 18 2015 Lucio Correia <luciojhc@linux.vnet.ibm.com> 1.6 -- Run kimchi as a plugin - -* Thu Feb 26 2015 Fr��d��ric Bonnard <frediz@linux.vnet.ibm.com> 1.4.0 -- Add man page for kimchid - -* Tue Feb 11 2014 Cr��stian Viana <vianac@linux.vnet.ibm.com> 1.1.0 -- Add help pages and XSLT dependency - -* Thu Jul 18 2013 Adam Litke <agl@us.ibm.com> 0.1.0-1 -- Adapted for autotools build -- Split Suse and Fedora spec files - -* Thu Apr 04 2013 Aline Manera <alinefm@br.ibm.com> 0.0-1 -- First build diff --git a/plugins/kimchi/contrib/make-deb.sh.in b/plugins/kimchi/contrib/make-deb.sh.in deleted file mode 100644 index 5a6e56a..0000000 --- a/plugins/kimchi/contrib/make-deb.sh.in +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -VERSION="@PACKAGE_VERSION@" -RELEASE="@PACKAGE_RELEASE@" - -if [ ! -f configure ]; then - echo "Please run this script from the top of the package tree" - exit 1 -fi - -TMPDIR=`mktemp -d` - -make DESTDIR=$TMPDIR install-deb -dpkg-deb -b $TMPDIR kimchi-${VERSION}-${RELEASE}.noarch.deb -rm -rf $TMPDIR diff --git a/plugins/kimchi/control/Makefile.am b/plugins/kimchi/control/Makefile.am deleted file mode 100644 index 33118ca..0000000 --- a/plugins/kimchi/control/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -SUBDIRS = vm - -control_PYTHON = *.py - -controldir = $(pythondir)/wok/plugins/kimchi/control - -install-data-local: - $(MKDIR_P) $(DESTDIR)$(controldir) diff --git a/plugins/kimchi/control/__init__.py b/plugins/kimchi/control/__init__.py deleted file mode 100644 index 4ad9459..0000000 --- a/plugins/kimchi/control/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os - - -from wok.control.utils import load_url_sub_node - - -sub_nodes = load_url_sub_node(os.path.dirname(__file__), __name__) diff --git a/plugins/kimchi/control/config.py b/plugins/kimchi/control/config.py deleted file mode 100644 index 15df68f..0000000 --- a/plugins/kimchi/control/config.py +++ /dev/null @@ -1,57 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import Collection, Resource -from wok.control.utils import UrlSubNode - - -@UrlSubNode("config") -class Config(Resource): - def __init__(self, model, id=None): - super(Config, self).__init__(model, id) - self.capabilities = Capabilities(self.model) - self.distros = Distros(model) - - @property - def data(self): - return self.info - - -class Capabilities(Resource): - def __init__(self, model, id=None): - super(Capabilities, self).__init__(model, id) - - @property - def data(self): - return self.info - - -class Distros(Collection): - def __init__(self, model): - super(Distros, self).__init__(model) - self.resource = Distro - - -class Distro(Resource): - def __init__(self, model, ident): - super(Distro, self).__init__(model, ident) - - @property - def data(self): - return self.info diff --git a/plugins/kimchi/control/cpuinfo.py b/plugins/kimchi/control/cpuinfo.py deleted file mode 100644 index 31f316c..0000000 --- a/plugins/kimchi/control/cpuinfo.py +++ /dev/null @@ -1,37 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -from wok.control.base import Resource - - -class CPUInfo(Resource): - def __init__(self, model): - super(CPUInfo, self).__init__(model) - self.admin_methods = ['GET'] - self.role_key = 'host' - self.uri_fmt = "/host/cpuinfo" - - @property - def data(self): - return {'threading_enabled': self.info['guest_threads_enabled'], - 'sockets': self.info['sockets'], - 'cores': self.info['cores_available'], - 'threads_per_core': self.info['threads_per_core'] - } diff --git a/plugins/kimchi/control/debugreports.py b/plugins/kimchi/control/debugreports.py deleted file mode 100644 index b5a3072..0000000 --- a/plugins/kimchi/control/debugreports.py +++ /dev/null @@ -1,61 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import AsyncCollection, Resource -from wok.control.utils import internal_redirect -from wok.control.utils import UrlSubNode - - -@UrlSubNode('debugreports', True) -class DebugReports(AsyncCollection): - def __init__(self, model): - super(DebugReports, self).__init__(model) - self.resource = DebugReport - self.role_key = 'host' - self.admin_methods = ['GET', 'POST'] - - def _get_resources(self, filter_params): - res_list = super(DebugReports, self)._get_resources(filter_params) - return sorted(res_list, key=lambda x: x.data['time'], reverse=True) - - -class DebugReport(Resource): - def __init__(self, model, ident): - super(DebugReport, self).__init__(model, ident) - self.role_key = 'host' - self.admin_methods = ['GET', 'PUT', 'POST'] - self.uri_fmt = '/debugreports/%s' - self.content = DebugReportContent(model, ident) - - @property - def data(self): - return {'name': self.ident, - 'uri': self.info['uri'], - 'time': self.info['ctime']} - - -class DebugReportContent(Resource): - def __init__(self, model, ident): - super(DebugReportContent, self).__init__(model, ident) - self.role_key = 'host' - self.admin_methods = ['GET'] - - def get(self): - self.lookup() - raise internal_redirect(self.info['uri']) diff --git a/plugins/kimchi/control/groups.py b/plugins/kimchi/control/groups.py deleted file mode 100644 index 649ff09..0000000 --- a/plugins/kimchi/control/groups.py +++ /dev/null @@ -1,28 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import SimpleCollection -from wok.control.utils import UrlSubNode - - -@UrlSubNode('groups', True) -class Groups(SimpleCollection): - def __init__(self, model): - super(Groups, self).__init__(model) - self.role_key = 'guests' diff --git a/plugins/kimchi/control/host.py b/plugins/kimchi/control/host.py deleted file mode 100644 index 0a40f1b..0000000 --- a/plugins/kimchi/control/host.py +++ /dev/null @@ -1,157 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import Collection, Resource, SimpleCollection -from wok.control.utils import UrlSubNode -from wok.exception import NotFoundError - -from cpuinfo import CPUInfo - - -@UrlSubNode('host', True) -class Host(Resource): - def __init__(self, model, id=None): - super(Host, self).__init__(model, id) - self.role_key = 'host' - self.admin_methods = ['GET', 'POST'] - self.uri_fmt = '/host/%s' - self.reboot = self.generate_action_handler('reboot') - self.shutdown = self.generate_action_handler('shutdown') - self.stats = HostStats(self.model) - self.partitions = Partitions(self.model) - self.devices = Devices(self.model) - self.packagesupdate = PackagesUpdate(self.model) - self.repositories = Repositories(self.model) - self.swupdate = self.generate_action_handler_task('swupdate') - self.cpuinfo = CPUInfo(self.model) - - @property - def data(self): - return self.info - - -class HostStats(Resource): - def __init__(self, model, id=None): - super(HostStats, self).__init__(model, id) - self.role_key = 'host' - self.admin_methods = ['GET'] - self.history = HostStatsHistory(self.model) - - @property - def data(self): - return self.info - - -class HostStatsHistory(Resource): - @property - def data(self): - return self.info - - -class Partitions(Collection): - def __init__(self, model): - super(Partitions, self).__init__(model) - self.role_key = 'storage' - self.admin_methods = ['GET'] - self.resource = Partition - - # Defining get_resources in order to return list of partitions in UI - # sorted by their path - def _get_resources(self, flag_filter): - res_list = super(Partitions, self)._get_resources(flag_filter) - res_list = filter(lambda x: x.info['available'], res_list) - res_list.sort(key=lambda x: x.info['path']) - return res_list - - -class Partition(Resource): - def __init__(self, model, id): - self.role_key = 'storage' - self.admin_methods = ['GET'] - super(Partition, self).__init__(model, id) - - @property - def data(self): - if not self.info['available']: - raise NotFoundError("KCHPART0001E", {'name': self.info['name']}) - - return self.info - - -class Devices(Collection): - def __init__(self, model): - super(Devices, self).__init__(model) - self.resource = Device - - -class VMHolders(SimpleCollection): - def __init__(self, model, device_id): - super(VMHolders, self).__init__(model) - self.model_args = (device_id, ) - - -class Device(Resource): - def __init__(self, model, id): - super(Device, self).__init__(model, id) - self.vm_holders = VMHolders(self.model, id) - - @property - def data(self): - return self.info - - -class PackagesUpdate(Collection): - def __init__(self, model): - super(PackagesUpdate, self).__init__(model) - self.role_key = 'host' - self.admin_methods = ['GET'] - self.resource = PackageUpdate - - -class PackageUpdate(Resource): - def __init__(self, model, id=None): - super(PackageUpdate, self).__init__(model, id) - self.role_key = 'host' - self.admin_methods = ['GET'] - - @property - def data(self): - return self.info - - -class Repositories(Collection): - def __init__(self, model): - super(Repositories, self).__init__(model) - self.role_key = 'host' - self.admin_methods = ['GET', 'POST'] - self.resource = Repository - - -class Repository(Resource): - def __init__(self, model, id): - super(Repository, self).__init__(model, id) - self.role_key = 'host' - self.admin_methods = ['GET', 'PUT', 'POST', 'DELETE'] - self.uri_fmt = "/host/repositories/%s" - self.enable = self.generate_action_handler('enable') - self.disable = self.generate_action_handler('disable') - - @property - def data(self): - return self.info diff --git a/plugins/kimchi/control/interfaces.py b/plugins/kimchi/control/interfaces.py deleted file mode 100644 index d698b7a..0000000 --- a/plugins/kimchi/control/interfaces.py +++ /dev/null @@ -1,46 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import Collection, Resource -from wok.control.utils import UrlSubNode - - -@UrlSubNode('interfaces', True) -class Interfaces(Collection): - def __init__(self, model): - super(Interfaces, self).__init__(model) - self.role_key = 'network' - self.admin_methods = ['GET'] - self.resource = Interface - - -class Interface(Resource): - def __init__(self, model, ident): - super(Interface, self).__init__(model, ident) - self.role_key = 'network' - self.admin_methods = ['GET'] - self.uri_fmt = "/interfaces/%s" - - @property - def data(self): - return {'name': self.ident, - 'type': self.info['type'], - 'ipaddr': self.info['ipaddr'], - 'netmask': self.info['netmask'], - 'status': self.info['status']} diff --git a/plugins/kimchi/control/networks.py b/plugins/kimchi/control/networks.py deleted file mode 100644 index fd92111..0000000 --- a/plugins/kimchi/control/networks.py +++ /dev/null @@ -1,54 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import Collection, Resource -from wok.control.utils import UrlSubNode - - -@UrlSubNode('networks', True) -class Networks(Collection): - def __init__(self, model): - super(Networks, self).__init__(model) - self.role_key = 'network' - self.admin_methods = ['POST'] - self.resource = Network - - -class Network(Resource): - def __init__(self, model, ident): - super(Network, self).__init__(model, ident) - self.role_key = 'network' - self.admin_methods = ['PUT', 'POST', 'DELETE'] - self.uri_fmt = "/networks/%s" - self.activate = self.generate_action_handler('activate') - self.deactivate = self.generate_action_handler('deactivate', - destructive=True) - - @property - def data(self): - return {'name': self.ident, - 'vms': self.info['vms'], - 'in_use': self.info['in_use'], - 'autostart': self.info['autostart'], - 'connection': self.info['connection'], - 'interface': self.info['interface'], - 'subnet': self.info['subnet'], - 'dhcp': self.info['dhcp'], - 'state': self.info['state'], - 'persistent': self.info['persistent']} diff --git a/plugins/kimchi/control/peers.py b/plugins/kimchi/control/peers.py deleted file mode 100644 index 21e9f13..0000000 --- a/plugins/kimchi/control/peers.py +++ /dev/null @@ -1,29 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import SimpleCollection -from wok.control.utils import UrlSubNode - - -@UrlSubNode("peers", True) -class Peers(SimpleCollection): - def __init__(self, model): - super(Peers, self).__init__(model) - self.role_key = 'peers' - self.admin_methods = ['GET'] diff --git a/plugins/kimchi/control/storagepools.py b/plugins/kimchi/control/storagepools.py deleted file mode 100644 index e5f264e..0000000 --- a/plugins/kimchi/control/storagepools.py +++ /dev/null @@ -1,116 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import cherrypy - -from wok.control.base import Collection, Resource -from wok.control.utils import get_class_name, model_fn -from wok.control.utils import validate_params -from wok.control.utils import UrlSubNode - -from ..model.storagepools import ISO_POOL_NAME -from storagevolumes import IsoVolumes, StorageVolumes - - -@UrlSubNode('storagepools', True) -class StoragePools(Collection): - def __init__(self, model): - super(StoragePools, self).__init__(model) - self.role_key = 'storage' - self.admin_methods = ['POST'] - self.resource = StoragePool - isos = IsoPool(model) - setattr(self, ISO_POOL_NAME, isos) - - def create(self, params, *args): - try: - create = getattr(self.model, model_fn(self, 'create')) - except AttributeError: - error = 'Create is not allowed for %s' % get_class_name(self) - raise cherrypy.HTTPError(405, error) - - validate_params(params, self, 'create') - args = self.model_args + [params] - name = create(*args) - args = self.resource_args + [name] - res = self.resource(self.model, *args) - resp = res.get() - - if 'task_id' in res.data: - cherrypy.response.status = 202 - else: - cherrypy.response.status = 201 - - return resp - - def _get_resources(self, filter_params): - try: - res_list = super(StoragePools, self)._get_resources(filter_params) - # Append reserved pools - isos = getattr(self, ISO_POOL_NAME) - isos.lookup() - res_list.append(isos) - except AttributeError: - pass - - return res_list - - -class StoragePool(Resource): - def __init__(self, model, ident): - super(StoragePool, self).__init__(model, ident) - self.role_key = 'storage' - self.admin_methods = ['PUT', 'POST', 'DELETE'] - self.uri_fmt = "/storagepools/%s" - self.activate = self.generate_action_handler('activate') - self.deactivate = self.generate_action_handler('deactivate', - destructive=True) - self.storagevolumes = StorageVolumes(self.model, ident) - - @property - def data(self): - res = {'name': self.ident, - 'state': self.info['state'], - 'capacity': self.info['capacity'], - 'allocated': self.info['allocated'], - 'available': self.info['available'], - 'path': self.info['path'], - 'source': self.info['source'], - 'type': self.info['type'], - 'nr_volumes': self.info['nr_volumes'], - 'autostart': self.info['autostart'], - 'persistent': self.info['persistent']} - - val = self.info.get('task_id') - if val: - res['task_id'] = val - - return res - - -class IsoPool(Resource): - def __init__(self, model): - super(IsoPool, self).__init__(model, ISO_POOL_NAME) - self.storagevolumes = IsoVolumes(self.model, ISO_POOL_NAME) - - @property - def data(self): - return {'name': self.ident, - 'state': self.info['state'], - 'type': self.info['type']} diff --git a/plugins/kimchi/control/storageservers.py b/plugins/kimchi/control/storageservers.py deleted file mode 100644 index 654ab47..0000000 --- a/plugins/kimchi/control/storageservers.py +++ /dev/null @@ -1,60 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok import template -from wok.control.base import Collection, Resource -from wok.control.utils import get_class_name, model_fn, UrlSubNode - - -@UrlSubNode('storageservers', True) -class StorageServers(Collection): - def __init__(self, model): - super(StorageServers, self).__init__(model) - self.role_key = 'storage' - self.admin_methods = ['GET'] - self.resource = StorageServer - - -class StorageServer(Resource): - def __init__(self, model, ident): - super(StorageServer, self).__init__(model, ident) - self.role_key = 'storage' - self.admin_methods = ['GET'] - self.storagetargets = StorageTargets(self.model, - self.ident.decode("utf-8")) - - @property - def data(self): - return self.info - - -class StorageTargets(Collection): - def __init__(self, model, server): - super(StorageTargets, self).__init__(model) - self.role_key = 'storage' - self.admin_methods = ['GET'] - self.server = server - self.resource_args = [self.server, ] - self.model_args = [self.server, ] - - def get(self, filter_params): - res_list = [] - get_list = getattr(self.model, model_fn(self, 'get_list')) - res_list = get_list(*self.model_args, **filter_params) - return template.render(get_class_name(self), res_list) diff --git a/plugins/kimchi/control/storagevolumes.py b/plugins/kimchi/control/storagevolumes.py deleted file mode 100644 index bbe6627..0000000 --- a/plugins/kimchi/control/storagevolumes.py +++ /dev/null @@ -1,83 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok import template -from wok.control.base import AsyncCollection, Collection, Resource -from wok.control.utils import get_class_name, model_fn - - -class StorageVolumes(AsyncCollection): - def __init__(self, model, pool): - super(StorageVolumes, self).__init__(model) - self.resource = StorageVolume - self.pool = pool - self.resource_args = [self.pool, ] - self.model_args = [self.pool, ] - - def filter_data(self, resources, fields_filter): - # filter directory from storage volumes - fields_filter.update({'type': ['file', 'block', 'network']}) - return super(StorageVolumes, self).filter_data(resources, - fields_filter) - - -class StorageVolume(Resource): - def __init__(self, model, pool, ident): - super(StorageVolume, self).__init__(model, ident) - self.pool = pool - self.ident = ident - self.info = {} - self.model_args = [self.pool, self.ident] - self.uri_fmt = '/storagepools/%s/storagevolumes/%s' - self.resize = self.generate_action_handler('resize', ['size']) - self.wipe = self.generate_action_handler('wipe') - self.clone = self.generate_action_handler_task('clone') - - @property - def data(self): - res = {'name': self.ident, - 'type': self.info['type'], - 'capacity': self.info['capacity'], - 'allocation': self.info['allocation'], - 'path': self.info['path'], - 'used_by': self.info['used_by'], - 'format': self.info['format']} - - for key in ('os_version', 'os_distro', 'bootable', 'base'): - val = self.info.get(key) - if val: - res[key] = val - - return res - - -class IsoVolumes(Collection): - def __init__(self, model, pool): - super(IsoVolumes, self).__init__(model) - self.pool = pool - - def get(self, filter_params): - res_list = [] - try: - get_list = getattr(self.model, model_fn(self, 'get_list')) - res_list = get_list(*self.model_args) - except AttributeError: - pass - - return template.render(get_class_name(self), res_list) diff --git a/plugins/kimchi/control/templates.py b/plugins/kimchi/control/templates.py deleted file mode 100644 index fc58815..0000000 --- a/plugins/kimchi/control/templates.py +++ /dev/null @@ -1,58 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import Collection, Resource -from wok.control.utils import UrlSubNode - - -@UrlSubNode('templates', True) -class Templates(Collection): - def __init__(self, model): - super(Templates, self).__init__(model) - self.role_key = 'templates' - self.admin_methods = ['GET', 'POST'] - self.resource = Template - - -class Template(Resource): - def __init__(self, model, ident): - super(Template, self).__init__(model, ident) - self.role_key = 'templates' - self.admin_methods = ['PUT', 'POST', 'DELETE'] - self.uri_fmt = "/templates/%s" - self.clone = self.generate_action_handler('clone') - - @property - def data(self): - return { - 'name': self.ident, - 'icon': self.info['icon'], - 'invalid': self.info['invalid'], - 'os_distro': self.info['os_distro'], - 'os_version': self.info['os_version'], - 'cpus': self.info['cpus'], - 'memory': self.info['memory'], - 'cdrom': self.info.get('cdrom', None), - 'disks': self.info['disks'], - 'storagepool': self.info['storagepool'], - 'networks': self.info['networks'], - 'folder': self.info.get('folder', []), - 'graphics': self.info['graphics'], - 'cpu_info': self.info.get('cpu_info') - } diff --git a/plugins/kimchi/control/users.py b/plugins/kimchi/control/users.py deleted file mode 100644 index 756a2f7..0000000 --- a/plugins/kimchi/control/users.py +++ /dev/null @@ -1,35 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import SimpleCollection -from wok.control.utils import get_class_name, model_fn, UrlSubNode -from wok.template import render - - -@UrlSubNode('users', True) -class Users(SimpleCollection): - def __init__(self, model): - super(Users, self).__init__(model) - self.role_key = 'guests' - - def get(self, filter_params): - res_list = [] - get_list = getattr(self.model, model_fn(self, 'get_list')) - res_list = get_list(*self.model_args, **filter_params) - return render(get_class_name(self), res_list) diff --git a/plugins/kimchi/control/vm/Makefile.am b/plugins/kimchi/control/vm/Makefile.am deleted file mode 100644 index b17c68a..0000000 --- a/plugins/kimchi/control/vm/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -vm_PYTHON = *.py - -vmdir = $(pythondir)/wok/plugins/kimchi/control/vm - -install-data-local: - $(MKDIR_P) $(DESTDIR)$(vmdir) diff --git a/plugins/kimchi/control/vm/__init__.py b/plugins/kimchi/control/vm/__init__.py deleted file mode 100644 index a311045..0000000 --- a/plugins/kimchi/control/vm/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os - - -from wok.control.utils import load_url_sub_node - - -sub_nodes = load_url_sub_node(os.path.dirname(__file__), __name__) diff --git a/plugins/kimchi/control/vm/hostdevs.py b/plugins/kimchi/control/vm/hostdevs.py deleted file mode 100644 index a43b9d8..0000000 --- a/plugins/kimchi/control/vm/hostdevs.py +++ /dev/null @@ -1,43 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import Collection, Resource -from wok.control.utils import UrlSubNode - - -@UrlSubNode("hostdevs") -class VMHostDevs(Collection): - def __init__(self, model, vmid): - super(VMHostDevs, self).__init__(model) - self.resource = VMHostDev - self.vmid = vmid - self.resource_args = [self.vmid, ] - self.model_args = [self.vmid, ] - - -class VMHostDev(Resource): - def __init__(self, model, vmid, ident): - super(VMHostDev, self).__init__(model, ident) - self.vmid = vmid - self.ident = ident - self.model_args = [self.vmid, self.ident] - - @property - def data(self): - return self.info diff --git a/plugins/kimchi/control/vm/ifaces.py b/plugins/kimchi/control/vm/ifaces.py deleted file mode 100644 index ac957fd..0000000 --- a/plugins/kimchi/control/vm/ifaces.py +++ /dev/null @@ -1,45 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import Collection, Resource -from wok.control.utils import UrlSubNode - - -@UrlSubNode("ifaces") -class VMIfaces(Collection): - def __init__(self, model, vm): - super(VMIfaces, self).__init__(model) - self.resource = VMIface - self.vm = vm - self.resource_args = [self.vm, ] - self.model_args = [self.vm, ] - - -class VMIface(Resource): - def __init__(self, model, vm, ident): - super(VMIface, self).__init__(model, ident) - self.vm = vm - self.ident = ident - self.info = {} - self.model_args = [self.vm, self.ident] - self.uri_fmt = '/vms/%s/ifaces/%s' - - @property - def data(self): - return self.info diff --git a/plugins/kimchi/control/vm/snapshots.py b/plugins/kimchi/control/vm/snapshots.py deleted file mode 100644 index dd17b85..0000000 --- a/plugins/kimchi/control/vm/snapshots.py +++ /dev/null @@ -1,58 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import AsyncCollection, Resource -from wok.control.utils import UrlSubNode - - -@UrlSubNode('snapshots') -class VMSnapshots(AsyncCollection): - def __init__(self, model, vm): - super(VMSnapshots, self).__init__(model) - self.resource = VMSnapshot - self.vm = vm - self.resource_args = [self.vm, ] - self.model_args = [self.vm, ] - self.current = CurrentVMSnapshot(model, vm) - - -class VMSnapshot(Resource): - def __init__(self, model, vm, ident): - super(VMSnapshot, self).__init__(model, ident) - self.vm = vm - self.ident = ident - self.model_args = [self.vm, self.ident] - self.uri_fmt = '/vms/%s/snapshots/%s' - self.revert = self.generate_action_handler('revert') - - @property - def data(self): - return self.info - - -class CurrentVMSnapshot(Resource): - def __init__(self, model, vm): - super(CurrentVMSnapshot, self).__init__(model) - self.vm = vm - self.model_args = [self.vm] - self.uri_fmt = '/vms/%s/snapshots/current' - - @property - def data(self): - return self.info diff --git a/plugins/kimchi/control/vm/storages.py b/plugins/kimchi/control/vm/storages.py deleted file mode 100644 index f502caa..0000000 --- a/plugins/kimchi/control/vm/storages.py +++ /dev/null @@ -1,45 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import Collection, Resource -from wok.control.utils import UrlSubNode - - -@UrlSubNode("storages") -class VMStorages(Collection): - def __init__(self, model, vm): - super(VMStorages, self).__init__(model) - self.resource = VMStorage - self.vm = vm - self.resource_args = [self.vm, ] - self.model_args = [self.vm, ] - - -class VMStorage(Resource): - def __init__(self, model, vm, ident): - super(VMStorage, self).__init__(model, ident) - self.vm = vm - self.ident = ident - self.info = {} - self.model_args = [self.vm, self.ident] - self.uri_fmt = '/vms/%s/storages/%s' - - @property - def data(self): - return self.info diff --git a/plugins/kimchi/control/vms.py b/plugins/kimchi/control/vms.py deleted file mode 100644 index 858b23c..0000000 --- a/plugins/kimchi/control/vms.py +++ /dev/null @@ -1,67 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.control.base import AsyncCollection, Resource -from wok.control.utils import internal_redirect, UrlSubNode - -from vm import sub_nodes - - -@UrlSubNode('vms', True) -class VMs(AsyncCollection): - def __init__(self, model): - super(VMs, self).__init__(model) - self.resource = VM - self.role_key = 'guests' - self.admin_methods = ['POST'] - - -class VM(Resource): - def __init__(self, model, ident): - super(VM, self).__init__(model, ident) - self.role_key = 'guests' - self.screenshot = VMScreenShot(model, ident) - self.uri_fmt = '/vms/%s' - for ident, node in sub_nodes.items(): - setattr(self, ident, node(model, self.ident)) - self.start = self.generate_action_handler('start') - self.poweroff = self.generate_action_handler('poweroff', - destructive=True) - self.shutdown = self.generate_action_handler('shutdown', - destructive=True) - self.reset = self.generate_action_handler('reset', - destructive=True) - self.connect = self.generate_action_handler('connect') - self.clone = self.generate_action_handler_task('clone') - self.suspend = self.generate_action_handler('suspend') - self.resume = self.generate_action_handler('resume') - - @property - def data(self): - return self.info - - -class VMScreenShot(Resource): - def __init__(self, model, ident): - super(VMScreenShot, self).__init__(model, ident) - self.role_key = 'guests' - - def get(self): - self.lookup() - raise internal_redirect(self.info) diff --git a/plugins/kimchi/disks.py b/plugins/kimchi/disks.py deleted file mode 100644 index eb40e3a..0000000 --- a/plugins/kimchi/disks.py +++ /dev/null @@ -1,196 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os.path -import re -import subprocess -from parted import Device as PDevice -from parted import Disk as PDisk - -from wok.exception import OperationFailed -from wok.utils import wok_log - - -def _get_dev_node_path(maj_min): - """ Returns device node path given the device number 'major:min' """ - - dm_name = "/sys/dev/block/%s/dm/name" % maj_min - if os.path.exists(dm_name): - with open(dm_name) as dm_f: - content = dm_f.read().rstrip('\n') - return "/dev/mapper/" + content - - uevent = "/sys/dev/block/%s/uevent" % maj_min - with open(uevent) as ueventf: - content = ueventf.read() - - data = dict(re.findall(r'(\S+)=(".*?"|\S+)', content.replace("\n", " "))) - - return "/dev/%s" % data["DEVNAME"] - - -def _get_lsblk_devs(keys, devs=[]): - lsblk = subprocess.Popen( - ["lsblk", "-Pbo"] + [','.join(keys)] + devs, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = lsblk.communicate() - if lsblk.returncode != 0: - raise OperationFailed("KCHDISKS0001E", {'err': err}) - - return _parse_lsblk_output(out, keys) - - -def _get_dev_major_min(name): - maj_min = None - - keys = ["NAME", "MAJ:MIN"] - dev_list = _get_lsblk_devs(keys) - - for dev in dev_list: - if dev['name'].split()[0] == name: - maj_min = dev['maj:min'] - break - else: - raise OperationFailed("KCHDISKS0002E", {'device': name}) - - return maj_min - - -def _is_dev_leaf(devNodePath): - try: - # By default, lsblk prints a device information followed by children - # device information - childrenCount = len( - _get_lsblk_devs(["NAME"], [devNodePath])) - 1 - except OperationFailed as e: - # lsblk is known to fail on multipath devices - # Assume these devices contain children - wok_log.error( - "Error getting device info for %s: %s", devNodePath, e) - return False - - return childrenCount == 0 - - -def _is_dev_extended_partition(devType, devNodePath): - if devType != 'part': - return False - diskPath = devNodePath.rstrip('0123456789') - device = PDevice(diskPath) - try: - extended_part = PDisk(device).getExtendedPartition() - except NotImplementedError as e: - wok_log.warning( - "Error getting extended partition info for dev %s type %s: %s", - devNodePath, devType, e.message) - # Treate disk with unsupported partiton table as if it does not - # contain extended partitions. - return False - if extended_part and extended_part.path == devNodePath: - return True - return False - - -def _parse_lsblk_output(output, keys): - # output is on format key="value", - # where key can be NAME, TYPE, FSTYPE, SIZE, MOUNTPOINT, etc - lines = output.rstrip("\n").split("\n") - r = [] - for line in lines: - d = {} - for key in keys: - expression = r"%s=\".*?\"" % key - match = re.search(expression, line) - field = match.group() - k, v = field.split('=', 1) - d[k.lower()] = v[1:-1] - r.append(d) - return r - - -def _get_vgname(devNodePath): - """ Return volume group name of a physical volume. If the device node path - is not a physical volume, return empty string. """ - pvs = subprocess.Popen( - ["pvs", "--unbuffered", "--nameprefixes", "--noheadings", - "-o", "vg_name", devNodePath], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = pvs.communicate() - if pvs.returncode != 0: - return "" - - return re.findall(r"LVM2_VG_NAME='([^\']*)'", out)[0] - - -def _is_available(name, devtype, fstype, mountpoint, majmin): - devNodePath = _get_dev_node_path(majmin) - # Only list unmounted and unformated and leaf and (partition or disk) - # leaf means a partition, a disk has no partition, or a disk not held - # by any multipath device. Physical volume belongs to no volume group - # is also listed. Extended partitions should not be listed. - if (devtype in ['part', 'disk', 'mpath'] and - fstype in ['', 'LVM2_member'] and - mountpoint == "" and - _get_vgname(devNodePath) == "" and - _is_dev_leaf(devNodePath) and - not _is_dev_extended_partition(devtype, devNodePath)): - return True - return False - - -def get_partitions_names(check=False): - names = set() - keys = ["NAME", "TYPE", "FSTYPE", "MOUNTPOINT", "MAJ:MIN"] - # output is on format key="value", - # where key can be NAME, TYPE, FSTYPE, MOUNTPOINT - for dev in _get_lsblk_devs(keys): - # split()[0] to avoid the second part of the name, after the - # whiteline - name = dev['name'].split()[0] - if check and not _is_available(name, dev['type'], dev['fstype'], - dev['mountpoint'], dev['maj:min']): - continue - names.add(name) - - return list(names) - - -def get_partition_details(name): - majmin = _get_dev_major_min(name) - dev_path = _get_dev_node_path(majmin) - - keys = ["TYPE", "FSTYPE", "SIZE", "MOUNTPOINT"] - try: - dev = _get_lsblk_devs(keys, [dev_path])[0] - except OperationFailed as e: - wok_log.error( - "Error getting partition info for %s: %s", name, e) - return {} - - dev['available'] = _is_available(name, dev['type'], dev['fstype'], - dev['mountpoint'], majmin) - if dev['mountpoint']: - # Sometimes the mountpoint comes with [SWAP] or other - # info which is not an actual mount point. Filtering it - regexp = re.compile(r"\[.*\]") - if regexp.search(dev['mountpoint']) is not None: - dev['mountpoint'] = '' - dev['path'] = dev_path - dev['name'] = name - return dev diff --git a/plugins/kimchi/distroloader.py b/plugins/kimchi/distroloader.py deleted file mode 100644 index 0032737..0000000 --- a/plugins/kimchi/distroloader.py +++ /dev/null @@ -1,67 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -import glob -import json -import os - - -from wok.exception import NotFoundError, OperationFailed -from wok.utils import wok_log - -import config - - -ARCHS = {'x86_64': ['x86_64', 'amd64', 'i686', 'x86', 'i386'], - 'amd64': ['x86_64', 'amd64', 'i686', 'x86', 'i386'], - 'ppc64': ['ppc', 'ppc64'], - 'ppc64le': ['ppc64', 'ppc64le']} - - -class DistroLoader(object): - - def __init__(self, location=None): - self.location = location or config.get_distros_store() - - def _get_json_info(self, fname): - msg_args = {'filename': fname} - if not os.path.isfile(fname): - msg = "DistroLoader: failed to find distro file: %s" % fname - wok_log.error(msg) - raise NotFoundError("KCHDL0001E", msg_args) - try: - with open(fname) as f: - data = json.load(f) - return data - except ValueError: - msg = "DistroLoader: failed to parse distro file: %s" % fname - wok_log.error(msg) - raise OperationFailed("KCHDL0002E", msg_args) - - def get(self): - arch_list = ARCHS.get(os.uname()[4]) - all_json_files = glob.glob("%s/%s" % (self.location, "*.json")) - distros = [] - for f in all_json_files: - distros.extend(self._get_json_info(f)) - - # Return all remote ISOs arch not found - return dict([(distro['name'], distro) for distro in distros if - (arch_list is None or distro['os_arch'] in arch_list)]) diff --git a/plugins/kimchi/distros.d/Makefile.am b/plugins/kimchi/distros.d/Makefile.am deleted file mode 100644 index 684fe60..0000000 --- a/plugins/kimchi/distros.d/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -distrosdir = $(sysconfdir)/kimchi/distros.d - -dist_distros_DATA = *.json diff --git a/plugins/kimchi/distros.d/debian.json b/plugins/kimchi/distros.d/debian.json deleted file mode 100644 index 5d6a313..0000000 --- a/plugins/kimchi/distros.d/debian.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "name": "debian-Wheezy", - "os_distro": "debian", - "os_arch": "x86_64", - "os_version": "7.7.0", - "path": "http://caesar.acc.umu.se/debian-cd/7.7.0/amd64/iso-cd/debian-7.7.0-amd64-net..." - } -] diff --git a/plugins/kimchi/distros.d/fedora.json b/plugins/kimchi/distros.d/fedora.json deleted file mode 100644 index bce72d6..0000000 --- a/plugins/kimchi/distros.d/fedora.json +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "name": "Fedora 20", - "os_distro": "fedora", - "os_arch": "x86_64", - "os_version": "20", - "path": "http://fedora.mirrors.tds.net/pub/fedora/releases/20/Live/x86_64/Fedora-Live..." - }, - { - "name": "Fedora 18 (PPC64)", - "os_distro": "fedora", - "os_arch": "ppc64", - "os_version": "18", - "path": "http://mirrors.kernel.org/fedora-secondary/releases/18/Fedora/ppc64/iso/Fedo..." - }, - { - "name": "Fedora 19 (PPC64)", - "os_distro": "fedora", - "os_arch": "ppc64", - "os_version": "19", - "path": "http://mirrors.kernel.org/fedora-secondary/releases/19/Fedora/ppc64/iso/Fedo..." - }, - { - "name": "Fedora 20 (PPC64)", - "os_distro": "fedora", - "os_arch": "ppc64", - "os_version": "20", - "path": "http://mirrors.kernel.org/fedora-secondary/releases/20/Fedora/ppc64/iso/Fedo..." - } -] diff --git a/plugins/kimchi/distros.d/gentoo.json b/plugins/kimchi/distros.d/gentoo.json deleted file mode 100644 index 2c0f012..0000000 --- a/plugins/kimchi/distros.d/gentoo.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "name": "gentoo-20141204", - "os_distro": "gentoo", - "os_arch": "x86_64", - "os_version": "20141204", - "path": "http://distfiles.gentoo.org/releases/amd64/autobuilds/current-iso/install-am..." - } -] diff --git a/plugins/kimchi/distros.d/opensuse.json b/plugins/kimchi/distros.d/opensuse.json deleted file mode 100644 index f51de97..0000000 --- a/plugins/kimchi/distros.d/opensuse.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "name": "opensuse-12.3", - "os_distro": "opensuse", - "os_arch": "x86_64", - "os_version": "12.3", - "path": "http://suse.mirrors.tds.net/pub/opensuse/distribution/12.3/iso/openSUSE-12.3..." - }, - { - "name": "opensuse-13.1", - "os_distro": "opensuse", - "os_arch": "x86_64", - "os_version": "13.1", - "path": "http://suse.mirrors.tds.net/pub/opensuse/distribution/13.1/iso/openSUSE-13.1..." - }, - { - "name": "opensuse-13.2", - "os_distro": "opensuse", - "os_arch": "x86_64", - "os_version": "13.2", - "path": "http://suse.mirrors.tds.net/pub/opensuse/distribution/13.2/iso/openSUSE-13.2..." - } -] diff --git a/plugins/kimchi/distros.d/ubuntu.json b/plugins/kimchi/distros.d/ubuntu.json deleted file mode 100644 index 161fbc8..0000000 --- a/plugins/kimchi/distros.d/ubuntu.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "name": "Ubuntu 13.04 (Raring Ringtail)", - "os_distro": "ubuntu", - "os_arch": "x86_64", - "os_version": "13.04", - "path": "http://ubuntu-releases.cs.umn.edu/13.04/ubuntu-13.04-desktop-amd64.iso" - }, - { - "name": "Ubuntu 13.10 (Saucy Salamander)", - "os_distro": "ubuntu", - "os_arch": "x86_64", - "os_version": "13.10", - "path": "http://ubuntu-releases.cs.umn.edu/13.10/ubuntu-13.10-desktop-amd64.iso" - }, - { - "name": "Ubuntu Server 14.04 LE (Trusty Tahr)", - "os_distro": "ubuntu", - "os_arch": "ppc64", - "os_version": "14.04", - "path": "http://cdimages.ubuntu.com/releases/14.04/release/ubuntu-14.04-server-ppc64e..." - }, - { - "name": "Ubuntu Server 14.04 LE (Trusty Tahr)", - "os_distro": "ubuntu", - "os_arch": "x86_64", - "os_version": "14.04", - "path": "http://releases.ubuntu.com/14.04/ubuntu-14.04-desktop-amd64.iso" - }, - { - "name": "Ubuntu Server 14.10 (Utopic Unicorn)", - "os_distro": "ubuntu", - "os_arch": "x86_64", - "os_version": "14.10", - "path": "http://releases.ubuntu.com/14.10/ubuntu-14.10-desktop-amd64.iso" - } -] diff --git a/plugins/kimchi/docs/API.md b/plugins/kimchi/docs/API.md deleted file mode 100644 index fca424c..0000000 --- a/plugins/kimchi/docs/API.md +++ /dev/null @@ -1,1116 +0,0 @@ -## Project Kimchi REST API Specification - -The Kimchi API provides all functionality to the application and may be used -directly by external tools. In the following sections you will find the -specification of all Collections and Resource types that are supported and the -URIs where they can be accessed. In order to use the API effectively, please -the following general conventions: - -* The **Content Type** of the API is JSON. When making HTTP requests to this - API you should specify the following headers: - * Accept: application/json - * Content-type: application/json -* A **Collection** is a group of Resources of a given type. - * A **GET** request retrieves a list of summarized Resource representations - This summary *may* include all or some of the Resource properties but - *must* include a link to the full Resource representation. - * A **POST** request will create a new Resource in the Collection. The set - of Resource properties *must* be specified as a JSON object in the request - body. - * No other HTTP methods are supported for Collections -* A **Resource** is a representation of a singular object in the API (eg. - Virtual Machine). - * A **GET** request retrieves the full Resource representation. - * A **DELETE** request will delete the Resource. This request *may* contain - a JSON object which specifies optional parameters. - * A **PUT** request is used to modify the properties of a Resource (eg. - Change the name of a Virtual Machine). This kind of request *must not* - alter the live state of the Resource. Only *actions* may alter live state. - * A **POST** request commits an *action* upon a Resource (eg. Start a - Virtual Machine). This request is made to a URI relative to the Resource - URI. Available *actions* are described within the *actions* property of a - Resource representation. The request body *must* contain a JSON object - which specifies parameters. -* URIs begin with '/plugins/kimchi' to indicate the root of Kimchi plugin. - * Variable segments in the URI begin with a ':' and should replaced with the - appropriate resource identifier. - -### Collection: Virtual Machines - -**URI:** /plugins/kimchi/vms - -**Methods:** - -* **GET**: Retrieve a summarized list of all defined Virtual Machines -* **POST**: Create a new Virtual Machine - * name *(optional)*: The name of the VM. Used to identify the VM in this - API. If omitted, a name will be chosen based on the template used. - * persistent: If 'true', vm will persist after a Power Off or host reboot. - All virtual machines created by Kimchi are persistent. - * template: The URI of a Template to use when building the VM - * storagepool *(optional)*: Assign a specific Storage Pool to the new VM - * graphics *(optional)*: Specify the graphics paramenter for this vm - * type: The type of graphics. It can be VNC or spice or None. - * vnc: Graphical display using the Virtual Network - Computing protocol - * spice: Graphical display using the Simple Protocol for - Independent Computing Environments - * null: Graphics is disabled or type not supported - * listen: The network which the vnc/spice server listens on. - - -### Resource: Virtual Machine - -**URI:** /plugins/kimchi/vms/*:name* - -**Methods:** - -* **GET**: Retrieve the full description of a Virtual Machine - * name: The name of the VM. Used to identify the VM in this API - * state: Indicates the current state in the VM lifecycle - * running: The VM is powered on - * paused: The VMs virtual CPUs are paused - * shutoff: The VM is powered off - * stats: Virtual machine statistics: - * cpu_utilization: A number between 0 and 100 which indicates the - percentage of CPU utilization. - * net_throughput: Expresses total network throughput for reads and - writes across all virtual interfaces (kb/s). - * net_throughput_peak: The highest recent value of 'net_throughput'. - * io_throughput: Expresses the total IO throughput for reads and - writes across all virtual disks (kb/s). - * io_throughput_peak: The highest recent value of 'io_throughput'. - * uuid: UUID of the VM. - * memory: The amount of memory assigned to the VM (in MB) - * cpus: The number of CPUs assigned to the VM - * screenshot: A link to a recent capture of the screen in PNG format - * icon: A link to an icon that represents the VM - * graphics: A dict to show detail of VM graphics. - * type: The type of graphics. It can be VNC or spice or None. - * vnc: Graphical display using the Virtual Network - Computing protocol - * spice: Graphical display using the Simple Protocol for - Independent Computing Environments - * null: Graphics is disabled or type not supported - * listen: The network which the vnc/spice server listens on. - * port: The real port number of the graphics, vnc or spice. Users - can use this port to connect to the vm with general vnc/spice - clients. - * passwd: console password - * passwdValidTo: lifetime for the console password. - * users: A list of system users who have permission to access the VM. - Default is: empty (i.e. only root-users may access). - * groups: A list of system groups whose users have permission to access - the VM. Default is: empty (i.e. no groups given access). -* **DELETE**: Remove the Virtual Machine -* **PUT**: update the parameters of existed VM - * name: New name for this VM (only applied for shutoff VM) - * users: New list of system users. - * groups: New list of system groups. - * cpus: New number of virtual cpus for this VM (if VM is running, new value - will take effect in next reboot) - * memory: New amount of memory (MB) for this VM (if VM is running, new - value will take effect in next reboot) - * graphics: A dict to show detail of VM graphics. - * passwd *(optional)*: console password. When omitted a random password - willbe generated. - * passwdValidTo *(optional)*: lifetime for the console password. When - omitted the password will be valid just - for 30 seconds. - -* **POST**: *See Virtual Machine Actions* - -**Actions (POST):** - -* start: Power on a VM -* poweroff: Power off a VM forcefully. Note this action may produce undesirable - results, for example unflushed disk cache in the guest. -* shutdown: Shut down a VM graceful. This action issue shutdown request to guest. - And the guest will react this request. Note the guest OS may ignore - the request. -* reset: Reset a VM immediately without the guest OS shutdown. - It emulates the power reset button on a machine. Note that there is a - risk of data loss caused by reset without the guest OS shutdown. -* connect: Prepare the connection for spice or vnc - -* clone: Create a new VM identical to this VM. The new VM's name, UUID and - network MAC addresses will be generated automatically. Each existing - disks will be copied to a new volume in the same storage pool. If - there is no available space on that storage pool to hold the new - volume, it will be created on the pool 'default'. This action returns - a Task. - -* suspend: Suspend an active domain. The process is frozen without further - access to CPU resources and I/O but the memory used by the domain at - the hypervisor level will stay allocated. - -* resume: Resume a suspended domain. The process is restarted from the state - where it was frozen by calling "suspend". - -### Sub-resource: Virtual Machine Screenshot - -**URI:** /plugins/kimchi/vms/*:name*/screenshot - -Represents a snapshot of the Virtual Machine's primary monitor. - -**Methods:** - -* **GET**: Redirect to the latest screenshot of a Virtual Machine in PNG format - - -### Sub-collection: Virtual Machine storages -**URI:** /plugins/kimchi/vms/*:name*/storages -* **GET**: Retrieve a summarized list of all storages of specified guest -* **POST**: Attach a new storage or virtual drive to specified virtual machine. - * type: The type of the storage (currently support 'cdrom' and 'disk'). - * path: Path of cdrom iso. - * pool: Storage pool which disk image file locate in. - * vol: Storage volume name of disk image. - -### Sub-resource: storage -**URI:** /plugins/kimchi/vms/*:name*/storages/*:dev* -* **GET**: Retrieve storage information - * dev: The name of the storage in the vm. - * type: The type of the storage (currently support 'cdrom' and 'disk'). - * path: Path of cdrom iso or disk image file. - * bus: Bus type of disk attached. -* **PUT**: Update storage information - * path: Path of cdrom iso. Can not be blank. Now just support cdrom type. -* **DELETE**: Remove the storage. - -**Actions (POST):** - - -### Sub-collection: Virtual Machine Passthrough Devices -**URI:** /plugins/kimchi/vms/*:name*/hostdevs -* **GET**: Retrieve a summarized list of all directly assigned host device of - specified guest. -* **POST**: Directly assign a host device to guest. - * name: The name of the host device to be assigned to vm. - -### Sub-resource: Device -**URI:** /plugins/kimchi/vms/*:name*/hostdevs/*:dev* -* **GET**: Retrieve assigned device information - * name: The name of the assigned device. - * type: The type of the assigned device. -* **DELETE**: Detach the host device from VM. - -### Sub-collection: Virtual Machine Snapshots -**URI:** /plugins/kimchi/vms/*:name*/snapshots -* **POST**: Create a new snapshot on a VM. - * name: The snapshot name (optional, defaults to a value based on the - current time). -* **GET**: Retrieve a list of snapshots on a VM. - -### Sub-resource: Snapshot -**URI:** /plugins/kimchi/vms/*:name*/snapshots/*:snapshot* -* **GET**: Retrieve snapshot information. - * created: The time when the snapshot was created - (in seconds, since the epoch). - * name: The snapshot name. - * parent: The name of the parent snapshot, or an empty string if there is - no parent. - * state: The corresponding domain's state when the snapshot was created. -* **DELETE**: Delete snapshot. If the snapshot has any children, they will be - merged automatically with the snapshot's parent. -* **POST**: See "Snapshot actions (POST)" - -**Snapshot Actions (POST):** - -* revert: Revert the domain to the given snapshot. - -### Sub-resource: Current snapshot -**URI:** /plugins/kimchi/vms/*:name*/snapshots/current -* **GET**: Retrieve current snapshot information for the virtual machine. - -### Collection: Templates - -**URI:** /plugins/kimchi/templates - -**Methods:** - -* **GET**: Retrieve a summarized list of all defined Templates -* **POST**: Create a new Template - * name: The name of the Template. Used to identify the Template in this API - * os_distro *(optional)*: The operating system distribution - * os_version *(optional)*: The version of the operating system distribution - * cpus *(optional)*: The number of CPUs assigned to the VM. - Default is 1, unlees specifying a cpu topology. In that case, cpus - will default to a product of the topology values (see cpu_info). - * memory *(optional)*: The amount of memory assigned to the VM. - Default is 1024M. - * cdrom *(optional)*: A volume name or URI to an ISO image. - * storagepool *(optional)*: URI of the storagepool. - Default is '/storagepools/default' - * networks *(optional)*: list of networks will be assigned to the new VM. - Default is '[default]' - * disks *(optional)*: An array of requested disks with the following optional fields - (either *size* or *volume* must be specified): - * index: The device index - * size: The device size in GB - * base: Base image of this disk - - * graphics *(optional)*: The graphics paramenters of this template - * type: The type of graphics. It can be VNC or spice or None. - * vnc: Graphical display using the Virtual Network - Computing protocol - * spice: Graphical display using the Simple Protocol for - Independent Computing Environments - * null: Graphics is disabled or type not supported - * listen: The network which the vnc/spice server listens on. - * cpu_info *(optional)*: CPU-specific information. - * topology: Specify sockets, threads, and cores to run the virtual CPU - threads on. - All three are required in order to specify cpu topology. - * sockets - The number of sockets to use. - * cores - The number of cores per socket. - * threads - The number of threads per core. - If specifying both cpus and CPU topology, make sure cpus is - equal to the product of sockets, cores, and threads. - -### Sub-Collection: Virtual Machine Network Interfaces - -**URI:** /plugins/kimchi/vms/*:name*/ifaces - -Represents all network interfaces attached to a Virtual Machine. - -**Methods:** - -* **GET**: Retrieve a summarized list of all network interfaces attached to a Virtual Machine. - -* **POST**: attach a network interface to VM - * model *(optional)*: model of emulated network interface card. It can be one of these models: - ne2k_pci, i82551, i82557b, i82559er, rtl8139, e1000, pcnet and virtio. - When model is missing, libvirt will set 'rtl8139' as default value. - * network *(optional)*: the name of resource network, it is required when the - interface type is network. - * type: The type of VM network interface that libvirt supports. - Now kimchi just supports 'network' type. - -### Sub-Resource: Virtual Machine Network Interface - -**URI:** /plugins/kimchi/vms/*:name*/ifaces/*:mac* - -A interface represents available network interface on VM. - -**Methods:** - -* **GET**: Retrieve the full description of the VM network interface - * bridge *(optional)*: the name of resource bridge, only be available when the - interface type is bridge. - * mac: Media Access Control Address of the VM interface. - * model *(optional)*: model of emulated network interface card. It will be one of these models: - ne2k_pci, i82551, i82557b, i82559er, rtl8139, e1000, pcnet and virtio. - * network *(optional)*: the name of resource network, only be available when the - interface type is network. - * type: The type of VM network interface that libvirt supports. - It will be one of these types: 'network', 'bridge', 'user','ethernet', - 'direct', 'hostdev', 'mcast', 'server' and 'client'. - -* **DELETE**: detach the network interface from VM - -* **PUT**: update the parameters of existing VM interface. - * model *(optional)*: model of emulated network interface card. It will be one of these models: - ne2k_pci, i82551, i82557b, i82559er, rtl8139, e1000, pcnet and virtio. - This change is only on the persisted VM configuration. - * network *(optional)*: the name of resource network, only be available when the - interface type is network. - This change is on the active VM instance and persisted VM configuration. - -**Actions (POST):** - -*No actions defined* - - -### Resource: Template - -**URI:** /plugins/kimchi/templates/*:name* - -**Methods:** - -* **GET**: Retrieve the full description of a Template - * name: A name for this template - * folder: A virtual path which can be used to organize Templates in a user - interface. The format is an array of path components. - * icon: A URI to a PNG image representing this template - * os_distro: The operating system distribution - * os_version: The version of the operating system distribution - * cpus: The number of CPUs assigned to the VM - * memory: The amount of memory assigned to the VM in the unit of MB - * cdrom: A volume name or URI to an ISO image - * storagepool: URI of the storagepool where template allocates vm storage. - * networks *(optional)*: list of networks will be assigned to the new VM. - * disks: An array of requested disks with the following optional fields - (either *size* or *volume* must be specified): - * index: The device index - * size: The device size in GB - * volume: A volume name that contains the initial disk contents - * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc. - * graphics: A dict of graphics paramenters of this template - * type: The type of graphics. It can be VNC or spice or None. - * vnc: Graphical display using the Virtual Network - Computing protocol - * spice: Graphical display using the Simple Protocol for - Independent Computing Environments - * null: Graphics is disabled or type not supported - * listen: The network which the vnc/spice server listens on. - * invalid: A dict indicates which paramenters of this template are invalid. - * networks *(optional)*: An array of invalid network names. - * cdrom *(optional)*: An array of invalid cdrom names. - * disks *(optional)*: An array of invalid volume names. - * storagepools *(optional)*: An array of invalid storagepool names. - -* **DELETE**: Remove the Template -* **POST**: *See Template Actions* -* **PUT**: update the parameters of existed template - * name: A name for this template - * folder: A virtual path which can be used to organize Templates in the user - interface. The format is an array of path components. - * icon: A URI to a PNG image representing this template - * os_distro: The operating system distribution - * os_version: The version of the operating system distribution - * cpus: The number of CPUs assigned to the VM - * memory: The amount of memory assigned to the VM - * cdrom: A volume name or URI to an ISO image - * storagepool: URI of the storagepool where template allocates vm storage. - * networks *(optional)*: list of networks will be assigned to the new VM. - * disks: An array of requested disks with the following optional fields - (either *size* or *volume* must be specified): - * index: The device index - * size: The device size in GB - * volume: A volume name that contains the initial disk contents - * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc. - * graphics *(optional)*: A dict of graphics paramenters of this template - * type: The type of graphics. It can be VNC or spice or None. - * vnc: Graphical display using the Virtual Network - Computing protocol - * spice: Graphical display using the Simple Protocol for - Independent Computing Environments - * null: Graphics is disabled or type not supported - * listen: The network which the vnc/spice server listens on. - -**Actions (POST):** - -* clone: clone a template from an existing template with different name. - It will provide a reasonable default name with "-cloneN" as suffix - for the new clone template. The "N" means the number of clone times. - -### Collection: Storage Pools - -**URI:** /plugins/kimchi/storagepools - -**Methods:** - -* **GET**: Retrieve a summarized list of all defined Storage Pools -* **POST**: Create a new Storage Pool - * name: The name of the Storage Pool. - * type: The type of the defined Storage Pool. - Supported types: 'dir', 'kimchi-iso', 'netfs', 'logical', 'iscsi', 'scsi' - * path: The path of the defined Storage Pool. - For 'kimchi-iso' pool refers to targeted deep scan path. - Pool types: 'dir', 'kimchi-iso'. - * source: Dictionary containing source information of the pool. - * host: IP or hostname of server for a pool backed from a remote host. - Pool types: 'netfs', 'iscsi'. - * path: Export path on NFS server for NFS pool. - Pool types: 'netfs'. - * devices: Array of devices to be used in the Storage Pool - Pool types: 'logical'. - * target: Target IQN of an iSCSI pool. - Pool types: 'iscsi'. - * port *(optional)*: Listening port of a remote storage server. - Pool types: 'iscsi'. - * auth *(optional)*: Storage back-end authentication information. - Pool types: 'iscsi'. - * username: Login username of the iSCSI target. - * password: Login password of the iSCSI target. - * adapter_name: SCSI host name. - -### Resource: Storage Pool - -**URI:** /plugins/kimchi/storagepools/*:name* - -**Methods:** - -* **GET**: Retrieve the full description of a Storage Pool - * name: The name of the Storage Pool - Used to identify the Storage Pool in this API - 'kimchi_isos' is a reserved storage pool - which aggregates all ISO images - across all active storage pools into a single view. - * state: Indicates the current state of the Storage Pool - * active: The Storage Pool is ready for use - * inactive: The Storage Pool is not available - * path: The path of the defined Storage Pool - * type: The type of the Storage Pool - * capacity: The total space which can be used to store volumes - The unit is Bytes - * allocated: The amount of space which is being used to store volumes - The unit is Bytes - * available: Free space available for creating new volumes in the pool - * nr_volumes: The number of storage volumes for active pools, 0 for inactive pools - * autostart: Whether the storage pool will be enabled - automatically when the system boots - * persistent: True, when pool persist after a system reboot or be stopped. - All storage pools created by Kimchi are persistent. - * source: Source of the storage pool, - * addr: mount address of this storage pool(for 'netfs' pool) - * path: export path of this storage pool(for 'netfs' pool) - -* **PUT**: Set whether the Storage Pool should be enabled automatically when the - system boots - * autostart: Toggle the autostart flag of the VM. This flag sets whether - the Storage Pool should be enabled automatically when the - system boots - * disks: Adds one or more disks to the pool (for 'logical' pool only) -* **DELETE**: Remove the Storage Pool -* **POST**: *See Storage Pool Actions* - -**Actions (POST):** - -* activate: Activate an inactive Storage Pool -* deactivate: Deactivate an active Storage Pool - -### Collection: Storage Volumes - -**URI:** /plugins/kimchi/storagepools/*:poolname*/storagevolumes - -**Methods:** - -* **GET**: Retrieve a summarized list of all defined Storage Volumes - in the defined Storage Pool -* **POST**: Create a new Storage Volume in the Storage Pool - The return resource is a task resource * See Resource: Task * - Only one of 'capacity', 'url' can be specified. - * name: The name of the Storage Volume - * capacity: The total space which can be used to store volumes - The unit is bytes - * format: The format of the defined Storage Volume. Only used when creating - a storage volume with 'capacity'. - * upload: True to start an upload process. False, otherwise. - Only used when creating a storage volume 'capacity' parameter. - * file: File to be uploaded, passed through form data - -### Resource: Storage Volume - -**URI:** /plugins/kimchi/storagepools/*:poolname*/storagevolumes/*:name* - -**Methods:** - -* **GET**: Retrieve the full description of a Storage Volume - * name: The name of the Storage Volume - Used to identify the Storage Volume in this API - * type: The type of the Storage Volume - * capacity: The total space which can be used to store data - The unit is Bytes - * allocation: The amount of space which is being used to store data - The unit is Bytes - * format: The format of the file or volume - * path: Full path of the volume on the host filesystem. - * os_distro *(optional)*: os distribution of the volume, for iso volume only. - * os_version *(optional)*: os version of the volume, for iso volume only. - * bootable *(optional)*: True if iso image is bootable and not corrupted. - * used_by: Name of vms which use this volume. - -* **DELETE**: Remove the Storage Volume -* **POST**: *See Storage Volume Actions* -* **PUT**: Upload storage volume chunk - * chunk_size: Chunk size of the slice in Bytes. - * chunk: Actual data of uploaded file - -**Actions (POST):** - -* resize: Resize a Storage Volume - * size: resize the total space which can be used to store data - The unit is bytes -* wipe: Wipe a Storage Volume -* clone: Clone a Storage Volume. - * pool: The name of the destination pool (optional). - * name: The new storage volume name (optional). - - -### Collection: Interfaces - -**URI:** /plugins/kimchi/interfaces - -**Methods:** - -* **GET**: Retrieve a summarized list of current Interfaces - -### Resource: Interface - -**URI:** /plugins/kimchi/interfaces/*:name* - -A interface represents available interface on host. - -**Methods:** - -* **GET**: Retrieve the full description of the Interface - * name: The name of the interface. - * status: The current status of the Interface. - * active: The interface is active. - * inactive: The interface is inactive. - * ipaddr: The ip address assigned to this interface in subnet. - * netmask: Is used to divide an IP address into subnets and specify the - networks available hosts - * type: The net device type of the interface. - * nic: Network interface controller that connects a computer to a - computer network - * vlan: A logical interface that represents a VLAN in all Layer 3 - activities the unit may participate in - * bonding: The combination of network interfaces on one host for redundancy - and/or increased throughput. - * bridge: A network device that connects multiple network segments. - -* **POST**: *See Interface Actions* - -**Actions (POST):** - -*No actions defined* - -### Collection: Networks - -**URI:** /plugins/kimchi/networks - -**Methods:** - -* **GET**: Retrieve a summarized list of all defined Networks -* **POST**: Create a new Network - * name: The name of the Network - * connection: Specifies how this network should be connected to the other - networks visible to this host. - * isolated: Create a private, isolated virtual network. - * nat: Outgoing traffic will be routed through the host. - * bridge: All traffic on this network will be bridged through the indicated - interface. - * subnet *(optional)*: Network segment in slash-separated format with ip address and - prefix or netmask used to create nat network. - * interface *(optional)*: The name of a network interface on the host. - For bridge network, the interface can be a bridge or nic/bonding - device. - * vlan_id *(optional)*: VLAN tagging ID for the bridge network. - -### Resource: Network - -**URI:** /plugins/kimchi/networks/*:name* - -**Methods:** - -* **GET**: Retrieve the full description of a Network - * name: The name of the Network - Used to identify the Network in this API - * state: Indicates the current state of the Network - * active: The Network is ready for use - * inactive: The Network is not available - * autostart: Network autostart onboot - * in_use: Indicates ('true') if some guest is attached to this network and 'false' otherwise. - * vms: all vms attached to this network - * subnet: Network segment in slash-separated format with ip address and prefix - * dhcp: DHCP services on the virtual network is enabled. - * start: start boundary of a pool of addresses to be provided to DHCP clients. - * end: end boundary of a pool of addresses to be provided to DHCP clients. - * connection: Specifies how this network should be connected to the other networks - visible to this host. - * isolated: A private, isolated virtual network. - The VMs attached to it can not be reached by the systems - outside of this network and vice versa. - * nat: Outgoing traffic will be routed through the host. - The VM attached to it will have internet access via the host but - other computers will not be able to connect to the VM. - * bridge: Aggregated Public Network. - The VM that joines this network is seen as a peer on this network - and it may offer network services such as HTTP or SSH. - * interface: The name of a bridge network interface on the host. All traffic - on this network will be bridged through the indicated interface. - The interface is a bridge or ethernet/bonding device. - * persistent: If 'true', network will persist after a system reboot or be stopped. - All networks created by Kimchi are persistent. - -* **DELETE**: Remove the Network -* **POST**: *See Network Actions* - -**Actions (POST):** - -* activate: Activate an inactive Network -* deactivate: Deactivate an active Network - - -### Resource: Configuration - -**URI:** /plugins/kimchi/config - -Contains information about the application environment and configuration. - -**Methods:** - -* **GET**: Retrieve configuration information - * display_proxy_port: Port for vnc and spice's websocket proxy to listen on - * version: The version of the kimchi service -* **POST**: *See Configuration Actions* - -**Actions (POST):** - -*No actions defined* - -### Resource: Capabilities - -**URI:** /plugins/kimchi/config/capabilities - -Contains information about the host capabilities: iso streaming, screenshot -creation. - -**Methods:** - -* **GET**: Retrieve capabilities information - * libvirt_stream_protocols: list of which network protocols are accepted - for iso streaming by libvirt - * qemu_spice: True, if QEMU supports Spice; False, otherwise - * qemu_stream: True, if QEMU supports ISO streaming; False, otherwise - * screenshot: True, if libvirt stream functionality can create screenshot - file without problems; False, otherwise or None if the functionality was - not tested yet - * system_report_tool: True if the is some debug report tool installed on - the system; False, otherwise. - * update_tool: True if there is a compatible package manager for the - system; False, otherwise - * repo_mngt_tool: 'deb', 'yum' or None - when the repository management - tool is not identified - * federation: 'on' if federation feature is enabled, 'off' otherwise. - * auth: authentication type, 'pam' and 'ldap' are supported. -* **POST**: *See Configuration Actions* - -**Actions (POST):** - -*No actions defined* - -### Collection: Storage Servers - -**URI:** /plugins/kimchi/storageservers - -**Methods:** - -* **GET**: Retrieve a summarized list of used storage servers. - * Parameters: - * _target_type: Filter server list with given type, currently support - 'netfs' and 'iscsi'. - -### Resource: Storage Server - -**URI:** /plugins/kimchi/storageservers/*:host* - -**Methods:** - -* **GET**: Retrieve description of a Storage Server - * host: IP or host name of storage server - * port: port of storage server, only for "iscsi" - -### Collection: Storage Targets - -**URI:** /plugins/kimchi/storageservers/*:name*/storagetargets - -**Methods:** - -* **GET**: Retrieve a list of available storage targets. - * Parameters: - * _target_type: Filter target list with given type, currently support - 'netfs' and 'iscsi'. - * _server_port: Filter target list with given server port, - currently support 'iscsi'. - * Response: A list with storage targets information. - * host: IP or host name of storage server of this target. - * target_type: Type of storage target, supported: 'nfs'. - * target: Storage target path. - -### Collection: Distros - -**URI:** /plugins/kimchi/config/distros - -**Methods:** - -* **GET**: Retrieve a summarized list of all Distros - -### Resource: Distro - -**URI:** /plugins/kimchi/config/distros/*:name* - -Contains information about the OS distribution. - -**Methods:** - -* **GET**: Retrieve a OS distribution information. - * name: The name of the Distro. - * os_distro: The operating system distribution. - * os_version: The version of the operating system distribution. - * path: A URI to an ISO image. - -**Actions (POST):** - -*No actions defined* - -#### Collection: Debug Reports - -**URI:** /plugins/kimchi/debugreports - -**Methods:** - -* **GET**: Retrieve a summarized list of all available Debug Reports -* **POST**: Create a new Debug Report. This POST method is different - from the other ones. The return resource is a task resource which - is identified by the url below - * task resource. * See Resource: Task * - -### Resource: Debug Report - -**URI:** /plugins/kimchi/debugreports/*:name* - -A Debug Report is an archive of logs and other information about the host that -is used to diagnose and debug problems. The exact format and contents are -specific to the low level collection tool being used. - -**Methods:** - -* **GET**: Retrieve the full description of Debug Report - * name: The debug report name used to identify the report - * uri: The URI path to download a debug report - * time: The time when the debug report is created - -* **PUT**: rename an existed debug report - * name: The new name for this debug report - -* **DELETE**: Remove the Debug Report - * name: The debug report name used to identify the report - -* **POST**: *See Debug Report Actions* - -**Actions (POST):** - -*No actions defined* - -### Sub-resource: Debug Report content - -**URI:** /plugins/kimchi/debugreports/*:name*/content - -It is the sub-resource of Debug Report and the client use it to get the real content -of the Debug Report file from the server - -* **GET**: Retrieve the content of a Debug Report file - -**Actions (POST):** - -*No actions defined* - -### Resource: Host - -**URI:** /plugins/kimchi/host -Contains information of host. - -**Methods:** - -* **GET**: Retrieve host static information - * memory: Total size of host physical memory - The unit is Bytes - * cpu_model: The model name of host CPU - * cpus: The number of online CPUs available on host - * os_distro: The OS distribution that runs on host - * os_version: The version of OS distribution - * os_codename: The code name of OS distribution - -* **POST**: *See Host Actions* - -**Actions (POST):** - -* reboot: Restart the host machine. - Only allowed if there is not vm running. -* shutdown: Power off the host machine. - Only allowed if there is not vm running. -* swupdate: Start the update of packages in background and return a Task resource - * task resource. * See Resource: Task * - -### Resource: Users - -**URI:** /plugins/kimchi/users -List of available users. - -**Methods:** - -* **GET**: Retrieve list of available users. - * Parameters: - * _user_id: Validate whether user exists. - Essential for 'ldap' authentication. - -### Resource: Groups - -**URI:** /plugins/kimchi/groups -List of available groups. - -**Methods:** - -* **GET**: Retrieve list of available groups, only support 'pam' authentication. - -### Resource: HostStats - -**URI:** /plugins/kimchi/host/stats - -Contains the host sample data. - -**Methods:** - -* **GET**: Retrieve host sample data - * cpu_utilization: A number between 0 and 100 which indicates the - percentage of CPU utilization. - * memory: memory statistics of host - * total: Total amount of memory. The unit is Bytes. - * free: The amount of memory left unused by the system. The unit is Bytes. - * buffers: The amount of memory used for file buffers. The unit is Bytes. - * cached: The amount of memory used as cache memory. The unit is Bytes. - * avail: The total amount of buffer, cache and free memory. The unit is Bytes. - * disk_read_rate: Expresses the total IO throughput for reads across - all disks (B/s). - * disk_write_rate: Expresses the total IO throughput for writes across - all disks (B/s). - * net_sent_rate: Expresses the total network throughput for writes across - all interfaces (B/s). - * net_recv_rate: Expresses the total network throughput for reads across - all interfaces (B/s). - -* **POST**: *See HostStats Actions* - -**Actions (POST):** - -*No actions defined* - -### Resource: HostStats - -**URI:** /plugins/kimchi/host/cpuinfo - -The cores and sockets of a hosts's CPU. Useful when sizing VMs to take -advantages of the perforamance benefits of SMT (Power) or Hyper-Threading (Intel). - -**Methods:** - -* **GET**: Retreives the sockets, cores, and threads values. - * threading_enabled: Whether CPU topology is supported on this system. - * sockets: The number of total sockets on a system. - * cores: The total number of cores per socket. - * threads_per_core: The threads per core. - -**Actions (PUT):** - -*No actions defined* - -**Actions (POST):** - -*No actions defined* - - -### Resource: HostStatsHistory - -**URI:** /plugins/kimchi/host/stats/history - -It is the sub-resource of Host Stats and the client uses it to get the host -stats history - -**Methods:** - -* **GET**: Retrieve host sample data history - * cpu_utilization: CPU utilization history - * memory: Memory statistics history - * total: Total amount of memory. The unit is Bytes. - * free: The amount of memory left unused by the system. The unit is Bytes. - * buffers: The amount of memory used for file buffers. The unit is Bytes. - * cached: The amount of memory used as cache memory. The unit is Bytes. - * avail: The total amount of buffer, cache and free memory. The unit is Bytes. - * disk_read_rate: IO throughput for reads history - * disk_write_rate: IO throughput for writes history - * net_sent_rate: Network throughput for writes history - * net_recv_rate: Network throughput for reads history - -* **POST**: *See HostStatsHistory Actions* - -**Actions (POST):** - -*No actions defined* - -### Collection: Partitions - -**URI:** /plugins/kimchi/host/partitions - -**Methods:** - -* **GET**: Retrieves a detailed list of all partitions of the host. - -### Resource: Partition - -**URI:** /plugins/kimchi/host/partitions/*:name* - -**Methods:** - -* **GET**: Retrieve the description of a single Partition: - * name: The name of the partition. Used to identify it in this API - * path: The device path of this partition. - * type: The type of the partition: - * part: a standard partition - * lvm: a partition that belongs to a lvm - * fstype: The file system type of the partition - * size: The total size of the partition, in bytes - * mountpoint: If the partition is mounted, represents the mountpoint. - Otherwise blank. - * available: false, if the partition is in use by system; true, otherwise. - -### Collection: Devices - -**URI:** /plugins/kimchi/host/devices - -**Methods:** - -* **GET**: Retrieves list of host devices (Node Devices). - * Parameters: - * _cap: Filter node device list with given node device capability. - To list Fibre Channel SCSI Host devices, use "_cap=fc_host". - Other available values are "fc_host", "net", "pci", "scsi", - "storage", "system", "usb" and "usb_device". - * _passthrough: Filter devices eligible to be assigned to guest - directly. Possible values are "ture" and "false". - * _passthrough_affected_by: Filter the affected devices in the same - group of a certain directly assigned device. - The value should be the name of a device. - -### Resource: Device - -**URI:** /plugins/kimchi/host/devices/*:name* - -**Methods:** - -* **GET**: Retrieve information of a single host device. - * device_type: Type of the device, supported types are "net", "pci", "scsi", - "storage", "system", "usb" and "usb_device". - * name: The name of the device. - * path: Path of device in sysfs. - * parent: The name of the parent parent device. - * adapter: Host adapter information of a "scsi_host" or "fc_host" device. - * type: The capability type of the scsi_host device (fc_host, vport_ops). - * wwnn: The HBA Word Wide Node Name. Empty if pci device is not fc_host. - * wwpn: The HBA Word Wide Port Name. Empty if pci device is not fc_host. - * domain: Domain number of a "pci" device. - * bus: Bus number of a "pci" device. - * slot: Slot number of a "pci" device. - * function: Function number of a "pci" device. - * vendor: Vendor information of a "pci" device. - * id: Vendor id of a "pci" device. - * description: Vendor description of a "pci" device. - * product: Product information of a "pci" device. - * id: Product id of a "pci" device. - * description: Product description of a "pci" device. - * iommuGroup: IOMMU group number of a "pci" device. Would be None/null if - host does not enable IOMMU support. - - -### Sub-collection: VMs with the device assigned. -**URI:** /plugins/kimchi/host/devices/*:name*/vmholders -* **GET**: Retrieve a summarized list of all VMs holding the device. - -### Sub-resource: VM holder -**URI:** /plugins/kimchi/host/devices/*:name*/vmholders/*:vm* -* **GET**: Retrieve information of the VM which is holding the device - * name: The name of the VM. - * state: The power state of the VM. Could be "running" and "shutdown". - - -### Collection: Host Packages Update - -**URI:** /plugins/kimchi/host/packagesupdate - -Contains the information and action of packages update in the host. - -**Methods:** - -* **GET**: Retrieves a list of all packages to be updated in the host: - -### Resource: Host Package Update - -**URI:** /plugins/kimchi/host/packagesupdate/*:name* - -Contains the information for a specific package to be updated. - -**Methods:** - -* **GET**: Retrieves a full description of a package: - * package_name: The name of the package to be updated - * arch: The architecture of the package - * version: The new version of the package - * repository: The repository name from where package will be downloaded - -### Collection: Host Repositories - -**URI:** /plugins/kimchi/host/repositories - -**Methods:** - -* **GET**: Retrieve a summarized list of all repositories available -* **POST**: Add a new repository - * baseurl: URL to the repodata directory when "is_mirror" is false. -Otherwise, it can be URL to the mirror system for YUM. Can be an -http://, ftp:// or file:// URL. - * repo_id *(optional)*: Unique YUM repository ID - * config: A dictionary that contains specific data according to repository - type. - * repo_name *(optional)*: YUM Repository name - * mirrorlist *(optional)*: Specifies a URL to a file containing a - list of baseurls for YUM repository - * dist: Distribution to DEB repository - * comps *(optional)*: List of components to DEB repository - -### Resource: Repository - -**URI:** /plugins/kimchi/host/repositories/*:repo-id* - -**Methods:** - -* **GET**: Retrieve the full description of a Repository - * repo_id: Unique repository name for each repository, one word. - * baseurl: URL to the repodata directory when "is_mirror" is false. -Otherwise, it can be URL to the mirror system for YUM. Can be an -http://, ftp:// or file:// URL. - * enabled: True, when repository is enabled; False, otherwise - * config: A dictionary that contains specific data according to repository - type. - * repo_name: Human-readable string describing the YUM repository. - * mirrorlist: Specifies a URL to a file containing a list of baseurls - for YUM repository - * gpgcheck: True, to enable GPG signature verification; False, otherwise. - * gpgkey: URL pointing to the ASCII-armored GPG key file for the YUM - repository. - * dist: Distribution to DEB repository - * comps: List of components to DEB repository - -* **DELETE**: Remove the Repository -* **POST**: *See Repository Actions* -* **PUT**: update the parameters of existing Repository - * repo_id: Unique repository name for each repository, one word. - * baseurl: URL to the repodata directory when "is_mirror" is false. -Otherwise, it can be URL to the mirror system for YUM. Can be an -http://, ftp:// or file:// URL. - * config: A dictionary that contains specific data according to repository - type. - * repo_name: Human-readable string describing the YUM repository. - * mirrorlist: Specifies a URL to a file containing a list of baseurls - for YUM repository - * gpgcheck: True, to enable GPG signature verification; False, otherwise. - * gpgkey: URL pointing to the ASCII-armored GPG key file for the YUM - repository. - * dist: Distribution to DEB repository - * comps: List of components to DEB repository - -**Actions (POST):** - -* enable: Enable the Repository as package source -* disable: Disable the Repository as package source - -### Collection: Peers - -**URI:** /plugins/kimchi/peers - -**Methods:** - -* **GET**: Return the list of Kimchi peers in the same network - (It uses openSLP for discovering) diff --git a/plugins/kimchi/docs/Makefile.am b/plugins/kimchi/docs/Makefile.am deleted file mode 100644 index 679aa18..0000000 --- a/plugins/kimchi/docs/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -docdir = $(datadir)/kimchi/doc - -dist_doc_DATA = \ - API.md \ - README.md \ - README-federation.md \ - kimchi-guest.png \ - kimchi-templates.png \ - $(NULL) diff --git a/plugins/kimchi/docs/README-federation.md b/plugins/kimchi/docs/README-federation.md deleted file mode 100644 index c184f4f..0000000 --- a/plugins/kimchi/docs/README-federation.md +++ /dev/null @@ -1,60 +0,0 @@ -Kimchi Project - Federation Feature -=================================== - -Federation feature is a Kimchi mechanism to discover Wok peers in the same -network. It uses openSLP tool (http://www.openslp.org/) to register and find Wok -servers. - -By default this feature is disabled on Wok as it is not critical for KVM -virtualization and requires additional software installation. - -To enable it, do the following: - -1. Install openslp and openslp-server rpm packages, - or install slpd and slptool deb packages. - -2. openSLP uses port 427 (UDP) and port 427 (TCP) so make sure to open those - ports in your firewall configuration - - For system using firewalld, do: - sudo firewall-cmd --permanent --add-port=427/udp - sudo firewall-cmd --permanent --add-port=427/tcp - sudo firewall-cmd --reload - - For openSUSE systems, do: - sudo /sbin/SuSEfirewall2 open EXT TCP 427 - sudo /sbin/SuSEfirewall2 open EXT UDP 427 - - For system using iptables, do: - sudo iptables -A INPUT -p tcp --dport 427 -j ACCEPT - sudo iptables -A INPUT -p udp --dport 427 -j ACCEPT - -3. In addition to the openSLP ports, you also need to allow multicast in the - firewall configuration - - For system using firewalld, do: - sudo firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -s <subnet> -j ACCEPT - - For openSUSE systems, do: - Add the subnet to the trusted networks listed on FW_TRUSTED_NETS in - /etc/sysconfig/SuSEfirewall2 file. - Make sure to restart /sbin/SuSEfirewall2 after modifying /etc/sysconfig/SuSEfirewall2 - - For system using iptables, do: - sudo iptables -A INPUT -s <subnet> -j ACCEPT - -4. Start slpd service and make sure it is up while running Wok - sudo service slpd start - -5. Enable federation on Wok by editing the /etc/wok/wok.conf file: - - federation = on - -6. Then start Wok service - sudo service wokd start - -The Wok server will be registered on openSLP on server starting up and will -be found by other Wok peers (with federation feature enabled) in the same -network. - -Enjoy! diff --git a/plugins/kimchi/docs/README.md b/plugins/kimchi/docs/README.md deleted file mode 100644 index f400333..0000000 --- a/plugins/kimchi/docs/README.md +++ /dev/null @@ -1,247 +0,0 @@ -Kimchi Project -============== - -Kimchi is an HTML5 based management tool for KVM. It is designed to make it as -easy as possible to get started with KVM and create your first guest. - -Kimchi runs as a Wok plugin. Wok runs as a daemon on the hypervisor host. - -Kimchi manages KVM guests through libvirt. The management interface is accessed -over the web using a browser that supports HTML5. - -Browser Support -=============== -Desktop Browser Support: ------------------------ -* **Internet Explorer:** IE9+ -* **Chrome:** Current-1 version -* **Firefox:** Current-1 version Firefox 24ESR -* **Safari:** Current-1 version -* **Opera:** Current-1 version - -Mobile Browser Support: ------------------------ -* **Safari iOS:** Current-1 version -* **Android Browser** Current-1 version - -Current-1 version denotes that we support the current stable version of the -browser and the version that preceded it. For example, if the current version of -a browser is 24.x, we support the 24.x and 23.x versions.This does not mean that -kimchi cannot be used in other browsers, however, functionality and appearance -may be diminished and we may not be able to provide support for any problems you -find. - -Hypervisor Distro Support -========================= - -Kimchi and Wok might run on any GNU/Linux distribution that meets the conditions -described on the 'Getting Started' section below. - -The Kimchi community makes an effort to test it with the latest versions of -Fedora, RHEL, OpenSuSe, and Ubuntu. - -Getting Started -=============== - -Install Dependencies --------------------- - -**For fedora and RHEL:** - - $ sudo yum install gcc make autoconf automake gettext-devel git \ - python-cherrypy python-cheetah libvirt-python \ - libvirt libvirt-daemon-config-network python-imaging \ - PyPAM m2crypto python-jsonschema rpm-build \ - qemu-kvm python-psutil python-ethtool sos \ - python-ipaddr python-ldap python-lxml nfs-utils \ - iscsi-initiator-utils libxslt pyparted nginx \ - python-libguestfs libguestfs-tools python-websockify \ - novnc spice-html5 python-configobj - - # If using RHEL, install the following additional packages: - $ sudo yum install python-unittest2 python-ordereddict - - # Restart libvirt to allow configuration changes to take effect - $ sudo service libvirtd restart - - Packages version requirement: - python-psutil >= 0.6.0 - - # These dependencies are only required if you want to run the tests: - $ sudo yum install pyflakes python-pep8 python-requests - -*Note for RHEL users*: Some of the above packages are located in the Red Hat -EPEL repositories. See -[this FAQ](http://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F) -for more information on how to configure your system to access this repository. - -And for RHEL7 systems, you also need to subscribe to the "RHEL Server Optional" -channel at RHN Classic or Red Hat Satellite. - -**For debian:** - - $ sudo apt-get install gcc make autoconf automake gettext git \ - python-cherrypy3 python-cheetah python-libvirt \ - libvirt-bin python-imaging python-configobj \ - python-pam python-m2crypto python-jsonschema \ - qemu-kvm libtool python-psutil python-ethtool \ - sosreport python-ipaddr python-ldap \ - python-lxml nfs-common open-iscsi lvm2 xsltproc \ - python-parted nginx python-guestfs libguestfs-tools \ - websockify novnc spice-html5 - - Packages version requirement: - python-jsonschema >= 1.3.0 - python-psutil >= 0.6.0 - - # These dependencies are only required if you want to run the tests: - $ sudo apt-get install pep8 pyflakes python-requests - -**For openSUSE:** - - $ sudo zypper install gcc make autoconf automake gettext-tools git \ - python-CherryPy python-Cheetah libvirt-python \ - libvirt libvirt-daemon-config-network python-pam \ - python-imaging python-M2Crypto python-jsonschema \ - rpm-build kvm python-psutil python-ethtool \ - python-ipaddr python-ldap python-lxml nfs-client \ - open-iscsi libxslt-tools python-xml python-parted \ - nginx python-libguestfs python-configobj \ - guestfs-tools python-websockify novnc - - Packages version requirement: - python-psutil >= 0.6.0 - - # These dependencies are only required if you want to run the tests: - $ sudo zypper install python-pyflakes python-pep8 python-requests - -*Note for openSUSE users*: Some of the above packages are located in different -openSUSE repositories. See -[this FAQ](http://download.opensuse.org/repositories/home:GRNET:synnefo/) for -python-parted; and -[this FAQ](http://download.opensuse.org/repositories/systemsmanagement:/spacewalk/) -for python-ethtool to get the correct repository based on your openSUSE version. And -[this FAQ](http://en.opensuse.org/SDB:Add_package_repositories) for more -information on how configure your system to access this repository. - -Build and Install ------------------ - - Wok: - $ ./autogen.sh --system - - $ make - $ sudo make install # Optional if running from the source tree - - - Kimchi: - $ cd plugins/kimchi - - For openSUSE 13.1: - $ ./autogen.sh --with-spice-html5 - - Otherwise: - $ ./autogen.sh --system - - $ make - $ sudo make install # Optional if running from the source tree - -Run ---- - - $ sudo wokd --host=0.0.0.0 - -If you cannot access Wok, take a look at these 2 points: - -1. Firewall -Wok uses by default the ports 8000, 8001 and 64667. To allow incoming connections: - - For system using firewalld, do: - sudo firewall-cmd --add-port=8000/tcp --permanent - sudo firewall-cmd --add-port=8001/tcp --permanent - sudo firewall-cmd --add-port=64667/tcp --permanent - sudo firewall-cmd --reload - - For openSUSE systems, do: - sudo /sbin/SuSEfirewall2 open EXT TCP 8000 - sudo /sbin/SuSEfirewall2 open EXT TCP 8001 - sudo /sbin/SuSEfirewall2 open EXT TCP 64667 - - For system using iptables, do: - sudo iptables -A INPUT -p tcp --dport 8000 -j ACCEPT - sudo iptables -A INPUT -p tcp --dport 8001 -j ACCEPT - sudo iptables -A INPUT -p tcp --dport 64667 -j ACCEPT - - Don't forget to correctly save the rules. - - -2. SELinux -Allow httpd_t context for Wok web server: - - semanage permissive -a httpd_t - - -Test ----- - - $ cd plugins/kimchi - $ make check-local # check for i18n and formatting errors - $ sudo make check - -After all tests are executed, a summary will be displayed containing any -errors/failures which might have occurred. - -Usage ------ - -Connect your browser to https://localhost:8001. You should see a screen like: - - - -Wok uses PAM to authenticate users so you can log in with the same username -and password that you would use to log in to the machine itself. Once logged in -you will see a screen like: - - - -This shows you the list of running guests including a live screenshot of -the guest session. You can use the action buttons to shutdown the guests -or connect to the display in a new window. - -To create a new guest, click on the "+" button in the upper right corner. -In Kimchi, all guest creation is done through templates. - -You can view or modify templates by clicking on the Templates link in the -top navigation bar. - -The template screen looks like: - - - -From this view, you can change the parameters of a template or create a -new template using the "+" button in the upper right corner. - -To create a template, you need an ISO on your host or using remote one. -If you are willing to use your own ISO, please copy it to out of box storage -pool (default path is: /var/lib/kimchi/isos). - -Known Issues ------------- - -1. When you are using NFS as storage pool, check the nfs export path permission -is configured as: - (1) export path need to be squashed as kvm gid and libvirt uid: - /my_export_path *(all_squash,anongid=<kvm-gid>, anonuid=<libvirt-uid>,rw,sync) - So that root user can create volume with right user/group. - (2) Chown of export path as libvirt user, group as kvm group, - In order to make sure all mapped user can get into the mount point. - -Participating -------------- - -All patches are sent through our mailing list hosted by oVirt. More -information can be found at: - -https://github.com/kimchi-project/kimchi/wiki/Communications - -Patches should be sent using git-send-email to kimchi-devel@ovirt.org. diff --git a/plugins/kimchi/docs/kimchi-guest.png b/plugins/kimchi/docs/kimchi-guest.png deleted file mode 100644 index 2ec8fea930b71c0e03a40700d79c4bbb63bf54e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192281 zcmX_H1ymftwj_bz?yd>$?gV#t3&Gvpli=>|PJ+7ym&M%|cXwapFM03%;c$Rucc!QN zcHLWbYr>QiB$43p;UOR(kff!=R3IQA*&rZ3mcc@UU+F)bp$GqfHj<STgLr%Y%55)6 z0KWp~Af@dL0fB(={`~<WJrfuFB8-c)yg1A%93~nE6l}>L_!S5|7jZ2YQF~ikQ#%(3 zQ72PF7gG~bcS{!wQb}ofCC#76I1mt|5Yl48Y97lctL~X<bE|;Mi5Ao0aqOe%I7)c( zd{WM8x&i#K)IRhAX`k}27-_kyLW^`tt9Ys~mj2IAVn*x(iwJI*g=M8bq|WI_?pD)U zPBZsomhjwCJ|zcHZ=Jt*ePQLhUvu6cKN){qo0+}Z9f{iaWar>eR#yIb4uTT?F^^9c zh$;e07Why~Q&er6k)KZ<KlFLXBwmX?I6<LAx?~3Y?l_quZqP~Ht`*#W-h3xL!GDb? zLz7P}GM38H>yZsutTCoxVEBS48p-06^q&)=f->bOd&{-!AgXC;X<>i;FkzKOg+e#^ z-+#-+$bYJYr>Em*GD|r>9VQH!OfNPvXiCCf4&`Ddt9)noVp{7}P7Y#)ULB9h%Mxg^ z*F%q3`7)LI{5XAA({0ha=JUyR<Zwq>DOu#hN$-LdELq<gi{<p^*UK3Hjlj51xb!3O z8hB)VuL<h(1PiV;a#HgsAA+`97n46Nn;*Ag(Z7C2I*YxGBuEuGcg$B#txguNThH$R zDh&{^|43cU&zGl&Fvw9<|HBj#g)8AGcj^b%C_3s05fJ9{JjwpXFR?QA!hph`W6|`M zOh-RrKKJWW`87RsG=DsqK4kJ(+5~jg_rbwlJf)-S?s89?S{ZJO9Sbk))3ryw8mMS1 zqF<5Gq514|`|U%#>t>UKHHg%82cw#Cnr(6SDV6!%DAI{UU53Wc+rwg<BCs{<(>lhH z-5;0-q+-!TPBhaw88(ATifdS02@Rf}wNzT;coYRkfMr}51TN%~uDWA0Z$7{BuO*rN zl)|Z(dpm#1<OS&L30~t`BMZie2H*BJsBQAdF0g@WU_49CFA;J16BFCoLbz=7`4cSJ z)+lXlo}xQrospR+SUHhoi8s$uIDaWPK8xcp|FQPD*U7+KY@FD_$^NbrHBvGRVEr31 z0jd%N9Q$dGAG&h~w3=w&OtX!;K`Ze)U<yQ>Ap6-<+W?H$*5CRv@eu%4$gC1m)`K47 zg3h=R+5VaP#~7KbAP4AVZD7M6>i%&^g~_hxl((UJPhF|o!;#!PQ$k+KrUailIPhwY zS*F<pq8j<5dCJ>pcLsClOJG>$h|iGhE-kF}3vH;bxZG_fN`yEa*X$dUqpZi={rzgp z3~dAGZdAXP&wqACBWr)0W;zo_Lkm=<dfmhSRjk8VVIbMwXvxmD<aEGuQ-7R#zd|^# zu7g{Z=z@Fd$Hi=X@%OX2@4nl(axgU_oJfEv-(q8wh%us;!kOb)!%=ioF0Q<4KkvMT zR&x-uao#X8<#7o&sLkD>l2y#`D{h0W{1lWR_ahO|yXu8~?wBj?%!{9E)qz-FJ(L7W zsx1;#<fQXzWRTm5CJ+_GP*fcWI9ht!+bmh9;Jjk*@Oz|5gtpWe_e%y5dqwZ?2yJ*L zcwL-1zipjQjOJTBr`_oDWd*5=6S|ILA`gvkZCWB+4hK7*nWi||ypfYvMc<osbX`|< z4i!s8>CWcRXzGt|>dRHi*&|fFY;%q3HUIQj7kwBNSLH5uC%X5$HvbE}=dNr!`3Rk; zmF2Hp^Z8btq}s+enAMEApod)fBo-VkT@U5@+*#(?-cfU|g2SiXn^f7|cmNUwpBK^R z3od77IGiGidgU8jH$=^EuDo^rer!zht(k89?%d`cKx$JReNEsv>vmP=?$T})E(WU7 z=*4A;!&za$A)2+2T#$m|IH<?pu_rWML@Df-3~}cv@;57~i{Eq|V`(s)R~IPu+pe8~ zXuZ(2m#d!^F*=9t#}9|M7IO9vQ}$I4@r?RkQa$ENcn&AgzdfxI{rzSjS0j*+<KxWh zJK!5;Ewq~TX+mHqqHe8#x0>dRB{E^0Cj_o{#ACmu^P;Ohitsjx;PIx5_w_QQ&6A4% zm-QRS8Bu{2PFMtX>Vq=oC2;*USvrA|#c5}7wL^LzB*<nyZZerGjEKh?2u8f)s?PC? z&0aiq3#E`4s?|~Ol72CU*xi^P+c!`&r53nRV{E-Jk!etb)ryv_Ee*|24Vs4rMyaZ) z$eBIjKN0z}uKh}*_u2E)K;}(XRS<~wWHY}!xjuK^NkK6l`-S7VRn(%@tFV>t2nkzu ze1JX?b*nU-Z}<q0ACuFy)ZTWv6(Q?!+MX17qOCx#E~ZQ#U9@;+Us+4I;zL58@1_%x z9uSTkij+3^^SJo38^(UK%0MjkU;?c`V9kRkKsc__BSMnIGduXFB-?KJ<}6dzc)ewe zk^6afNeBr5rxN$4I0IWw#&~)#y>Bp)NZ6+ulla1YbZa|pD`lr+zi$J%6yoQiihFec zS1RFTr0eY67Eh)Nor#~B?s5id5tp=&`V6aGZT9@~b0EjAe4oL%NTJUX^l63Ea;SB} z1mgT@pOeEZ;KO-Ndm^Oos7<%G79Q_suBnCmSXCulO&?FpQ|~T150~%Zqq(hF33B|x zQGTJxy^d}s-k%J_A1Ypt638BK-sz1K{Ym9|QP1|=AnCJzz{gPF$>Fd*H-4RoF(iuJ zdl`io@7yAUraJ8Npa3U74+lb+A~nAClwf8=J|Du7TBnLTnW=VfcW^Rnv^~Fb>|y?l zC~7vAE>4+{S6ds;pxZcEWzgB<dHU?VCY6dN;)8BSRCGxn5<du8Fe$;MIia5S$4<^! z0~WHC$eYtVJ9gvp_Pn++Kf7i>a|rGXRIYVHsm`HZ_(D&>S(!g|-u<|rHLfh6M_v)e zE{4ZU*+b;QZJx>fQ>~HjT+TnF^@)D7QP8}iE%(E)lXR6wqL4r%Jb(jgsP}O?MWJw3 zj6nzPit4v=jUb`t^Vc(9JACVWcKw))9^o*5wq6Js<<31@PLmPt&C<(AffI=7U9^bx z^x^oT3?BEJ%}CyIs&hsE%;8|(aO9Ry1O+?=xrOtM=g~&%*(=XoBbbcT#}m2qU!jB6 zJvEqVM=~F0aGKO{S;q`1$HLv$H(rziu#BN#*j{6aE1Im=<gr{0M=#ACMt{<{r0!<z zua^k(R6n>9>zZwv9#ylt(rYD{u8_efXZ!r>cjJMH!WU077@Eo8+z@Z)z8u}g)7|PF zm@8jzO$~}@bXuW#;W<7DqwhTbvgWmJx>J+07y8;C$ZGfl)kp}L6<paAwYGY-?YFuf z55!3lFXfTuCmP)z&6Vr7VHaTvc-?%T`=efN&`At%<i1-p<|DKKuP9ZP3%dQ^OX!hg zhTcY71^!F1r@K>G%+pp-Qy{ot@RKL#5);#p*(uGxPrdH8d406uVtkp^3fHfz049=g zy%x0eWK&0AK;z45e?=>T6Wy?MVvEPC=fq`~;8~<3hb855|3RxZu>G6+AXI99AQV@$ zO!(BcH<AUK$a8jKVZSGGsN%6m7wJ3Kfvv0Wa0np)0wkzm0&;%s`zB_8Ac7Fif?t5y z$Py?lRoY#PDM3(=ywvOgt=P#NQv7OunH7OTm5da+GS9$NAv53NOtUhfifq=)e&%b$ zShE(ub2+L?tq;QV_pfO6q?bQFPkhGBo}}4-X8JZH9g?`aRzMm+GT-De)2L51QWHi+ z^s5VC0ck;g%Dk~5imOG~`+ZVa%<>%9Z!(aQYs?KdFi?5c=ath96CFyKtiviH<0CI{ zHZ-J1WZRVBk|L^L$6E=uCdZG;D#{kfJ$^?aM?bP$ae2+qL`Orjbk?#eprEXbmL>;1 zGJLBLnqRt#U6>V&M;5sFwnN*Mr#_CSsjqld<-awj9mA%s?Q^Co`ThLhym0)~TBkwE z2Gm=g3Dxe6QoNW37@09s^}2!RS=I@MCK6kJX#CN4hS(kBqXJ_vFk!duhAw{_b&&PU zqUd_uYY2$!o|9xH&-1KO(p@M-#+4_zcU=3{94g%Zp+R=PW?Yu#X=5$*kGtoU!9?v8 zQO_e4vdKv8u2vZ9(_K_kix(e{|0m(r59?YtN1UOMpp@FHF~mQfca4ppbZi_hpqip@ zfYocBIQ_g6ooE{$ZG_!Ru<9@(Yt6Sv+&PqAl=DpbvJ0#!^QujFYJXD&1wiOc>*i0# z=kfT(p60h+>2f%f(FYQ0b-zkV+QV>;CpKX?S^T@@unE}%w?kZ$mL|Yyqlg)i=josT z;b)%hq@|6`iPDcr9X6XqW{GG*xGuV?zdeI-6o+$VI1snDw?w=OubJ3P-{eF^A$x<7 z3V#0%`y!hRF<GLRvr52L(7-qfOA0<EBvG)*jC|oL;!<v80^{GrgFKMuVMEAc=Q0DK zD}=`(yT<jXk@7);G*=uFhlI5clPvEkh6H|vXzddFAvI}_;X!Ibs@nPW@JY$TO9njE zS_Z<aHLR}@+PBuQ`h5(`0L~Twp3ql}&5{|DTH?5Qi`A!?_VIb;l-0Awna1buKaqWF z57|3#^0Lqevb<O%%VOmyMNv(pxIRHCOVt9j#`#LZOALInIvM@2PFN+fJg^fa?ur~= zg*?kt5@>aL6YgK(MD0HQ7^&h;Bh4Voa=a*5A!;Q}pgaY@)eq!evRSgaC6mHBKod{= zrkKC#;hVVL|HFZJj2&lb)pMPpn{>5KBV&jsA1j}rU=G)_r#&ghXoK%knHkw_Z+Cme zW;v})saZKLKc^>n!aXin5w~9=)W!5IVl!Xr7Ps46B1XInR%k|S8DVl6RU1x%$QM2; zO0Y`djiA$W>C2oeDaM3QjBzU`%YGPDS`+U^-&^aCI+)qG)eF9CzXzJ(DiA*mj;>g| z1$Zg)f`fyz1lOl7VuwryO;~Y_rHWJ@Iu!NwSM5k7t>ww%zV8gi-JGowOk6vpn~$AH z$tu5kOT4_C`*ZE*_zQNNkF?PTF8Wg^>5^guL_4ikmOsl}<0jU2TQH|f5hR)#(j*<H z7iTo7=N6RqcK}JOfh2RVqRwdpsFv-ggpri2^@2GH?Vk}wRDzuCZZl1dcPDVF=`-fJ z08YEpfAxV(%oQBTw)>Sa(UZYM{G4M3tnecmE#vNE6(Zq!DeZUIq^oZ9?W?@3e6*U! z7P{H0@FT-X3r8GS<3;_Tg!OOQ6;(fnqHI-?dsO~B>UB5XpZKDQgev}tk4LXvT9L0D zcOWd8EX_~saU{&AK2oBPrN`c$k|gOLy0=YWVG{{`31@*CgM?MT{u80>EG|SvuNIH> zy(hNxVi7gC;vNY|TxKfH_vU<M`bY1}a=qWmkq_@}yoghXQoTSR9ArK=AUePLcKvp5 zK^n6jc$J$-KI)IhVV~ijDP(pG2&P_~&!fLjxSL?mv{8b^v&~ua<N>ZtNHw)@r!bA6 zLfckWu!z;)6aPe(FSEvi^1kZ;(@QFK@aho1oZ8_1iezb<YmT2_V*T&~bqgcbdQ?F) zW@%`<5p;H-RpD>9Oi$hN^5adwN1RWudivxcEUS?h*ZA%LKNUF>SUFx$u;69BU}z3H zIeNGfpbkX!e&o9orPk~LQvom+N8K{U%cpO_{P(*^XiS0P=<Mj@hsq@z?Dc!TdfXUP z5XMNYgMNw_xw6(L?r?ISb-?xC6_0oUi@Y(Em56?$zU@o5690cEh-ID$BgGI$!@|N+ zQ&(43QJFr=7Zy30=wapxvS&>zH0bo>juy4GWjLO%po7X3fFo7LL=#8L-e+;x_}c1n zNDlcY=zUa%X7;6(m1e80u7s|$%8ALzoQiF<SPYj#c@2~aL(Jymgf_rp@B1@)gO1F# zcJCQ*@ni#Bqx<<ATrQc8B(s=};u--p#QrxXya8NJyOlw3r3@AhlEg*&sWiYLKU=Ci zn#G5+;5wy~AX7AGR_9$22@V*rfB@bi=w|QQK}}UKUeM`cDsy2$%~x$VJI7k;&$A?J zCzb=a(}(Qf;aPKNP{MxXv|kg`*2Y6ZLV^<hnj`32`ulet7!=7wgKMqkXop8eXc!rj z6(b%NBl1Hl_1mUrXT^B480!a4tjZ&8cjvDsgWYh%Y;L{3X|++rA~1rl9O_FpO1)wd zA82bhSRqouX6?CUKf(6>N}MngamkgF#YSH+0Fa#>!1hXB$=!&fe6tCKZ;U96im8G3 zDHO2%d~ERc89RavJP-3#29n0c6sD&7TAh9Z8C>>eleyi0L1%o0Gx9!rY^uD>;}V;c z=!<!hoF_gbF|~x~jxbCaw$Azt=;ClLoKZ|jviS*Hm)wT9=)r~|zYx1listC`v_}>p z+noAh8Qb)}v=@}!!@r9)&mp~$<k%xuD;4XTRrVEt2zJAPt@;dmv-<7HDP=0&()}XI zY*L;xgiHsA6#cbT+p3S)P{L*K@!Q;s$x-{>Z7V{szch{y7aPaG#AaaC{Vk3Z7MJ@1 zB2mSn0*~u#ut!c2M~^uOX#a+1h}(#(nj2aYuCzp1i$={Sq1+=5!yyN{C8FoOV(s8< zq!KpQ$w?HSDdu^8B8h0(SROgp77NM&WQ{%Vh38D~C%2`ouyrlea>gF`G%x7j_))oG zTVP(qEO4>x?!>Ktdb}fvbQ)&}(2`B1!8JE{M|Pl_eWj6KZRNP>I3hk1BokNtu7sN} zirnQS@=>Tu3!X@vdSt-WriYYt8rqbnxl;asLrLEpm&b>?UDg<vXcLBP04z-O*I+5* zey4{4sNfQzTLo<|LUjPn{oV)^gly4!gOMd^f>?r6zIn!dk;T4jIJWP*b|bd9ni=1t zvyF<1dOp(ZT-w$8X~Q|P&~djO6i%Ymw>|g#bfWtE`RsaycieE~S?Ds&zH>C_4Fp3; z?2c|K5Dwc=tXj8%FN#_GyS$uolHn|!KpwT2`)FogSq~G{<?cbGCz2)5P%E|aF9mDI z00PAy{Ac9VuEjeL`THKYL<>pd=fkEVj=|9WdLg*p`G6hWc0XbBG8FZ9))W`=g<g~@ zyEjZ=;i3)n&B&Tl3;=STLNXwKebDFcH2LCe-x=^!Wiaxi#ee6%$_AoH8ab`6sgpO% z)c=j=?TYfM?k&CRSLa(|$u!_{l_^JN+6~vGi}ah%;ipJtL?YHi9%u6!k4x`J!JBI2 z3cMLNq$oAo{@oP+pWf%~IWDc1A)x+kN4vJu5<TDBhR^6>K7V`N^z`VA=E~jxO>ciw znVw$-1^si4PHS0*(UJ2sM~1O7U<(kjI0SuzV~VR9(%jb!Vpd<iM&r)Kq(aMb)LgZT zm#?LF)13Aih7iO4C}Jzu{`({8R{jQ;JzNy|;1>(0zE=`P({2FWog8kkMMV?BW6(N| ztycRNd0S(~ztrp*O`ND+#LjE$GPstlNdtH*ZMbD)<v$*OPyPe9*O`-{1gdqXi*A_n z!mB)o%-DV={@xJ;oH~o~GJY;=ieBW?eh?GG_pUVatqHH>q+X`ol=Wx+ZP2{a{um0& z)c~;NG(Ccck~1eq(6sqzU?Nt(Hqp7`o^HH4dkfg9H$LaS+V5}RfT>FYE>K&|omS0} zO>aBj22@8<uGV1seRiKB4icEDO{Y57AsX#gd-D6wmDTn8VMzW?9EbuOPFOJ9JYm34 zpUj{;APhsKc0gO)Q0)KqdULYmTmm96K3J-wT5Y?xAYLqY$fUm}e#JQt6hy$W+3l(F zPpAv&gL6qv@xPbNW+3i$9P0Pkw{};VYY<YH(>rTB|H5frms{q!S#__<v!zP7O0u^K zVmtFNr4tyoq2=P5zVGVB^gMpJUoVMcJPiXr2)_9_@UF)21VPHuJ&bAE<sZ#P;OU~H z4Mo{crSaiL_pY=!zZa%UHpzCYt+w}kN^={Ror;x4&H+Z^;>jNb!nIYWzD_X0VOJ^E zdFZF(>{sjtPPK=&R4f!L%hY&Yo4w;R4NcsCaJQYr$R?vmHpQ*pbl^L={A10&)8!`I zba7(#kj-XGC}x4gy{KueN!daTXI*rVP-{5VhrcrOl;OXxk;%i^{ZM1qF0eTSV)i!d zf+G+61C3j+XM5xy5&(|<rWB8}nk1W%x+J@?jL=n{B8A{M#!DFAssWG~-X5tFx=cz% z<NM2nEQAlmq*?whK!Bp18+W7Ks-Vi=-XicD=p*ZYh#RQEa-)|RRrw*G(oMm0{7gfr zqap8ghs93xY%A#R#IrqJ<$OFs(Cp>#snfssC)4YzcjoL^4+?oTVfqp2oIS3&e0C3+ zKEKTTw=vxaEAHP-K^amTw6TN~cVd2{awCpx43B<dyaX!hIeBDRpf89N^5kb*yqt}v z)qd6#hPZ~2b*o4ahh~)TNeV?Yq%94vg62>tGmau$3I-dQPFJlIOT)QZ`4T-m!MOR! z-@mIypOBmgEg0=v@4yP?xQ=nk9hGutx|M-4_DHRtDWpDh(x#cl6;OzNquM#f^fBPR z#^`1a(LqGc`4bIs%yrsO&Ta!<mBUsaMqYq$@$TXepHFny5tsgN?o95hx8Bo-Hwvoj z&JzN?U`z<};Lk>IlL&C+-aTTfJBnMs8r?W|+zTbfMZ|<w6Qxy`p@r7zKU7KYI!o^n z3pbIDtnQ((Dlg>ai4`v5RL0%?rs%i6#j4^MG|xF?l)_AqpAl1~n@A>RzSH(A$go)- zNA5>_VgCoyVDU1p{6w-e+O6t17*^*yk@7(bcn+$_1L+lYV8c-(VFJZFcGf5crcI7) zg^am7vizXD;AcmD68uT2Id$fQo04+{@BiGt>f>NxkZA+?Z9Pnnd7kn{Ab$`*>?N2( z?8N5Z4DuUDwl!J~7HxS>C;scTPDGE-8)V>XOJ4Q5=l{^@-_aeFL!daltRY=%8!@9O zVBEA&ZK1mf-y0i-5km#rlXX_oV0LrRyR1*t4iHXw81AyNdsv!~UVk8B6lkrtO>zW< zSOFo+fT+P<idRR|UL8Ij?$aC%fi*jKZL(QPC#H`qY<%#9;&377-&pa1wMy{gFKZ(= zN7@qd`srL}ydk8sfpKKVL8pHF?i`}&@1<K`2&Ngh5HarISl^B9aQr*@V@m91tH<6a zs?srI)8HBYTPOEVmV+*%n@<ZDQT^vNPO=y-$KpAL`Zf9)b&PMUMW*RW?&enuZy|=~ z^aYgMKM4FCaA8s`lA{D-&Jl5=F|_2GAE1Z19<@$qLwM_O4ZPiRGSbtX>WWTx9Atj) zrA_NJisIEqA+bL(Z!||V_clJ9Dca>el?mk<Y{VfU4Fnd>XkVcX+gtTnXLHMd<k`(W z{+c!PIW5Czd2wIgLl_u1^}~I8iDH_R-M^b_>4B}4H_0%M9pU8MBH-o!(um3j@?D&o z9Ub_}OMvYMgE`qC3kNUmo1j>o;F{=Wp3MGU3xx{g6)R*}jq{!J`>e0q8x)>{_-`gf z^_+&j^ck^0fQ2EUhgbKOtKqW4)e^3O)ShM5WYfGvaa?F9;jWzXM+!}!L%JZ}Zg3(Q zkdGw*mBaCq7z3*1LmTz=iY_6e2%MF_?s(%;MH~MN<M%m5cdzK_FuZ1;uSty%pY>Yr z64hnVBltKW*}ugdZze|d1s%?={Z=EI_lVlc$_kgqX@^l)`OL?GjEQNntFQptVLPZG z>}Gr+EltQ@P?FFQ3K9l6@xO@32;OZE+cD>Bv!f)Mr>it~{4pa{59t1{BP2YxvoqSw z7q*Rd6+6?iOxq0$#dRh_MjdZ2x(}Bz_M4e?6aB8M$#|$#*%sQqy$t-(amTS{7!kI| z>1Kc};9cW3L$T)g>2V`(8z-pM@hWD;Lr<{XXyWWUd&pguJjCSuo1PQ5(8HEikJ9$1 zDMtVGWotOBcdD`o6l5_hK261|;COku-479Zh7(3*HtZ2gtQ|CC({o$eU2GIpRi$uW zd!+MOKUZ7eB)e08WS*Jo+613RR1Ub#^S(^5aBSYcx8}d$hUJ$sCuooC*Dcv>uFK2I zU(uj}cF)B|CLaB_pnpOA>s&sUXoElqYBI{Is-pbF=NGN4U}{r8kBH0sBZ`1aMMvj} zgr=arzTT78`CkaU5mFg!uK)GCR#?z|<Sr{OHyKT3nI0yGYWeVlL8V}Fce2!6IZ`a2 zad$@qB_ktKT2b*OVQBCZ4)_MeLR{(*d}x!524l&9J(1hoe{c6P%Ju8asx+;Z6<SSy z5LMna7l<?8SGUP@h?~t5*bkP7!5UZ7BLEyrfB$(x!KTn3d%r=51=mYok|Gn{<*ZL> z0g{oq)=hS8D~-EPF$x{EZ?Dru^m@$>6ScC=T0@#fE|^#vWfP`YLAKgssw8Env;vQ( zI(9KCL9UES@MWGtzsdh~WkY=h2f2}}I-Y3Fvs|$o8XEXIJm28J-3bbb=tBGTj<yv} z><FwYk-UthXy_q#O7-2h1*a#?py5>{HzFJ0_$SOF_%UgQk}z8u5}$HTGO75AcjyRw z;4ZBw6D0^Bfl>)sl}-&?Hu>peEGfuU53sb~7C>VCM-~k+jYLG%FgDdK60Mba>tWkw z?c6~kbPAY1p-t%$x4$oOx?MXzD%F+j)4tz7I8?YyYqjUgwPoeyk-(JAc%$pXXN)lY zkTikA?Q9gvcVa_E$sB0SahXo;71Ul$BSPi-yk$jBXVXwI@SVf7<`}=4RWOYDBY;xw zGi-PQ)T)eQx*`{eRiRMFe=d;Hpx3N#&A_$oo@?4J7*4KHsVD9#kCbd$Q&bxdrZA2d z!W9D}_3&)oIvyQmS{+IKV$jL7tsIGLiJLcOsMykf7C5ROyWC4n^bK{D`jV@P3R|PI z<HTFSrXVAlr`flZP1S4i*oAj5ek#RV&CSVujQV$BRFGmS+^<|z6H=~|!s143Ay}z1 z>d_PFGC99>5qB2E@pRl>q;|YrLWy$+(s1smz{KC&Ln(A=|MLPEYV+vg&+jRWqeyq$ z3ciSpS;%lFa=)l$8qpJC5(o1V)z%b;HDOnp%(E0+7;$PukW&1Vc-IU>PL7jYe%GDx zDt@)gXR2^5;~;OCKOJ{ip&fN;JS<a>Wx+37%hwbq8K8>Z`(Z)-A=s<d0#RSlNy|Vl z#HzYlBxlE477xoxLE&yIR*PjdNq!iGH0zU5t{x&|uX?;_EmmO<Hxo7xsK`tz@Akfk zs753+jTve5TOG%fO?;W{j=9hDCIh&L!PDWa68(~FJv>k%85Ofiyo_PI&B1d;vcFer zu>iGU6~IBMZHJq{ZOfz8gp_a$t>k?30>Gd=5@Gd*fZ8%-5^1y%1X)PZ{jO_Ubl0`> z>QbTWe{XR=$*qO44VKNjAS12&dkFRm>kDoge;}hF&YvD$86gtmsjen%gNA4q{dDF? zhk{VM2JJ2L%$@`q9IE1}!l}4{KJpb|76k&9FvYi1o~<PrQt~5#&?e|xv5GRL`aU0Y z>^<u?%9#H|{)5`|{eYM*x*0F38SjjK*=fdhAfxYrYzq*fjRt!E;qMek{itz%(~~$& zE|@tyw-F6=(5szYU+p5c(U4ZGZC%VcUw4vTms)K_r;wW_R4Zg({t6*<y!l8hjOy|f z0RG^i3;u$uG-X0i8d^Se&ozJT5`FYGSQAy20sm9S8a)gudfUfhb=haVq_Hu%!xyv# z5*$c9HFLCh{Pxfha}EMaH~hpY#d80^Ehg554cIO>b;vxkq&7=CitA8;D^Q;OxqzJ2 zm-Vmf2EUb+^@Tu=3vZS#Dpj~cYqF9qA;6?AsGm(2I_;S>M{~_HVJQp>KInej%%Vo# zd?8&~Mp;{Xs3_%I_&MnB<p9B0-5+7Fa-m~AE(o%bk(GT<O(Q8xC8edIstP<oJkEPy zHB&GV#mJ9k<^v@3#Yx@7Rf*6`7z~MzL&&)@ZZJDLyTh!qB>3*iG^>(p#Qwz*$u&HP zYIoU1qNFXYfv{}a$pA~WFq2%ZJ%2Beq1;+Wo-@Jv5G)2kjnU=c14Yd1f{el37?wR~ z+X^x{pA4}kiF{Znhe`IgNa<phOq)u0aWN%0-<{W)j$kL#Ym2C>V}VyFI2gL)X|Bp? z)pdczevN<4V;iZ5d8atTZfnJPV)qqvzCYprdM$Y+Jgc+Kt&k`F=hXV+!CE`t{faXR zc(8j%WmS|JW5Z1U_IaP6igb$Ck|3&?4$^}?o=GCP+=GYPS6oX@WF5(ubZBy+1y{Ot zbvhD}9%dWYzdmewoBTc~WxtbC*F&vEcbZL%#UB(b?c(G|80*JR6lA44!W6CLaf25d z<x!z#=jK@ao;@nt&UnGf*TYndpBSciVq)S2IG?|(a@dS|p~tOI!WVg+HGBkAiJizb zT9GN=yxt{$%*wFm>3?|O!+s~hRd;t305VQp+O{(z;`u7*vZJef1=30mGS&82HkZvA z6H5}*O{cxAC8lJB5>{FiT(2m%ZL!_o)Ub=xn&`MuA`VzZT<xL7@1gw@U^Sm!sg|xn zj^yUdyp+Y&bV^&m!NGxvgL6G%@EQ+x@^n0o*`tdq=gBUCZ9g8T4GYvXG~JE1KI>Eo zL%9u<*bxo*W$`ja@C?-8cF_8L%|E*ldYD)liera5ZNd;{PqwM{XLPvm@Nk{>8Xaq} zo(E23fre82#8hc=Tdj7R>GQL*7q?aZS<}-hdJ7Ct;_q<}dpV^x&8KR(prfjxG0=}= zFe;9tulDd*<^N)x?S00BkB@&>cFE;kVQOanGuJkDN@oU>$Ac_!fXtLY&O(dV1r5L` zKn!pW%}2$sT~D7`8)~xgRFc_+UXx6}rG;JvG5bwANWestMt|?0*V$7yO-&*Cfg{G< z*slA#VYd;i0f9>fgV!q@ubYGJ7{8kWk)}H8aH*1+LKT|IjwdVdat&tkID-Qikwh>v z41>yPLEoLlYL=Q(F7?NJI)K<aax8<ZAknBN5H6B{3wh!?mBknu9CDO#Qs04YWSMGe zYRpbMQsB3LoyZno833ykB-JKE=vLO&2>XYg#D=&|<2?J!CWEN&>cGw6%q4$}7`ZTR z@I%K0SH~ri*=TBazIeplF%;ALbk%f1=ZcYcH+9@HL<_w>XiWH?S{oSO985iLzz7}O zJY2r;j-DKSePk{u2wkQg`Xh%En)1DbA{cOdXjt-FMw8|KhU=iE66Z5!90~RvaOn~l zoSwW2nAfz~ML9(G^VsPoG{a^q)l@`YZcXYS;JUEbRU&6<f1%Ceo4k@=(7}NE(D~5M zge&01?!NBJ1@7U3ODxRR_#i{6s&DPh&sQU!J8_b!eC~`o)&r4vy<qr(?@H4ACM_=h z30wp3gws`S<VP@WJsnq>uQWTFu;L+eZ$L11K0DcUJeuu|XCWxTvI>E1U|_R=kSthL z2KRY`lGDK9a18Fg;#A5yI<hDVKAPkm>ypQ9th%r7mKnTQ8IFQYacC)ePH-LPbuNd~ zJrn<wp}vqRTduljd=4v2aD8ZV-?AOe7yXWPmNUht4#~i`L2EeQdMAgI_I2|51v9o| z>L5deb}2++*}p!xmP{t{r%q3;_FGmto@UtFPlV#iw&6PZbpR%r4-Ip3&vyac&o&Of zvcrCCzO*Wx*cA`UUk~fx$fhaCn>ZX6r8r#;QL%a7*${hdd@!ofGUQhTDt!XSM4ql@ z3Zs7W-LiGdUb?kbqYYjHmEzu?vdS%ce-Ht<R$g(Lk+)f{4}(PEk2QFETF~=8ZJ^hx z{=tk0794k|gdX8E^&CGTVAF4a=}=*1CGwB_{QMphI8SgKr?l*6dwU$@g~0a4X4rS6 zVJPy)(Wn+PyB?`UvIJe%(<1;Ib=#5uZM~XvwgJp!7)wQZY~zcKZi@<`zs$z;64|#{ z&<k?=k340ecX8NxtKZBiJF{4z%L++qx-po)wAa){^@Yni;A<M=bAp=<b#!LAq5;v3 zQB{Wr&6&x<`LQNZhL^Qia_3VC*GAS3L@6BtBixd<M$$9Xf2@uWfNq6BaJh;(f|=fD zEnxfM!Bhbrw*x7O&&7utEqbnForo|v9q968Kqu&|O}oJgOBs^|JbK2~1M=bF;pXdc zKJ6wuA{}dNdaW*s82+9hoNrPKmHOIXHJ(Bu^80WiO}SRhFI~HqB4!}LS5;MvuVu_v zJqSz};0#e$eKvO5v_39PmDR@rAnXl55e(h;JRN7HGXB?}AQNo;KHW&X6zA(U7hYF) ziyajW`wJFW6WRk?V57Itt&&^tgLxMBt2SqJ0?6|^`+)g#sFSI^_gd~ttT2`Ss5D*5 z<!D*NMLBLwbMIO>d)BFRJ#cljQNX?$gGS0ta*1((T4m_-7v;z&UU0iLt>?-bP>(2_ z<@<90H<Z1O6H1PLI*|%#*bz@<ez3X{ZO#?>pnB4(wxCw0v6ef!x2&pTIR1<5!<l>M z2ol#ymps?%tQA9A<3iDC&AJ~5jMji_evJwpb=<aEu;HaA_jO=E0$i#?c7>u*Xo2UF zD%0WPmoHzyNmF2Ue%>gOMovBp#ff1=r`5&MP<etnT&w!~2Z-Nl;b85r2E0q$dLv!f zF#d4~3zx=>C9nzgeWG7L_v>dZF1%x-X>3gyYIG9}BttkQk;Z$@BRqT0Y`D9XTND1C zKkm6Wr*9|gT6SgtQ%$qguN9gP3!Px!qs)dDJcjrU$s3-a`v97YEOdG5Eny5lM?i&k z23byfS_FzC4W0u{6Eb&3wI8MX^NztRZ%sS81#bo#@9L&Jjri!iSSdCWsaQyhI7<L2 zDPnI=YSg$|sjdRIQfa1fX{mL7EsY2PB(;j8Xbw3F(2;j`cAhoUX6<j<J781g_{5jw z_@!TN1DuyFOHMT|hC><~8FX!RC3O_UD-!en{w4e|SElKHfZu?`Wn1#i4)}+%g7sgy z0}5WPNT|?liUtR7$?E=D`~9~y-}_afaWk`&o4rA{%FX-E)=-DF0y$qNXslaHbmNZU z*>(R2$bh21oYovL25tnMPfO}Is)Cd^)HxTnXKgRCi5eYakz8~<d)99wimxD_)|TK3 z=bZ0*UO7>+Ya4MP#2Yy=6D32--VAJ6yE}B<Z36R9;y7htx5}Xb!ZcDK<YWS>jIn&6 zW!Taxmm{#14c}NtZu10G=o`iP9WvTfm2e`;G|Xi&Zzn@Y15=!xlha5WyJ_8z4-ASs z??4O&YBdcFqo%Yk746vNL=C@A%F8rIPz<D{r466<?s`_vk{jxB{zFw`DEnMoXwZxi z-~BmzqiJ&4{Ana_4}f>pK0GY*j^doQ%VM6MJmB;XT=2{|9(DWp?Q#76VVhtMa|wFl zxMyy?GxGZxO3P)k<lq42#CZA66ri(*MpCfHz#ztX>Me7kmdb8p@69)9Qh8J_ac^@y z3veK5uz8DhUh`+!d}9ymZ^L)NjwAw6g@}a|sn1fB38(V{*S(*?+9mSw3&}Dsn+#24 z?SU2T?@7TpPA!=!Tx}b;HdJvkVO-n$k8bx-O!cE$Xv5UZ@Jie=1(DF05;Td(HMTIo z+E5Gs)%2_(_ka--*5{iNq1}C<Hy)wqO%$-QL<dCj;zK|_Z4bU{bR`VwkHEnQCIgW8 z^T!Cia#tQV!n51X+>Q54jgKq;rx)BOiDSm=<!nGB?&~X%qVI;c{xshN@s40T+mUS5 z^bw@6%{%e3sl2YV5dI+GdNVjZfsF(eBVRXz={#*+gPRM$UZ&rMa)huWuk2Y~R0`9| zO1Jn-HmzZ=FJ8t;H(RM^f_3Kfq}G7YrSO|#ywMS#=$`_uUE%P|e8^TZG?WUNgE9Wk z+e955@2P?R`J&g`6*jQ0ZuntbEBO-=0UjZPp|S%a90KdIAyL2q0aFjkk*=%%@~UUG zu0|ij2)SI5BY`aQz~m0*Hf3$!FIqL+t^RGB8kmm+d}?76If}sAL>0Ll!7MOTyxX_m z^Y~c@=uG2-u_gm4A3V41+i5G~_5Or8SSZN!dpgu}Uv*vaI<6?3v5aI%OiG$6kc`P9 zHkOQtIy;H}@gM5u&?_f-3_Ns62V-~;0@L5>>ecr`D4Kf<mJrZ=@2eniJ1f$Di(v5Z z5fU141029$3R5c1^A!`7Lx_3cd;O4U+};4DF$AQ{&%AbC8)r957F~xCUKek!`5ezZ zJg{Kbd|cV4V_TKDrMv!w&D8O*g&Y!i(%@>wD?=lW`H-l|Kau<)Kr4rV60c56c_C=p zE(A?>f;6(ReX;R_k$X>MSguWMz#9CwpnO3GkMT&VC2>_kgjD7AoTdev?t@TfM0cKp z_EUDZWYY%xoa>a%=O8!?N{4<dO=jOG7ci?)SrjB0q#v>3Kyq4(js`k;?LW_sgJ}-9 z006#Yv!3gm`g?k$*RF*EIO6iUP;;$$P=LuA6CvB%`m?pQw*rIze60-}+kZgGFZI$l z$2dm7t?g-bh$`o=z5xGuAcjKMy>I-`&Yh`M04H=%kConVS=q)fX)5KX^N>O6AmBN_ z!nuAwq%|k{obBc<1B-+_e|+B!4xCcqlbnf<50av~8duC4r`E89B--+F$9|Hj_Gmgs zL<D1NC=9VjZtRE3zgIHgG^|vbb5?$~e#l(M7goBPpNy1|?5y+HE2o$}5v=oR2z_mt zH`TBxDUqYR59%A^WrIc9QWni&{X8|M9s2M<*Pf<6;>AEMEw-%!T1?Aqi6+Jq*dc>M zNwhe(l?hHoNCccp>gsbxA9a%Z!97aA%l-Pq&QL<j!&XGgX(JH);KTCra?eA$7QF;2 zlu6x^Mjly`47eT?CXcgF&wl4xUqwYlH=pT8jKF@vO!qa<chxx4V=F9@SRnoA$O^0& zf<M_@Da)Tt5Ry1#qNCplrYPV>o{k4tbBdFr95SmboH<m83PS%k-EV2kb!9AU3=4=S zr9NLRfMcVzHn}b05;S^E@tyu}F><dn{?|a@u&1AAq%^p(nyz`a71WZ%&AIZ{3*&il z_qI9jfO_3{x3NN3d@)YZbaD5GH?l?>v<Hv;c*CPtEvR663ttRQBju(|=}=#3`rlLj z7Eb5jJ5PD%X{`RQ&skvB-*AY?0WOWMTPA#?!5#i=Fokz%rqk*$CFi=YH=5jlEIo9? zJkDQJ12J+Wl{r{rPkm{NR!Jhm_N3+&Or{_~1wRC$9bVfj8k~u$e7*8>R+Ak)qTk6r z{$qiwA@2?;EWGh|H#Zw#<3CQKY|&`VBddiePF>`nk5i;(=+^k0Tl{=ts$;G4Ta8R= zH-;bvfbfCxt$U1wElm!493!2I(ZX-Mwp^ov`_a|>7b$6y44SyIp$7X%EqoPO=htGE zU{Y9WT3Qh<1DyYoLGWs}IPYIQPWX4I+vnVw)M>x7FtC-SR@d;b5oiaTXEp9R<jF)3 zV$0_7_m4G2GBhN@Bl2(&FhR%3c4cpuMI>1F%>t+Sv@zw63m=KZZwTCx6BO}87Xl~# zcrsn~)i2Gab2qYb{}#;T-K`^J$)%f}*lThZ6wbo1u2GObzNTelWGv5WrUQ3C&wcj! z2p#*-Olr0F#xr8JZLHnldSfrQ2jb-@!vNbiM{^P2E7{yHqzzG3Cjabq)t|4_m$Xs+ z1Q{`Mpny)8;!;b-<?HkvK8!A>)h(&x3TRcKoZQ1@S?(d$xvBqqRcl?(5d}Ukf7hSy ziWjURIcAD*FHSWlJpU4VL@C(!46?n-qY$DK72M&D4w!G9w3@kU-EB)bE&c1$Ww}J6 zOcS)t9VE`8E4XmSK@ENes10?zQ2n3YwpB1wTV$#!N(T0t_&@ZLxV1%!kxv~p`}G^0 zfyTTS?d*<BvZ|1m8RsGlHY(jq3=yeEdK`@wE$X2Yjb2s&54$Il&fAt?zTl|5V}^Ej z%yrR6V!!Wb{1q&+BS_fu`4PNZ7wxDYmD<vF>BejWL@5)B{<M0PY_l&T<6AXIgsTM2 zXZUclEN@`)hz&^?g`v0JMHzB5iM;DS1hyqKXM@%Uqt0#1m28012azIgjsM8M4-O6b z?9Q62qdJWeF2#|AV8c*L_nR%326nV@1AYB1XR`cA2~g0!iCf6nZIz?Ez;$NajSX07 zYUVzzDmYn>$f0w*f)M>>GCE@08}+GzQ3SYClt}KPpUA>(D3xfR6vnPGT3ploD|=UZ z>kFfXZRM`;ajE+8e>LE(1k<+UwDGkira*Y(QpH3i0;VrA*k}u6?f7NY8AmK*!T|P? zzdrZBd4Xi7&4`GiwG28Y4p_J1y3}U`N`m!#HGu<R;mV~N`*eo?RX!u!N-~zHmO=zM zoV}^OM^ZXr*qqK2m@iTry+9{~iD;BR{_wM22UM(t!t>J`ce%k5hA=??u?@N0ZMW2G zp<lq?UM|d{#NSfKybbZ&ZjC!S-k{XOZ_?T!h`CywDzr}empB)3c6((<c6r4>3zjhh zqbHWJAC!j4BdMx`V<<T;5nUFtOKpN}I)%#*RifLU1ytrT9G(${3oYxhic3Q`VTh!_ z53(sG2gzucYtXTn60bsIPr19`>7ytZeGx@J+_d?o8d971S@+*YB@^7tYz!-9v#dc4 zjLZ`g-u}=V`h?i`aT2;sSJ9{-rt5qy;VIm8QVGcrJ6x4;v5ilX-e7pz2AXQGmbN2v z;|G1aWYVOuLwIdAixIfQ5U$QA;n1DODkdDC*!aTmpR{IVFzc3;wyH0=m*A1bi)FSv z&Nz=ZTuVALIH+!4W4a<X&+SNF;Ji9v1V??2px^p6^-JEzXh-&!6nc}F0VM8dS>8d^ zn=6_$B{3_DUt-h3G(nP(kk(YSjtbbFo{po>PYlz%|N6>gf{aNnEpTrnh-}`NCg}@G z-L*p<0vUqpScGnSm}}=8iBXN@6<uz*pOe4CG8<WcnRDJ#(KpD^C6SQiUM^~Or$O4) zJ^Y3Vm?5()!p#!M2;P_dz0wRnaed+2*?T<nPt${~VN#neI%~Z?t_K{Co*d?WE^;!~ z?x7~Hb7UYmf58&<N_O^mgOs9D`5Z~PTl8D2Egi{F3N_dxTM}&2lfNXCAZ&efpuLqK zY>N{#G#IcE47#1LDg5K~Da|GsY{liw06)WLne^_h3PdHzV5V3d<#l_Xw|6P=nI6gz zch3(s;=P6P=ZKaNIOHnI2AxQbDC)D$R9}y4T&)*z(&~lmcZ&M!r=^#tuU3l*hbxD= zi9n1TuRLeQYGZEke;5Cf<xipP%dHTaS>i9!_byNo91PQJ;Ib0ByTyeFp)8s^J$^0O z@8$rOV3%APd2W+mu(pW(jv>J|QY#H%e8`8BlSS0X$>J9D!{K_Y!i+yY6N<YUW5Xax zsHWV}NOM~h44O@Iv(*K%5n37PhPH(N2}W#$yR6kdVk4$mAm0uVYi-eE>T6&yYRnfT zP$6`m9Ei0P1k{s!hz(zwH5c8g3^Jwxj{rO@A=U>&JD>zpUoECISCeg=bzWlr5CV-f zuZQrl_4aajYWwMOJw4a9qy=I>3zcT2@#bQSlPo&2p~;1ayyf(VM?Hl1ct7z^asfhj zMb{qKKqj9Kid&xZnzE%*pO~b=)v^=26CIyDvgNdT3*y8ak2s39Id$i(ZxzuEFuThW z-H$DGIWI(Rw}#-TraL@rruA~4R(kpz*OT2a$X+DDtnC(+0WL3eGdy<#Xo+8j(R^Mz zf(YlU0_kE1x(e6F_PKB(NeL`EKszv_?PpSck5{xB>ZZ--@uEB+6a;R27asG-gCS3U zuY}(zL<8~R5`Oo~I(y&vqV4&g1mT-sW?&qb^{<;>10lIf`TL9fy+hL8IFikAG_Q8r zbUm*A)abdr@gbfn_aRXsZQZo(UA8%gY%gPTy?Vp3RSLuljcWng2nZfPI4IlT$7OaB z16r@sSlW4x@2}ImF7wK(hMYhVbe`9(m(LrArtDs1oms5$(w!LqEWnNVN*AjjXramT zb|mEbDIEWm#h+qAk1hJ`2|zw9YvkiTt)$RqP29<EOueeYxWHeZs#%2xcyZ=pwpM3& zdz#*qdpy=9<S0c*i8=>7@U7*_#zjE6zOP5<%LJLub@s6m`w?#oE+1Hb;;07MotL~@ z1Q^p<)2?5cL#S{xVncxsdBWDBtY!(96!fxa&Y0RvJ+8K0s8H!*D+34|17D{bh91Zo zv#f6~o<p@pDW`*}r#~CFXb@Vg%_BJKA;{AB2$2)l!PN^(0*BSH`-sZKTTr2t+jeyt zgMj&Z6-b7q(gVQ6;}Gt~AX8g9E*s})nFjiWk7{`<S^61TqY?z7i$ASZshg(Ed(SCn z&VvC`*!?>R^zTY8nV=)<&%OJ7lCH1-St;|n(JU?!z|wp;RxsH%AnHq+9C{4k-G~(< zaHll_2Z8y!Fr)0IsZ_ND9mpyDr3pzZoTtS>8M98u<{10+l->S#`SC44?eA_)qwO)L z{qf?Dwlb#*<fI6s%e!IulhT#DaYv97pOftt(O=GJq;Jxh2K;Xy+*Z14O~keSVfy8e zv3B_QY@jJ`P)w>ZjagNBPtERs8p)_4J);1rd4#u|_VehJI_mqkaoxLBr)g32cv7-J zbQuUy81b*+p=#p0Yt}8{-`bB9TawGZRh2Fv=NsV^1q7{mqqI{de*Gv-TDYLv_}6sr z9*}K*y*iYg;H*G9<nx$`LgnpdzMti}mv*kYhsXbLOQBr$*^Zg;|Bt7id){Uc&0;0; z5!58#-$>S?N>N*XnIZr00DfkN)>vtxVckYdlaFC%d+16$MKeG9s08!hBg7U1vO!cY zeaTEB+3exI*Zr4tCd>B5{~wWQO=#hdsNOlwRN?)TNWlUBJ9@uH;kjFG7fZGzZ_P8c zBbaJJbanstFeK>zIu_f-X_6^i_dD<6saD}D4cFcO#)Leceh9<AHH)0_;c*h+Z@>om zsJ8*#`@au&8-5*#>@^c^NdG>MvL0f^;})>_|HIh;j|b&fW=tKUFTCFlIotoA6B&}z zOzz(Qs_muqg==O@2voNsq1bs}bgGflU|@Z_rjet+-l%)qQe_LQqM>%_x1<=eC$+uj z9Pq_Ej#_e4WSvf7Swjb|>D8{P0ts{)7fMdo1ncq^#*#^ay4S6a-aUIjj3-uNJ4J`u z_LjTAF$SQW;v(m~yg%BF>krUXQ-_}$sV$1jH5CE(zeX4m#BXz#Lh4v)sQc(FxMd z+jz`42gnIs!wKtyvK9>f`wlpCCy{U}KXsQ(OQ9<Yd`U8Bvg6FM>14Qrq5>*3a>d)U z2^b#hb3s->RGaQ_;&q`wMp_}n-D6=Qw*G<BNL2kyP}-Bi(iNNMxig|puh5w31*0t3 zSGnGT)Pm$O5&5%ckPIyt>b5I`6IzCb8p1LC`{ohU60~2mFoonsOi6SvQ)T+kl2)(m zfNs$%YK<~2T>Ao^=<JwN=v`)NHRk1971`=SHu1{DUgj(#Vf8j0!v9UTJ%RCnMX7M_ zWyAe>;O|F7x<7b{B|n;jt%);2`1Ti+!Z`kB#$^8K?8GMsj6>-s=`j4C7l7nzyvbnw zhun=IK_}wxk-`j9tFFaZY8%~s#DY(UqK-RA?%Ron(8Apz!>pgRn;LdJLq+TpFotx} zH#=k2iQYW>X9&vkwT(U!)~tIFa?pz4?p|c;LvIFY(^Z$6Re!%!dA^BmQc{P%;1A3T zf%wWWo-6Rlq*XAPhomDi<|=l?^8&);w}eVl?0lqdE`+gCv}>=F%nai1$cl3ccuXsf zpcx@YW`(wEK|)YuaLzrN*KG^yGK5Swif<r1cuJDpCh}A+AW1fXD^Jp_C;-9+m=2zy z-jz8TME=wx8J}Yk`|nNniUW#3^X=TW<)4`$e^L6vg6+Nlf1iEhgBLE1En3}PU^tGe zYE4P5tb(L2{n~AEkS#e=Yx}<~X+C;05iiU!ws~!S5`|Lkg;k>828Cdaf8iU6hc4Vt zV^#da{u#uW>b!m3Y{s$C6g5Ed<_hcQ+fV1g0(aR_K)GE8LKarD1AOA@2)9lyrcRW3 zc&=&NxFNb?cEoyXcBiz19oRDd5)em4{DTkqv`^9A2MGb7*ryn?h-~Z=@TqE|x5Qp2 z61gF)fOB~xH%kIyDY(sqvIJev_niKD6{3Gr)NwP7Z>x!`Bh-?P6*B~}_w5<f&27{M zac$NfX21SK`Ayd8;X<-_BX=nRjhOiZOzGT1XXjX-Zrkb4Yh;pW^}79yIxdDj8IM%2 zgU^}2t+X0?9ZvLBJT_Z+9xks>=j**ZCgKt<8)yPpMn{-WhqNE=AnBOhh7}%~y5Y|~ z)?b@na#{WS_ia`lurKVX<Oj6du;b_rg3k@u5Kvrb5D7Rw3i0|;5%SW1Z7}8-Z+qcb zX+N;_sVSWr%tw3JQx<g`VIt|9SYw5~{?KTB9T!C$&gMq^i|GHTdh58T+BIAlq>&Ek z?(UNA2I-KLl1_n<p}V_b07<1&8mXa66d1Ze>2CPe{?6I&e$V_fxn`~3^W67!-MwD> zt<Ra_i=92PgHP&7H6#NJ!0xru)0GBW%Vc(2HH0h?iR1}WN0NAq7<GHzAhnJYLfxBH zB&z(RNQ27t20ydG(pr5uD&~0daP$1PxDVT`w@V0P^;_Ghfvw(xX6hcoJFP2#|AO3m zU>IIte#7cw`W3f5De3>9YX8z)7EkU*pPE%rFWuSKd<@RFJ~X>};&PCXNnUmnt%z5J z@sasM*b1;(6wI{D{xk{|RJ`z;yiTeBQ3sZUmld@%A25o`%YuvV(<9N0pbZnb;rlq9 zzz$S<-5*%a$gY!t2$_^!2v}VQB;ea{4C1#~Q+a~ql5bylOy;xuySHRY7A~!Dc3zQR z&-&r+^kd$ysIVZSqlzIRA!)LNwc&N&oOLCMKZ>nBfRTpsxe0qj1^Pz}*as_S`cF6N z_3|#uncV&aKdjHa_;9;`_6hUubMJ1CiLU!ku1zAa#WRceD=_US=OVD5tlxI;VM5I% z+Q=k2Zb6UD=!KMp!4Wd0{z#MEZj8H#vhKY^*MoOQv!}4~y{(2~?*TMyiO5u2>v!3a ze3JgelgByXTY+t;bY;ikOOoH&uq1u3Bs_j4C_w^|6esrkPHB*~o4=0jFL{4uDf}6& zs2_2={ooB9yW!}gdp&B{Vl10WFh6M=F5bSoUV`!#uKKh)^`?JHfuo;?s55TUEY<C5 zh;gH7ZG7OII?@V@BD|6-0Qp6*Jf@`=>G0vF3HUU_n_wuhKb%Pu`koCk=*)(GJHm7= zbyUN21|dN<fBYpa+~&;kjKkLXLWi=x+z0Nw2_Y)-&JF93>|)z}K4j=b#I7lW{NIhY z?S%tD=704uKJ!4~+TcR<LgZ~Q_X&vk;IY9+@5b*}{Z2c45~XT-Pe0uxe#PIFA(Qy- z7&KO1E!AX-Cc6aW93wWWC<rpVf4w8+As9O0CBRoDy~xzFEIdH4Zs*7-iJ5;ZM&7db zvD424Yb-NEOAy%sKT*1xbPIMu9%|gy;@;g)EJY$!&KyUQX!V-H_oI8n$kJZ@>CX3{ znPTp?ijBJ;_%{=MvqxwUZ~%$^&WFddRR+VAW>TUFmAacrB<k5yg!Sggz0Kza<VAyx z+6!K=hYBU*Y&@OmD7|mMt_ouRQk}tj!g+CnewPmHS6=$HHkKGkHr%o;{qszvt^4)A zi3M5^pP({gA|L%8$0{&ft5kqOOC@qicbteyMAf&O$Ne8%=c%aA$8P69v#0&vJ#Lqk z{kCRYDHF&vNMeulBF4SOnrDX3<@4%OBMa7U0TALH_jQq=oR&SST>>dt)Hz*iFJJ4E zKtDFsa#}%Ch(%r2B6!*nfQGp&ZZRpBOJQ<+_952-d&Laz^$@bX;uRD%d*<#=Hn*96 zHtvsJWaz4yTgl7JU<dLf8`r(FPm;$&PpwopTLH^cOV4(2b86EB3^P}c_X5!Pza1<{ zHvZ76Go{+!`aS`Y7<KIwTnEa&^M=?4Q@^HNyCUcU?nx6QJOcA@nWY?wy$W`w(X;hY zb)U%PEx?DT2^+$UTEi@%Mw*lTY;1g;r}s{II%M%%-lWlV*HmGD$vn@RMGbz@i5oq2 zO4m4|Nd#EN@Lf{|<71JBB1EK}HLIHU^3~`2l^cuMX-=)p^Avff_hC+TA>BGmh@`=P zU)dC}B1O(4LS&Z5y)NK?W!jBR9DhIwN&KF2zxU0?R0xcb#K<$cQlOU|jLza@qbANV z`Kz1(wf(^bqmZwnj~jeL*HP#^qSC3Sp+)*f)__3F>aX}OQf|^yvF*4>Q^o|T^*dC{ z({<CvGcU!E$m5*oQos1VjSlBTY*(U<vmv_;O|DP0M|zC!hqJZg8+8sKikG!VX4V~g z7Rbolzcow(#=J}dQiDm~lFozuSi7IjX-yzG?a~Vz2s9Y&+sm1g?`EY|D--?54~}_s zv+8CI!CTWCh7DD5H5dz@>LNkV9~WZ2Z>tMH=kTc|QR=#qOr_##S={79AE`uaP7h^k zw+6j`$oj`u_c*zRe40JE`}@aLd}2##QBa@CFQsSV_jQ?x5W*6E%VEoRYuNDtq^`Lp zccP1_bH%1Z(it$##*&Y!-88335$bJoKpivmRNwB_*oDz2?hMb(N|{M5KD9))g#P6P zAMB>L9+=+@U1X{a?KHkk-icjsR-?SzLGG^E98AFROL!d&5+HYbG>kJK%$oe&YHJzu z!m8(Xy|(+o=FNw4<$jAr0cav|Sb~V_=8z_I;VLTB9TwcreVM>un0-$yq6SYPKyRh6 zE<VU<0$!rE=s5E|%<ZsDJhc%s(z%k>dLmBMuN@m;b0|Jr%yCEeU$4cUP}pbtVeRkQ zVQ=y~=VU_!r@#22Yv=pw57{06>1XJBVIKt|?usyR#htphBkeZLOT+u!FACXjEo;8# z|DN)vM;4{%=F<RgyDyuN#Y`PThB)Rwy)t{hB0Rx+8>+b8IwO#G_V6bw8xtzj!-Ez8 zld@saFQaTBJBH6kD<s<b$<VQ><SNkZaY0KT5H`|*G59wpvP&_-_d0vt{e}*m>Uo+* z*xm^@(ElsN*CKZ(Qo3wD)#oMw6oeFKK5AIYyn6~+$ctEKl>HPt)RPSlgG#G!QY19< zEuL4|kJAkaH4)@Zjph1<euG4ka7QkGgm7`j^{#MEu&sTJTg9J*fZuzzn+qGv9HwC} zZO@olMOJP{&sOX3QAAzg<(?-4*&PwL8?mHRfor05`DW-%Ttj-X1QJI3eVH#JRHnn0 znWhn6=CXTT+g>geTZE?D?OB#=onZ>EjSTIUeo5Z>RDPOOdGpz6>FviMXGe8^{t2sa ziKZ0?lX-{twSHpLv+aMRTZD$&XAXK?jN=Kvb8Nj`Z<#1dKaw~^L&!XmI7WL)Ig+T# z4IaG?0vrr$zt?N{a|}xdD=qfo&t%pst>Tum$7r@oFnqvISsPZvzjHV{rL9^tl(8@l zT+M1mf;uc=6PWqmDwB6P5It`8M{bt)zp7}B@q^@qQfa&o8J}_+Tr=-0E$}6>B{zWj zPt^=mHjB}6LDMrOqnE!vtpD*Wx2RC&KDZJ(%T_h$C6mM=D)>wdRYYfd!vXzXn-f21 z7Li+15dR{4z^t2K9?bXBf>Tb;hh`8LyUw7u>^5|9tB8WbB8y*sFUS}q!1MTcnS+{R zMh8}AfW}G+BeW%&M^q3ryY!T|7~z!k{A%eGn)r)m+}@7<;tylHy;H;*`Z*O=;qA5l z&ChN#a4(~X&s2z@ozBZWqZ-u2E?ad_`_SEck;p#uAbDkG(k<?`Cq8?&HSai#$wo7R z5vQ$`F+Rv;mLKEzd}CN;*o^mm>R7JrW6}lR^5-qb+hrrgLa-B4x7W<9@QqNSRG^pS z_|xy;;Xwhhi_L@EOG!~~(21$r3Xy_Emh0(#<;7{Z<D23y2MlF?8O@Z?VT;D$mX(%h zN2SP<xY(W+B1Qr+uV$b1Z#|m*H+v=AN3NSNO^x1B^Sjoo?()<6O30x1O9PkL!_}&i zLCwI6sQ`jznt%e9DPI9MvSueYQ90PlRqQN2+He^bT<Y1L#2ij-6zyupPnH?5$qZ)L zACUK%8akjmkJ62keBR-yz&;MmoD5`IY(V6i$cb&_d=GC$G<KZmlp9c!i%GL2{)Zzu zS>O5Q^2xE;*?3HStVMmwW41rXiGvOy>FBv><!@J4{76Qf%jfi-c-Zyl;p@-GXyV^j zo?usILQl!gm+V3a$w%=mE?x%$4Gbq}x#}%PH{N6Y$mT*To}1T*-<dGvS{~3o-R)%N z@=1D;N}T3Ky5Eecegx~r)+JFa9;kkt2?#uxvbB$B5|x2trar|9lK|UTG%1)Iw9LIi zDv^4Jiu0q8w7jCx4Gt1XjUL1<Pa5m<BQyrQEvCn`(~J=m5(CZ>eoseGlvrUSQm+4` z!1Z#>QZo11<mdRhX-7O%ww7IC-LDHw^cgMm+T(p?O*zAz2vso3N9Uwp4FY{6zY03^ zm4i)!z&>FW#yqGoS3DY91T0|0?!;n^&rIF*=Y-_`^D*}ZDDWO4wJvajqyYrf?~t2~ zjU_ir2-Zn{+(yx2E7(O<UIFQI>T?VS_c_xEb@=W`?(-xliP~Z{hB%VsIWDsk|J_nn z!$d*lAW70+fm}t-eNN|Ut;({i`Tjx)re+t|b^F>L+sEo;dSuJV&~jaW=K)yGbsBsK zTrxIdaAM7G8)~gAx66&z>!2Os=MW=9Lf@z@FLfmGHAS4e(|MMqGHk2)*;|Xyv1_O+ zSy!j#6%E4&(<7(27NG(sS4c~J0?%RPDzNje%i@+7!`_;nGnp;<PObs4W6dQp?Uoft zox8Q4qq&gym^a7dX$SUk2%QgQh(~h_69kMdUB`HwQpSR{9LS0u{t8I50X1jtPgnDv z)(W*E<}+KF2XC+)=6HtBJM6l?-|=;$+-glfe)cIKAowzDKHKElKJ^n$YuyraOkl;1 zhu{%Bz3f_DsQZ*Ms<1{kb)J&_2LH=vU&`MH7ncH&Mh6(FEo>XlnGMH7AAfsSjtK3K zWs@LLkAg5YgXf7=KNkqb&u@39FegHZAA(V+q;l-TiV~%ZP~;?N6J>I_uTK6z8ksNW zGjysCJhN}+FZEW*JOcSW;z4>GRiAA}3Z7n`oyNuEciOExYMn3Ic~;K<3VdJl*I;xQ z4!p?=qx_qBkQIU9$Nj0e!%vI=<4a!894TLR@8rW#{K+BymlP1O_`v$j{6sG=Qka6z z_X#ul6-AifzIi}^`MmmzO~;<P{nNbqNyCiF^W0TumotQ{()l<LK>8)08-o_1ONd3! z<jIlhlE3MR|8Im`AUJf}5Kno(nEROhJ=@7OLA>Y$9C;H4>G8AzloTKggt3+-e8Gu! zqf95)GV$K3lWY>JDwF0_<XRgH3yNBsr;kgQjn1=)f(@9{-hn-hdp9}8F$Lg{tel-& z4230gXX5)-<`ZxbyA@{?%F}5M%?;gD+Hy5)dmOTFYh{TSjWkPuU|=^nH{#B#&uwFa z{GqD1i%wMCuN;~Y$Hwee0(f#2T2NN6%QBBX1qN7+UhkR++2YscUS%F(_Aog`J=uCz zkva7q*s3NucdA=2Ic*$3kI>%lL8c3MR>KaURhj~Pr516)B<sCok->E14-0pdFH(l6 zt8cc<t97-Gw(vX`I-@G}*elxI-Tu$RmrTme@MSn|?!bIzqR3pyf#vzW&C2bb>sXGH zsvZ8nKXY5S=Kis?Rn5n@*tR4TN|-Z+^vO~8!A0z!xMz#B6(d=av=s?oHrcRxoXKQA zNlzz5+py2p$$w*ob<Q82X2-pJ==345_HP%}2mS}&yyxFP_*Y!pVkF7NU{E&sYeGM_ zbWM&195{58-&jsKx-&pKd-B4MB=4BEw;|c9-&U@Qj{@|j4^)?IgHDcI&F`1IU7cM< zTjs-`hi4Sbgbp~C4!%is)U*hNJGl<GJg_a1IjlHEH*|%cpuN9r|5N+uobYMuKalAZ zC2pyj<_x^J^XrSKwY62Z)qF9Vf4J9)>V3X>i_T!Z*pJglx+dz*dmI4baRF5$PhAKq zEgi5kTCU9eZXh+)Jn|H1hr6A*(wrOHR<SOt4d)pD9A^_4lXKbZeA#%^P0%-O=wpAr zx@fW%a8vGlsWT@u+YX~{Sb4wn4cplj9VVEo)lyG5cKxQ4>9XVKdGxw$0bfmW*Iso6 z|DN_g@yzy{Fb=K%pvKM#+Gp94?B<wpr=sD)X?@eM%I5=wg}@t%vu@e;y8Fk<v-O{1 zubQK=o-aSW^1G|T4rMYoh0{DUrNTm>G>GI-XjuWjg{|)HT3FSPF)g{QI92<FgpyS< zT9v&}z3+hgv1DBnxzA|=x{hA(EU&Nlg|}TyUh{O!<hDE?7+T&D;ruq#)<3?%0~7lN z0K>dX{6dbCHx2(pp9MdTSNr4``B*DBk0g^ISP?`Zp-n#Q!)LWWApY7cIh(I>h+7K0 zE)agoi#<K1MVeYWuM9;3Q9b1O<37rqw(u}g{3A?)>=Wj-ui(BdWx*OoywJmGV62b# zRwun@k;jpfDi`rVD)8yXA+M*Nak@{J$lT_aiMtmYW_N$m589(>^kF}@payWdg&h7P zct<qvr}+4w#917z{BFqM(q}4<7r9h@tD=eKV@Z|-7of)t)$$GV=aUa=?;(m6Ef#bf z%BRuA<?AS!tFQ6f$yEQjv=(U$ZrQJv<6)E*4H#OSQe^^7f~fvf${D>n=-qoX8rq0O z*u>Q8eA^!IKlwx9agZfa_`}P^d?7L^)~K>ni^SH(bbBaDpH>Xf!9A-PC(<mRYXzqj z=q?fHjgU(TUiCb8(S;xe-kqaxgZd2V?N1ak1(Bt3)-wwH;fJ1kE>6|#$iT#i!B<`O zH#fG|H?M;C=rnW?yRj>d_b?HxjcyjgBvR-@_dX@6=g?mI6T{i-2fF6iaF<C4x~KHr zi1~KQ;MJ0lrQh(}UG&HrqRx?n9rW<9=T7#w{HDhqgyfdG(oYXGm;6EIm4fr%o$o08 zKX!0AUo{^=c2T;-`0j;k5S%+|FJMc)P7Zf|qD?DQu+=0WY%fXXxl*P2+>-XGk;S@$ z%hAd4z0lGkq>ceVu|@nAZ`f+ab(s2ygc{)^H&jTwyWkR>VnObg|@v__Eh(ru%Qx z#LbyMjcyx0l8IA~>o*I5=W^h~u>P~)#;N{0yMpKh4?@Y-)3?j_m5uJlJKsO_{!G6e zG?0u=47dR21#H6$Z|0|-ZMd2SsZQPTmrVuW2exeln0T%loE^QckxP4h)>9x(!4!D6 zcl%Q@VJPfKakGlbEb1WOS$_F)ny>ZXjHGoN#k`Lw;L+|-!jk=YtEt%ikSH*Yt>>!t zG&U5M$-aQ9rnoYOEa1GL)p1eB7o^1$a5>25z8LsKZkO*tf4vAo0YBzRu2V@qiyiy@ zWiau1No_qJGVe8*>_XjA#O#OJL4xqRA3ec0v*m@lQEu0FnOkKSJz=UY0XS2gyhMSI z1us9!C+|40*6f7x+{dMb?|K4)*T7F}bzU~20iXY<x87x%4{CC@!?V3@KW*d+#IOTD ziRFPFi-dh^m2dZ79^V)|uQ&Q`4$iv`0-?IZf+wO?(C$1>N%ek}$A9D5k<M7n!h@%I ze{Q~#{Qov%s-^@<rNQ^&H0&9puQWu+Kt{wgomAxx_3K<zDuHu2YPvCo6b)7Q{x@CR za2heqB9nM6Ryn1g81@-OX^HP@pr>NkTEvBo+VV7`@Nlfn#Lk0a4(_k2F=Ot?+gSy| zf)lAvXY{@nWhE9iD^x%Db$mk`hpQ4OCFuJRS+4u!_Zsvog~0gW{zl&s6-;Hh<>xsK z1olgq32Aj5(cnU5(%$n4LLzG%FiT~^_<`3u#u%C`a&0)KJFH)r!^;0!&FT-+Y0N?w zy!5OPyCY5BQRViQzKV0ddi_7e6$i?WKKypjb>w0F%?j~7XF=@Ex!AVP+5GWT{^cDr zbqp;~Wk))19{7~Q&o`yBU-b(P&OL=z<8OS1qkA##ov6jM-dFf{6`vGUbcO7{uT?g- zyBDX)G<Te5X@7gTm^g`_#c($cbS>Svxu$|<DewamU26U=uH}}Hq(E=9KQ-z5t7#8( ziF0B6RKa|Q-rRb!wxm__mc{%3GO^o&ZG1LAnMF=^QUDRje?N3{Tlh=^4)i<^C?!bK zbN4NLLKBpu`)}3<cz!RqDGVJ=XRCLD@ea6SbVb+NXsH0jrv$O`apWR+p(xl9nl~~z zS6mZ^aU}m00F=mTG!>R#4g%x3LfDOVQ&3<&M*=XlNXoHGKg`;yk65QxpBzzXmf+~< zh*->*TWpHVP4eGa$T~t<$9SNy*y{fBkMP+5K5hgJcr9`d1UG&AQpRoDG&kIU;Z9y` zT>Yi1i$XRMi^45!*i_^nOJKc@kWLwIyg-sFlJYb27iI@JMev$yo;i#_8ncw3f!&dq z-`EkjJYPs8`xvsz_%MRg-*>71rJB&teyDtg%|}<)A)to|4zBw|h?dVkew5hiUG?0% zYI<%cHHK_cGvPXDe}08K#i6WOq1jkIg&wsZ$N1n%l&|0Xzr+AM*L{)-d1LGtX1T!q z;of0bNzUf?Xn0oRzF?Kg+vF)C?$4L-3pV4HQAt;@!sKEOW5*Kv7>~B)C>%`0<MFtE zE~#JNWqbjuTsiOe0M4+f_?__~V7{RK2Rn)bC35a8kL|CHWSu`jaU^&4df#9q|H_hL zIl4avFAFq6^|`sZ-&MR|!L?H<Bop(Vi{99TmSl?v|MPI_QkamM9KEr2BGwUdxt~RT zQ6g-->gG=+^Zb{zy!{b*;7s?0Yrk#LNL*sJp#MR8P)(v=E9Z*W_8)#FCvVYMfT{)R zj5p0qLj{8{;sm*kZz{iJI}cZ3FK7QtPMm)v84;bFaC}HDWAQ3G!j`gQ`RR1@3eKaV zKnFILZrfsJXKRv^{l9gXL(;%?w2?b~U`<EYuh|dLAUs^MiWA)bt7bW#<1uMp9U<?^ zE?Zv1-?gMeiHzyczg~nJXP>aR5c%@(-l$s93i?mlx!3YQMiVznze2a2+Xse}MX?s4 z7QTKC2Sg)DN%UolTn=?NJI;nTho(&we!#tZH@3)a|3I~obc7A()jsF5WM?C&1P_;K zyZg^}*IkkDx6DlcJtnc@Z~7w>XEUtUdhD$w@AR$uCF3^^9YUHz%q#oq+!#1(qq$$@ zOXP|BuovXW3tMJVB^Y-$jY-8;6WbAQi(QA^j$(pBZNU`|}qh#xiaG{NX(z%>uQ( z?PS(J)-#~Q7MXg-)dUSENW|ig?+!_jxTSwx3RMe??(7&YUcrq<!NXY!<EBRRkb%;h zqb>=!%beL8_@z_m<L4XMWmD*tW}D6$CESw#wKdfQ-t=;x%Ke+SpGNzqe`*nnTpA)u zPp6%ym$7892f$CI7szCOmF|_5kR;S$0#k*~PG*#5H|r~HE*jh0cIokvx&3S7Li^{O z7n<%@8a^g5lG@|FkBC-C`ADq7tMhJ}<Xtsmm%e;UPbSyIav>62)7(=_#J^?9iLR_C z)B5~@Atw}aTsFeH|0b~UC`SKgr7DqT)_S~ZN#$P>>MKgh=SV{R)M~E1>I(O8PeQB{ z__day@Q9z!AP4rp%`Y;Cjw3ty7hlc(TU{oz>>pR(3p9Rev252F8ea@NQ1t`vuO$p$ zGHL(%nUxIvf26m1zK|q}2SDk19NI&6x*A<LxcZu2sjEtH!4IFSz6s)3mHplk_&1sY z7rf+nAd^Ow_~hM6fI{Gb8UhCqLX_55Xr@w#rpW*E2X6wN?BDwPzJRB(I|2cRT6YV# z1RlKAPaG<I@YgdYiwD_0hgKO6kR<Mpb4+~WD}4W};;2iP#fZ2P`WOVj+oedgz)ybD zu|msG#~*-Fsy6*w>F*Tcc#tiL`-nr?$8d&te)6xB7#W?fG#g|7b|7>or&CU8{yBl{ zH2x1v2n#!zazlZN`v1T`@Ed4W1W!E+0*UcK1P$R3k3%zQ1G_AN{6V07nV}N^VXs#` z+5TG#@NYFPB>+Z%Mgv3jEP+WB6}qg<nPW<`Ua6#dDYlF(w#q3M=i4K|$4V)P-6z=N zS;<^((0{?<TqIZ`Q8-}+27@WxeA8vkrGGp7jocIHJqGRN^SCSvSDCco0Sxhu8DlwX zgUjPz2==)!O@=t)6qsG1jaIA>zv$%81EtO!D>7vNPg(qdjc(iUzfPo&wQ;BYn;k<| zP74um&)P77qjSpk_xC>%^B$N^jQ>xdEDscO$_%?cU)i1v-7j-BX7J3yV9|P&`qehQ z&QV;jU;1{M{sE#AQxW8`&VTOaud0@E*qt0N4y+d^R$7>6UCZl_zSh1cJ6V|9SvbRD zVtNXmBfSFyjj`8jSu@5~Kw~Yi7;Pq4Mj1c>CpBu44T;zk0vx^atEr2eztVmXlv0AG zIlxkq#^G1#0zo3VF>r@?;C@_mLict&wK+MJQzF8lnfGo~o5Dbu|GWRNc!~WY^97?w z(0|Cf8Tyc>9Utr8$1MloK?+bNDJVfDuT`8A3RbuWS{{lyTbj6v>Zwslty0VEi#4^Q zr5BT@9IA66nyXCCXB-vh<3A(f>gU?eL;^Tn6wMO9pt_Uy-#kGtfd9T9K!N}E+hGfK z*I}I?N7*zNf0hQ?bil`hr1gw-D*M^z2u_4=D?3z^U06(Y?12D&2c$c5OaNj4k++t% zR^C;)PZ`@GonrN*f65TFdA5<byR+%ENpNg7-l`)VGt96V-n&prDN)uhReug}NoD)2 zluNq>469~#V0VG|kkFCX9p_%ELNy`L4~!m+&ZB(g_A$&c#@(9t<LHs;4dVsFZNs6a zLXbTfv&`!q5r%RD>+l}MOSD=eE4A6247)vvv5V+KJEOTI_yFv&pvNBLYC&tYMO!2M zwlurfA%!#8f2eMx=e|6?-&HruwA-z>7TIn~J4xD$-fC4o8D4fn2YQ*OjfE~7s^tH~ zb{!klDoOB-HC@hMbe3IBJw%LG4ttRg#XrZI;gD#n2tZ9BZSR=*M<V0W<G9M17XIKh zl-K7iT}+_p$ggf^Z}Xjt{fu1oYC0_VViiLDai21oCYdF>(u8w9$p%y_RxVcX$mtK9 zx=7O6#pvWL0P4qefCdvaR8;<|J0~h8_}Fn7+(U=@N|!ZV;o&FIowzdI_Qjn7L$Q9R z?EPwt&+sz$Nz$m&xTxG4Bh8V$&zlrK744UHDH@(1Mn&bY3>8PZ>v=$tmw|<yp^{u% zgAX}kl}&Vh6{lGCLpT1qmA|12^A63;zL6ZWRe{!6#%EZ`@-ymWAwE$q1f~q0aD_ZW zf+tCzVE89VXB&4!T|bFdd$*|l$x%;|+FC#;YZt(7&u!LJ`$nFEXG8!K3|idNDeF~m z*$k}voNZ4Wi4_I_ATVO)KZy7ee+u_NQD0Dj?|6!2I4|zNv(_qhVIR*FQl|EDCAeg0 zkKV)%mSGy-)6<u0f8`J3M-72m^TBMj@etwPii-01o~|=COl(8ao0w7FqYV!Ls{-8~ z85o5!jT&_KUx=lR?UcP;Y!D7_idk>iw6l_jsv}B6R0UtzH|nwqK-tuFFet@ZXEGg{ zV{qvd_><8Xy=gyoDo4X*sFXr)+|9#$8#Ys>Vp6uW{dfa;^_^~8Xd~3n<?eVkw(2cI zRRpsElg}3dY@Riu=Znq74km{(UYbfNa*<64GxW=N^LR148i<p|7FdUGQQH?FK%>e+ zeYIWvfsy@~*>6Iozv&j?T&a|X07f=H!Pg}12M>1G@=-k@D19&U6a5ywr+&3Q8859T zGrE=_I_C-V!TU7w@BL(02K<&=5liXKBXUMise8`1N*I2tt%k}fWGXBKv4atKd-L-8 zC7AZLCY(a|EEnu0YSyOrmZ^9%44pKuX*PS%aPj?VE=C$A5tY1R_CJD<LHVEB_uXcy z&kvmn<+OfHJInl#r<70FNeE(&$q{6m$>v45w$zxJJzwTElR36I0ov5|r;FmxGS95r zzEjAl<=8mcK;+6`7M5G4+v?i|BT1KQH%|)YzBM*eA9y)mh>EqK^23dXl?~T&Lp%!~ z--u+~)T=d$ZF{sK*C&B&?oytkoUDx^fb~o=H;PmfwC*k~XweDE$M|VZq6y)f8I(zr z!yazsOC}N@?UZHtJ)J9f0u1z)F0@&d%Zv&jG^0k;o6EhVORxg|MW$%_Hg7@{K&vM? zsNQw=s;{Dffq|8n+{^WVXjU3ln9s1-&48%f)D=|Jkg1mI1PA3WFbwwnIo90#t6U%M z0*h4|4~BE5Cp;^q>kj?SP|UUNQ>?r1<M^U$)`!+FxJH>R;pPjS{TYF~6oVh?EfE_U zdx>YcKLF|y!0C>PcEU`6j#>N@P`kBA%LTd<oPc?QRT^Yn*G}2%w=*-m8nHxN$KQFj z3cMHX_YQ%!Ak1DII)$ii)cVfJ*kH8MBi!}LGdX#!UkhP!7B-frvW<fyh*EDL%tDlE zj9XR0VL?Rb;ZUhjD0@k`5W7)W6=Jqnv{b!;CNw&|keU9Cmk}|qAT9ZqLf8_uik6@n zV{4}f-&xwVwWkd)jm+5EP@vT&O9sCptwXc1RZTIo!z1SfM=m9sBuL>}WlSs<BTAc4 z1UHdFl5C1?&(8xfNJ#sxYB;*dwDLFU8iOZCL}^_5<3z&ZDPtcbk~xNyELkkIX^>3R zuiMCIGz%z@Sx_^&&JN?rR!u<+mnouo{lRSk3c;~v{M-o|LGITg0lk?);#D}5P7{DC zlvVj%(~m7&lu?gnNm}{MfiCJt#9k(G5wAn)rAJhBpH08&=ETvtL%BuLZt8*uAQs8k z+2$mEFm^et_wtTek1a9aQ@@f#UWj(PHpXisE1AhsSGDVGu!_0ie01loM_YthQ}G&Y z<+&I+N0LBaX5EMar(*;rXM)tojgn-x(&>gSNP%(WXIUpy%ZAb?Ss5l|9hVh1OdNe! zPn1`nwXM9%1W;O>sbGr@xo_w8CldVQ+I=P(yf3O@1gO%MiF}GRV>=$QZw9#6c>r(H z)YLTo%vyU)ivm_F%sOJ7@riOOSd44zb*;1+(;>U{D$Ri2DxC(MUt*@a%b;kM7!1H} zhg37ziTn%ja$BHas&<DR@UPaLPyrhukN!Nab7KB4M|#x0i%lY>pfWm-7dG7ZV_* zoX+}{zma=w=o$!5lDbSTv*I#O(HYO3S}!93$ZlvP_r<nz8JziWN4dJ>wA%adM)4>+ zapa(?7$hERqWaJ$WMgKXxGOPc7_C-6TS$0<lfBVpY@JK@+;xUEnZ^1hR$Z*7wo{h; z)t8%vg+_{d_R#akO<${3njtgmC!meF*Z5q-<!}M&)6(2*3A9r?#*x6@$&*AEHVVBb z5W=?xS(uGiKTmDXY8a(PZY6bNVEFm^ZV_R3GTUF%^7L+=GW*f^&f3{<ji%}FZM&*D zfOwYdu^VteVn@GF7}u+!VEBVyLA2xze^egMC5+(C#Xih5;-E_>ufb-aT3op$3uYvg z2wE1KxE4n16B_rlCB_7TTyTPQzMb+kOQVWnc!%MsC+Y9%FS9WTmvW&IahJhpDHOc6 z;p`A`Eirb*^SnorY*kTADJ6ctgK(S$i0gG>gILs%LRumYt^PKxk08vZlrC3vjCzc! z9MWK*wJROP;yNJ4^%F}JFHDJ7%i6Rg&B2#JL{EO#gqEKC$@0UGgQQ}HJdF?dVl?GW z{7bmXTF`UXGl`{vpjms7QI7lc_`qy35=lWR!y6CuoVeG1hfc0sii9vxXIB$)2BHvW zd`*ozYa>fjj)I*g6z_A?Kk0ThPXl2w6gZs{BF#{5TDO=iXQeU9J_T~cm|KzsBL;t) zt@x|Z@$$H~B-8*G`^b1sv#pkXDOSvAAM@?t;y|&4PUw!0#=)CA0+KB|98*rup$CNW zS=gWOlsB}<p~UA-AKl6FTA=oP<Dw-TGm!wtpMC!%$F@pyZe5PTcT#slm+P~@qA7lc z#TY`1f5^QR^)(;L_1R=w)j9)&Qr=!K8{cT2<ugor6z{WeVhOSZvN^%Cq#|T8sH`{2 z*MiUa6vn{8qQ*bTPAm|9X^^D4<7RKCbpqf@L9j`lHZ|%e?7_U%d;c|EEtX~uA2{Q* zKFed3=K{CY5EYqZ=Zo8Cci?g)|6_g7@V3$TqD-Yvhz>~4{Qmvh)e5@Rh$zNgwJegx zL1PNTIK+|U!Vqm57*z^0PRpqFI==&_GG&Xm0fq)k7~>jCDD!C6QtFg@NocW{Q~hWk zerQlve^nGH6@Q0l$bA-sr9UmB54y0CAA~3>tKub!`W1m>x9az%YuTmr9X?dl*E3Nf z924!C#Yl~HHsV$2SE}O*<{s8>u*M`1qV26WFsVFq6l6w`j)mlV&|NV9dDY2nleh3= zr>Pl0OEZ&I{)O8*A}W09>&=GDcuZfd#k@XRYsEO)vxw1%p@{G#L=8>chGBd0&XM!Q z)RR<qfazDMHKvj!E;zdKj;ZC;yu!x`{T4ucxLn#r?>;t-B;)^yt@4~Bk#P|55Ah7L zVYjy0Y92X?^+*R1oTTJKp~+Ha2i^|k<#G#_zFGs|gb<;7{jXH#7}sqW&s9>FRHCVd zl2Mj+ie83^^+dB8={WheeiI`3@4RZoiuYe9ILE6!z;~wOsNWg2*Od*;kV#^N<*L zi;aZ4R$r6ByhJ>pldOyvY8fK(s=Mj)b#cLRWehpy0AaL`XcW{><wPwvB<wZ`%ymGC zy*_;s_@nb+5{eT6*iKQehVQqUnCH-1z_AItX}sPaqA||1-001=)#nr|n;a!-={%<V z8w=ihWyF0y#qzG=23d)GBoyDefZLQ?_tM;;czjzv4*=(G90(;*nr*N66ibjEM#9K) zIbQBWr?;CZlC!TPI9y8AQmi${st5^-jdt053cFHaqu{vDoXvFVayjV*s{!bj#FGxP z)8_h9`6Uu&Il{}aMbn-oqOaK*8c&cQ5yign)s7dr;W^u<j%O5^wSWU})zXd!upz8X z&)33+>JZE>%ktA_@J|4jM*ShE%HLaw_asT;YCzQ28P*v(<<MZI;k6+(9W{=s)r@`W z!HVSiD{qbIB-O;p4^Lz;wo3<G7UJo5bcsW=4<=6ULP)t8n`2YdUD)a+3l1ZMT}(s@ z?D$NcY@2v$>3c`Td%B27)&b520jZxS{gw3MZWG~1xb?X$8TXfx*Woh#etoMhxXdH* zyHR+4=Dy=LoYqyP=3qhPU3rg*_d9hB<4WJc#3U7s2Ba+M6j9N}Nc<qI=_*z_^<B^} zX?LPoYVHHkHu?k!?BigGHDRv)0XfGNCA8G|oGu*R8}Re6VA4X+E`f|jCf-lm$gV-h zNriM~B|&Cu9Sg-!Ik-dF&MG;Pd6TFLr+qa7n>gn_X0l}8U7LI~5j()#i*<_mvi(ax z!J*DdW{$qRre2G6ZO|Sr&x~0vTKpLgw#~1vQEG8c1Dfb0X}pQ2W2<5cI~`e$GQ$zK zEC+^(q;xkHht2aJAmxsGmYC)dJFSoTHtuPN-O0opswdA=D9VOqjU50~te(rE_$|wD z*re`wC+)RF?SMR!^`VG*$Q75Loz2BAYT~{l&5jJg!r1U18s45S#dnX`e&ZtP#>21u z^1~NARB+1QkCKmG@MhQ3$vDX=-KQO*o#$^-Z}D>_3nW;NZTM%{bCUkBmv8A018(k? z0Ol%a!|bnPsm>kwI!u}<Ni}Cq1h6WujDsklQ?a{gr|jxbiMB6Ftztq#jE0T&s8#Qi zlg;uuNFO92+BbzuuMxhd3;9sLz;=?<Jkcq8DKW-Fw2$*d3kcyW?_Ji^R@++bNAJ z06803<P?<<y9rO$H|YSrRu<Uy0`7AsjFbn8tg@NBwpg`PEP&PbYP{=+!t{K-L2(G@ zFetj<{zI&PmnKhrI>yJXo%{kzv|(gsZ`Bt?@g~d1jemNVf;SV0?_=)y^vsS6hYkEe z6C0^!B|O_q3ykG$ywEq&a@*l!-0((1z3%f&;EsHqeL0HgZYDy-xr@W(R|wM?oguwm ztrrR!3hUx)c-Q(DsT{}s7Iyu3vGMK!1G{{r>6_Xn$c&E2SSiF8`>qpSvHMo!jvOgc zDBR+#$m!ZE8YPr%9PmWTkj6oKc?T?7OiMWRl}KkkOLtf2Ro9Fk{kUPO{T}v_<)w*V zf=V4w$%v|DhQV1n1oVo+u(6R<vJCs@{DSo2>@UpO%+V=H^#ma<_&SW)-rwN;AR=9% zo*f_w;in2cbnH~JWcy^<WMz#j3)ohm>bJ})=Y+CT8he_}Jc+@naTdPA>^**9l$|PN z?RdEFA*cp+)|-sN(<JOXcm3^xajHGzD%xKm4%0ypQ5esnTn~o)t%}S2d4bp2Kw`7e ziv7Y{u2&=3f~%Pa88Cy3@I{=ZhYOR^^^>hRS$kI{A?6Qo?MEcGc0t3@`{>@hZpjFY zEDb}aB4iSoP)hd%(mKd@@#6EUD)X$<sL&aSa;O!xAEsXcEGQkc)x<#)O@7pfMnYx0 z``6$5im#)OMv?LGLWW##cORwP?##^b0xLsSLUhotx7{~#xRbaBAmEzmLA#)ZI>5+V z<$9nI<vslCeHd)JYFR$i{5EpLs?P|U{k69Wj%dyyUzGm_g*Sb{&D(@$_tJN{KEr(1 z;XYAVN6|h}%K+Mv+f~zgjf)PP4NsczbQ&r)Lad&8BR&9Nc||0;Xh>Bz&IeeeK~u;c zlJC#3?l_gZ8ri7M-CyOZUYvl<qVnAYPwJ-ht}=a^Hh+%W1K#|D^SJM!-d9~#b$tj& zQ;SS;Pkm%?wW^=ao8ZQayX~a%B!LdvWYdhSF7CV#XslvbxRC7iePbzWE&*^SOz{ov zY?GY{tZ-GTBUTKPi7?q9r?!iT$vxIXk1lUi$kIB3<zY4uFaMf_P$0BE5i){Zpt{lD z(OF+_m!p%29xgN6x_Eb;cfnB-(=(+ZYt`2m6Ro3j%MIx)*RK??&LLt=CDLckyBL9x zB>Zw~#$g<~-es42hm}6YcLsx7Wo~V!DDYc9Pc*@rfpF>n-L$cFB?+XGOa(*Oh(`H5 zMp<0n${Zj4(q%M0H}RIn<iv!18>q}TV;D%KV{fRDj}ZQ1!=@k@0V>`_sB@C?gehw@ zZ_B(^gD%{r&hKR39imRrC{~EbFp(jrYA2AZI+Qyt=4p?vDy?4H9NyJ^%_klDYW$(3 zfphypv#QwHY9vE-?sZC_3%;3#^u|SqSOBf)`SMRjgCpGh(LGDwwe?Zwyn?9*ys6lH z=m#REx>$r$_)n|8ZNwM{Aa9N6xU)OjngpoiGF1X`^tii9qw~VWns9s@;n$Ra=#9aF zq$x5Uqs=yal-E?K-)Bd5F1{3lR$;>5FCMdfhCe4yjkS72d%%i6Z&950M;>PnDVf_) zxNl%;INGgR5~*0?P1*k$|0)+5%?|h}-0;nyNdMi*jG^vxtOQ1-+^RL<t{f1GDCJQb z@Xav4XxHsH>B&izpF9^&pySTR?N@KSOLe?U7WUrAf3J=88E{_)I9A;~hd&TfneWcZ zULNm0^Cp=m;c|>z*#S~g$CC-fraTdIE0;P$Z<M{afn(fC^5P|SDaNZ0J!PLX__jig zoYEIJSZWpr|LB5=;P<2(4CJ3DQ0fowFRS15Q1EO_m-s$pDS3=WsiVVu*ZDcF_uY=X z64>jQOsizfDjvny3Ba5Y)%qI!7V_f^*zZ@2tTeqVe>PMJ?-&jK-HT6|TB+Oku~Q@x z4o&cip05SMS%|Y(6dpBIroADvoC^<ADg!k=Qz-57Z;aZ8A4hB_Hk|YgJKN48Ccesg zROAZjF+Q7kWQe=9DCY0XNmPuMHXad3aVCx<#wkONNYeUS51Z?i8y?pZu-w0;R}m&q z*Io2$xF@%*4`Uo)Yj8AIk~N>Zz<i|YHn*9vGgqB<dYeyL>#=hhboy&Jp(68Q^BBtS zQzYs_Y&CP3!4DExTAL<@K{`o>-PyhiTDlsEHsZ7w{YT1^Z~ee+!?9xJPFdi&J_&lK z13R+^kK<`U69(}pW#)1T*bSNTqIu<&O+jv5F{byRyr_9DU80Gp<{Vn0NICE5?Wy4@ z2$@FkP~NV;Hv!qRls$n{sbosRv;QDup7g{>EhlU}T5Fte{jgE#kbH|BO%Pd_A$$*_ z({cz(3Q!@<>vTEzm;hJDGr}+nm|}MMI`uHOl)Y^NR#Ex!Zpo2d3bjW$>;;x@-tIyA z@)p+B^_Ig(o`%S`Z9p{CJM33Y#2~|Wzb%StVfcd5rr7`3XIVd9pIA_gX*hdV00hf~ zMb>&qK(N}I;Mg&oXett$Z=IJ9u;nS}93b6%WN=_gb>h)z1^}lb*aNtU`knopkA2D5 zWY-eC54Z-SI~~EkRO=rNfM}1l;!%?o;5nJ(6bGGmUteDb8}MzNic)>F?G4w^s{Up1 z2-mGWt&Egz$XZyq@u%+M$f#%!2v`hFV#V{-CnJqT_Aca37RhOGg3$<N1vzUxtg$KI zr+OQXOH@Fc??v*)Vv}S&QglZD7=aUl#2vuhLs&hk-y;0yQ8KeKkl4}-4#A&0@X*U& zpOp=*Vvz79=#PXDrdanFOe&3h*l1#qxcH$ZKogOoK}$wO#8Jm3X@yNfMM@-3_w)yt zEW}E0;mS#_WpVP=sjx~3h!YW0;+dv|j^-H{2lgm5FNd?w4mU}s*zY$1$?u<CBqc%T zaH+KMRs$qSV@T8Pghv#n!`P&V)-3$a#D~twuZItRF-`K=k?ioJY0PiE<`c0|`}P^; zV>#Tu8yeuP5?W;=dK5Eu@dh2_<=sT5%<F3j9Q*Azr!}kG*H&Bnw8sbPQ>{w<^+?=J z<L0l^$Tv&fLP4*iPN7*gq;2mkcSgPC!fE3sb2{hYaD1gw9DsM=sn8S9{^6lq8D`wb zdT*h2by1~>bk-Q1YHG7~?m*)x$~b7&BHK1ae_oyC6%{Z?Wu}6EtgsWVSy+LmK(<<2 z9-XQ?k}-5jN2*y{K|qgrJNJ_Z4q}uC{Ahl@Qgb9TdU7d=m$v)|8M&g!R()wZMW&xX zX4YZ*3%P}<*Ql8x<IZ7LT`@w7j`AD<Q7X=pgE@5cPvxQ0?BWj{<YosX({w~F0vUKz zvCxDBjS6ZRVqf)1BF=!`ucRt0`|R?ia}@ciA4=RY>#r?-qK~E{E)pY3H^L8o%~AW+ zM$dYJCguVrA}F^R&3F7j&|rc_vfG$@EgdL9G=K{vq)GQMZJb0tjO`H~eq=LGVL4Er zYjsxhxMFyK5K{VyQpD<P8<XIh=*6;;obQAkl5c$T1*H1<m=Y8@`L0qg*&g9m!YiXj zZ~4``pqbM&Yz_ll=6HHO)DUuuOXEL5fYJGIO!U6|;&USi#qSc}`6XuiK~Z{%ei zIK{?oFpFr)T}6oh*XF~bYR={6G2PdR7OR85Yqz`dBG_jTyO(vz-;!S?U9nE$CD30E zh~AFViQZZtov)~X1?0>@k^793YJcN>>U84s!@x$hM_DagN7mxh4gC?Uq9lMmgL|ym zR(o-oB@hOESRJZoW@dQYtRj$tqBZEmdwrEMm*Z;#cKupi^~hE~{jg>a-1ocPEHEE{ zJRBv?gnA6`(GeG0dLd8USgz9$-E%9@pn`o>;DMOt;Whj1N?Thu_Sy~3yu)xi$Geu> zoi*}%Jb7C($rR+?@8dDAGWuQ4Nz3tJlnQ5)o|Jr%WH8d*3mzw+b;bR-95oR&Hc4Kh z#5vQp$(7qy6N!ypLwZYnv<7PsUDstkBYarM^#X)Q>Bxvr`%YXwS*}$c?aWWac^Zpv zi3W7d-`Ka;gl$%#=5hCu2N|N#m5>@T6GV$uEfAp{w6uXO-^qv-W9W~AaSR@JG+WOj zI!=Ee+-$ZHp8Tk}Q#{SDeL=<+yAr1Cd{Ph-6B;z@*mEBd*;^mATRL5}^6o!>9}w$W z@S^D(*-53NAcqMeAhGS&+>XVbQY|>dYsf2hDL`9~!Y*)4x|9@DvdOyzzj1|X`$4++ z!7X3ikyT24pC@BapH5z|_#%%Jt$eWE`>A?@CA)avD4qzQ-&Mf<pgt7`svEOrvjV0t zTaW)>ppe(m$pH5vmS*CKLoZZAcMkeckBWqefW7!j$XgTMK82bOUF(<W?$YZbB9p{g z@D|=a1@_=7J~G|tPN79o8A%AY%n;f4^)d7N*I!K6qJ83`lByuFY@BUaR@b7$6jLiv zu`iEACjLt+t$Q_*XU2X}(H%!|A<FABpX<asX?yY%n9O8F8tb6VZ>SH!1TX$`BCVjs z;?@_4sM}3yEgg9q9V3Qmg6iZ8;jvK*{;IeQ;wvsGoZI0B0?QV-z^4(Pvpu4gA(qG^ zxE+@5VpIx>{HQOl9xp#VUccX4KQBiY{=09Ad&g4tvLSlw=fRCd*$(&J^cv-H=dbA5 zY3R*|#f#TGANE#wXxG3xf{IMAHoCpsRyCH)wajHucX1S5iZ>1Z2-04fp+w;ch%&^9 zhV$<1=4=mzVAXG#lGzu&^P0)+Iq^9LRQkm8=>wSse+s=U=P2FiCq>y%at}+mYQC^w z>{8xw@U89gt#62b`EitBBi?uOGd~j^D`G5S5326-rw(rSzcj?6?AXNuuhweEm<Y2r zP=yNQH$q<yH<~_C8F&($G@3e?%n7aWPtm6poAL%!*Pu1u{BrqkEx<b2h<w39DHyii zPz)hgZ{nKW1_z2d2G7RJtqrfz6Hc|BVirhRTWNC6HeEcya6X*0<_A;DnffB9DrZcw zj|CBOZ9P&wV?W=2e^^%+hd&`Fq#oh_0)}rhK`jk3$&%FuVH!OBQ5c}}ftJ+E*8gqJ zJuNn0i=62=3B@fH(EB2WWNj=9g7+v&Ec819N(j}+e1j9g1T+{3zUbV@95-6IKBpoK z64*NIZ^$}BW5obaIgDyGW%-@ZvN(eZag``%2g2>n7g*l>p89YXSlyu2ZdWCxHXN6P z6oCB8QAITYKUk$YA7-g&ChRaegHjVWv>Y<!yqG>(G6l}CHth`E38s6=^I(TcDDJjS zCx8oduPgN{<J<83*|9#~VP&Hv!{_?A?Y^;-S?HAY?U$nEQ@_JAc@3%T;8$`=l3iNI zdn5TkO_}pzc6cEFk?l=VKkxFx&HJ;To1DJkmRX+<qqExmabwN9P<+&;xF^kHghu7n zV1elRJ(tY83|nWxiR6*VrmmKY{yrOjMA*2U_Cnp3XHcxXaMg?SS-v}DiV?`F4pZ!j ztG33TI9v2?U+^^4pE9_&WM+nESIW7e=XVuFeUBRBZD_Fh$*z#eF6O7@uF+yzZ2t4> z?K{RuY@@bVyM=276=UsEZF?1aOU=A|GFGxCaAe$fREhHYVFlLQ1ZL)E&NG)0M{@D4 zJd12q!FR%9Q#Yt?DsRdg>xCjcBkuUBIR&h_UPZ3O4$>|zE#=1T3y-{0Gap>zd|)z* z$Lh7~4!}^@*E3w?!LWae-&+`cJ8dTsPvJQ0wpvTsKdYli$DZ~shJe=h)B}_jBY$fY z!mfd9S5{=w`ZnKGI9SL+f4YUnVJ&zdlF<2tf{Yd{LQVFZCpn42$S_!_cL@|*2rJ|4 zo)e4lCyIQ3#@D3uedA#XKgcYF<C}Fe5Z`(b4U1ax9_UyNq=i<0M!#9+!)$cqJ9|j5 ztD8#uYIuFlm*smt#A6AgXbn)nrF#59Am+9)xS!=qu95ZSY~A!`Go3*oZt;qm{NnhD zr{aL+@v3&Jh~JhVg9EtpMLqnY3Ihf!Jl7gX<hWpGOPorCq62$Gnv8mcU{OUL5hA@F zX;^=#w@=ey(Q!#)a(W|Le@?-)9{U2q`BjyBcEDEK`-u+7fNU{JW$!i`kq4*WeMn^X zgA+MYvm@ab+eV51!Kny|zM&9CoHDyWSw5X|<ldFkkSj8j;W@AW{OsBKG-q#UtVP_? zFCo11)In{|`~}Eq_)J2th}I%n`Zarjx-w}pOk(Ud8Ti2ul-%fTi(+c;xsit+{m5)3 ze0f~JJbgX>&o7qRE)2)r_jo40ce1w|upx_zlU~D}YnzGlY<UgMb*1tuD^AM(8H-%R zXq1!_V0=Y5zdCLhO((UKF7ucDPkW0@Bwo8k?^ye)vZ5<r9?`wuZg?H?_4VTeu|Xjy zWwZ|VD&d&za&RuyXOiE2!sOsb6mFxgkcVS14&NfmmS(=DRc*h9RJWlVj}G^6kuE#+ zaCpU}KjQrIJ#j`hjqe^0(^labh*{F`K;NxnxniG$#wu@aJh#*Tp~X}qb7@2M!_m+A z&551AzSrVPV79kw^qdbpNgp(Bb}-<*&)sxqy2Fwhsc#?2@ofO?xKn%ZFn)NZ>JE^; z*Q(a%`8ZAO<?Ssff)OU{&fm97p}yyo)=TDTKIkEUo2tm!cllsGfZ~&jzK=mstKMII zBN_Sqtt>fs^x<9G)rqh5y-a7j0}n*>wD|Tm4Nqn8)g!l*^D2Jp@pE}SJ&R?cPkzwN zp#<J*yVd9=2&dJMHj3H%WXqdSjUO`)n0*&Mt1*%0W?}5aAy0`SSUONF8L6=J;;U+3 z6obDiDJ47-VpDxo!d)f-3;P)&8I9NtFAI6m(Hv_+3|3PHs>1<&Hh%!COrv*av<Nsx zF=hd`uQdFjU-bWD>aC;NXrt|69E!V3aV_rdw76SwcP&=j-8HzoTY&;ia1Sk3+^xka z1PYYjy!Tu8u8%*mkW9!-&YWkT^X#+tnN!1kFFSC$y$ZfaKvm53(gn@B_CyIl8Dwr` z-hwQR86My0QM)`$+@hfpHq+zLaQ>hR-iu&7yXuB+U9TPeF%VnIq1v6PdcsJ}X55an z47?xa4*QN`WXXR|MzE6-Dw)DhgE011lQjY_(__an)&g~A+%~j_OhqShuFCuBfXZ(t zyB_kR=5p9J_l3$k_ucRxrIyic8h;F^l!r)j(dq6LJ&xje8@uNnl?E-=(Acio;0x&X z`7s1@l0EAeQ@`Ux)D^t&9L4eH*Lwx4v!b0sW8nIsmKbj$%>{Is4D}jv2oCKvp{1A# zM0zV%O~sPR+|1lZd*1Y$M9T^aND|J#5`osbBaU`#Ay>Lp#8fQjxyc{nrWm04`aoTG zKlC_9>AI^hyM;c--d&;H4u5URATDIWT*4j}f5%lvT9`TO#e|BwN-$exb`D_RXz{+I z*^!MoOoEgLxO;LT1bRgcaF#^39PO25DejSM-W*Zw11%xIo95PxE8F!E6L@CXuEb=h z$#KU%o*wV1N1H}=zc_O}6uqIWI-vApQm4}idN24t6gNSlM2mo<<lN)2TX7r57>4+C zH@~;oth11JU*=G5XtU5YgI`3S|4u1!`=>^>4o@k0e&^zZ{OJDvGvol*zxTX#C5!c^ zV-_SrL}TyY>bc>+p_d-NwP{1)OA+zs5pP57rk$<dT%%nYpRC5?hp+a!NcPtpxoDd? z#*&z+$M+ZPEk_<a<FX>O$-QZMsYy&<2xF)|Gx$<rj(kX9P}|KkKr0^lVNfi$9yNeB z_{e+2EXhRuz<G9^a-H|-3NMe8oFmYONmN@$<3okqn#lo#b95?Jd$rW<1ipp(loN|8 z`daKfd0#^m&1saE!{3@Ghtnu3dRpx2heYT&yImmVC-4@jo9MjObZJ+Fd(M6}Mo2u_ zXVkO1l-*<p|NN=yvfV)Ru7HI$i$5|y=~v<dTIOU!pmH8N&0<zhZ@yZ#NZf~k?kI_? zs1cMmGm|GI?dcBm#36+(P`%?Q(l%8UfcbBJUa%s9zTT6iK>>zChs%nUE>ATgA%15V z#fH#mcF*tj+3t-KmAA)haEBHPrh@CmoiL2cZ@AzSw{N}LIODNtlF&^Bx7!T2|1Qf} z@8w`#Pf_a9G_m#Wjn{BubB@|@@3%e#ckE3Zo$*DF{g%*FdohWqt$h28WbqQHkRGd* z)f{8nDrgK@QP?Mv3SWy*Ks#0BU6mn6v(Gmqf>?c`^bwso>#4CEQ&!y{pu@{Tlu?oE z?uyza3G05GwG|{Z+RQ9kTHm14#*=gXB{D|jb<Q^DB$+y0C%Pg!=!{st8;??q2p_dl z=WC$no>;8)QX}e>abw!$XUuQUciH|y#gI8M?D3m>q<!CYy!0u{Cn^}Ym;j~XM;j$Z zPNy7KD8jeL;q9xDa(qP;cHj&+!2=l66QWz-1;6dsRnim)M#)H%-$sf-wNw<ldl2C$ zYwUjM=J?y>hW870Taa{25RLk`y;>unUPF%e#{oDtfjwuLz<I9iihX%dEhoJBuXIcp zn^Q1D4Ju9uKqa|%0N4>o(`H6&+2o-Fk4Go)HMX#5KMxxDt+R3z!CZhmF(P9DAUP|5 zv!ttU`oLU*YPAI++WN@@R={xq5m%&A!IyXZ9TpQd&7-0O65upf&EPfYM>rwe)!DSG zaO3olF{eRka*QIL&UPSLOur|eTToYw$xfMZo#o>+Y^Q#@863<tr{sES(s+M6@hC0o zWgc{u6bj)HbI2M~9YdA!Wb>T?ge3kJ7;@WFvtblN^m0v;jU3+;buF<l`^XU9uutXU z7%P|joSs{<=|M-#bwBuJU%nyy$u6)*1X-TAlLgC+v`}M$k!1BFgow4$i;_S=Oe0(6 z`Z@r!_bfFTcd`aB+)JKSE8cF#n1jy5q>y@<xTSeFf9>lde@VMMi2P*oPfrjTTWs1} zWgFP`v(8M1#%1gyW(3J~`=1Hh%%Vq0fK1{Ovw7Kdu{+jLPby{cX@2D(&!NZQnB44M z8aJV6EKO#g7AFGKT>cNg9pC&_Gr69A9e!LHj48U8fYX5i^Gk?eo2y+JXJkZVTg<GR z{EIic6Ip*E8<OL~M^U~cQ7JVYc>m}o1?`o!<79RW*`;R8e3_uCdE*sL$Qi%>i8&gT z;WI<Z%ax2n=uJu9;3D`IpCkC5wXwc)zwKi)Boad+%PX;Mh9>enHn()$7jW98Nh)GW z8jmWYzZxUpyZTGPqlklQR`QR5xB=hy=avQJOsI7~zGi0;R+3_Uk6H~iN}6HGYmJh? z5ksUAJ+(-hW6ita75}?4{PW)*=<dvmB82n<7u?W%Y`9E*CHJXz|Gg~oK8zH#$d{)2 z&)14Uk#Fj?!8poG^rKcM?e>~UmiKGkMDq7Zf(HbONED#uD?nx+7iqItmrK_3>v`+V zlKmB!fQy#;8XFUXzn@$7yqDbrns6<AILvJEq+JAOXG|aGb+>2^sQM%rlo-W%qMjw; z!!;4AX23Zm!+yY_d5hG#k>Se@%V*MS2AM_qz)A6K>y3ye+v=b-3O5UHCb0{XTbIIv z8$E>&hA#M<yS0AW?=j4T9w5(vB(U7E*53r42@+421fxth*ouc9FZKATCuzIEZ#80% zKJW~e-R^tL1FLTCIf4VCv`<aP1GpZ<W%;4d^1F`EZj6$7EJ^bSy9xoRjyb?<UoE4D zY5@gPuBBIggBtc@Qkm%;RPyZI+}Gyj<}t(fhhoi(BP4&<h~UrBO&^0onlc*8Nk#*w z@k|F}69yW6ZIvbcz%UKZUsXw_y(VUfnH~__!G;fPot~`b>tP3c`Cids;uVD&?Ey+f zE{}0vw?;6az7{Tdw1wQ%M#n)j{%ut3=Kk;)_2jW3zc7UFvUEIum=W+irUh%w(=w@w zAjMuv;u~ei1dvag=Z8m|zNs#L{P6s{?h=w$hH>?9#+Edfmb`&@DRsd>8TvrlcwrcB z>?W*;iNU>pv3@mEV4H=mK$sZag$?UK%y0PAw!d^lWpWh(<>tKv2<&PKbT*eqDx=ZT zD$1+|*85I2suPUm!?zHCoI(s_ja))IW}e*5V=Ekdg$xOGUQ7R$qZ3Q_{z#l106H!F z2D;E%4E>QSaAGb%ORCUp>bO>(*k<;9A2rG0?g^X0+WxJTNojbpF#xp`bPSKZefT9y zm{&Q@I_)+&3+E+QrdXYV6)bX_Ga(rs8|0Ursme|kpHPw{knAZR2tz_HgD^LJ#QUnZ z<JYUX#&%z?zvbO5-#y%7siZUT$X4tg6DBQd7R&A&<3?{Txeei?k5YPx(S&mqdUDT9 zDV%`c`gb)~%UKmFgNGP!ILdei@wOyqMsjVvK$c(SYgq)1Na;THPyV!LGla`y@p{lA zjsOM<trR(%9Jb%iP%DFI#5jzFgr~7^M80tb0~7(QNY%OXD?iUJoK+T^bbxSLJ*(u! z#Hh=aVBQ~bKR{r@T4%ypasJu?JF?7KT3S8%I?lILSJ%*R93K<o)+f`4hf72WhefI@ zuNmi{nv_2>a`}|O{OIO&sdh0C0#Ysio;F#_Gopbn5LZq`35SeCe&QB`(iiUb`J%b^ zmulc(sBY8d<>OLay-rO`vt`S1U2OH!qGaIfy}SR4@#SX&9i8k?v`VjwEZ8uy^k_yc zBuNJl`j{?TfaGqmcdTa@4XXQ%Q&u(co#tWL*do$w*q|MT;6Z3qFir?YYEuAe4jH2G z@^*L^8CLNiy3orMm*x7eDu<72DFCJPPy{P5&<u<bE4Y7<zEJBh-AYFSxqYs$B@rVi zBtEv1td8^ilp*rPiP^!7;6?(UY7f)8*CYjpYiq}lR#i|lyL-H7qk<(OB|YmCDP70o zrvLhy>BHEqEyqW9`pqr$ci9jz$s6aN%O=t*llaR%q(6zA=GjbzHy2Wu&WnEb4^qKi zU6_4+8ixzGPQjTt;#l<FBAmtr!>66e|0<ZT*2?Ixscz@{L{JxM;qp^dy{Wb0c4b4@ zWAB`Eb`DVo6H%d$EX`Ya<C<kio2^P0nvs^(Wp|fjX2%H6zqG-ELe@=pe3TETur~Wg zqIvUwv}X5VE2bWJH;PEZt^31S&f7LA-kP#tcy^r8%kSKZ7qno_OV9qk7M!n_!IWC- z0ft}ukhv7_N*#q^cS3vjNBhFPmr6ay+yAhAk1xT}aMp*6h9qa>h&bnCB0?rfOtW&N zirnRR<c3J{*_`4FnPb0OoWkvDS}*$5JT3z<QwLk|j`KHvKAlM#7Pw0*X)0Py#8%hJ zd*KPt#O$GUn6#Y9aOgtFoVF^+I;RaiBkd<KNn@~Q=i${NkN)h<H?+Jxq%h3CE_0L) zqwF?o$7{lQA>95q7^`>OPcfYzrmRHqX&^}`bVtbZ5S>N|$9KQbme?!-Zu4}!Zb4$= zK)@lc^ppuxPL2@ablJ|qEDTHNAGuqoDX|g`CFF;9e(5PKW<7xoIc*DLwT$;Bnvlkk z&t!1$0ZcgYt+T;0{epgv5in_Hftm7Pa&RIkR0wq3^#-y|O}wblznB$jR0n&4RU?86 z9rvik>krzD*{9UopQ#fsJuEUS_D$>=E^7=q^x++|@!!D7R9fzUBmG&YtRBP1J-2Bw zrWc4PSHIyva(qw1Q!Ak7qdXO4>Q1csM$~|}a45|2Pqvsvz9_C^>rDWuWth&B`4A+9 zfRvQKm9u3S9h0;>o&{6Wm)=1Osk1P(U@Mdzn?@`_LTZ4-obB+6*{`2WWW8}nj55mh zj#C6x<Tu#9N%^`F)z9OlJwdFeIk8QaGdEGD1<7<tx^kldNx)Wp+J1b9YOgajTCB$> zb_aW|@~U{|3ADkrkKKH(<%udLZoP{Q=?nsTW$%rWvkSntlHe%|wu`ho78vWLsnf2% zyWYo~i9&ovfnu(+)`{R+Lz$}T4iCah`y??^4IV{@5zu#$O=zZaPq(T$f_PRUW7f22 zcmHoilQ3FL!l{WuKUU6*`PSd-=8)8TO1U!KaJzN14fKRV+!)&mZH{t7j<P*nP1bD9 zYoD{8BMC$AU-l2{&`|7GkCg%ce-F3_H)%%Sqhv%>Y=OB0Ed>peotfwwr+gJA0iieh zkzt9Gy3$aBWGW&~FKvtl5%lo{MiY)PE!Wjb5vRJT+d2Urr<i2=&-F>Ai;@$2_Eq$g zQFWgm`&*IDrUoVk+WeY-tiX*FP~3WeLZ{TDDP8JsaM&p)5e{N(@v*YE?W=fFI6WW* z^<`Wb=5U!wH7<pF8&hKjY}s@CW4Dz4r`|y0Z!0B{@9BC8`a<^a2E!bpVa^Jd9xFSk zH0a8j(|Kg^z=^;C>H4xAciZ^#@D=*Zda-)Ell)~P>Q;vuAs^?=zwMc&p`ZIuTTjIj z%=)|NRHObAJ(QhzNV7tX<4dEcZvBXTc76(qLwc-LUDVqN%O|lGxxgx#Xe(ru?JJds zQ8n^^ze}VNp_`9H8?XnND1B-Y7h~jxC;NwjZ-2!@e09hF&Q9-QQI1MG@o}2kT9$sJ z+3j;R-1-s!Wnf>lvgEI*<kMp)xY&ZdIrN3;q%2XpEh>RxWZT@!$7SG1u-|@EE9mgH zWccMNvDKBJ+ZE!;&O)qwg<Jj<KaOkSAtEY3qBYI<aA+PVwTvy1@a^@iWETV0pX7S^ z*LLGiH4%6DFKQk-`l-<yj>$$rJzKKnUFcIS=A9KR@|D8;VK4VO>kHYJ-~->n74mXj zj&faJkB8Hu2WX(*-uGY$hi!jkPQ&^#T~g`ZJFlRJd%yBm=FnKKmn%kpEwq)pQi?Dg z&a#6C=`xxDeX%*$*;3s%o{;Rz(LgiQ4ew*~-463-HnT2HNUZxHX78@NdUiWKBJD-M z+gN;9&z_X`azS0}27iX$VV>el*4nOwveHT56&q&)b7+E?)RR%rJ@j%U5>?~BP~Ag$ z@7_oFu^{GZNDI}OYc<7Whdy+2*8g&J*8iayy4&)4uhMhb7U^+ExZGrvQvHK-<1sfh znug{LZh&nT8>j5HOq*s@@3rg0jzEFugP1wE<aLR}6NUq`0$*E@e%50u4xIF0Fa@L7 ze|y}><jH_e_R_&4&E@m@sGgfc{@}ygAS@f%YepJ+c`aVRvfWqQpjzI*icm6X@h zzSo#UnA{Q|_bat);oJJwyQQ>@z2Yz>02Cn4m`<rAdaQS<oAOAe6ySyJK*Hr;DpzIZ zudYF729gN{Ei-$Q%zkCglX^Wb`L~`YTi-_Q|DCBnKV+MMjl)-5J+5~)&B0QVUI=mG zgo%uK$AeT~27~#4J*?Y@+m?T5YGPZdFgHh;Ds7oIT@-%Aa0A7*y`kU1Z??a|#C|@4 zq1VQ3Sh>aD&~tc<(M?^kz($<e0T6%rcg-!RepfvWJ(1hJ#=l2bc}_!zyS^of^%!xY z7Lcs~g8xeox>S?~(j!e+4zVjDJ!l^7BZ<(*Hn!n(R3a3jRv&*Ggc3;pfp*5N9#r z!wXVflGMcTyUMqtM7M?7_4QlqTXt!7)ZeGDRyfI7ballbxfrI^5ntdQE1$#H)$6J+ zcYeL-WA6jpZ1)|$$j8{gxBjU(?w#kq?o&b!{Dc^Oi5OSvh@$HKlR(9u_sRrykOsTq z_k$$nG<mw<C(FF$I4?}x7(9N{SX<+?ii`rqI!cY=4ed@&jO>DvI@3iEdNqRm2ObqC zJ+lnTT5*ukXB})feaU@YQIcnj&_XK26`%C!Lro6i1}8q?-JdPBkCedqrF460arnWA zHA*TT0jHtsqfF@Wz8}Y_eebw&QK0P);zR|0At3{W82|6wn(2Wgqx|ud@ALC|4=Ley z%-*mOMMlFJ`l$W22ZnhbOg(MVoFn~Z&|7k;egL*QO9DlK?^@+%UOpRs`&K^@5=9Qo zXj$gbPbu}mFLdG}h4`3b4NJG_%8C||d6q)wQKBp6vgGyCt+Mft3a2|fxmbO*1Bxb0 z@cYVVJVlTgt(b0Oa6-D=<4p{Bu_;fp*Wye#W5KZ99%_zt@^t<sJbApKw_(kWak$Az zN@x}jmxx+A2s<J~q}9>fNomuzI{}iI3$nesy7JO44&*z+M0wT7V%ZU8zge;qJWO#O zkL-G~c_X+ZY;km2V^&JA!C|gAdj+q@CA5FLq#$ZV*s`1QxDUfHb|)LHsIbMdMKiVf z+ZpFrNM-*qU)V_4@!u=N_(IePn;(E;1s>ccw<Y;7?_7Shj1Xo|3Zm%>+-#UFIZLhz zw<-mw(*_L_DFjXm&EwZ<iN$d`rQ}U<172_Tu8ShB^n&7YO0^7yCkrX}d+8|Xn-niz zpQIuJc$&fwI~E_Bu)jC<4I6!cXCLIUP^2OHkW>oc{{-m0Y?9{8bSWOWv)QKd_cfIE z_98bQr_`=K&if$BkPh);=~Ci!+rC8`N>7Tznr`2R_7-C#2|wl7S~@t?Di7-3`%ZGU zvb{y^O&GP(Q_Swr!AG`-dka=t&XuI2;)K(>m)1Mah-USd;JeDYgA%^)+LDQ2Mi^Wy z*0>3=kxG}yUs|(qn}F%<V{>h3JZ!BR9bDWxVdXqil|(K%PdBcOiv*7K&|gVN^H~@( z6)GdgG`?GpVD@>N77>J4e2i@`t;U|?hf}fpw{tg;LQzbumm^`+vJR#yn#_V}u~vr% zdf)@8sIBZ0y!(j$TW<pb)veP_n?6*$L#vM#i;7`<sw&*vAW(;Mf44!a-m$?2vjKj8 z;BqC-CE2lRne&u>+oZ_?T$SEm&j23TmxNFi24`{b*v~APN!|p_z*%lUqMstf7=F{= zz8{MxqdpUE6&^M0ky}pfclVX;?PdBxp>=wreMtwMR43oZ#<NQE$(yv<1LVs$%I;0H zJ!5Bx9{E<TYI`C(;#XaWQvhl4uN1(*@}V-a#@Xlgdg3iuu!-+!N*-?yAk6WfRhoSz z$mp*=%11huJ^1`;y-_{v;o5q`e0n(9+4(!Zes@i+VxAlAVQ#wBiCVUER?1LL**&$q zihsbm9eAbsW-pG~n^+`bCVG<>Z}t2BBoxnuGeoZ<%cOHEI)QTb=nQ9tp?0%cAwc$g zg5wW$ueqBI3ju4vtiHkzn;+A{b&KrPac^3*wuE%>4XZO*gM&&vv*K{9%}Sj*MD+yZ zlMy-=Sn7PLRch7fM~yP=@wrE}3;TIetD4K~6c!z7H=tMW%mpAk5(ezlZ!|TfBHq5$ zN-0`P?BQK6qrE#EWGh)bUFm$yg-h1pSuN2nQtd)(l<LN_@@4C`k!tw>vLNp434XPn zVpO%^Rt8?zGy7Vmx`(Uya!V!p=G}O@O6}A1?Xs~hdekyyD%~f=H_{nCLjCrq!zsF| zRlI;BB7f7H_2ype0zS@-_mPsk_QG$=7y9ZLN#-^z=UBX2qgKL_m}y*wpC&<=rlLhL zDn;E!W%dt#k^UhCM<9fa-Oj};SXZMYje$uIHCm))srxEiCmS+#bNJ4S0bFdDQ+6{8 zbOf8cgb(3NZ<MPGMZFv*USkvhy$v$VF+GGUS}jp3PoRgUmq{88XS>Qek`o7!=76c- zFX<wz^RL9EsvX<-5ae4w^qCXp8_ty^Mv7Q4Un<^<5gY9W4AG(KIr&xgjQmczY|)o_ zH%*^N560g$xvkW$=uI<B2H^3m(WigvAt*WVho5ypDnZp#8%GjRFk_!oeflX(GZFvV zJ#2k$B1VZwo3hxFKn8z$5Uw^|cK%0G8sZAH$!kh#48Q?yDCzgRKYT_VhC@P0h$>DL zh+SlKe5k^5Tu)dlW84>MZMdQ&sAr^pXwtd8Qq&h|!Ql!~q<*yzNp%L+Oa03CF-4We zJ#tm}?d`es<p*Egh5wfeP$Ou4L{51T$!oL$37#1nqAH}-@kGTqNs1O*{A{bwdN`Ai zq$OC;l>d|@miL_jIt_gnN}ObfbCG7>5-n!9s%FbL2{H%TPM3Vc;^OyS0qGtL=^}}$ zj@n;)yb=tTn(PO;g%-7iG*}mN2#HC;>Vr{#E@Y83B%of&+qmcO;WctY3O{n19Pt;e z37DSiHVFpU2oRgSZxoq}PBK|2{k&YLt{ade9xlu)p#RHIJa~}iVzFLvcL}Xn^i-Ir zp}N_5QU-k|)6<F@tczaEUP!x_)wOn#AVVi+Y;sFqK<3;t4hO<U&_B<BjT8vb6xNrg z30LOW>fPB}UNtz)VQ^<Vq^$i({+(n~aePLOsI>K9xck1@fc@)8y2sYcVIPO!TZ%k5 zoMHo$Kddm?ShCx~)oXiHP|<q<zFKX#1GC<3I3Z;lTrlK~p7t#!98Fn_LRj6zNc%$B zMF}wRR+&gKGu2VQqms;-_z=}+e$%&$Slj_>_tgt<z;-wxk3nW8bYl7DJ*c!*!zjzX zJ<Km(-OKBNo5r-Fe`<dQH-WR@;D5OzGWkd20t<4Cyb{;CFg(DoD?L6yqHCYUcQ?aq ze~m#@TQ>mlr?HNeeph(toe<8{@HrVd$XQ_NK%@~tqL|C+dhkriX<x2+TZclu9xu=+ zlVg5}kf3W!bujh!pFHelHn2c~*g-L4JIC7;y;j|t!n*Xvq-qp_2US~57HGvDwt)Ba zZNv)Oir;enLdF}tZJHLoob6+dpN2h=Q17{)Z3t(;cYJ=0;4$lwCiX?2Vc@4v`@7h7 zBS0iY@qmG+RkeA<qPeOf`+0=+eD**UqO;wA1QypnGl9h4#B{LPyxV}B<$=Idl$}-^ zT5Q=&=QAf~cONWE{IxO!?M{tAxO<b+HapcyXNI*}I63DW*~&b~iC_DsE|rnA`aiR> zWX)>+7#H6u-+HTy#F=B)>sZ}4L1$;iWp88yRw!0aR=)QB@JG7&-8OweQRTtIAzw>g zL7JyK8MS>g{hpeNPfyRSAdORoXm)gkGWD&1u=nU?8iaMhiZqRTKm!<lQ}5D`q@S<1 zVWz3xh|(I<;H4hgC#J6BAPpdPn;Mf=s|`NGY}cuCtK4&G+c&7wwdx`Y$h{E>SW)f8 zPk-afB+SNe8N(WICSDg?^!(lx#eUUry%<N*XrDK9={g5X?g+`Rm1KTmju`5wFRJym zj1TS5&dO;PdxgeBKD|Wc$Lm>G+w#CXLk|Y;Lcv2vkfBFw6h<<rehM7<xO9fbQ<Xrk zP076@@(#w_WwiHvvtiXN@M<K%Z&(xud51`ia;&<I1TeNpOE5UxhMeW;GG&!;4><*7 zCl$)d??;W0s;fL~^q1q;R1%-$d4!4}1T<+ks)b8APsg5VfyV(O$yv5IX%75ih)%;A zUBnrzY#W6cE0yyf^IXA%j=rjfi;)%3v!sd3DajG_+O_15$Q6zF^@>_X5eCTa{eIID zw!EO8oKYWBV7lHv^q`A15TE^(=R7W)WP0*O)NTV}gkJUmXgeI_%ZlatHSb~jwjR7p z6q^C5CZDlc#rC);aT*xW)#HwZ;Z_@aJ)sC7wiK_N)wYXLFZ>aH&j4@RrLK<keD!RR zH1y+J{eHRNk=>}Ana1<iBr##q+IwrOjk0EUU$+NU3JkxA?T$z$veZwa5}X%lU3v}f zI4fzMID*Z+T14+xWxObBez{l(raw3DcpFJYhzUOorKH;|+n8G%s}MN?03*wf$nWYO zEdnBsPGW>8<$Qk9D2S{qav~~+zgJaoc`64nEZ`a;L*!<RAOb#`(u{Ic=W8u5*mizm zvx5<zWs8XhsgUy^dO9PRqhjVXB)}}4`k=POg>r9TI@miWa=@}nr&;(TX53FP+YqJ| z5j4$Rhw}Oxx`GVXb)LJ(!;~e&bb8kIusj@d_K4}x5{`24W#ZQ{?@pynxTQTEPMh3` zB2A3LKw;j>h$`hOd>y2NznEi;YMihs>8xmYC!%Ivp)4xx>dwiYhRvDYeSVz;L!V>_ zvJ$P$FiA8?_26}Q4Ke1_5!*iJidD9#ewQURm(m_7W-S74qy8u|Xk#JVv0y0q*nzL6 zX$g&;M!eUAbIZf%yXNeSmsYLIQG4i>A~d*4_cQUdu2(YU0#i?esL*rf4*JUKwc%|D z<9?Z-zuqHc$okl!;LNDdN2}vx<85k{rmfTgTK9}nHu~EirIfVC0Zr818(iTqX3wJ@ zPjdSi!<X2S$d0NTY|sTe<PG)=+R34@c(pY5jsbn2XGtwy0$)R*m*$7%>@$&H`N!8< z;W-<DIyyQ;hC5x2g1v`UCe@cq8IHC!X0^JMWykL&zI_zIFw#54JX~t5SF*LwfC@FU z>vdpIGUi@qd&@4zEQ0HcrkE4OMr?wwpLOfh3R(4j8wJdI;(oY-hx(D(kMUC)S{w?A zZ0l~&?$2DBG^y-$WWvIYdm^3henF^ig1nYJe5GgcYmHQ=+xPn3g)p<F*^ZmJrb8g+ z0?v$qjcdcHp0S!+55>CaOn2hCp0P;shrx9b+CipcRQQb<0Zg|#PFi{K;2ybmtp=w> z?O!Ipa>rk=z}RJwn~4r)IKL=sdZL!R1RZ(G1?agr(rrMn%Pjmw5c8O3WPC*Y)D}j- zVCj8+zDKXE)`QC)2%Yy`p5o}}RpZETV(fs$YM!m!&P-Un6F4)MijKAaSb?b^HJ{fW zntDpEO0XYCK=Y}w8S-sf0Io1y8#3TQ3mO_Lz-&mZb<~_|Z~fFEOmMb2C7=18WLqlm zJFjPtBLj>t?G2|wKBepaQ_hEput-}6kYLT{>q7W+sP}Gded~}>I$syuE(>^AS-{I; zQgL$j?W$4s37S1*aSQDX?719SM7YXPIha5{8{}F&)7C8^7KS;e2SKQ|yB-@>>ouIx zr!%~PZLCC<<l<x-JNggWS2Nct3kLafXDh%lwNO+KaGx9xL>92tchW6a8x(wgqq%=% z+b?zf*ILA;x_wG~*CJuc(QZ7NiUNhz%h01TW2Lsw!0V67Y`@1r$+i$Ieoq>$#nQLD zca?F4oBKt2Irr?T{fO*@o7-}JE|v|-ldTOtMn_}>X7oyjo>)R-7$Zc)AQta^1pQmI zU<!IRa;Cq3U>footD5geg7`{IG{&Le6}!*x#9U0Ebg&s+iB-ABq#bFR1zFtyW6m)9 z@$9eO>$(eL0y_QXt&xqA1S^QVn@JVl`+a-1Nmop7MD(~WG@bRyJSHD&h{L?k;lv=S za{5##V^pd-dvI_isdqcr*!QZ$erWI7bDlkbMU>6L3%f1h#Ksd9mTU!P`<>`Kth)h$ zSlc<ba%0(V_?z$kJ-_ydT_k9rV>nA|z_I{}FnGi<s-P5ayl45INEn5YpZFK2??+Jr zv~yqk+^_r6FLgX)ZITUJ!y<9d=GzxcF#Kve1qW&7IO+r%z1#t9spN&3N||&H(fBiO zODZnWEwpI!`kO|O%49nG#pzHMN`Q<k>(1EwLbY8qw!m304O!%!VTGk1$FmuC&w9PK z>hOGE8{iGd@@_^2tn_Q<l}z%(U!+zbBp93crTm@nZ{r)8%k{rFi)-JgGgf6OKvBZU zvl?@v!=JQ#J8B_K943!$v>Qu8y4}LBnmK_AeFr+2As}i6ucDXvcrI}Dwix68Y?Lf# z>+%px5;E_q5YUMiuHstBu+K&O7=en(5>Py8l6!)xWN)kX#x<N`!fUO#2t8-Bk;o{! zw@wuGCa}Ju3I+M6(XPnEZEg`p3QK*-vA`^a5X^qhZ%kKX3D4H!?Gusn+BE!dNv;e2 z0@LHmL{MhA+LDZRqH6D((prr+wq*2wdP)jaB5lUmY}JrYLKmDZKdKi+#_tsO9<D5> z22}FMCoK}_T~((K8WZPzNv~?L(ONv`;P}A0&V&BX0q$0)N=?017g9>ehrNbx5@9xT z-0fGWh(b&8I{|fet_(kiq6dP;Y9;c8Nk=0P5atYdixA(+`W$l9h$qgl!b9*S4k!B7 zJTzE7-fTK0C!yEsPP(ohj}KGzw=6}9`ELZg<G#>DlmUSL4@T&O5%n0K*Sj&QvxBQ3 zeJb6qu~ZnMo^Zq}``sS)R;=zu8L?Tztjm%p`kcN7vfqS>%?4zZYm7=<N`!CRx!^a3 z-UjVAG2)9IY37FCZ&D6A28e+dABdQ(+)_S?1(2c9x)T}PH+Ma-VpaE)e|?v;b`BUi zw<tl4Dp_IM%-0c%n3_3C)m3ZHvB}|`d2Bw+&!@gWsn#x}pUBBTk@8v7146%mZu5QG zu3CGv$D5nR$!VWoJ<v<5(3pdTK$^H<3h!7hAu-c-7vo*LvtfN!V%#Nbrk-gj=CX)S zlcKAx47?<qaQVbeM!-V-CnlOTCmzy<DDE1AFk;xQrCX<}3#YD5g;OK{xR$X%1e6d? z{gF31uA;U6GpW+K(^6;a9;J}mUZ)6+qSwRXk9~u?Rof6il_b%8Oogc0f_pBOTnwpy z(i<slJh39J-U(MltHW%dZ?YCkYRTnoXbinTS33_|XkLf9D$!ooD4Pu1Xe=c5Osakl z^Af)Qdq+7f6m=_Ul{P(qYc5&2#?}ejUPmOOZcrmzgX^`re)0OV{_oAjmn0Z=4wY@% z`P0AJzgR?_wE`i4Eva)v5rNtC^S{OSoc49XeGP)q`?VZ8(NV->uUy{7P44?^h(0uX z&h=PApoFO%m3M-~N-9mxdvU%^wfv!G$tP3KA`5C}EmMSbWcC4HOkfZ~k!I5ayB}=a zIc;g4yP{$siXbW!R+Gw^RSb|uyP#2;^ifs*sr?(b>R(qzY?pe=1H$@FFHu2?MBqHm z4T!hdD5k2Ze%0yfcPnzErhLriyMq7*Z|Reo8DC9DYsyvtkzGA<!GU02KIR6jhSsx= zzER9WR8F5tA}P+&yq3*Jsgn4BmAJ<ssgZe={qYH?ZRrqIF$_FWFKfCyP)lq%9Ln~v zt6Az1sGhfa%ld7$fM>|UB_-<C6gxU3i7mDx<RBdLrF+Kq)7z18-$sU-zZ=-;kY7HS zpVxfe`ZYU~=Oj}rUa85?Ff^QCPPuwmV5t-tj;7R^*UY$rt6s*oJ~l@*4X#5z7q@7{ zYjN{$pPWMA#iU<Gu?M{eiEqdl5T_Fce&|qN4SEnWyy?}S(qPJw$27uIMDHa%@wSU} zX7V@b@hGX_&Q`9f|Cxp(RQF*Qt@ybJ-6`srV@I}-0>y)}%wXxGuA?gJFTF%S=jT{f z3Z4`J<?vtSmEpP8aGfcq1<|9adRardY1eKp`Ac2)1yK5_f1ieVAE;zo*~H50d1lDP z2??dpwVlyNQu~UFG)(-CPn2eKq908JsiFXl;fh}hc{g>-h?7A!WOk2cDcU^Twu9nI zPa;DNf;<GVYDWT*(vKZ~V7OPacVs^rK1jc5F#m8QcaOvAaWq^+Z!TV}ty!l$?p@<l z*J8mbAf%g#RRpOr?w_0e#}F}Rx_bC^(GM!%{6jO1Z^tB#(>bxCigIZmHW%ADwV==E zO(~(*VTXBU`-(A)tEQ%=r;f6~Z=0&krwmeM3Zc0vW_TLo9mCXLl=Z4k_joIBh`C3| z^VY6QoU_y(WZ3*QjZaTkNQ7ee*fBIzs(sakqk=scVpDPq8@?0Tpoq+td|VBHYKgq` zf0^vheE-Fypla{XB`yD>-l9zQm&5nX{eB?S=U^vAP-IY{2o10a&@FpmFTMfk0`?|# zqs4puh&42qFh%~Fv1MDqV|L*Q?_-<A@^-Ub>~NlMphq~H3xDRiRH9Tfi;ch|JppPJ z-CsoCq(BQ90k(FD8@XAiXiFMfV*A*0pC_o91A(J^4T#OGHXxuT029KCFR&r|wHk*1 z3ERy#n!C9Adn_tEM#W3bcA=T=?!1dF&;aa9Oc*txYy)i=Cq&Oj%Oix>ul;_j*0!kx z@T9BW0azaM2BTDT!!tdRE0%H~vXron<LN0%%nKs~?QC(o<{o305ejB5ag<AOQZG&J z8ol%NA+Rpfpa-oHV-iLaSs@>)9{R)*`J0sbo3he-a!Uoalu9odI`6sw?bf7*=WoK< zUM#KFbkb(Y)!gO=#H^t?kChx$tf!h?nz<N}0pdR~44xW2kcuDco$OsgBy&m*FP2T5 zhr~aYk$D~|U4ZKRZvs*@J-OiYL{zHuxCNr9sCVBq6zcaf+2=kOd+pr9L+iXzOuSql z{ZdM~H`7;GlzfbgvrhRieIJaBMB*58KtI5BzRM*B3yb14wl5QTd{sL4WW5GNEVp^w zSnA7M_5wZMn}YOh!j_5|F@t*C5?@nflE~w2ub@tHCi1gbF3w9nR~y7t%zAH<rJ%~j z?fN}qvW1LY@3Ubj)vfWvW1nO|C1?Cse>E}gm(*{A?BcF(F$UBnTNG24yrT-H<8{CT zvrgafK;*+da;nK%9o6kP?ZQ|qS{{T2RCstVxTWQGIR2?x<4JleBOfe2*PZ3Ax^%P2 z(eH!Xcb@IHzSyYMfi!)8h`>!6@r3BZ52>cxA`4)<O@(MW4@?`jF??;LKv`{Hxp@&v z5EGW0!NxCfox#V&Z2+=YI3G6=a~L4@9^hN4ON)MbSha^uY*7pB#B;?Pe;m3kCB8t5 zC`I?X+8T$P0SJ!mX}U))#HM5~iCC-@;eLsnlbFHsN`h<yvdBc_H&HweG+ktX_IOwB z9h3E>J@d+2Pq>022JCh(-@N0_1Tj*sj)^6pGj5Bs2n1X(i+zjUp&Dn+&YDD5a4bL% zFwflJ+sD=qv~6T?_HuA=_#wcj2O<;bs`72M$NAFGfH7+2NjRXSR+4Hk(WG8#+^;ei zQ(q3*kv|9G>+NH)ZoEYo3BoG{B1M-JdSLx?zmp}+0^wqy)}@9-8tCK1PTs;q*I2*4 z9E&=EcVGTvn^Qu@cyR}Y(-*gFK`^qJNnEqrXVul+OKnz7wxY08nqPd}<2p^lS|tVF zYKZR~#dRuHO*$LRI`m;?A(G9*yPXYxVfA!)FlCFhN!Ylzw(HH5F6lq95TUM%k5xOh z&TY$ub_s+e)b;4{*0Ue7l|KIdx70PNp58}u{cVL@$!GKSvVNt$t7Y-8pO1R|tx1!m zHVo_HxZ;8U(_*pQPmj&qRrjN_L@lhcS?%tn{+H>qh>v;$R-|+IbN$6{LRy-{;t4X@ zF5<8i^(Ie)QOjSe6(G)vdhxpN8h0)_jw3-YzqS;YykozaH`O%ypm^oTG=*y(M=OW# zi!>EyIwhwmt7(^Lod*oVr?=gEOSU)<u!qbUKP}pL#EJ?57(S(cjjMKf_2chgpo@0Z zv63jJi|X6n6UiDzu#4Sg*MhfE_OE#@@dMVFs?dezw=V$V3Z%IHYMa030<=?(Ko??E zJ#wRE$w0*rGzlu1KAc}$Gw$My!U9Y5GFda>pzFx>_{Pw8XDcHsrBKR9mW%`P<NFiR zP1wWnY9+IONTEx9!ZgP@)s83U=L&=hhV3?!Jus=Q+jpHlRg$Teq(3|CaX5PqGGc^U zABAI?yrp6+cScFfN5+yVl#o5~<%krn|C}xe9~XKvAtCbJaoT$q&sK>H%tJ#L_}lEE z)Fz+4D|Co{!QV)qIgS2vwx>yys8A>#fFCUj|9hn+wc`R<Cjh57uVv7$@@$};{FQI? z_-C87;TJd4nMYNQwh_gG{6l4zXEdFP<aXj=QqN5zD{HY}$}-?@pq~qwz1fCVIv?el znwlJ3T}R^ym|H_%LmEGR!G^PPVzv)p@^O7cWUoo8N({N$k!dvUV)L}YR{>u3{~r3( zf|7~Y^+(i`=aChJE7QTIdL?A64*1abPF5V#vKksVydX?Ks%me7A;-`vp7DPlutWq@ zayhB0evO~AFj@1=s_JS~&i?=g0XkM6R00D7+w5lZwG>o<1AaQ_B%%;d1SVy8*1J<P zTJvA;<|XM^dE1ucp9csNp>M1j^1ZR;;(?nu^a4bBCv152%HLv%@om7x-3>>NGqt-- z%B26_zt&%8bs$VrTN2SE>R}>)%bR_2JuoBqn8!3guHe-BeXa8+D1DR}0q({ebj2Z+ z`+vvfkk)(Pzs_{?RS4EnLl3B<_bQZ$po^q!jZ&`+-NI@|5&R@YUUp1q2>b#9WtuD_ zTj{Feb8G*<llDca#DJNT@6XvS%Tx(81ecC^^#^UIIukBduXpg+iTi$tvAfRC`r;9o z7gIzw-Oep69H+_@`4(+2Wd;yM_AHD_Ei|;kqV|Yi3T<V~nW?Ia=<StM4@&LI|IIl9 zD;M-AbO&b_V5QutkEUP$C%wA^SSkqzJ#d?>6m`Lz@|gfVk~Z6EVnAD!M~XQmX~P)+ z4cL^zVX|f1&SZ>g3-gPMQECN(mgj3-lT6)lP{CD_5s;(9#WamLG}3h)NVWCr?T-0a zfy)2;IsPPL6Iuv-xFoL6ob057;NNUVYx6-a1rq4aw!hJwe)`X2Ab7(gNRR^!q5o!z z{pVLdu5S136hOlBVj#vcPNznF7l{9!v-auv<z>N!{pF>l=-{XOGVQvZ=Ub?TV7!7$ zwld=ubIrj_+&&%ht2Pba>fFY!u|)^@Jr^H~CZ%2mt$OAE2}qZA=@r0qu^4q5*6<4% zX@d)Jk1kfC6oTMupEw)o>vb$VK8J`nd!PN}snlk5*&Ym@5_V`$NjeTN>~bP9SsDHJ z^3-NMo}#s*c_Dx)mo;ts2L{_uU~iUY%g(=kIuzM`lJx4O>~>v`IW7sMMnpseZW%R? zB|83Vp<hj~{CN=GMWrRFUbJz!i(vXB(`=C10>5ScQKcJa0$oot#xS>C7hexYD>vqT z;PK_Lt{0)gbqw%{{ukn_$XVWZg9kGnl&HW*-Od5TkRH_<M)qUrk5iKsg*x4YB`w$W z6h4yM0W^~nUZqs(QGpc`9dAs#o3FMh+0(WFmtjBKzzkBAYi7LgA?LLPxDk$T+vxcg zU~DT`5pd1F%S||kJt->}90}2pJG;9%g=-|+{;EcZ79R^_71jOXBS3=Zm`;%Joo=tE z1jXy3{QdixM|eJ!TQpO0&bGtB?NVA$kLF~B9}CEZFTn%cP5f)QoiZg=$%6nb_FD_d zsMVYN=CXlcR^#=LWvLuPfB<Y6L?%mF;Xwv%UA?SnfJ&{`MRr)F@o22bWol9wxRGzi z1hBkq3mNEl``l*y9o*cC_13<d_;WpP19AUJG})^+Nwy3QdYh(R(_mwCyiVSD*!m&O zyZeY<jBnJ6=ija2oTR<|;?OH-(EQO1daKEq3v82U0vio*1!q2qmoAx&O$<8ZZEWyx zlgcN3DY|S#Vhp^KW4Cz%YLN!Q$uuD^7(d14V{9M)c<4@Dd(1VJjE#5u4Pgw`C#5Q% zW+c7GMLH3CARK(ALA{~~{ln_w(1wfOVyGt9Ml!x~tiXdOC6qwt5I29f_wuleV?MNF zfup=8`h0Kx%EPIS%o0eAg8Jm?^h)rsi>Oh)A_NDOTOXVDd}>;;RFEv1nfm{-Xgwv_ zxM$j|-9FP|{C*v6!R%1C>z}*3GF>*>%t=hd43Ud@{=Mg!n9R4gv$x{HDFiDtwR8V$ zD7!&3b8&pbtDq6$7EpD(E?cyA-6HpTopSyvzuM1ktQDWK-=9_Q>V*y~9LZJbBNN^F z5&g~#F^tgjiy)c+Lv0_z&7T(&{%I=4ku;8<N(Q%7lY<V8zLEn&W(P9wW5dgOl8>?t z(_+cNRSYXb%(11*RF+x5>M4%ZuEX4%59f}sBcG_!0W5(=69CDGGI(w^L{Ju%nh@@i zhXcQwoM<K_AEOz}#eW(0IyLYBW7g*Ofm`E7ZutoiV9%aez1;h;XhQaxveXBoUZ4MN zKKvanxcVyOqDad0J?ek1&8Q2)GQN_X72LwsR?5YN8xXp{osq09@$tQPIrVWV@p)_U z_MvK`ut27dBGbCGPQ)<&2NIdY&nu`abAUfU+HLmFA?_8Q-2gK=TUNcfq-sYGQxYI8 zRcW(wPIb77aq2cY^T5T)O0UH9x__UDIn-4?p*T^3{)_e8PAwj(i%4ZWHcR;^<xe2^ zu1%ALkbB;n5-Q=(6>>A9RcedKIp9zANluRRfs~T1Vm^>Cka{gXwpb(qJYl{5(H;EM zGJwhYPWE*Y@!{gz<w$`0MvMVXFcOqx&2w5Q6!D`DbpI>tAJP+ck^JPBHm7Nd>oT0} zIDnunqwDPX%i&`$8A-RkN4r>bE!z!VnYM6>+#ykq^|=10Zrk}5S8%s??tXz(F!_Lx zNt__k`y6wtUyv*ypS+_c2s;wSR$Y*1%KQ+vN?QF}6!`MEIrsobNB6+_m;Ir#+%aq6 z1M(T*ya#xh*ycL`@=5FWJu7LzthgO7tai(N;5Nv^0gX!nCN91*icI1vr=)~h{wBnH zK;!Yl-1Mk(j3pquU%7Bv_kE_ECBe}y#};zi4`8Loto?UWEaad{a&G@;fwOgkD7TYV zzNU#oKGL5siJ-%+{hpg6oc&;SI`Nmtuh&bV@mKNY17vodxGj=5SZCs$gftIb+cIuD zWI?Y|Az}1mz7K<`WmZDPe_Pyl%C@{c)|t0(8k}(ky<w&gUv&8{{BOs0lc51vu#N2` zoY0%ly^3j<sLv>K4Z+;Y07Jds2l>yGqqxuOm+M}x>MNyhu*3;}>;tX55PfzwT5(BJ zR9V1AuuS{ACZ_?eBTDDRS4Bs)|K$SYdJe(o7>1Ql8po^glIJGr@TwEQC)*?)jhkdl z^y~`*h6#YG++<(_{mH`GTEfM}MV_6V(Q@JRT#^AF-;y7Px@w)Sth>2X3bj-`z&-uM z7TwigV71z=Zu5inq>tw?u%!9%M2S{C^!#b!b=RQmt0em6H}c2OXNjMzUw4C3R<x`V z?V-#3SarJSK;G>&adQHZ0SR%^ru4TcQ16@M9rw8vQQ*TlaL=OEnE9jQP;1bl%Ly-w zngnhto(+a_37R~8^oQvk53`Fn^qxkZyd1k*zV1?+%m-0wNC-rI34U1U`Bh%ULTCV{ z5sj}93r3PbYw<^d(#&7~+y3{qS^Nvx=pJv+!1#3wj(BpJP%(xaA_7-(!(|VZ``XWN zz#fEyc=uhf#MVxKl!2L8SOh_t>&xezQ|2oZ*xgU3oZY|FVd>=~x=tI73AP{y^FC_! zrjniGuduS0_GFKzl-+Fl@!ijYY?7s`(i!<5{#(gE_M>)OK6#i5NoEn)+gYhpX}5A< zr0nZ{5QH8(3@ERXb3Fl>zU{a-_~CH@y0@BZrU12g6M`$dBG7r%-gDLO<3CNbe*JgF zHQKhOzIoIrWzr@B=)(zTqi;xX(YJhbn5)Da_=K)_i92-YI$xUn`$|LJQDu2{55pl2 zO}a{(OhK%19TZ>AQk?}qTxXu1x#&Z6`l+v3O#u=2FS($pA4bSyyU*}k5)NjOKj}8> z35(RV+VdzM`4EdN;olQU$*?&u<n#dYfzQ~vT<*x_xZ#&{3!Rj%r}S{2qN+GCZP&kV zWyp}CT=m1vzN4DR#x5I2%*UhUH*OVme|r`DAQPrtm86sUA~txv^QQ6JnOCEWI^<f1 zn+_FODN<`Ind@aiLsLF#etO@u<blYfyB_&FX`<$ePv<)+9HET|l%Tthe*1H#v-5H^ zYQE^cOo=ASa_#s31KEjN=;@<pwFqg8)S1H?)d{|rm6g#x4C1VJlWc6%9x?zoTeS(c zTr|Sq>pa23<3;fNCn`%)2o54?ANC4{$LAGq|Gm{0|0jy>eFL`vyj2sotShYn^$CAi zji^990Y14Xg8YQBpeBOquympwEg}_nlO--Gd@JTjO!&MHUi9~<6f>*DbpW4o{qwGX zPXd-^Pp24Gz0duVJ<VcuA8HDSwY!tK6G|y)H&n45H^FOP`f-F@=7w*F@zi`VW>rMB zBz<u0NWnfP4}-|#p1YqpBXGGfsXntI&iZJwW$o~<vKUNVnWC0~6qIS|mg?B@5dXB2 zNQFKiSGN2$4SF7M_ULoQMMV92bz4FcUgkLQZZih9(T-$><Y0`>o^yl;j}~F6AY>F8 zPD9Ht3rEhsIrMks8_6r|ck^(Yb&Zyw3#P=Q=?0Mt*ogw|#m0*1zk=qSuf5{uN=A#O z5Fl7dNlC+w1JEMg&dtpnKXU7%&|%66r$hqCau=fHw;L(69cLc&o8oHb--;$ncH3kB zonc2mfy7IszuT)!PjO<x@qQqVL^#Ci&FjAP7f82Gg+pz!=$rb^fOl&Ko*uYdFQ*20 z5;x*&A(w)Uy}R|6S8v|R@@xM_B2-qOe8>&lEx8!3PTh>kA)02Q%(W?EfF#x3Z}0|0 zc*4|7SAe7+w5`OJosf7l)(naVe@N!jo|dkD2|5!NiXJ!fC##yxr7xjw77KTyv;D=L zQ<!?Yb~&t~Ar<TDdJK7YzrUEC`(4j5-1XyxPjPD3Sfu~2x&epvK@_cCoR<F2xN9N? z)<()oH2e-Tmp}L`&nyGJ%u~p_Z@*<5b?fi@O@>K6c4dDq=(6@hv2G1FJ0UXspCl#` zJBxmhyk*?K<^@uh544%nr6z3UUurPS9Kfv{qyw>6BP!!<`!OHWa1b9R%T*i4s)GgT z!>y@Iye(bk?uBRXc=CUHJ2nFrER@Wa{6GmA1(P!3w#skwkGOooY9ODzCvWuI@~oKJ zXV%zjV=jT<P>0};_o1`~Kl%1QPEB7q3XKF%=v(ji>7hm7_EndKwuXg1-s4=opwdKM zKKa|gBwa#wwECac8ltz&SN^RzyqFRy)Cyyp{hi7E{s)-H>T>y6(nEk4_yzJ_1w}2A zCZ_d=pxI-A``f2+KS)IQg%XVZ?oLY9?t}B@wuljY<OrZ@fuB$I^k1Qhj|^06ea!~0 z40r1Ps$Iy9cffDzpV2F|UHuo%{YsB7p04h=F6B7wWfI|<0uZ+X7rwSu`yg-q-E#JX z`GtnL|2b3GO3=K(ws3@}Q<Iy{!15n|Y98C%UXKqA<VpRcDZ6TzvM%Yx${T|%lqq}A zd!_V)wGZWIuU^m5-|6eFr+-xDzeP}I`w|nj;y*p2iJ!p5{PwIz6_DRf-+b7btI^`1 zlnY=PnhSkV67M|F4!X(Rj>)3l=^Bt4iTwK2!VpiK#_+xmwwI%#53q1Y(m%N9%WN4Y z&oli(9W4?2NHt;q^t2dR2<wi&&=^>WuI=N~kG=XlcH#o9>gA6?7$cYq-4Bdtl_#Eh zXw!u?pyF7r@Nw;YuPGTX+c!mnujD|~kc81S_Z-Ofza)#{qR;}u2NQh=KUgWg{Xe3< zIxMO$>Y5TzT9EDr5s)E<PC*)^TO@{*?(UF~5S*bwQo0*ykrpYD?gr_8kH7bOpYKoS zk-2m4-RGRO*IIk;tDLk-Z#|6r``wE!Jd{5dORJ50D_B)_+llJ9gPMKiQ+)Iq{evEU zBu!j*`1`ZWwapSpgyq&b_@R;EO)tmXsB+MGsh~m3&m#(4(XYEJvUl<B2^1gh18ARV z37F6v`X`;$G=k)Hs~LB${vV7SDIG|X(>nX<CYmDu74~lZx6W!C%>!z-m!1|?YdC&W zzJb$j|5Q$c17;kJ6okV(O@HindN6UAZq>TJuiZM+7MD<D46i=I#nWV5(qJJp2$Q1T zBwjVc<q^69Znoa{x)+iL8suQWpx0H?<ygQCFAvo)rrg2Am{MuWU(4I`t9eq6o3T>L z6jyU@*E?EgD$~8oO1+fWx=oXC1EG4Pg2zUvx!i#jo8#tWW5dLT*Yy{xe-sBX>2WNZ zA1kKRc24De=~sFOdzL<Zt&WFw6=1xZ=wu<-6NVytH5)=3Nr5yiEc*?9D)7KTG^^_t z(}*fSLZG@fbYz(L(%^gCqKw2xEeXP}i>^i$i91G^BYK~ZB=DCo@D95gJnpgKcH}A6 zU1Q;!0|$N>YVPUkVJF?}Rdj}2U0m&V%ASAWB*$9|Bu6{Tt5EOimLKq9lETT|A*8_f zq|n>HlDYvtH2Q87WkI;g(;pvxALfatBKt-g-q2z9_eYCglX}z4#Qq6H=SuBNeE1Xg z(}!AaCtQHexed{oD3c=i*!*<>qnIMOyCuh9iO|ujmwCoGj>-*VznggOsU~AIsWYA< zKJ^m*;9{7biYjow&Mcq|ObE*-v$8pq(YS#J;D!)%qCmpVEe46+K1D`^ZNxpZ%JCU3 z9YVqE(;R!f{<{*<u{M-J9~|zgA*{XT#qnRHPjwa+`F-y+QEk}P?|d=~MGHKZ<uSn{ z)y8}G)>v`7P+LaL&1NPip^9MBfzI)|pS-ZDuPC$W3-#*{!^QG;J8$)eb4LVLmn4W@ zRcf&LUgtHel2rITzh4`vSnk<A_{=mVp!RM1K#XJ8iYDoYB`NxX_x2;tzhSBBe?>*E z_OKe)x=w7ST6lkRYuvd6Vy;KHcZ=}_T0$O`ZFOBgh{YWJ-p9PYk;_#7K=6hXtx~(T z`~L4CUE>)SNZ+2x9vygLFSjh9#Sr=`+8rbG&1Sy)MrM#ryP0LOt8xxjgUnk_`LC?N ziMLnpcy$KG0{f?YH2#<tknY>+xd+~ZA684()`L$Xq5qGZV}C1E~@I;5L|PR^6; zON|D-S<mPIGJ#vnq|;Zvb_kye<YlVOFaw`Uzu6bdLeJ7G^1W|Glv{B00$7WsYz9k| zvj45kBiP1Ye=#!oRc>s@gWt~@ttNyh#hjk#4a)E*^?h5y&-B^`Y|Xe>NsBaTI4L<f zDA?=n!`U5Am(O`qzBE&OAiqp>M!icm_pS-e>_T!)3a6MGg`YFRe{k|h6t6jlK??H) zcF^kx;?OZ{sz~};ljdil4zn@!G-6n!LVKHW5_k-ugiEXoK7<B_oiyFtZxNPSm6dd` zzWV)=$BY>Gipu}a{IfY%q=u?yra?gRI+>uO$E{9EV7^{g&LhUxfDoP_V@{H@co|=j z*~a{GdQ-z~!z}ID&W>YWE<Ek~AYxo#tsR@7hTl)Ykg15>{_F7FliyOKKN(>bJpOgx zno2{0f{-aid@0pQO|5+>#Lkw}j%E)094SfsWADk^4_EIas9%jrAnO>mlIatnkgGZU zQI||Dh6e5EfmA;|I^;-~<R^D_7(wodHl39M1Ge-`eQf@r-}BrE<M1gyw7UWUDO-nd zV)P@oZ0GwYXyV?)%t)vbMBxnfg0ir{b^j!Nc&~NbYEN9u;f=;ucml5_K3Y|uFltcf z#An@iHMXte7?SuNB&nqm%t^&f{1k%Nq{$`f?z0#h^tw7}KaWYHe)*QYUx|$)fR)ae zzNrw`(faJ^J3}{OS(8T@D=YaZ{?X{X{+WCfQ~gIOgnr^sfoT`{Y{Q3qo)M##CkFiQ zi?+YN=FYFHd**TIONuAfPV#J2nn+f+zE-sSQK^=+;G`3n=tV$J>W@j-t@rsm4}lHC zuQy0d4R#U7CIKiDIQV78Pq@gPG?AbwxF$5n@Mf`er;>zc3Rad;v-LRrPDt4~;c%@H zC498k`EQ));&xuLfOlHsK|6>(suE+!m7&sIT}syCFk)VL!aFTtRrc~JOJ8-Vr+6CM z>R#A)1%*?$a>u)Vms3D<@Tb|c=8MCddI$tSgWLR<3P_&sYN}KRZYwqTQ(oAIoc}dV zht7xONRd(P^J5!P)QH*dM_X9^C>Wm*N3-f4W>>v9UG7EYGMnGgs<ij{ZKHO1p*#^< zS4!3Fjz7j5%HmCcLlmfKdwca(@41w+G%5NwOk5m8l9A3;%v&UGH(G3hF!?s6cXh)T zckIox$vhAcUE{cGho9rKlv;b9rg;T+(;E5bvIbitv_!KkyFVxPj&~FXj}^;qd@i6h zV^q-*%AnS|5tv~1VG^Hnjnl|8V~oR&C*U^3Vk5hpC1()(0@Z*};l}Et`PEDAN~y0Q zlvlmsO_2iR`w)l%ozk?^efZ?%IN@k#eNaWfMa1Q=i1*~F*T2UXqT|lBPjQLm&M9zI z#XD$P&JVg@bU5<)Uu}5A>S00PVvrr!#5Oj&!4!S-1>3hV({@iZzj*P8jSIstE13bi zUl+(*URT_;Ssh5-yhzg#_1<hUL)P>#=1%wrJO+7*;re~Vul452CnjSTcb`Klc7;GC z|EHuRfXRn%O$U}V-joBjXWR9<)G@m0y(Q-!YF&C8H@2yswo;og#YM4@Kg^|7_be{p zA6=CZM+L8WDZ68+Zv|6y)@J6{=9W6Yn6{sfnN*y6i$M3k?lJa#V2MXkhemIZy&}Li zl2de{-qmrJq8M1fCjOxNdm-AS?M&9tW0E5KxzB=Y5&V@p8X@_guMPB{25}~OZjr8O z0;u}47BC>GWa}|qykip+v6&ASU%yk)gcff{8e;Ul(4qTT=S0;7IK3#^c-|rVEpi*p z9w$nWq5)!-_k_^j<=?I4u<WX_3L*g>;9becY^{EY6>K8Gv=GGYD737Up#RVg%Dead zyJ6yQQm6BcpN0z2{)7gRH&>ps@p0$;tye$oCD1^c+0uSNc)Qzh&|RFwvfSKFTB^yu zvYu+vmluB+Y@s((>(3`L9YKTExNkJQ;u3Ia;Q7GS`p8z>wGYX$d0KtzM%QT|%=13n zCBYdbG(2u^0C`RPT2RDi+C$Ctxnnod`=z|S7SHtr7N=|J2dr&5V;KW>)I7By_gUgC z0pp;t<388Srv`tRrObX(7bLi}Mq8rOzSn2?;{X_rVM{_7b5)P!GSb?LT~zL9KDuvR z54xqTL(%#Xa-_9|%YdhnrORQd76XG%lll3^4k^>{$y0z(V%hzV?{^o&Q{&Tn{(%s7 z9Y^4{I6e{Odb?VJYyO7#i3JH4rAT;A^#|W}GM&9f%tH}Z%ER`9VJPfO0a`9xk~-}9 zt4#Kgk6jpgsQMt>oO#WQFxd;TCjXvJ-W9!g32SxVyui0##MEWJMU_kNwiB;54#kCp z#o%Q#VeF19hJM8nz$tU9h>}jyC3^MUvIcOD_4WdcDEJIW$I+j2O%cqlM)6$fj%0+2 zc7G#u+p<<s?48Uvyni*1-`IY!l<j-Xg9B3ZPYS(fFR`qB3xrZX>oeDBpCI${dIz}V zlxyTaW#T_`N_XIc)M*m-dlPqaA4POHVTe6&Jp@H$`Qolee~@NrKK?!MUdEL7&)YW? zBY%8P?jw$GvTm7fry>?3xMS4VQ~U2Sk9X8|yyDa!%B^1q?Bgx_t$g6733!}hpVO;E zcXn${bU__P5<aFx#WpBqEbunfckB7wTi;`WWd}X13eERhKsck^HS)z-ya4Rsuj?Ts z*yRvPNl&9AFQ9SK{EzyQ*_0<X&@61~k$pttuqOt465zXssX^y<fn`;caC2%Pef)9y z6_U`lED*5m*LYp6c=XMzrD_*WGB!Dfw}|)FfLZ9bfzuTe$;$8N9^bgJp>ZFqf_LNd zBl+QVd^<JjXntB4wE_1Ik?pmFmp@fV?_RC(u$k}u`7S55WkDl^vUS*seNE$wbYFkw zsJM<e6N#Eg{5+&Q?FJgd6f*uXb553!c%~RT(nklBm=Civ3CP@=MHXjvvXC~_q7fya z{HS~FY`1&VUHniQWh!<PF$lYlMX;W|2!#|996^ncW4u{?cJ7qdTMAe8u?S#F$rgzn zbM@A!^_dOSs9_#&E7d>>3W#z0VJ}_*i-_rS=&v;WSV*CFN6909Bzt-4>xb57efAEo zPMdtP=O1`agG|HtzSvti%%Gf12p~JOVa9ECR%qH-8r$$qDcd;-^QKtz$|tc+4mnQi z42--^R?Y4CL{10+51gWndsi=J$C6W-dNYY3FSrsuL(|xq_Z>PyA{U-z%FI-!hpW5s z)Az?gu?s8*X5EL{^e5Y$=O%KfCh9z|%I4Xn%UR@o(YL0lx(%C}dAPF*h1O2uXzhlJ zmF@fBaMP&O0X5?OJi)22uKeR|eQp`MLZ<%5(>cOorvwU=t~lQdmSyQ$otsL^<l1a$ zJ5xVU2moCI%-H#u3m>3J`ZdU1`Q+b(*;1+T>FHFZdJrPtT#e*xZEcM(Fi389o2kEI zjx<Oc^Ry(f@oM4KMp25rj})Zoe=RX@PG49W$v<xRu5grhxQ1C>l**-e+-l#j7*6K! zf_uh10exU8YQmOOc26_r(UZwc{#KPQCLtxI{jpVoq;x?_NXH)2PfCk+)%WojrV~Xa z%QaL#T5|Ghrhg|Wl6&vT!{-o-&U48@_F;-|%5Qoug8ANPF=F*5FdQO|q{e}=s%Goe zUgYA~>Z5G8jQBP5x-I4uVLby!Mgq0RDuv5XTp)5&_6J$$RT=({e)c?39-s*~8B%cX zUpnJmoigK@M`o19LZK)eVZkR(Dv?Pq=k+-FT3Al2uUd5mMf4-<5KntNxARjS!309} zlg@g3L$CEu+}I2wzovx#koADEz3)adMS;AnrNWH_S~tF%tG7oAEHCHWo2`KjahNhE zbxxHTjQ{-kbX1G)D+4_xkSBrI>TsK}<13&{Xi#q_34_6gZIv-TX5k&`p>z>iuowIl z&D`vCGiofS!1|)Z-$?HgHHR`3dex5C@3hp+DKh$X$Lw<v8K(;2E#O-d2F%HuW%q_& z=P4b36ajGT)yq0N&XNy|DKm!X6=x`8K&U<w$ih2-H!{a3m|JYrJd)(zcZKlz@R>Zh z?-!ogFw?f?anaALDlCK%9i95o00TpRwZ&jbbzPnLcsF<GZZp*DFJm0FsL+nSDe1fJ za2#;IW4t)M?+92_GbuHo-Q3u<4Gj!nU*vr?aKJ5bA%gc$3C)p?=+mU;Q6{vVDwPD$ zr1g*=);tZ#kLxdfQ~ZsIY#shtwf!&;$dqr2d*UW^cOw)ZuPx+{Myx^|DPgkY`6psv zLI=1-AVdC47OjFhLZ0c{eB!OKp97P5!%b;1QOs-fpm9mimr+dou}CKC{17IycJT_z z#EJDKM^|H>o)f>AU(G$+NSN%(*6qR&9$7ba;|*Fqi`=@y8!-d|0S;=Q9+hm=0Y^wj zfH)#8ZS`UxQ14L{AoW>P(j!0NU$s=va{Rp#0Z~-G3x1Xq?4~D*5X|<CY;mr^|A=%7 z#86ZW+!*0$Ah$3aN%^E>tHJSzAd`~d3Dw)1IXdDOSa&&55`B0DiqXji+`s!K4#liO zohrUX^@y+Cd1sPfR1U85DCEDP9LkKUN<K_%%0WMQTG|Ay`l;!MQ!^z=za+_w@KlP@ z0PslzgRjm?5-Vp(uNwDk%CiW=xvVWR=-Tjr1)^6eHtU2a5(wR!LwUP#168(+v5D=U z)!$8GtL0ZFeDUH1NXp314)5;nfGH*n6zJ5w(dr@We`jTdIX^$2*Up74&0$cFow?bI z{KH$Q_u~9Kx1xe8MGSUbWVpK28S?MXJr<*Li=q`64{MG4eK|)~k2AIGz(nN#=O3U} z94W!=axIxEcI9`nnJ(3X*cfVUK2I808q1MpCH~;#4g(j9TUC<RvuX9Q5K0^B2Nm@N z1qIF1s_(F{7@WQps247pb7e5e09C!ki8Hjw3BW2XIav9H0=!fjLZyQ774ibjdsbJ% zk3KC1F)8)^M-lFWZ;DMOYa&;2c@m3ioX|JXQEA|B`ThI%+qrXAK9P~3f3mF_YmE0r zy*)$PaNnYi15V;9bnD<i*1*7EZ|wE34n7*|Ck4;_y6GK68i!-$M@e?r5Wn3_AV~N` z?k`t$o186_9+_j93hl1{5|yA_vY)Gu#lq%OmIg^KupU*}PIHzTw~-?Xdih?IvhvMe z494a>|MUc`{fMb4?aTHov|*BBcmWygS>Z2OxF~&8k&;%8$iKtk;i!0$&$}Jft)NHA z;&7=-|Fzi{c12}5RZPw;qt`C-DAri=C3=)(>Y_v?@ay+CH#h2F(S!Vda@f(eCB=-6 zs78sIP@|QZ!NVI^D1aB}$v^Lrhk{Y>_C(?CQ|R*BP$5;4>h0z@Dq;5}U_ydAE=ec{ zg~EBdxhtK432C;P>0s_9L53Ufmsr`_cDMW8SZY;iPrCs-#@<X7D)0l96~9lJS>b-{ z3B+5+EYTzZ-Kf0*SvCr*L^zO!wjb3fW#~szOlZ>Y*bsT-Ji{F<FdB7HmK|}+8D?@n z@BhF(`szqS)i2CK?{(n>xCX`g5RycWngmecG&Bf<X#-73tGI*H$HDHnwY^Qo7Z1)K zv8?#C!RSA3Z6n(GZ#s)L3O|l+n!T!{#ax2oHa9n0YVO-`woMOMCeLge*I454zyIT@ zea@Map-l9V7=GX@7BA4Ytqgm#E005_ILK0enNF6Hn)SvKbXNlMXo<=i&$#Yav10_l zdd_d{IOJple@hu?&`XL?V}35O49BY<IIo0rr8QV1oS45-vrR?`S#$NsCME5Uy42fR zGNXFG>Vyp>GC`eIdWweR!7l_AOiCRD%_P(1m9;LDo$nD^BSSKAH9{V)M*ZMTR5`Ez zXvBSvEe*u-)AMtclFn^&@6w@O1bpDsL_I5iA-h*;zx%9Y?8)afW9b^vzQ=@C#|X8T zy%^R#O0zLCIMVakzKbRw1D{v*jMOK&)Z@m@&U`k<gX7Y+;P+cKvkKVcb%jAyu#TH# z<P~I)fF<Vo=H_cAu*`rFc&1l>*PYf7SjW9pMHV3S8Xg|5v==UjiWP_}Y0fOL{>Rst zn3x!P0J{nJvzJh)uG<Ui&C0QtUFIQ={_1I2ysy9bJa8ZfTNPzi8Cv1*=Kg1m$X4!# zld)BP3I?_~5SC^m>r(9P${bZqu27YRXLn+urjNr580>kw$I|eTSuaH~yXozQW&8Fd zzK~(&B3X1$C~rKKfWX$S$VDk9zaPfX6kw|Vy}=KEMv4fE8AmZ1rSBS|sw_!9)2x83 zo;)L0=%l@M#PlYjvsimeVUG#(jM>P`<0lwa!gb6+ywIyg^Yio58ZEXa_xAQKDYD!f z0#>2vWPKpi0w*1y6siJ8Wo*@UNE(Sj7^DliJyA^Ih_beiz@;j2=3c*G)`+k9Y}f8q ztC}9&Gt!qn;YL-y3v54^?c#M}5G5aO<r)P^3wrx&;DWGwN1I1&H}O~khxGF5n~I3{ z<-}M9!%-KegT6CEx&8@>=S%0~{ky|X%ddn+#v}*2Hyzn^hVg|M0l_-)_XO|fPG4M3 zIa^I!-X=vA#rG>_;oyIj>>l-gAdIKEqB6flhUP@rrubvd>D-AQmBo>zF=((k>PYr0 z2}97a_qaL&G2(7LT=7Igc>`T)NLGw?@5#OI+0ha(?9uy*sM+S4rc4Tqk)CTpfML<~ zUkl3Lwt2YDPOSO{249o?Df=ZI91dAo=%eWY2L)!uG-?-QA{dk>z*{wAvv8ulxxOBo zo{sPpqnX}xGy<muSh!#ZH;d~vUn|-C?W6o97_6L)*hfg@qJt%9NI$n-OT*slX{S@K zTgnaut8lzj!hF*wj9r*UST5PErr8(JdQD(x@4jT8)*eBVn$^n?5kRvK+Dx^!A+v2h z`%}G6;CnvC@{-$8-1*A(_<Pmp((3a7yr3q^$N~Y3ob%+*m_@%za^N_$Ig-*rtyh8n z=LK*Wi$A2i)%x?f4RcQ5p2;2e9#dTGnyeO9|4w<61^=BTCHrIA*oKC<-suXy083{F zcfO@ehK>)XORC4kZdv_U=L#aeM><FQAvFC|1{ZJfg}714$O&?bNw7!55OD9si1e}o zYx<;t?3x-v0Bg$h1rP-}pwk9GHBnmrUEDJNtOO1Y!?JL&sK8Uw61CBN+BjwSRDN+| z!_w8mBg^Zs`~xA2io`^1qgVvhkRAUAFc5s>M8$nnLmZ+*HTf@^$U`g`ke?1#F99uM zdQ7nE4QJ|V0Ki#J+RXBFEGaXmLc$YzSZ}S+jad)7odfWjPMKZT79$7e#3Km_xYfL= zryE)cd-rya3R_b1>W(nA-Tj|Fc%I@Nqx(D(`u#q<06xa+C!1L_4qI!-fxt6f@)F)C zjAlcQ#t|(<`%U|erFW=MYGjowL8~0$yd^6kR!xYgEIDubsS5ojbx?tU?vy`-)9&gK zQ7r%I^}NK@D~So1Ya2%og4W$q22(=o%LFgZx-%I-7r-HKp!0^6NOrOulhw-FI*N*n zc=U7RwdEW?08$`OCSe%p=#D$T*odBll^oV^JSQgmtR(&=4F3xv<|OG>1|~Z8apsS} z2(7C8Fh?}KIS&~?PasS+*@3bQARF;3Clde*&O4z-OG+Ve!Qx0*NW6pu*k4Y0MUYH& zWsD)m0rvB;&bm@l-&a`tE~F3Junb18gv2gZ4BmRmIa%M^H@@39$t%)B$`u6Ux3`}a z>E9bu<Vao$f?ChL+-xMA&Qj4$&GQ*J6$_4vS~zhmT3rk;$8czcb+-!>WhlD6am<9_ z9}Jnv(&FOBpgx3@lCty~u$KSa#&Z4K>o39XBIZY4zN@X?zJ^UAXpsY-teK94n31A8 zHyJ*wGelT9+v@-lV)F#>5Fc_qhRjj19vch!bf)%fY^HzYXdN@80MGRmZPGwbiRH@o z$XYXCNaSzJwiDt%!$;OGm|70P<nH3Zw%R(rNx;A-e-U}gk^UAl+;T~6otD~j-|SL+ z>VdHRPXJfBf`iOSctBUis9kUG@U(<O2bt-b@*HHuLeA22PpVYK;aeWv+egx`t@*ug z#n$L)tAz-xAuRqpMqq1ylGSt^J!VsvS4vii{EbGUQ;Ciw>?jYZQky}Fm*GH3ln;W{ z2~VhLXlf$+SG9x2?d{_O%zi7l`w@6F<zCERiE6wzNnnuxjd6os<j<JgK*_pLb9r7~ z9%`{>37y_?Q!R$lO=jY2Y}HE@5}SIys^Vd+?Ls~#nCzRM<-2{o#ene6MUqEwSM@OC z^=Q6t{>^13G^K(62s$l>VS2I-<vvC7zy0m78uj-*$8?YjVj)Iilr9>jF(IBN<5I)7 zXrEbT_%M+Fh=EiciN*1)ZD3B}(&!j@MWL)^X;s>QC`+WTor1ko@?x-2+oFWLL!WAd zf6Q4*(7LjN45sbIj+>3EeT4`1tQUOSDH=aV+CjScO31VDphvXAAI)#$P3VEC;esy? zy$>pWGo<8Jn~Ph_07g`?JFpM}eF_Xh0C|H1YK_&VVYeAz&Tv!Gt(_h6PoI#(*(`J4 z_4PiS4dE$Iyn_|w=Rblg6_g|tvMY?u&PFLQqt4YA#)g+qO%L(4zFfHb?oCw6$QL4y z?`a1MUvyge#qmBJEuGDc;J6AnldU6}C^V~dOaCVSbChg@Djuo?a`Xf-f7q(P@nOXs zI`wW7)(ctk>9Tw5DUKVW9}K72Itr@Y9AZ&!o3{?0NDEU}PQE9T!r6y&K?cI&ahiiI zOG-)Xle+Yn8jo%v$iI|_dkXpeu@?RJr;n|s#oxkbqdm&+P=3$74<>vB5u#zPS^iqx zRs*j)V!)s=xg)v66ODkWK2TLV9*@M~El2YOgmiun;}3}&^3C1{lo^WqtAeJoG92LH z`H}GPq^Y5S1oSZ~RLLNJl$d`c4jh+Yq8+q&1RizpYReipy1)U%m-XRLgWP817iGGl zga<uLEuHjA5O}HMC<POXI;Xhj>H*MFNcTBt!nt@RZ@2t;50<F>zGt(@1^_Md6>+R3 zkZDzQ>HS+xezfk*css4*!K#@TS!29Z>S&$`AKvIjWh4zZ4OY4hYB+|V1mfFHY_483 zh+$X-l3bHwD^AEhL&TBe$1M!=W^dQ(tTu37zRb3cr2mFP1x<k1p1dttEiLIEj#=GY zt)I*aYCj*1nBV07rly<jBxhM-#!Hh<n}b+)76e{jka=1CO6MZ}0OBEf+mfC1W6Tqc zp&cq=Wc(GRGQ*~)AiXZN`SK!Va2@oWS~-Nv2W4M9t<r(WW8hLs2xau0O`C`-{GzK` z7Ahq%_Cy{Py`bc5zg&Tad|n#rwSEIZ#h%8DV__06hjfp>i=xLQaj$251CDJvu3uI6 z0YcLnp_tDCiuxAu(rCPnx`QqcL%z$w@3X{(jgZVaq7_AXYmV;&nqNo+R*OS-RrYm% z4xWvCnmzclkH%Dlz=T|tv44ki@zxA1e1H-*mz(uQKZAOoZWS$_iQoYs=A?>V58SUH zy@Ni_tJnCLRW;%YmzMG(WS?E`j*y%D0nE`1Ndqyt)v<M!yIQp+OoJjO-oxM9cADe5 zBk&k9RDd^!O6#G0rdX3lRuZ2UTiWh-?c-6g8xCA*kw`4gMp|413#rTTFc#Zw1IO28 z<}ock2+shc5Cgkqy}gc;10h%l*8+#f_kMIF{Hi2}espmfM6aA+=iYr*tuOJ*@1@o@ zzt)kT1uiw=SAO2R0~@p+F#ygf9D2bMg{tv8lf1+hY^j4<>O;Q*rP?m&$>@=En_ahy z_LN>k&ze&PMNK)sh_Ec57`ileGwMHH?LR(m=<xg1A@ByHa*P988rZfTvf3`<>Q9Rf z9tCKb2yJhS$lJJm&DXZ6%T|}AWkg1if8F)=aVSooNcV}SWu`s#s3|oxaGD~%AL2=d zUfIb}D)&@3@KrJs9RXtwrBxX2PPzm1SW)Ywzv*T|Y;v=}#ld4y&8N)RZ{n(}+{ov_ zz0|ucPBt$nUomwB4$JKH+RT8(Bk5(!tZstx4FlZ7Oy{K!0ZD*z$R`h{3#P49woBm{ zu9Qqa%!d#y@1NcgD-gM`j|@qDV#+lAJbEa9sDL~CcYTnh4TII-DVij|v7W;0c#n)2 zW_Cvh4ag0LWo11;g7Nk(t&64Ak7E0U_v<D^ui$ww3>K=2nncEd5rvZJ-N;pFlAa<~ zs^Ro-br%&LQZ~+OlGQYB`KQ7H^NIOnyzU#CHCO29&~Mu^4z;$fS@9x?Z&aRxL3`#= zs5wz<7UdmZH@)=S3%-8+YJUi(P;LSUCcJC9{i`#Z7R>@yJ2lhjWajS3FKWV>I*5|N za{Fycu(f{w2QG<_x+QZoJuf+qjCyj}%fqDF+Db}8Hl|$GAMDsd)Wb^o=1!D(pivv( zq}+^n$zxMC_$W*(&5LV>g^2Mp;%}nlbo!!|RDMCay?AMYkS5VJXu8c8oOnb&tNPMM z#P95}Fksc>!@|uwl6FC(S}<h%d<gD-s2HL1SDI(;EF)&}!#jV~NixuSWRNJ|`gdX- zouS0YrTO`#`SknxvmqtR0A<TV{k_nXyMzL^6=>##_t4L^GrvSes#JI#C4wzqhO+;~ zIMt64-Q{X?>y4N!FT}ZTbdgVH>UPY)c}NWGa>L9$Je|y+v)8kgZ1+z2NFd8oCL4h? zY97uwRNyB@1q;Wm5b-=(3Y~4~{XhaEqY{hrDn;tly;y&+swT5A+tN>NN_b;Q7}1v` z=sz4qiKt4?YT`zCwT`;(%#6tKpc-!cVjnCFi%oic;U<EBb0&hujuq2@U;WAZN-Rr` zvVRr{38YfPhD5<cH@>Lbl%69!WRR0sIT1D9BoRaf?xNI=FfA+yw_<4B*(?Rz)7au- zJfKO@BtP=q$1|adOjw{ic79v*E5<zeL6i$4cl0>(xBFk14;_bIH7}VksN_;?((50= zws?D~NlE^RBs}Nr^9wy8WQxxZ;xv)*u34p0h^;%=^~Z4yWi+8;SDWh1K-V7~P0a$n zi=)hToJ2R>g$Oqgr|UmHLEZOeoP4uI|D6;7f)2sSzAmJve|c9G2`Z+{r}Gxi&d=+i zGKS^91sOy%R&T^oUKoVS<|Pd9mYG!P+W7=-YPzi%GEO|!QFyUs`gk=KqoKAk3Pa{Q z-u4VUhuoti%wC{(=t(w{qK3}G>Rl$qep7n`_!$yHLHSWX3YiC4qESZOs2|hmD-1E) z&cJfBEIIenq;kf(^4wuxYf;-kI9WE&@{gY2qaja~8-1`COtDbDM2j4V0`^5=Ru_?o zpmg~Cy+7Cv+0y7A(c12et~>V&%B+6MALk39{noUZ`9Z%d<(1a<rbdQ0KgDQW+R(3W z#hE!ZAMICkZ$A&Wy-86iRr+Y0HiAT$`n-h}^CRQqL`Li4i2Yi+{zN84Le%UlsrEw} zjGu+?mY7#2eV52y6+iwwqB+&M_Z%@OLZ2;`AT2V7bf~nACe)b79Ntt8CORyxj2%1k zE^tk7evs0mWJg}dF#G8x=Nela__zz5H~jM&Vr}fCb?>SG0bd^JEFQ8{>aRlVndV^O zG{y-qcK@|9eOjTtbt+Oo3<E0`jM>QjmHfs`CB4#o;O7wQWs|YLL|_=|7@Swha{k^h zA6zh@yWyibTh=J-kVj{5sNkk`4O<Ph9p1Ux_M)}lg1$c_9e44<;76vX*@Na<1SLbJ z6C>G|O++a}%~&AE=A_K+@@{#ZY}*1-s07_6YS%fV9%4>rwb}aUdo2${e;51XX9Xrq z6dsCPkLO%l6!*PD9@aL(bGssLGm8d8w#}Cx=3&$N>>970GepM}NhuV-YnXw3;7{ zrOx8W5~6yVHnc#h%6}>7oMBiv55o)`>f!76>Ch<4Dy+Gf6I`3LdB*Tb=-OLh>&H!G z9jXLPYS@%Mpu;5;G46UP-@W+w#jW)=&%vyJwqa#{^MYQ*t^d%2M{&un{>M*U?=0?~ zTHImA(MYrpxIex`Vu@pPKFI<>r|~E0&LBE^gbAszPPSO{M_)6cT9!h`m?k#ctE5c? zb*^(7uX4?sh2qm6N}!F8t5vz6-x?9>_e<Vq-R|tjZ(3aPEdT2Lw)j&pVe<1pKf@5# zx~p=A*q1mk6ogrFU^sD*y`CVFUVq~LaGG^ob!gw~Msvd<<|v75`tueTFu`8$LKGnv zw{rZ?ndpBXakM#I8ob%`(K^_hoi<<MPb7Xg9g_LFpQe^HnF{;j7pG0jfC<gH$IJ*# zSSB8y-o0LW6Svb-Dy)g^Q}a|TW@Lh=Hcxx5#yo8Ye%dXL-JZ@hRW8;}>4k8;`dP@6 z^Of*OMg*Y<#}Eqq2rE}H-zLJ~av8`O*gSdRZdDD3&rU&Hasw};Sm#9GZ#y(TLUepA zhiJJUd`ZJ2Z7`0vP)FagQuo9kw2~Yy_+rWE_K%I>qhnwsFh9Pf1uUgZoqp%|T}xHl z1OAV7<6q=2iH(3(Z!3@7y-toxBNl3t{{)9Nb<p&9r57pi?&bnjUpg)Y$>ZWQyX7ku zNQy|w$b#@uBtLe4`-T+V+m*a<7{!wLZK2I4Uif)9Wz(w<#LGjFQ5h4HMJHPu7K9$p z#gn^TqKDdKxVj6wm;A<%7uZ@eNLOw?c&l2r<X-sET=|NjZYK@%51|pLW$oj};-i31 zo^!3jza}|3*p#I26QM~CB9Z&3)#P6(=-X<RX#MgK4L70Ii^99Bm|k7HKR38s&!ngn zH0fXNzNx$;S?m<WYYRm@#k`(gj&*1!RXr36^}A^gjTaXWjCE*4?mc|qyT98RU2>UT zdwKbz;wYoVKaeC|7PA|TqWoUjcPr&NcjLuN-{prk!n-u%h|3vjN=l-}duf{9-4x0m zRFhi~>OUl%1mvCYhUJI*LxJp%jGy<)zfRg*)`;Ige%aKm(r+uUp-Bb`AGX%?!mG@! zOGPD_`k1K^)e!0MP?Jb<r@hDZ;4!o+D;GaRsoaZwT7%+(LFykECalYLHIaoZs98fq z(x?!iGHu#TRX1zMGw!8D6@VMT8a0z_oJ3FHlx~UhX=Oo=6<yL&C)&it&BCjdz|k+_ zOVr`N#};`~-lg|^wA*X2JuYkh0d2&0V!MdOmvr&!*!a(VfFFT_k%`pZjF=roDP4o< zBb$l`Mlp|F^1b;RdVg03+*hjfHrOkvi+9v<=@-biCvxSzo&5)WCb#PyD}@G}-+-t* zY7i<ge=OJN3h&EXyu|wBx7h7DFD&)P?E!z`A#8MMe)F8RT*mQJFrury<@WEO(`JUp zN}TY4)p#e7#1(M6$DNFd(|l4`hu-u-cvCozml-m4?uXzxTN!WI({j6T=pX00*>LC~ zJ`24#Ubc9axoN>STBCdn+Sn;M92vul$*)w-p4^FYMP=C20!xX7Uj4SYg^+R!p^5eB zf!&b%m>^raoQ5dxzRX#%>kkK8mQ5BK;Yp1G->F?UY?|2!maMt>7Y*g%N=E5!$B!CM z#v>f}{zCAne2HUUZJM5J1BJ_iQH8+kWhkqbS}gg`qBz;l61GTE5{!I%<Zl}PRzv7) zEf{+(X1KGDZgbE%cam5+4WidSC=^ZOc5Uln!?o3QFH~*^B8)pz?{_?oKNV3-w?E(= zceLJ#D6OC6vUY*;?Bk@YTQrdE(4nKFBOw9iw(Fn3Ix!JqQzx`xoME;9;spo&4RoKU z1{$Z%N`(JP-O_w((<NuEH!=Upe5lwxSz^mB>Mc01Kv@vSphVnIv8ULNF*O_SdMNK3 z1u$Tw9(+Xm<DGiARsGiA{|ad!)OrSH)~!n;#mx^&LNIH@JI^mMzpGL!&2FegZnwp| z@j?UNybPZdYUR=GE(y|ljqYK(TR#sKRl`J~krH|xCSxcTp5QE=tbmM+NvF<wmMy?? zw4&HjS@B%fZw>QD&bR7J!;N&-{OnJ`=-EkVlg`mN4mYB=@f3mGqxTf|r-T6^H5Hfa z<%h}y1xeHE>O?@!db>MS*0`1XA-k^ce1C4)i<&&P&&fRqW^UIT&(z-kC3*I!Dz5Ue zz&F=rXk1RRR3amsptjgWF-1j8jRhk(JwihsK++GnY2bFb6<k$OcE4b&T9_}KhyaD+ zHQSt}xypGB0qK{Yy|YV{8Z-o-_>(w>Cm|LpjQGZp*_LAM(_bF~X+J`5ztZGhPCbOT zJe+2*exdsj;^Q>E=#TAjcl+#izhyCO`eBW*@#Ms$FKqWF!9}FB?b_0A#*@7LzQ)JV z<HAeVWn=c}RrG5tSDex=w`rr8j+=8Gr|C|Y1RCGRHzY>U7a47&BMT^+l#;RNc+Jt& zE1I-|x2)~AhaIwuE7Yz`5n~PahNbLYV_O_9dr;i=t6>KzwnvK>HS*SG$6W__ip<As zmJ>U0b%mU9D|3?ATvo`p%uPL5Ut+$-TeJb%F-P1dyy>NPuVcNgeA_K*9Sf5NRT$%~ zPFV%<Su|iyfw<YdQG%1cD=IYNp~vPl;iYvW;j(I~p9P!jI8iD6#Uhyo727YY9u(Qe zrsrZ^%I~@P%UhnjqN0=6SZhgHDge%P72)3zZ$`=g9Gi#-!7@E@<#yRx57wb=9g+72 z;xXca`__9E!mLCXj>irU1lpY2(z%A|F8e;mQGBXqyXBHwb+F~(3cnZH7nfGh&DFL; zlhBDL<X&r)=eN5@_xaQ+CI;UoQ!yzy<pO<#?zh6HmxB$1Ws8J3W5sq$YiL8iJFe+Y z!;4=orEH8Evrr7o=?l4Ag4%JAQN=O@kuHdv*^<4`Lm(2f4*cmp_K%`wC#EM!hDj|$ z167b*g_b6G|4u9uav5dsh3qzCb{~cAK7Vo!wiOQ4pXIf7%$L0Ln_o6H6f7c=)yH<s zNlU>TCt^99f@*CDn<AuYv0sRB{O8)0fPpv5kW!b-<`<<6hcL{_gG2!-%pg`@z7Tc8 zCIX%ElrbmlhDPiPue-mNs@YSowPJpm#9&pl5|hY3mXI!MMpHzVaYD%#Ert4EX=m-m zoKv!Xkw;<K>h?+_L5@r)AP>8*o2e~|+T=Gm@3Z@!r2Qn8dk1Q!_)Iiu{%ew6fFc%b zaWpi3+}WyN6$+Tw7jZ)ah;L>CiTPCm!Wg}^0$%5?1wkyzpI307dAzeU=x%$=$eJb- zw-~iVpzI34>rO9&ql@W9o%-RUjp@TI=pa|EyyQZugLJ8blC~Mg5rc^tR^|iAWD}3G zxKzmT-qhU)x057yIT5}{l8L3bwDFivv9*c~onJNIb()xM@L7C1M!6=<ABn4SFaux4 z(Cl@>{+E|lZw~2J^D0KlRTh7Vrg*uaDL8wl5TMASoRlXsyn9O{K4Vk=l;%d>EXqqQ zoU*F;FQ!#Wl@qmkN>IAO$#o4Ml6i2{G45G9N7j~669+;3Rt(ih*3}eEcV}b%HU{Iy zobarj^bKFVNL8{RL#cqLz9{6>l&42?V$Un{8B{UFl1z6qABOf@P>pHKDzjDzWBCc) zQuF&M=}v}R1-4Mr8Ryt0*LM($YN+n!;Q$L(or_o`NxIyx8X1w5S?nY^7rNh8!5sd~ zv726S%Fhqbtk-dkNpd19=b^&fhGLrx1mbo*O)m3&s6{6Og0;{c&v~<q07aQrjuyhZ zZ3IPZZmjvO7eiSrCwK~O`F^=E^g%K__h{^F>?3JbSJSuf*VeVD<t#s=1j%3_YM~M6 z%=iJAtiaX6M(wn!IPtTw+mjwIP<T8E4Ciu0pv#HaY;OJCP#R%r5APwo7f;P=VpY`e zBBn$8PrIo;cYY#6HZmJ3V7Vf~kp>rBFr`w2=^MXLN|&kc#SV8{8yb7n%{>%D6hEc+ zF9CNKQbZ%QrsQTrMakUnqjHY;&dbw^w<#06l{CPxkUpB%e!J^_cFmmSb#5UROP22@ zkkR4pYr~?LPGXs2Ll^rlpQptgW~WP@W%ah-6=~QG-8N+`muBxHwqn8Ea!_qt2B<q< zx)Iws^VVKff^@?SYATo%Q{n_th>%&-_=qnl@k&Q^R_8cF-u{KrQ^T{eDtuQ)OoYkE zKd54b$(a$5nF1SK#q_upZ*`DR3Uf*eNChoYHl?!;?0%4r@UvKQetKab<VDo~5;UMN zhU*~;NU5o1RaI3LR|E3KzsuI>gS$Kkbk9AO=q%;|q^{=S>`2}$vs{X5l8aT*sExTf z+LiADd%nCHD7Mo6I_oO2kj0;RfiM2{(mWH7-yj1HjU#xaJ{UBZ!cm8n>$W#E)`aSc zE=d~BO7ui;6x$)a4rFw{B$lND!rjA%HO*7xY96jE8L}(~1tDvD;AjS?F6bG+nL0i> zX|cb7CL-*4^j7=v3Us72p`kb(GBJ`6wMrT*i|Rzlwe^IAT`)Em6a34R)bcLEGCsK% zj-|?P<!zIrwl%Zt0JoH-CZO^M&HItQWkSGm2M?1&8RfGg8vz<Jz!V7#a@7(!`R5WF zN6X#+o<u-Ez{ZfP_mfLIT2N&V>_<>s5GiHa(rv~KBiMsOA43GDr+@z(8o*EvVl??; z1`Ag;%{h7gJz+U10k9S3|E{o~L55)dJh+bE{}Pu<C=`%!^jV{G)#M={VTh5A!2Ks6 zhDp)6SZ>fS(Bjv>>wO|}_Df@?)eDl#Dg|bZlxYtJ_h8M!Uk)B1E!9q_)ZBDE1;k_` zV^DH+-kSUeh&1d+k5f7hDzL3+kNxje^W~BBovn)OS`0bOHb*ja>+Q&{udj)3iC9*~ zf%ikLO#5FK2KG;YR1g_Ws~LVko6#vZj9Okc75V#}LATx4OWXJr%wv3!lNT0#KdleL zV03qLTTXWwv37cI_iU_-!5NS*!*LmKUS$wmNJt>*ph(gN7A^Kq`e@_eu9GyD+&f|% z{;2R~X(DLl-+Vh>YI!=wmJ1C-UuvcfRrtt?V}&F7r1r~dmm6b%ZjTd6{|Rkx@$y8} zCx%#PboSD>3nNUcFY+;rlON+SrjZk&;Xld9!|-uMMv-B1<Z`dWFczPkyh$lQnX<;0 z07PF2HGn=5;0~~{vCUzWFOs7%^phCnL92;Mhea_Y2^}3B1363n^GIdcdaJTg@dsZ@ zs3VfF``&lQPi60|=NbNa-NJDwvXg({D%GwcNSKN7rD&Bk8q4RL>n-F)urro8LO}`8 zm_7rb0TjN1(Ai*=mouG<?}+BQUove>d%zOA3euXn{?@Uq=yCV-09Y(28Wv+N7Xtcp z{OhnBPgp(KN}?hrHw}Z+-g`ZtB1X<<%3Urzz8by9Fn+klTMd3D2z_HoYy1^WUMMxT zLPCEr46NrQ&)OSr-@kbRUE;Tt?Pqlr%f;PZhSzb6eQB!V;avCo4-xw%SVpgC<TWD% zDv_t#Pcj-;PN}V4EVW2qPA&RAo#VP<y+3NsA5#b%3ZHsn{nM3}BxW!699eCEUr?Y< zAE(9RaOB4r$d7)MY&?(5vx(=%1}_!xK*6*URk|{O)x$?~X>Ki@zhRaSULQ;~1MVOf zp*dH2Hf0S)`Cvx*YUIaL33{L7UK|$goEi?M@IY+7(Md8`C`IV~TLeGTQ9fnH`{p3^ zD;|MV=Uc|2-xJY_Hspr+BlPs~ilgUT5}<8Uu5!a_!$NYupNBtH{Chu4JTVu+DWe6f zGOA<~Z?xmYSg4;D0Rz_qinx!BF#0arA47uYBkfOhGN&>43aQAWXid;=)c5|+3m{RP zEVtf!;{=3|<xf_R-d|<RInG}DYvN(kefK)LUI=_R&BRh)xW{b2E2CMx!E3`!&2U2g z;{I{Zk9>4WXLUc7L)zC4kJ@jIU=L~-MoitTW7qS^U__QpS2wo(PYxX{e9xLR9PD{| zc%8n(D}Sqn>CiygE(o)YZ<p<hJkeh5Nd71=g<`LZ_mE+ho%||2c$i{xY>xcL2_fDj zz|tsTzalJ|ED`+&KiS9~6>EOvN&4+hJ8sszB(`rNJ8WBa+rk;+;G)RixrZGOM!ac- zYKE+q^$1dUXFsF0AR85}#zH0e6B_h;_41}-J|xeZjdP}z{5UA}Xpn_}>4!4vH^WR# zMx@sy3*#nBChc(g1jVDcivT18?e**^xvrqngRa$hCf37+Xj9R^4<iOoig`l`%{C{v z7!3U$^Ap>6{>AWE6~4eTTg~4D7UJ;K%z($6Ssoj~E|!hb4EaMPG=RyB6Q#w6#j$6p z#$kI{8BW_@_2Yd{ckoWa2rq+7WbQ#N6&W!Am|m5)d@&O9=1JyeolI1b`UiSN?In<( zwi49bSop46kk^uRMEtZe)|M!IDb+!<X=nH$mnAznT+OETR6hIVB~NCN{Ff+{XeOvS zT9`;r73}D%^dm$6&L@#pEKf5~jFC|lr{500N?qx@=lo*o+;!zjzyA8GWe2`%G`E7< z@5V<II%wZm19*998PhM3GW~W~v)?uLinKCHmLPM9gco{Xzniz%B>>bXuPnW&>)EN< z{Ew64>raa6PyP^|<JN4a!;gb0h;j-yHjh=LvUa^g7T~C!&W4xbxPM{0WU?9Q5NVlb zoKp$#8C+fcMjqPyp=yW|rE0}c3~ovEDk(_7qxmsW((Y@_i&3TDZ)<X)Sq~B&tSIYN zWcG`iv=N?p{E6PJPe)e$NSIr>QoYz8&|=SIe7Ui>d>C*_?|<DL;dCBRE_rn<$NeXO zV1!C7^32xpW|+?Z{LlM6&s+aLH?c;JQ--new+m;aV~>9sZX{`|g-uj?SwB)0yR*Md z(&%?saD9}rE{Dgh#2_=c82zxC=OEF1A@6$y=AMNt-qO_@o(k)Fo71>!H9HL>P~L1W z-zvVB>h{8JF}dP9@H>r|(KzUD5kEC(bo8>8+(pCvL)9;c%Q|}D!J;2|$3QF&=y`s5 zHb{RK4Pq_<97{uMCtg-%1mSeiz4Tq&Lqz|u3&*f1V*<Ty{iDNnZ-%2@hm}H)2UTp` zg_yYofBrRA1kLQR%k5Dnz5AUvzW(z_!^c5l!9H2g;PupY3_mG4DsQs*R>S^iH<+2d zD`vMGp4n(zD)(mv4(Gt8`Q>tajOR|n!X_aQ>PzB-<_C<+RPV^e=GC&TXMriWYe!g( zhy5>C%qreKL<axxpbPBE@oT~7G>&-YMIsbi>9aZb`pKZvNWp~TRv5va?-nMm4mm!n zX^ugHJK2Y;_XhTk{|NC_A^LJG(8;J`y2iN%oPey+z>Nq%R*hvZG|oVT8Qh~DLc>4i zJ%4JnW=`Wf!h=hyAg;UB>7yY(ldzuxE2WwY%Foa}L?Q#`igRReZAUtY1=?2mKKf91 zLDu~ZJBsnx)$z+etR1;rE;B@oy+&@RCDLiz<S#v05uE2iEz9{yWQ~yU@|(HcxR8jh zSee7SN6Wgu;aNB-ccJ5@{V}?Fv*<%jj?&vpveb6y3n4DXkKg+f{tVXoNKgk!U!o_( zbLIZVkwY`^)aiWEp)-Z=u5y_h>l~Qo%m==(Mpt)-7aCd0`n{CG1f#V|t(Dor0M8v8 zS4&2&n8Mr@-n>7Z(zh`lwWNW-EN$6nyZqX4Py8|5>KA?X1?BAli`XL!2}IB9USh-J zOr6dz-?nCX+4~k!&n3%egK-|kGHQ+8Z#Q0fJm4QDKb7Lm5{zPCj1nroMJzv;-k4gt z%ev+eD<b6WA|>~-Yd;oWc58s*3rP~?LmxD<!cp%^q;uuutf%lyALwXyISp}(`G^cl zTP`y$x1Jr2l-z2PGsI00E<jx9Ed~-NHMHwF^n_meDA~q>dDGcmBkQ#V@M9q1GD!PD z+<9yM9pd!Gj8Y7ynbF#jvUpV#lfJK4SH)Sf)kIEs{<yny-P)-IN>PSIZqlUU^X-(y zy``)>V&d~xHB5X@P|<eJe9HNv-Mfxg_H&>1<$u`gXAkk~;=Oc5a%(ZI#M^gZ;pf5G z7?R*+)-g&o01)Ok$&f!a`jBF3VS+@_PnM?G#rC$h#DcXkg#rW)fZIDVFlDEJJTn+` z>L6&cW<LDzpEF(>6Pe9|zkc=~W+g_`oc=AuleC^>5%O<M=^^OHJF7uGlJdm1Dnvse z2lTl-^QLM)WQa2Zekn$Ilzbwv2H8J70hS#50XR@~0$X%CE9alD9)JI9{TICVABjxQ z4Z!MTQAk9KTcwqM3XIBH5z3#chm`(do^Bx4*d8#QU0i^#3^lbXtoYYQ@!xOx-`_kE zkz6!s1FEP%*TeF;p)yzRa*K_jvF#pxTOfo2qi!=N0IXBwajS0ucmOoGB+;v>oT~r- z6$3w$Dd7nT1VEfE)vH05#5a$NNp|+mgNNbImTvMY8?-VgRBW7hahSAIV&GASZhC=U zf^forUr;MUY^T>XBQx<-u!Ey6m1!k4|JWjGFquga!esF4x!qY4lj1}JOg=GNzpTs6 zsMM&1UwD)!b<pAtGC@A9L^A#l(J{&=QW-OZ2JSYG>6?w`z5?E3$tJ@Qk>|#%eH{fn zeAk&2mI`c6k8<kXdp*7uG>Q;Y9UVB7U!0h}y}ot$zPlQrdZ9GId()QuRH4`o3587Y z8u5^+8pzQ95%iqZu@S>N&RY0H#M(hKAL7}0*xga+k#l%e<GkQZJ=O+oTx)%u_{G8= zdbsU#LY*#fJ6|lDxVX4RGM{=9R6#QTm5N4bG}H5A!M4-k?*sT2d4b3Y-|DF1s00&S zfh{H`MglX)xhdUfdM{vUy5QlehD9D_+6~ggyZE8PRQRb>?I-K|%njJw@pSUG`vtEB zLQKwgb63fv<ERVkpZ6VfEm}st%goI1SK;}7Atiie-Ec0SSZkQ&*?obX`ba}HhGn8) zFU==!9`TVH;^ojj`u#g5FplQGvAz=i`PHyMx$S#a)L`uu-*IGss`I;@ckSVZVvQ<m zf8QQ3=xa2$4}3i~Pn^R~QU!1myxZHAYSZ$^)5vDqRwrbaHED6oM*YbQoE^7!mwd0$ zt@nQ)r=5HnB;B+S&JakUwkq@(@>rkdJu7FcD4=wjGyRSEes{>WsXUDeqw}J?iR*F` zbRYi0Vu|7b9tACCu${zD&&Cj)M%Q5BOP{A5f*rq?asB6umvH?Z;=~I=goo-t^X|{h zT|HE;;_p+Hz1IJ7Pc(*z4=OF=CdLzn2@fIdxH?5dHGrwI`+KIse<Xc=UikfMt@-?g zEiZY|^zM-eo+&9v<2-onN-eSrcALRxdR}C0jLH!3AK*EMAbRl8j{F{=ZzZ@$`d<Q^ z#P3NdFiIV{N_yo>?L-L+1{voHG<>&tc9T`QN8qWz${$js@1H^ciothBuLbA(HFe)8 zfW-hrX=421WKf|-M*39BJcecAqZ)!DGZZwoQqrB^eZ`q7oya&V49xf_mq@hO-6>6T z8;c2n<84<yV?JJ)sq;xwsh7&5vbP1Jb*Nsy<X#156tIDQg}|1PWJ@l@ITN>9+bRum z%&DwPyZ468%%6DCC6VaR$YW*u3Z-%ap>Z`AYoliD|HIT<g|*d1?V@;~IJ9VRFYXrH zT?>UGEl$w@#U;4AyGx-!DHPY@?oiyVxI3Kn{r^7u**D2m@~q5E8FRem0^EOrGj6Zw z5I6Te1Gm}=dm_V$c=K@BJSp(Y;s||XK{UAxF2HE4H<s@U>-a)cpw3t~z%xkOfo+(} z3}<g(g-2DHzUQ&vV`XPGj$6$b@Mk{jauyOBfk5fvvxzK%pIm{bw!h~h&OS&S8z8HZ zB!Yh)*w>$U<ftzFm~!=Ip0#LxpE!)r;C5my5#lHpC5-EWxyVn;d?j|kxQTq;G-(Cc zok?pTF`3tc1RMe=tvI)rt){r+|1gM190Jjj@&Do4gEvUW*jW0F{snt<>6D@qy!)5H zpJAhHBYz=3zu~nM^|jPGqfNLHXl^cWL-lAy<SzQW_zy(0*n6-SL(M3^gS2h34;-iA zH`b#At*hkr)A#p!0%Z#)f9+YX;hrkktB6jV-v1t8OEAoDOQuBw21MtRs@GzY^~;f2 zZCEu@`G`27VdN3Q0m1m?FAIYc7JQU-E|rILGj3qF=k$!h7Xb~D9;4yMwNwGPeTe4w zq+<pBPiwchAz#o5@-5e4_JD8uxYZ`suU^v)EPdw1C2*S4PbH_rX8XwHIE=GLWfZr# zlbuI##q>&kAA9O$iB^YD;kvnnTZ7R0ZnBxA(QA}`vO2fM!Xb|yDCn8yhwNj9@Ax;C zell9_qJ{(KWr<9dlRObip-^zggl|drHfgl%O~bJx$j1)F%{teKMW!CMM4T|_+8B6B zcLISD(`ApI!!00J9qyl^CT27S-dveEf}XRMY^S&l{3cep&NUKffv|gku23sc^hxOZ zjgx)TPD*U<w>iCqO<=T%rP~FY-0ZnBgQ5sR`H;{gGfG%}_yAUqPQ`EO0r{VTRz=af z0;(kwBdBr2*XwVnF}kCgz**DzkY%M(H)=<TThwkG;OvW_23%7KV7<A?NRgz}Ifi+b z+W{(1-{%jBjjhiG%NTIP1Bv$^Xg}Av7Bwo=WW-?cPbGN_BYn{hQ`o=T%^RO2iPNB= z+C_<Dey1r^6xV1%A8c4XAA5OW%__fvFpx#0Z#>P26KhSA=JYn?%T1P9-M%Qe(b-&r zR4}5z))`NrK;%y$A9!S1v|tcsAZvxGOv$0clbZxg4lDSHtFfyiu==G0ITFr3`L*Y> zK%Vl@Uuc#x`GJwas=UPc0G?oYQJj^bz{GA}Fo^#SUJq=0VGH!h7KA5rw&6ln(@DQJ z%MpbTkB?62H8ZS4-kHf(g^geR085_@ycIzt;~MFr0g3fUVTE{TC&}H6%5!4NPUHaU zxM*1#=b^=8FHiCWYlO%4Q_I$k(|!rcL7wx_TTQ%<gIfrqg{(kRI|D~Iwi!L~Hn125 z%`=bCp4n8iW)81yjh$(fz2eN0R)ceLF@&*o;>l?pB~Evn*~(|X(toNmZY-4BlCgG3 ze~darJF&$b*!!h)(PKv{){}Af$DjBVN|$GTf?riDAivd|`Vx|p?5iqWA9zKJ9TA7M zPIqX4<*^=v==jk3eXTKvySkV24ZJkIo1=(+#jO5nuFKno3b5ORC?_|?art|Bx0q02 zf%Pq-fF=9{tr+1y9JXi$=Pamh@{K>vluZK3-YR>w>r{|6RI8jRdwro^1{O`pk^-B` zlej<p;wP{hjt&Qz5x!fTXz8=%Ce|DGgcWjhw~6Kpxc6(MGu>TK5H??CW1#4;T~xU6 zKnT>UGZBUU1fVc<XTBYvH0b(9bDngWcG=rQR`h9<g>&r|_(qi77`$WlO@=|N%E|xE z9NTy;^9MM9)R~yy_IN{<ifi0tBGXr@`8}xeQ$zc|5gcwb4s|gMG%hBeF$40^y@(l> z(M=7CoPt7|vnyg^lq$&nDbu2~1{b%v0%_b^);1Q<{MA#B`hyQq2*3>;B8bOeUP)aG zl!KvV#hFyjAF>WbGfN@__SkT}MUr(#N(`i{f}yTE??{mb@NqDSkaw+r4xS6gfY)U) zlP8Hr0eqe#3kRmBuj~QDuZ7*18&7cv;%F{D>7D@Z>8j~;RfS}7Ah?uV<4CEXfq>N+ zrUn3^Z-SNY;{u8-0e)&a*r{n3SIb_$k$O`DZIi*+3qjl4wA4C+67`o?{V*d`N+Be` z5=oG8(<||Wte+FW<>@1fvfO79a$*DD=p$A!T4N3pZ^yHEVm}C<&^j;hM5_Wss_<pp zHTm%KE5T#VW_}S;5n(3xF^Va8gZ7a&Wv{RofYX#dMGt3VVY9E-c(U0S;X78Vko4`l zP6aCnZ`$k3N_0LLV%l}8a5y-hEjP*(FmTI<jWXH(b&nPrDEq4$llWNB{;yT#<-Iq$ z{GM#0aMx8-k&PhxKpE6BNQ}D@{ye}IfjyMcV|{%Un#CeHtkfxA;;{f)3AKEKN;~O! z9tCKrKC)OG+E^sXi|)U=jv-eHJ{P*}6xTzhRBXCy+s)SY+vFS0m9x|RseC#;{$#(y z+DAp7$e2C6W*Js|{5$gV{4?3Hl+*43IsM7{e14m}-#psMy3=sQdsNDd#_kbG=jAS% zHSis<0nY=WSctN;gkZO`h=dwP&>rR>C35JfFX9-YFC!Ib@U6j)Q};E_x%dChaACm{ zN)g%S;GB4~h(n?nVRy&G)K(`E6|Z;@`as{Lehgs7Z<r?{{|K9l942+k@qmTgFjtNO z*@u>x3ad<rf1n_C9~zM_7SSVkEHT1&i<ePcz-gdM>kK5`ILRyc%Ih#%{l^m3E7$`( zU5Yio_o_mPd7z;2Ih+(gm!gMbJ~S4Uj>V%yD-gCFpcpVr!}f%{-wg5TiGF+gZzKns z`&(~eSJrvm`ZDAB4^%r^t~zjBq9as&MC%lyXgXJMnX3^L`O1wc7z>y16S#A-{F9Va zuzWtVVl@nvOKqg0v5fvjZ-9np{QW6#F62(aPcCyBnq_NeW!U|n=4QxuTuJY)(Y{%X z_%nI%I)s;u0$AL%Q~()FHnx<(T18ndYCBoZ+2c(%hCpSoUc20>l-L$rny^+KXVagJ zi@{qwwaW|7GW)Cvl1S!Z2=jhJ4;_A4(Ti@@MMwUGvaZ+W>LaV^e)>&HcK)Q6V5R zX}O6?E{XK*3l?Nr;zDtfx*hOj9QnOP#{dq4c6QO2El*5c3s7=+$y>3<7b<xrMNzRc z^E`UE8}h`a;Steq^&aMgmugG?>7q_WBd^@X^}_nN|6F#GCfDZC7k3q%&bf&aTQyiK zWub=xim>?po__@C1eM4M&Pw*6=|{Y30dFDic72d=V{4E9S}GzMmPM0Y;Vob7$uj50 zj=R~mN1O0@3fKIyYg#dQS)<skSme)ezk5$=JAHqApiKgM)i7hDTyFlU;9a4J443@) zU^Zu!TVoF0`X4gumsZ;8R-OdQ*G5~d-*D`a+qkByr+<_RJ*+wU$;|qJQrp`hLp*+| z6quUl5myQ6qja6Jt|`J%Z-cm?pwtc5#_prvg(F?S1WT=et|$pbUomW88R_)g15no2 z-};f2cA>(H*HaVCmrfszocfepn+!{ioPo}1B#qpK1f<AExv~4l2oaEVvalCZy(IuZ zMXaoZ7JB>#6841*K<bk@qFWA{RKoKn{0#663l^(vok|*lY(SyoewJ_<+<`x?nEA2U z5ZkyENCqR6(Fg)yFJxw6CkuhN^>_txx?&Km`G^FLNLEw$2r7ZDMP1G4TRuN1m%G7z zgU#p7Tdv_P_w6ZVk&A~9SdhW3ZN*Tz_je^baKS*dfm$tmf-oOA&q-YAmKL5NG(>KV ziOa$B27+gH)98pe@(zD|=FExrA(vSnt3Hfjd1;Rhz6i3!>xvte$GdxAjb-cJ6E@F% zX(eW7;AE@de?j5|l-89xwetAvr5l+eQ8$jgf1*WF?Q#s)I}=}U2a495P5b6!OS1(z z*1w&YA-P9$^G_@jT}<KR@KVG2lG#C=7DEdL__Zgw!fW1Q7h&YO4-ly#L?$HZ5n0C^ zL#|A*QD2-KD$Y=o3GTGf)K;D#VTPyEM$SERO^cM67pPBPARf5KY4t)BS)YG#&0v?& zL<J=*N|5*+!cTC~rM$Z^nO#bz<HVqnqdSWKki#fTtRP$`3-2Z$EcGjN_40yiwL@W^ zD(|!G>L8`FVLvzjaYl>>6B~#Y!flr_pRNiT&x^0z&?B}7mhzsDh{Y@7X&aS~*^T++ z+F63kwCu%u<Y@)E&aWv!&YvZT{fxMJy$DA<{c^r>(R9q9o1t)`xuuQnLMlvec%y*= z;G>=HNxz3U*QnRO65xWzJvol%=Ex8aigKSz1Yx1=12w4J7!bTPLZxOPH!b3EmQQxF zE|h5bsjr(XE7p5l6~%2LXSXr%h;*%^HNb*pd9q6R7ug9%=G-V8{i)^7JU26myLk2) z%}OLna$GizWgH0aZt)yLus_TKB|(>2IY@Y9J@S4G?B=-AeNB7Xw)5!Cvi#+S$_aRp zeM1F6PC{-L14}!<1HrB5S3<Fr36|r-L?Z+Ex<bpH(C$vH0~ZzYoe~wvzC=<#O_wVX z2b>)&jOxOoeL9&SmD2D6B!e>#L9FX{IG2KOC03$t+V0wk=mfC@xN7d!1U_@O&qp4N zDnEY90te>?-D&!Io`0Ytw~cuW?+#|F#Z{UdgL1FkT<isjtMd>TL<i|zvoFBOO_MWs z0Sv?q*eo%#E&R~fS-I{zAA?ZeI(3UrV%vXqpC%ti$#^Df#STf$IzLhsE=|f}H|kd+ z{vYnKL<&4$h=O}MxPH!paE$3GYmYPf@F`*j8YgpG%v%^DyZTejD`j=%$MfD8?JEW* zPX1nAo8n`46bUr0Pf54YX*YV#!1cT3pDZ@h8&HOZe$|yiu6li(7~%N{7=dF>n`KJs z3S8HB?J4q@D+f2q#OG}#-g00Fx%@NC(}Y{pCPU}ot#$!q?N-t+6pM7iGY`gE?^~@f z4l5Ev-kWYiwsWZrRXrz1rp_!WpZl({$8j$3-mOB^xW+&|aWA`_i&35#@8AIRp_Q=G zSu}S%OU{UI$ivJcZUoKYN(_|OIu08a24U0tHHvJ~d9)e~V-%f#p*t=aJzwR~Cp97% z1@WGV<Bt!VC1_)nyZ0=NggBSRSVrvMLI#G`BIh6Q|88?xSA~ZQk4&jO<d`MjB<pQ{ z-NagKDKZAa>gxRDW6y2y#~JU20!u9D`hc86_L{B6z*V5As5cY7%R|CX%Xo;;wK?0{ zPA71NAq=ATlX<f?jq!WQj{YE`pzel-3L;0}UgDkPi8Es2t-~7_x%Mw{3!DI#N1+T* z8n7u}aqF|kjE|DnpF4sa=+*<h+}Cq$@!3sxC2Z~GJPv+`3paM#32hqmpDU7Y_74om z?~P%s0Br=@a=2WsZV~C}={=NOIbT$79Qn<W^}gWS+_MlmZqFgoqOb+X8>Ll22Sr{n z2LuWHw1h8vOvde9qvtgcr$026yPpxTl7M~PmBMJKdw6Xmhf=ZYlHSN!D8<9!#1{Hf zN;XqYV-!#D{qTlj;E4)XCynNn^J;DP;q9otk+UsD?8C(c#bT!!i$LDS;ZWfztsA7+ zey;4&ZENx^_u_c+o7{Do2!A<-(eFY}`Vg<K$5D4ae?Fg<uy?s678dtb&y7(RT%=X< z?$&Q(5ukDjmZk2r@z@{pY~p?uDoA*TA?wz+9>w4OJcof&Kh)ZWiy;~_7)59^zSW1L zU<c6&uIqi$CoR9`&-T>(Y3ANo`)58%?$N_#Jj&=2#Rq|`6{+_KN|Qav9amIsMTE@H z<t=h=IiiV%g{p8f%Jufdz>%!yn%UuISHrIs5`H&I=4R9<3F5gd6JgKZ_?##g=t0>9 z#$2@D=H63i(ZtWG1nx}>B1~bO@bL>u@?1myaBF){*?s>MzVer($z6HG`R7E>#Rf9{ z+5)eia|v=g+o*oF)m<F8Wm%iwPCM&+1k?cublWyvO8obom{XIGz%dEtR0n4>kp&si zi2z-lw8lW;(yJrLzfms%_n9;`oo!--_O-jygUjQ-q01LD(fvLaV_vze%q>R`*qpc6 z6xEf-(3`j|(@iX+0)8O<u-@{=7KOkGM?Z!0{T94zjPQuRDE;`T@?YR$pK6V@tg_r? zhd7vU`k3CD@%+=<FB2Y+x}+MKQZIkWiSIoYs>UkNbjEi}qv=y=;;uC=i3V!LN~-ht zqulhSjV=gKVscQ%j4P+_HYVxHVPIpcdBDMj3uhp|hoW(b&2th8QOL+E_d*g%HJWO> zh8ss1vjj`VA)ictOm<j=gV*AoZg;8cGf&6*N7FUbxR1v~)M}UeY`ON(H=5Z1vi8!L zi~~Pm7PE>on8N>SyXvks9y$CjE-}`CVA&3xfw#!0CU})cNz!(#Xm3m2V|z5qa4a)% zbm~nld9ttrI4#{$Fm3IUcROAJYpMyl?ae(7-n<ye7O4_n%%1-|=0b6ZL4ePbUM#n} zyUSa;OvP6izx;(G8<{+cBN}&27;KiVCpW#o&kYZG(>JWwl)u&KKi`-6IbAMeQ=ku6 zcf-Ptp_8_od%s2>ZQYSFQ<c&%<97w+EeLuc!vVKC>G<>R#CV|h$2X{{q&b+obb1CI zli%*l1Yedd>Z8_DZ<Xq|zO<~ex9b8U=oKQI4N0^{!5N`KSZ3lHKeT43ZbeE${9ILd zFS>5Cd;&qU&mH02aQga>#d%wBezKJ(BQ^Shm-AbiHTu#u5Y=IBfv!>-n>vzCS#0PS zdO5dT>aE<Whoy8eO6KTX@U|b_Tf2@4WFZ^A#MF*WA1J)2Vr%EdHv!1@N`Z6Gc2#*D zE2n06r+m3-bBup)$Gx$;=MB)AYR}Q?CG%$N1+rOFXEJsifGGx7KaC4qX}%^MY+}_W zWew9C&xbpP3dR*1su9f7SagdS6FT?&I^b~x1)Fkd5vI-W&7vJ6$Q(O{>b-Z^#B$nH zDxQKC{<$|g3DVCZcGkoxrt|Ow(mjqAf1@`UU;)N8{j<M6{i>S?r$*P$&s+Pyz5q6W z$;P5qVLv4kUA_HEL^LVCtBd@c<i>wgn4g~4|6){Sj2Pd_-~zrzfHRcN-)9SJ*+D4S zcBT29c9#hN*^Gt7Ff24UPym|s6gERo17qiwiz6mMZf($@l31C2rrf^k@nZ0QilHqe z07Y|w@RCH^LaK^uvPF%)ntvCG1-KP`hx#PlaZPNpva-LRYXH(xms5b-0>CH#vVgQ} z;5}fa#m#iS%J5^G=eJ=b-r6IdUrBoXK>rn*(CQbW8Lr55wAw}rsO)6i+!_pV{}*}r zKNO~nx;fxuyZ|i-AQde;5pkRj9uA~$ghrgBxa8>#8?mKQ6$7e*+-TMR7q<CM6KVly zpa2$Uqcc?KoYUY1(_wR?@Culw|1qIF%?|%#ABv`9)&h86{Lb|D_P~Xe$(F$MuNj5o z`eLn?ms%OM?4xHPLp_o7ahuy@x&olj0o2-LjHCEWWP;p0cCayxJi!&0642;y1Iq0G z;6<aB;=^*+`Wd9sS_MLOlsVR+5849UyH~Y?kkjvPlFrb~QwZ4NtG|%<t<-Q!asRl_ zcjB3giPfx|hWszU=1o`p7U*RBH;{>Cb~p~MiT}gl{13<YuKf=cW3&i=*&h5n=!kLm zcP%^%=~7QEMawkD$sq^d+<F6<%AGO*>-iY428$a#+P!SP$FTlCD3+)ez<&dSdjKL4 zbbo>hz!Lsat};>kRt<cFrG~uwPlij%XFE{xnym~Q8K)_9E)=pe%L%vK0Hk&fceQwB zko0jY@-r*4jNnS=18*u{Mkjzb#AGA%H-f@dDzt5(*-j~?#D1McWfbnyuU{_j?*Zan zNJz*}AVtjkERez$-V<CjCUe${J>g<V_=Tt*3>G9Exb*>Yj<%fyd!SMC9WU4J8^MH* zSNoGG-2#G)bNXG-3@u%2p(*8n%kVR7UbcQ{mifhhOsH&OH;Yiq+#lD50QqZ7a1Z=n zrqpW;m^dN;fWBJqHY3xwe7Vd%q51>byDXoZ1;E&-c-BG3(h~Hn%FHblI_I7f3V^0e zbdd4kr0jP*|1(HDq}KFZgvkaJ!mbzq%`Vlzi8IH~mw8j*&*SQ?C|J;m2<URb2<zKn z8u*Yot;u)&cY@C+W`ZbpO-j3aLr~Jdm|2%rKJm}x_B8Xn5kDDy(rsqGZ{S1T6 zHD3K1KFe8h=m&|O!NYX|tMP0~iM>FlVq+07_qSndMs-_z&Yt{S(aGH6y3y*)*6EK3 z`ssdd0th;h&DH2B3lmu3{?^-({^98PJ#Pd6kE)B#z`y~$x6Si@ihe-7x44=qR-yUk zKUXp!C+erir3Emnwu>(8USFQwchfC#WN-nUoegvsVQ#JJP_+W@hdCT<OCYR(5#N;x z2{K;Gbc5drbN+UzdUfP{zXE)??xzA%Fi*JuCLW~883+24h<f5~H`X_tF`TLxvF1uy zJW-fB<FjE@${1y^qasWPkQ52QXBbN;g7i^v^d%07;@IjEaN6PO5Z=P|!%rbeHcw2! zYa=j<3n1w8vNpv1^6;a}h!H1|=(a5*7|o4-P+!8sthq5cQh9enE`L6ZIQ}P*t>-~0 zV?I)gau5D{K!gb@6}+6Jl{h+bJc7OzrD}|ux-88PYG-BbOTXezuR8pK61lj2-%fl? z7<`+qPhrKDh;Sz_2U=ytA~?fi-OuAkeNy9OQbeVWhS-ARa=#sg$i0d~3^-u<Qn=vz zuWEgRKP4<W2D<`5xH7m^jhhjPC(6av5!Z+FTfu}zol5L&L4YKCUErxNmmfn43~|TN zHT?F@scBikOQ(`Iffg{FVXwDc2q?|*d=p8)DygfR+KY)EHxRCnP_*USkn$hq476P@ zcc*zq|IO3m-$!gU7Q;uQvwM8vUP+UiFR}Qg>Z=C29_g{_9yDTBNErFDtp%o6N@69g zPPvoDDZXcFb6Cy2Q-LrzEd96XsM3mOc$gC+RyScn^RZze0X<<luq|;Lcy~51Q|3p* z0eat5ya~=Cez*-*<OB&TDoQet{)fCE*a&Ngsy8ZoKuqX{KxCeiXx)#lc#nOKkOZtC zWvVs^-hp@!Q;;@}e~`Shd^S$Oy2MwI<PNTGtfaVv4LlW@)ucB)Q^q(0xcWfA9m^#{ zvJvZN5mFSbdJG~vj=BcMymMTU!t^s!X`BouKQ2yq=l~j3aR>>E6fK%dmbgISScHy> zrQKTr^kjth{wdW$+y&O+c^}>+_u&*`WzIAopoZ_B!uxyTNj2k9M{Brx!Am=85ef;0 zd}I&ZVxo=4O~REFq7x^WIP;1l_aK&(!6|T2G*ed$*ERA$2L6&+=r0dyiRL*HC>U^{ zo&lsi7#Qn=47oieDw&Hy--15;yB2D0Y2lXJHN#|;Pe201CPvjX5!3*u04UoED=LOj zBnhp~2EMIWCkxbHjR0y9RH|R-=u`kX<`a?+go>1$JY?^2pDj59mly>mCo4-yMkr!f z*^$WxG-aHcFxGA-KM1`nLcykHMNyJev67;G1_i<~rZb0_+fMKZYq>fp*;UEoptH7` z>UT1@z?P5G%X!fR_VjFqXQlUXsN@~m;o9Ws6?fpLR2$n);Zf13(pImSiz|QID+%w@ z*49~8TaYCATVLk4P9S-u9^2asMuLbqJFo)!FBTP9fW!dF2y<8KcDbKH*nfhXK%)es ze$P*WInvUazfD3wqBQ3=rPh8U@Qicf1m_js$2*Wm_=YV{5hr*uN~R85ku8Mg5$6$B z8k+xs+?q)8hLDmPbLO21dq5N-DzVf(j0SFJW+M+t`@Om^zqXxN-t|7WqBs+(;6I4f z%1Biik>Z<yqJy)6b_mB?Nny6D8mc^P=|u|hBZ>f`0mM*JN1a_tohzCJ9}JT+4BXT> zZEUHMK`U2z$%D7lb{4s`Z-b^LBqa(DmQmq6uRQWxxbf+bg5JhSN}!8JTQ~$M<_E(C zS@>1M@nRfgqmbE!IzCW+3*t$R^Ch=_Pw9dbPOWVKAN2SYx`u&xSz|T~?q9azp^r|t z5Go@Lp(>w!53JO}Nup`2N#|ng3}g?r6dEZ#S|^MD?s|>|v)|CC>n9hr)HdrpEe4o3 zHC)Ptv!fi*sMG~p$=2@v%-7uCiiYr4Qdnh|=abw`?!6G4n|Fk|8GBf8lbCw1F3XpM zmh|5#?@SEe{Ubd2)BAdF+W6JZ_|P&KCi(z=*=6?&BNcmDJ8u@nW@=H+q9t0qCn9$@ zL2~dNkN)`Yt6BIdl#4Zs;i`o(270t(yzXy_*ZLgOU>dJnYXdE<F{<ABo3nRLvG(ZJ z>dq3h=7aWfXxv8ltnl<z);H@`S5b=UPonW1QhU`}B>U6BJN3fQteD$Y{PUI-kxy0d z@C?h5kEbu9IZHL9AS`Xi4KF_miuN1HMuakc62@3?cMgMJ!0GFiAh?p*-LT>;Wy!vu zcdr^Yf$os_A8Q^<s{nr7Uy}q6FXr+qy=<%yI?Psx3yx9|)`CP$7Bb<{IV=%rfupjG z2L~Tlf)fKu*NNXH?3%{aUIrb{Qbk}%uW7FDQ!(-f%R{W*@os%6#&hvw?-_21OOceH zMKlydU_}BS<mnyJ=LN$8;3y|qd~E)?e1}8rG}I1I)f8x>lYWem+;$#~nsmfyDkCi* zrygwS<V0qbg)z$fBUlf@6i|4BiB_p44=4YPd${o0%42zdoH8%i*1|l<_Qfdn#b0Nl zT<>d1vXy9#ICo)@T&=LABpl8ke^orj--LgR(Z8G0Uau6Ur&0&0#|g=hkonIb#2L*6 zxRld8l{ouQ=LRbRxnq(<AyzyjWGkm;5cb?6f)J|z8o*mX9fm77qsRo*BnK+oiJBJX zCfYi(bTT}nwwwEDLAk?S$#{yzWjcpvfpCIql0u?me$&G1mHGjmzforEaKkp=R?*-h ziB8c<(5O=7;ogZlwa;sZSy_mXd~qJ~r^#%C+;@_GaL1Ei6E~<X)V$u1_xEOlC9&o4 zX61ZvUvgLu<5nc^jez6f#*F5WG<ByS_cCMP>(~-vIliGnR(A-plI9Gu;u1O&agRZy zqupebY{QMYQ0csdxK{;oMB$KoA!Ca{f|OQ0SP2Np<f*v!!VCCjWrJvh$-9_?(a$^l zwvRt9B!<3`N;<?WT6k<ig<!{F@$hUi%2wh^zJVYA2JGVf<5aOFI6+^+WQlllb@}cO zn%H<UK=~oih%5%2UJ~DRsy#&>lVFY*s=5#y@%6_u2!F++J%giRF*QN;LRh4l7@-&W zGknli3`w*_k@@}t#kz4vExxYz*)4P@1Foa})#h&3vI91i`^r>ha6+v?u>J{{m{sc2 zM)FK~dB&K3G&+VVIJvDf0?u?0JW&-tP-Y{n-ym9vH#52X<CBt%K~RU?v`{7B3?-}E z6SFB!MB_Yk+5<wX@95&1p>b&16POy|c{ZVN9dPrLVW3+HcXIH`h_86F$~3)Pi&+r) z@ty{b$~>Zz9>27nL<@rTM;jsb*|$PJ;PojL5CqzTT=0va2zrxoLxK3k;;VAh5uNJD zQ&7q&q_|%TuLW|2|Gw7A$)lofChJUSnzivDEc?R;sf!COdKJMlN#8`zA!s&Fl*9Kt z#y2ZbW%*heBD-Kxzr#_*in+*pLW!fVW*Y)y*`^mSB|^pTB&v58<P)JsLW8z^43C01 zaGJdL5*kk)iL`=M2TLg#fK)X7+DFW$Yab9`<p7)ofa8<1N5+rtP2I+h6xV|r5+aN9 z0c%st*OA{y&zsf0$py{G<Ah1zge0jIlJmOS@!1WEpHfEVez)Mm_~UOFf5)}{6@}N^ zwU-xmN9k`H-yE8V9Xv*b_IbMGn<5%pL255Y5|D?(wy+fh)s{1oWv3N-E4ViZ&CO)D zPs38~yW&CSq}82d4XxxJ-!;e}L8X4z7!Q1gLGa^t3mgXnqL8a;Ib5j?=GQ&ruH==* zBfAEZ=|!U=P;Ot_?F)i1*1WnwJFY|9HGx6nNdKhMyN!uR_p{L3t$8oGyjE(RTpy;@ zMsv8^=O;l_c<%!(KX@un=rh@A_YNt6<vsC%!qL--*gEMrFr=YpO&wk+h^anE6s_f; z*}|5y?Q!x>nvT^_p83$x`Bp@JdqFa20f*-Ig8D~=r|s3ypFXG`J-T`YL}p=#(n5Xm z#Swk04A4`*Cj@p1`#hV4^v099%o=kUTxf>Le4yKA%O@|#<6dhpkWzLBOP{|5Oy; zE4PIL`{~H~h@!lUiKUBf-Y~X;T_4nNeDO7GQ{TY(nFK7@NO~*wN(0_C$!B)oNY9p^ z?|66G?1HGBC2rusJLa+Ne0LwnzB#o9=~x(OR{tEAo#`+*1zzhZobF3P0P`d6BaF(r zQz22l<?*D<dMDnDsgEH(U}PmHS@yoJloAg_O(<@SoK5R^DcEx@v@YMNK=nIlj#pkI zAVwB0308;Tj~WKAM;^j*Bh`Yn*$6M99T=w)Dsh=ZmW|-aqecD80JBcrk>DGR$Q+y# zg6coYXgIkL^>)NCNESyxfUG{YKc$su%YFdXI~RQ!&qkC6OSp1faqJi#pO8uA2rx2j z4AJjCO-U*7QXx`{yt<I2Lh`(~g$t=JGr#tC<KUxi#^Hb)g#4s;>|0osM5$N)&cDgk zjPAGsY{gjd0cz<fI5TnvciN?-Y$9LSuGx#I0v<r=_<{7}Ba5nlP^K{T_Jqr()p<hh zpm&vy&F9CPV}PJ$S+xYqX`c$p-Ggjs&HiXJ_`5BjN)O5&kPOi)Wc+GDDVzCvZ|l;0 z7L@rb-A%62K$f-oY}>6PO75!oF7R+HlzcI;3(*V4O``r@T%Zvo=I4%+x$4MU<#m|u zeiZ7qwPd{TCR-R&xAlNtddWA$tNn@fhsg77O?{pQ#j<~{_jASF2OqLkkKyBwQQhtj z_qa1I+!0&Drgs~<r@b=s9heTnZeqR{Z4T?Tk*fU^Mr|nX%RjH3w3X4m(YI#QAx}9q z4v%DC4YE94ja<76jQw0$sG$bC>O{PIvOJMFn96j#%p~}-gy^=B`;t4p{_OVz`dA#Z z-tPCpm7{khyZq9w;&=#5;lnRI&xBh;^EttLr^H=$uRGlzX?UE9*~IxznSx+@?jPM& zfDFX5YImN+sM|GnL2v%fvyJ1%Q&P9hjR()x!?`7@Td|myjwkH0cduan>fwCox`Ow$ z-)eCF@A<722cvLfu`@)-&o&H?6!Ajxg7!zkyFY}d{-U?Xjo19C>+@nS1fs9=xgigS zu^YB(RF#-t#_LM~R-uafc<3vtOnfLa(!ZTAEP{JZt*#1aa&C|iuhXYDZwxzPhv#n_ zSnsEs7nXC2tcO2pR`P<sYsB)JF=6{#2pXmd40v@;J};?v-7{K82je-^{O(9m<9;{! z8zSWKYsLw4_6Skq4NUl<V+-zmFbsVMPSZ_77$$!!6-ix35`Z(D_YD!xP#h0Y74eq? zCJx<1Hz@Bb+OjvfwGhU!n*@s}=HE*$p7IG#I4;pQ`y_A;3vvaTJ<(qTgs?5$i571& ziLt5VYNZdX!c%O8FeKr>@;t-CCtt41pt;~lR2ssIOu+;o82twU<^Aey<Ss~ILzH#+ z;vu{PIpC`^4wo9#s34dwECydd0$#xl0cuOMXx*$NpZU#|dLD%PAumCw8<UB4)Jv;C z5bpDg5geX+q2;0iT9H}qx9JUygEBED$|RWTKiDeTL1oBS+KB>;FndN3R8&wHv!33H za_(0#qwx{t<-m;1irM!!$6~Orl_3Uk-Tyu?13sv!A4Zk8<CL$CxO=gSVRFU~y2}m6 zh4L<8DwD^J_XXpfmn$*XS-;WHbse;1Eq*0`HWlLj&(0!FrJz6-{P}{R`=3Vd2eD={ zY_U5E_o0@zuS=&ZQ8HYA{PQ)`Awoh^xCoK_h9ScCUg)j*WQGqMqPN9_XG?w_!u2fU z8w39!MjrRMXFV@(=CXD-CT{l5j^cOjw$yxx4&RLKE!H7h%^dz^K+-OPj(Ld&tTnqM zzn}dw@Vs<ZY}^Wa$W$%tN|N6q+EEO1znb{zEsEWLuFkkkRTS$l6Uj+w0v4(##rC-s zof&IIqwrb#?O4wHL;pph==JW_{c6%sU@HN~D^&AGlLfa9JF)opLkwF_JD6fqRNFmV z96Soab)j)DqwXP5l{5@4AWzV&^YEXX+gR|a%a`*6y0FmL&7I@%jr2goyR+QokZWZB zhvpqr6t^vOw`Z`!!`8g%t@HSoST|(R`&<X<YLu~$o9pX2<6lar)SE+6$$c^UAJza% zfB{TKtIsPD5EQX%Ywy!F<IaUseRN$b)FvW+?|ptp9SNFn{HUbij~=U}>OxMa-Lp8w z#iWiWLo4nskG{5omFUr)h>E<0QvWg4x1xLs0&q~@JPVk9U?=z9By{(lC;qrmQg-A8 z&yEe>RE$aM`lkVCAnd+XD4K|?vZ5C*f)RMu!5ej>dFB_|%kPM{NWm^BS9)R7EcjZ@ z2>r()1PFuix|BhPj35#$?Jdf6S1D~8tD~<%_%dk3<l^Nfs2hCnZRBJxStS#{QIZa$ z2s+RNGEgYsBpWBV>{Rs;DP@P_;o*sGdU(ZC5I*<g!XZ>?iIbGzNJ?m%G_Dkvthmt? zvHPpjpcyn;W2~%U&m78E(BN3(QqN<GQ2Lt&PMGj4XzmBZNC_1C=6SzW&<xyabi{*G zpNI)k#YdI<qcJ+gUy0WV4{n^W=KAL~sKHQjFvD0(MFwB2X|?eOYEpCn-#IEZfEV`w zo5p6<>|`3x=o!)Wv>=JbSu*xO?(qDl2YK4Q6mYDIVpQ3X5APMBvu#>uY2BEbH(6Pn z?#~_)A_Li%W2qHRc8<|t!}}r{B7asFiShJAtuhj|ZvR-?n=mJo>8XSdU%E3gLA1hw zk=e<E8k1?u$BEXc`YzV{_OJ}26_?`muJYr_d!9dA$U5C!1v$L~Xq3t(@};oV9VN~< zXWU-2Bu5-1tf6Zp%|;?}Aq;4r;KyC2qQQ!EtcXp<QVL7<K`Irzo^V;ty{_mX)bFB% zDyA;BOFnleh}GgKSO^Z7t52&9X3+<V){ObEKHOFaBiu7}`?;EMe9`D0MHSsy%u(Qy z8(Nj$(&5=L#Vfw(^Q94sVLJ+;fzvxSgSFHHjbfO#by<96<D)QkVa8YaB*%kj{?Fg? z)3Yb^sZ=tVHsUvcWY9O{cYV5NaaO8)T7msIC!XYTQ_P$KJV8@}srjFnd!P}2KLyo3 zh}eQC6NGNC=O!8sAaCKMp+V|wT^<$Q-hQX9+E<=%Z%}o%>Jaj#-bQou3`~51_^owp z=sqG7up1)D^$WQC2+-%1F6Y5&2a>O!E=3#>Kuyc~%UAxS6V)bB$(=XL)O>9_C<d<U zN_SIY-teS4JB~+I??fU+dQ{<b5#*0||I=YFQ^Lc`@m~M#u>y&}Q5m8(pqJS^y&koB z{4`(quzUN-CfE7oZa1s;SI7?!b(Qj|C|Vp=T7R4YSQ=7U`Vowe{%7VH#qrN>*M=om zVaFw`kP<t6mqHZ&&%8YH1$652FbfS$h4%_{AHKh@ec#W&wvknPYxJ_U?0mRek#%YQ z!D7x37tlR=pXNB9w0nJ=zV)FMi6YQv!(B$piw;WKhg7BGdQ<GRgk6VkmW4IPM8VEU z2ad38n_^u_<oy!&eR^Mr5Xwj!3@5+l&&dp_NKPWEgawr&&>*Z9PKGJW>g#-nr9_F< zr_Er{C$y6}i;0slp~-8KqYEB|pBhv@tugX<#m~|$z!vC;sasO7`$-+@4aY{M_t)Q8 z)ZfO183QZgv{KS0r^rECtg|56G5v#5hWt0a_wckjv&_6KSCqRS-u0REI?B!-Sekbh z$j#yg=GUv%!4_CZ0LEWOIjlFCP&M$18ZlS_ood4V_us#Nw{Ks&L+}4uwg;8t$+3Pc zS9DN6>#6nYHum|4-nu1h+%LTLKvtx;<#GHa6-YNa)MLhr3bK++VX{CpD5$ffvXQJ! zkE&r))zT&t-M0MEtc;lceYQr94)#eQ2_v*yseh!0Xz(&CJv|*d$gQF^^b5RpbtD=7 znX6yQp)qv)b$0J=y2Blo`%op!?Ag0_%<<vA#r}g(rOriJ8=s1nK>{9%)I|ZUirI`` zMHFWUFYg|cZcR8ki9$+^^P1iAYbQbiV*z>{(ojVAuSFMps$mjZi;-1#{_0i-|3A9N z-!6u9Ya1Wo!gWvX#wd2h{CZIsV#sz+MPJ}w*4^4i7RR68yICi5*W$+2a5toSowUVD z@C2bKajT#PYKac;C@CZcx%gt=irwK<YFA)uk#Bx;$TV#rQENu>RtSrCx?1SLO<Sd7 z`Um!%py^4VW@n59qvI-MSczc$>+8lVh<AVtGIVgQ3;XU8dYm;A3^U|x)Ka)-sDWsP zxo!;Hgm1-u77oqODe?G!v_T<GL({o!(b*tA*gSsf1Rkwg%rmHaSZeW-*!Z<=ZIiUc zz8IZ7oS@eF^mL}gHQEd_T-rqD{t(aPY*sLJ3{Ocy2v{*DzJWxc0_hC;5+iSDJvWaG zIUoq#yk~YZ7^WWDLvWGE^-zQZmOqYd<=SNxn~6Oige`c?tZ~Vb;%+93BI%jT+jV}Y z2cuf+XA8flIqmq07K1x;5JpHT*)E~H8$RaP9(%F`U*6NrfHsyNOjF+9jMZY!?s<pw zvMrQ9DKiwtOO_yK>-;X`GRPO(FpK5}ed<JXD4Aj62O>fEf_Jb7vAt+N$1a{S#=9=b z@J3>mY^f)-p5JmKc32S+@|5L>%s8_VJ)IcgvW^jj*d(0uy?h=1C3XR>RcTrlHj(>t zu&z`(xmdCt{M=^*2d~S9%ZJdDz3EudF<FOBR{kT)wJNe7KkUwC8FKnqezi{SwY|P{ zXMNP$6MH^?Et+Bz8WmxqmrpC=TO(PX5yM77eA(oFWf-@8!mMsN)@{5Dna?-<K~Sb` zhSTl8hj0Ak^Uw=5@;Z&>6z2Au`)olnql}q1f5^$rEmb=G#oT;nGccWq##}F<gvleP zu)Or@XEt`+=*UmF7K$ec-~0O40kKEISM1lS`)Tj-ZvLouVQS&p^k)R7K4}_*%d&8? zFj_mum2V*H=UIlk?X6qr>lk0i<kxSG;iR1Pwu3AjP$@6AzyFTf6X#Fbou3#zG$xd| zXF{?J^el||>9X5m9vy7YUl>#;e3pD%<V4!6Q>Luy7YsgGa4<TC7q<P(oo_!rh3@<L zva3-HHZ`PEK|2R`-nsrxs;h}i?eIKhYAj4n?gGx(65_|ImhfFUF{!MTL4UI2_sldC zCnK8%+Yg5~TzC7a9v3~wBML<yJu>=ZQun`29I-eJ`;$Fgmx_%Mt~Q1i@7KJ{-)$%M z#hkWh5=VoxiBJpimXr-C`}6VkZ}|?Yv$yxBfsnO;a<1AvHlv2qCT!M_1f%Nl-9D7e zHuBY|f{wwy2cc|Nba+1gIbsawsS|3@Vu;@+qPO?AlvBTH5!y+uRwTYkX81kFo1#Di z=+?L5=xLXzs#VTKoe>P&cXUxfWK;!0vB7W81GszZ&}!7q5T%9FD)abarGG}3Qt~UN ze)$y;0-nUE{n!hpZd^yR8K)kj$`B8mRV5S2C>eM{$UmL5N9PK)v!~<=ME6&}VV0Zm z5@#M{H~vQT@t-;pD`E=mJ3$!glyLYGZ)BxE_!9#k7%Gx5$`B+GTZT49d|nZX+D5f_ zMBOdgg``p&@i*^x;>Rk*3j)vo-xr`u8U0X>C;HAC(c%WrYq+Ni&A=2(!6F<Q_EB}F zoYWu3Up`^%vk-Q7DQZ5tCiMc#F8_OlU|gf`CEo~YHEao~Pzk8_QK(S{*?#aas&U+( zcf_To*IG{~zZj&@F*8?qKb*FAK8js5K+Z?F8rGm72cPMNns~31)_atb)*Td+A0H1? ztE$cqUw32g_ZeQXaJK^eF7@mM-9;Q;>U9lgng!<5vQE<5Zl4wyUid}bE+`UtH>B1c zSiJVgsZ_Xadk*kh8RF?FUXH3SYb;->#=5w3?>WTI?K<Q#c-XD7*y*{&epk#JzaLJp zs2%L<Ls_xEEtorEni)|@h^pWySIj8cGn-8F&U3Bsm&PU%K7E$(-C#)aJAZA*PNvw1 zb{kFH98|G#6XNO7iqVfrpe>$NMibQz_Qus8#rO?t_;(9B@j!O)J?6ikUh`o$7IY`O zv>v-S6Y@P{Sd(m+6_+f#9+sbuaz!YPZKTa#QLN#Z@?Q9*o+aeE?1;{P{D9<l^Y}`! zw%8FUOzz2A{c`Sh+2imc+VOlC+5~+ClPF#+I}h9V2F;VZC-_}2QAoR<TI45c<ah^c zJ)Z2yQT**48x?N+a(?+V`1q36e|x<CGT)k#={B0hr5Y_On?htR7K0F(ba>*4?BE4F zW#ZcNy!Xq4$OuoTLynoxx!n`tX?y6B(Y;;kzna^N)!S#{>SkvK($J2<&ReFyO)IC@ z%(XwdSg+)-|M>k<g&oq&uLt{y$)B)%Pgv(So?tpANyW2Z%%X79FXJnapO0JKM^Y4K zmvdx4$b6$1_(||X{c$BBI}5#Y_eY^(JzAuhV8JQV+SmD~$#C}Ct(%66n|TUKkq7hD zM+ebhmkin+5;Zb*kNr@;@Y7{<^ZTiR_SOm2)rDWymY(&M8JhE+yw*-E|89Ltq<n0U zo5?d%C3}y(_okFAqOt<s;9+(JE`9hw2$?v-eGGZPRL0L5`7($iiM~mnF#7o!&zf-z z`zJ>yEpdZdeng)D!X(2x;dGrKz6h!@i3%B1_!=Z3OcsSW35fxaRYhP>tJAJrR!&IF zN15V~W&Gsw9p(3!B<S#hHU4a)c)I8qH0dg540B=T{x+kZeUPuM7HQwoS@ZXzNd4fT zRlq$itVD4~CJb*1u-%j-wPwR}N#1|7l6PDo>+vRL1trVI224<u)N(AtS#YYZPqj%? zzz|&Ul{q8JghmkPBZMRhwSPELhq<NQ;9y(W$=5PFsiYIjXgFT|<!rx8uD(poy#vRJ z`j#b_;A~tPzmTwZ?78}`vpP@)$?J*sKM0B~?R4CO#ClJU9-UWj8D8Tdx2>=2qGQi) z%R@26!PE2;Y<xrlcAqVV)<l5><Blh_{Sm<oL#ZEfQ$L|@sM?jO7DMM3T6Mw`Cnexo z?6bYxR|k*Bz*qD#vD2ZEq>TGw^WOuuDdvPeF<E#cVW?wGH6(|@<m#8g)q5?g*K8JU z<9S5<txv~Kn@<us`~2zYpEf@@ylOnfw7Gn;JMkTESx8<9LWftucU^O*IDN<uJo+lE zoiA7$$?ts{t9hbFNn&Lh&fj_|vh4l31r};ohzkO_uJu$|1RS-;H@uu-b9Pi1BBNUa zdisv^T+s<LS>y#bhSR5W!K%YX&cp@hNE8y`)6M?XOK$Jy@1_`%iVf*;tjoh{FH`p9 zuZxLU%PgJdBPV}{qvyw`6;F0Ued`9}cQ8ZDdseO~9a^s0s&X-tvL8Lh$6ef?CKOO= zB$$=d^wOv$YZo?wR7#1K9~@E$@_hX^Yv+l}E~oq+4}aemGewUfJUT$aLgcx;;waq5 z{rXIepHYUT{$4Hu#epuQr=gKJtSHj$d`s*#();*O?bkB88Fst>r<3-;Y!XI;KdYe~ zslbmh=_{vEleQW^+NeCe_h^6l?NF0L+G6zl-1@Kt$}+Q*N%6?QELq9fS+{fhxlV%( zxqH(?O@;ESm`yc!?8M9C(alYuJ>FCyk)NV5Ss06Dz2R(C&F-;6EHQcd^83gPLdEq% z#~eatCH#ol9D5MA4fPCVk0(q0OUqo=&EUOriSo(9?$lgOQ^~F->PL*QrU?6mJtXvX ziwTa<K{#~4KRn5vc#;h-$%;wGUg!OFFA82{JfQ<>&6Fh?F8+JZ9S$Z&YpV>CQLK+4 zn-z1_g~N@qibO<<UvVQb(+=_G`8q+g3LMm7-I8=)tqb8w3LIl*L?mj?25NXeW=Ir% z879S%oP9}l$kQXOi{6o{L;uo`fI&JCZ{CBR@ZosM2%*`J@aDQSZUlEYjI*aG@E?8B zVWG4Mei#maTpvUde;D+cl+n5IirxfFxl3i2zes-*BUQH-r%0otF6myyYKVaj&w#uS z2})uv9<}}TZFmHA^-_-Ffzj`&D|TxtiA6=;@C~*1Ze;BF$*I>cafPsq_0zy@YdE|2 z4wU@<AOHPgVyJ-2wt!OPWoq$zJ!82K9=i+O-v1W-lxq=>7b12aD;r+8GY%k7$*)~u zM1pJ3TlUMA+*ceuuRvO%c8wQ;SPBoIf$v8~l~QWglv!`lQO6o2UO1Vzc52)_rpy|b zZoZI4!m6SriCVfpn#CJFyYDpYb4x>mf=Byhyb}ATZaG@ZX$+|Eb8hh`<1s8;lQJ&Z z=o7Y+Hiz4?DBCa_=$0Y2&OBE|``5_lhSlM34cYG*&Gk}0o#r;OPb_;eW1m+1QlHb` zHfLWuU$(eweaA9#)Dj$evnI6h<X%)0xOB4Qq3D*Cj$7H){^`Wxl?i=<(Wgf_P1sQw z+xQjyhOuuCgnapUYVn1ZPmfsvL~<nPPUz(zdfoi(o3v0%<755`e#cTj8)ZteDgCkG z@_py_sYozIbbmXLvg_OBEm+kWhB~_7vwR!zTnbrxsTJU$w>xpaOD<jU9s$W)2)d64 zE<?^Attp*7z~h5+<CS)KrKG2_T-<Zcj9WPI9C#wr(2GrdM`?!sb>%IW`iSoByE#)$ z;lu0O#ICVf(bTUh5!2DL2mJ&2n;eSoP2Q1mvt-+|86L+d%3#fPs%s;5=}e}59uY79 zNOgCFw8@p$g!M39;DK;}S0jM(B}_r{gL(k2Veqpf>Z*88pHQzw2rX8+UT1Z6qFI2; zuENl_5vCo=0ye6@^i%TCrq3&U&^BE(U40c)oex$nLCBa~n^$!j{4mAY=5My?WkLlK z<iGjS@Io^Oe#U-E3!eJf6&IIkMNCD82TF$fZG#T+YAr{(Mp6>dM2SPm7~Swe<COay zzCb_qSL63_Fu2rwwm=SqUV$V2gBI)YvvAxlHT0Qyq$!@Ul<LcjVIHj7W$vv+f{40p zK(YZ72HdAaL_M0V(~iSOk83G*VEZ1UaC9>FSvK-B@yNy>u3%vu$>z)h%qC8~dsiS2 zqos_Gbh(dH^X>~|{9^1@&1reNQFc}(5Z^1Bt78Qr?ikqKhezM^7Pr>W+1b(Z9fv5K zGI{zNw&h{Bl`GPx>xbA6kqk_Ci~k-Q?bZ&*KPIOu->4oJTaGnx%D$TLhW2$SV_vaG zm?$Ufs2%-c$#v_@hHBX2+Hj%ojbw-tsxRnOf2(KNxO|yAdb|0<IYQp<{!u7SpnEG< z%AtQuVewo2k25`^-i5V3Jzu{*OQCsQ_ABCa6t+@9%6jgwh4%t{9;makvw(>Dx28Ml z_LCaLc$&?~2G5oq|EmqwNPGMgcE643)R$bBb#}MeZKtc>x%OH0D6G6>X2)Ukr*1YA zS`425&ew!gQ!jDa!FLsx=}OmL<$LkY_D}8Dm3~pCZR}?kZLct#=gXOX24<eb%l%+S z?RsWmk(c*q5#5_8oGxK3R0#$2ca1TNkd%+_P?P9>cq0~k)(g0f-6EOC-4P%NO|zzZ zYaJhk)3YI4*B2%w7cOeejuR?nFon?Je=WY78rJrq2W$i?s)C<CrW5rjLpWw1r5Yw3 zD4TMaM8v}H^_EU7r=}^Qp&y;}0wZ&pT26J2Y#B(N(fw*xv~`=1I>b?uM9lIx7yJhl zh7#We@wB{2pb9_02FB}`1z!ib!+OySrr^J&QAk3w)?K$;up%p@ZSoW-YLOZq&4UVK zsmvoX7oyj|8{sC`-cadi)~_FUm9WJB_PD(B)@gfX^}lodk$pLtF8JsZq(ifne7o9J zancre>$mM-)rj%Iymo$TI96=%&=^YbiCqJqJDs>;%?aQ6n7)@|@6$Ng2g}BreDAC` zN})q+-RhOQXcRU~ee8mLdwj1a`BOukgsMgZ-S3*570A>)qi??$AQiOt3y;`xe<7yK znN~|%wk*AwI!|o9Ep?GLz_TbpC@9@REHe_PmP|394)ge`)gr!B#mk*8Uq*KL@VL03 zoL~m-v0cHCPLl9NU{LSDjNqaskz?`Cn!L{)sW(12d{r)=O6&@Cwuh)DR=So7e?IJ} zu9Z!^O#{CQ!It%Bn-c;Lr=vA|;*?`1)3FF@VG)7hw+68XI>;A7jUM@d8Fsb%-?{YB z?kwYIDVs?n59Pt)lL)EQizpr8*5U@}7rg%;05d_%zK}K{KMvUvq9=$&AD3iA1UDkM zu^N*oV5*1;as33+-Gex-s5XNquCF3#3T7mIflv~@@hz|vYY4j9LmM5!a1D`>4owVH zgasAjnMH%dQx%9JDix)(g;-&Of?*0`La?%;kS<ElUPVQn36!4TBO)1=<#?|!beIU* zH0UniR#w3Rp|GlL%&%bxp&a5&Q3PX_>Smi2{-&HmwFL|by%k)@uvCfpDvn(v5zrN) zM$C`M03<<e4`u~1mJl42;fi9++*(OjRaRD4c>Kwyh|$=&G|#)g@4NWO-+q>(Cznsb zsMhAa=ffZSTZ%Gp&+P|sRMn9FU^wnJ*;-M(6rGvL*AIt7)`w4$Gz`O7Y~D>K^Mnw{ zvXtAe`%YGl|2e_dI57VjTImuo06t+(U&b;2msRy_6y%=iIVbnsX)^Ss>nqhk&BfR_ zm??^aX0tgK&8!#T`L>u%ZE91ye9mVb#MF+Ws?umQ#?^(hWxE7nP@WuRZ51KXPIgu; zjuXAnlg?{>zcT^7uQX?2YjvRhIZe~?9ya;x7qekbR=u_cHk0jDSIZbp2CZ3^of5#D zZH#=(EAhuO+-GtwZ4D}~x;Dlz5)P1vNCS&2sB=WO2gL&=#8oU=z$C?43$qe&yRq_d zG~10>iDYw_Cd6X1YDcpQV}R-?yB-nIYPD*D4NhR~1zfX39Ij*KCc+%jXd_ZqS~Q7a zc*45J)R0(`&MZ)Du2K~(97MwywQcAqfXAwDM^&8qt7-My8go*~9|#nlKuOYU5|fND z%n{ZQn<pj$so_!~t`*QSoCsb)vVis1M(u8u$e6_e;@U{oK@zQkvO-9bRV2<pY+#!w zh-m`}>xi30Bq8_>G@S)oL!=rvaeJ^l66FLc3dt^@;7Sqz*cw=j^)yC(g+)>F>ih5J zH4ogwAkR;`=A2Vd$M5}z53~5OPqW^uw0m|e&YjZAw)M=o)V-p5UL(p7O{%$(Y6r|! z?aB)GU;j?_?Yw~~J@#~72~jJu1_SXeEVwF|*^)fkuIHWFwPPWKaYxw2oDKTif^n2( zc}nK4uE<<Uv^2G;P3__imD=en%M$NB-up37uH9~vW!ZTq8kD|2@!Yk6X1Y{4Q)h76 zlO!2q=O(K`+qDmDha)=~=xrS%Ri)eQ(rh+Qsl;q&CdoNhRkubOUFSnz|6&C)F~;%u zlw~;%_}c9@?RNWul2#%PC+YbeFr%treMn8V>|GUSN;0DTAL)jfLGa6n9R=HsaRQSR z37e=(F&z?p#So_H^$>+vE)#~4%+2GHE;3>;GmIGgSdJiCB!<!aQGwnG%t~T1ho)^} z7-Icnm`hLxaRB0)XwpJ`50#8q3T|;18i7~=`iT|ZgcvKpw#Dk6F^t;4jcBnFsx-g? z5=Ye0qu;sN4zZOHRgq>&bREP3QUnx7%m;+oCUR^AUj!f^8!MxrC{~&`RVj*Cu47?< z_c>Msq`O4u?g#B-!J}>t!YUSLAST4}8>2v|z?iRs#pEWeI7xH?VuG*)5<u3u(o{3I zRy?w-!LFq_RF%U=PS76=aZc&9ny1B*h$sgS?5Ewzc=p69Wr#SZZ1nmZdgkzWEpL}@ z%j7kZB%#~fiE5Rk=@rkAmm3p*1G`!evA6X`2u*zOqdmD~rS~*Gjw-Y<j*@3gHD;!E zTC4q?x)b6ew(80z53@R`2_fLUr_pGfHp?)zsZH(tvvL>uy4nG)Gux_4tJNA;1}@~< zgYv|4?bQa&WNGA7+Bu!kt&Zn*u+Lm7W@f9CK8e?8Hk)H@tQTUxsso$JO4fEU^jr#N zX7aUl#l3cXk|d$gXk1)d$4JM^Vg)8YU#rJx>$7dgIBf+%Z`-;J6=)x=FefUmdjH`V znkp6!B66Ha3-Lpc60;QZE6|$9g%)NxAr8rV;M!eqh7~!uifUM*Rm@|AQFR9J6%HY; zAHv%EiAe`34x?@s?H{LT&mb`pdOebvMND@QeXnY@vL<nU9@$tUgmP4U(dRN5u_B#u zTHzZ^1&y();z&ghA|e&;#z5vegdUi9tXbmH84?^}aJ;Gz#aT$ZxZxT}w}l_%gte3C zNTgX}Eh1gDDp~1qojF7uHrzzi16@KHDyFxhhtNVqv9JN|08*X=-HF;dmK-DwpRHQw z^l4Q05o3nMV^F5swhy20b<Q>KPR9^-^Y#1q$Y;KUOB{dr!N20~|G;;jo}6g(`W=gN zEG^8lx>0G=B@RCI$YXr&i;wY+H@${;zw@nUrBy#)otdqF+iW)3(Y=#rHvfbK<>c^D z4zE1Q%{#w+B!>R{`^9J+Up~a)jlab$DUm=YT^wPx;yHtvsh|1M^ONdxyFN=VsWMXo z%)IyG1y_H6IWn75o7&V)zp!h^d@_*9vW#}SJ=RCLFh@`6m&d7_Oq@WbUCy^1V-m={ zoq*a)bt>vHs-1M_9IaOCytT0|M?kZkPW5&KL6a4kx_!9WY>p3(i?Kjazv&A<a3<!_ zl`xmi9f2um)ox{@>IS03;E3TQ;*LPtsTj4ifz028OH#xs;`<;a(e13p%AFwkK9Y8E zqDTy*V4^0U&@pu~P9Pe%3>h537(#OgCXq62phbzOM^q^`S0Qy+)<y7GERZt7+#*hE zh4!ifBa8wTt*S1#s>RJPqSQjwhNvN8ShtCglFT)cW{Mjo;5P}9W1S^5YZ5~rDK<d5 z<h?!&)+*q?L_|mXhpW`#O$0Zy4+|Mq4v;Lv*4L1YCsAn=Ee976nT5EH#Wf&>WDhER z%r&9h#5LOBGMw&3T^G?KRr?v?irv>I*W`mQyNkU`3uI}+pMUgIeC(5-L*@Au>$-(? zVQ!A=_v{?6o&GRqw%g|0UiknozwaKhG<#lx=whF5^0i4K>}|b)X4(J~0z*Ff&40wR z$DbhEB7|8vrH<Zaj}JfkPZ`J)q=`}lxP8YDA!yZJISo{%c9w)-d6De5T3;xHz+f<- zEXz}vkZP*5sZDKaFH9h_71PjawZ>vn7i)v^#3+<8n(6ErTg=Y3*=)swycmblWYuc2 z+R$h;Xf~TKI==5p7^g|6sUDxn%3j^_b@A5^C>O8iF-Zte|9r(dI3Z%eh#^)LjTng0 zqZTXHvT}pyH_#-5a#)E#T8YJy7?couK#8M+vo5Ma%m;YQkk%3sL!|)|?K!=f7?BVw zj9ZL|3ATQuVgXCrXz=J#7hBwgrI6sUjiRFZYIIRw5_`+A(L?5DiP1)s{56?@VbNFr zf+za2Y8k8B%ZNmuBWa7o+9)Nl+eEreEaZft5c>h~IWCz+e7~wjtsMs%1eal<#DZZy zRJaSPs-~{7lb8#>{}kkXtSq6?z=kvUyudWU{D6?JU{Sz!U?wOlm?`FskR%lYvlC(f zE7yr$K~kW3#q8y0t2*r2y^~kncLx@YyeRnXKl}jy{)2zT>dG=P1Tdq>ha5WeG+%i1 zOEel8x81m(qAVHa1#f=c!~FNZ{4@OWdwz)f@4SU#BzC^ttdKsG+<M)sXs*2laUQXR ze)=dM_~uXWsV{y2p9>b07zAIy<4-)wAAb7hd1CXA>C7Z}JiFRAbH~!V@Szx2a?iI? zG_{w8)r4bp0p(&WsV7sj*&Js9>cgcz^ri#=Q=8fg@1z6cYRn}$*uWrE1OS-PN)|53 zS$}>uPF}Dv+Ulg&dsmvKSIlR*bv$0ks`lwx%j)*GOR2_eol)a<sBIdj`pmiFIsnoH z74R6YDl=4-6Rj!@B8u61g)2!HEB3P3B1T0Up{iOCiOG(tx<ZMQ1Wk6r@F=dmK*-lH zQ3N*@x{MZ4({VeWCJu%xSZau*(9025B0@#+oOsj^N!@O|4iV{Kso{H@XzFmy4t}G; zlPFp-o2eiby}_6iAdXtl48_U~R9XZ};p7SoOR$P54c){BZLHD9wQs-=o`Gfu3Xe3q zhy^Hz<MuM5p)-4l{eamDn(aYiAJZ1nQ#1)!*o3kGW<U>vT~C@iigJ}0=8*Ixq;t6D zZN!yNA;F>A#M^O_q=__dB={A;uE@Q8(qUH-e&l=q9$)_EA)Yw&EUW9A{L4T35Fh>Y z7r5>EU9_7S8~vOwe*Gy{`#JyPFLim%%kSf}U->3K@YXkS=fN8ZF^ns(+l50p{p(A9 z@D;ztzx=yTBF(38ny~4<%wHb=5kC3U!|dt4ibNY6+xRli4n9I~8+4b1v=s@!TW<a> zlomx8KJOk^MRj&+m)+{PV^R|4qJkNya59ZXW87+1Uw9JyKaHTLHnj^s7|!=^>$a)- zHLX@_Te8+g=<{7S{U&d^@&6$AE0nQMh{d)!?iY&-y3lcYl6Nz?R2X)C+j<8vu< zX=_DBL};~I+vYUfvhaPCcF{J^p-UO7NviE_#mxAU*h<hE8y^E`-A)*)(7-C}N7+ar z&Y<L^jV5Jd7U$bl#YT^hgee8d=J123aoHTvm(b|KU=yp^%*?73gcynuMMfk9f~~J2 z^E<G90UC(0fhJ{zUkE8>IEu|I;s)!4=s_HAW)boYBx@jLiG_gZNLaJR>x{tM^=IG! z%ux=HkTiEgKN3eeBCcUbXb^o5Kgf_|1<9IdVOS@Deu*?@2xds$!^A;*i8v^cumQd# z(F{x5;QQc)L`o#-VCKL!LG~jK%3^>@mq;He9U6PY!RL^eVqOXI1ZldPP!!N#27i)T z$o0(5`Sz~C$$M-~Je@7TXf_-C(|`E${MY~MZ}IrI4&!~~D^DKgD^DJ-f=#okMG*M6 zfBsQ^<)`1pKl;U=#0-kEIO~0$k7J4F^yAL-dc#PQChxlE5BSq>{xF;2Ns>g7uBWFT z<4e7d5kfV+vstCv7F@%VxHfOO@z>bXehq_R@4TON>Sw+*eWkji;bJ?%bn9VI6venN zzh=FuGoVwO+SD#jz%%K5*42jX%Tfzv9AFk{xOuwS{;P7FCTV_a8pkWCB6F@y`h^^$ zdOp<^neDV_CBceqeeNsPf`N|^0*n~HBm{!@m<gtW#R!tYaD+>93lIYhoy90By%<yQ z5s?`}KSwOX@@0a}5Te61XA!CvuX;2r#?iGaZIx=T5d7Nl3R~hE2tyJTWPT^4DItR9 zYgjSB(IiRc@h6`p<Pk|TEX^twvrxUKIJ$?#s>RJlElx(oLWT)(Z~}={?o(XEl8msl z100ZsN&?0gh~}`cR0T9X$7~MCc0qeL6g?={iI$?tE<#ceiar*HNai4ILOEhGGDWN; z`b|VUQF}-V;y_H1C?jahiHf1EI0_i}XSrYn=ofe|IAv;uD$($df8}TS*>`;p_uh3g zt!9I~C>iECK15pW77yNgC$GH!ZbX!#cuv@S>vhkzjxKfoi56LG-Ok%@`M2CU|AUwb zQ9P{~VScA$akpcBm(ZM#NF%VP`w(xt<^SgP#UEvu_b&<0Gqr2q>ek~t&o8<Y<&@@W z@BNr5$vH<+6k}GPDFMLLrgr(A&^nO0JguD-o6vT5VbsZw%Y8^qVu{i;y<{BG3;Fq; zkABN`-D?sfQ!|!bO^4bQ<?yIf*>M>OvtW=qbR<@YL{Jb4G@V7WtisCJ3^F)`n#W{_ zg$|PLhGGR|6HRuZ&0SD#U}}WeAZa_Szk;Ad3~@4UGpqGz)F7IoWe>78vDv_jM_k27 zCP|Y}Y@n`%x;ACGfsj<pWHOJkhIG2bL7(WY(t4?p3{sJWFrsL#xBx0LfS8{oG@H0) z7ws2_U%|=*%d`>-Et>?}L{A<8i&$(x7!bR&NNx~PEFMR7FVYg?a1*BsnA^mX1~jij zdSAsz5Z8pbin>K&Ttyq#S0oFYj}wY!MPk4qB(+M%#0<hR>UI*ivZ$HQRfVV%4sU+l z!@Tb0_j2UKGArwwc<)Kmgr&JzcJExI)yPI?#OZ^At%AXq+GcjT?6?mlbJ?wY`+;BM zo*h5M=a2n!p4#{@-bO@G3VYfw<H5bZz`=#L<3g9gVE8=NvoneIPVJ>@ldPl{i<>zm zn8~t?as(txl4N`+)_rW#NjJ5rou5N?J`UvR1TnAlwyD#-hs*7RP9Au*lYX@XGL!G2 z4*D(!;C-uuQ0ZA@R~6oIGHG_jkOEYNimFPYhL}Q8qRt_SVm?&W0nN~4A7O9;iz%W@ z__TpYfk*?@c|vgntN`s)0Ytuu(L+KPDTnxwp-C4jdWci3tSUcJaoSdGWuizhBx?|f z*sz7mfWuEgYoTHQ^MW-x`2Gr7ZbG&b(ufut#H4}6fNM6;!4Seo;7}_HYBP_dZmdmX zWgxl=BjpBt%p2t}W?TROAOJ~3K~$1<h^s?<6Wm}ONf$AV#IjB3Zy>%wv>{0=!HRW| zS=2Iu+lw|j#C#cC6T%Q1&Jn{JtUrcWiin57F(Q!|hqydLv?PXS@k2l(=AS?`K?2xB z%V~&5APipAVCGEiTjz5QG#e>5UAKpWwUQ}S>t7x8Tu9(_v8_7ide#^NA{o0|ui|Y7 zUqz6L;G$ZyN~UuV6N<dR$NYi<y{S!ordr$Xk}xwhR;FeK3L%hX8F`+MZ}#MqPfkaD zYEwIhIp^53XU{nghpi5%h>&I3RmUDUneey}jL_Bt?Ofwjx4ULpcGVqzlaBg@VyU)L z8J}y6YL)S;DJY(NACn@a7xVh<!pxW%;wp+_oPsnFiV;A5B&2DErCro5Vm`-2F<nEF z7A|#^h2dl;W`}_RqWh3EC5jP!4^1GtCNe)yvT~Rp4qOwnyu!)gs)~sUCZHJ7XcMzV z;$WF93xs?I>p1WmB))|-x`cccY>1?bL@klviGY@1Q3*-2Y7xr^Ag&77MzqE<)}InY zYkGi6Xp>?SPlTCSTz`#dO{7>w+zd$yq3j^ykpyCM9?<|B%Y<wZ)f^vAqGU*(V_5=L zpfU%Xgv?-Y0#ijyz*e9=kIzpaF-6lB=AU6CNB^8Cs962Mfx0t(mX{i!oC|BRb^p6q zT;Qc9GPbUrGlA{T#3*(?dkw^@qtBX5GRXBQf#R&myvgL<)@Qw{1a+sjtqFh{w|}v1 z*~z2>R%Z_DQcwMV^@O|m=9{OJY-&?Gk1Rv4*E{b+s9sYw0ms$&eru<@-Y>RuquZ)T zeX$C`FZLMKLEm;C*w0rCm#Z@1o3zPu=S4keV<d)%y4@I?5ZVZRNT^!K=z`5xn3ix9 z8VkUV${7zm9CIMcm?aQekU7i(He5xM9f%oX17y$y=a9TvfkV<3p*V>~!<kY>t3)T8 zbBNAhgFYHPVX%U>I)tK+h(j!)>>a{lB*_+tsi850P$E{KyA~*-;+BsS(*{;VBn-d_ zVv&eccp4Q10ShC>HUp_Bq#15N5pa#&P#gtGkl4r5KwQAAK!c*C5JCmqH%?&YQP&}q z8`$h#5)&*xjFt&TmpJ@ZMSdWH#fm1{!ZMQXK%B?&Bh-la3QHuFXlLaHj~E*4MPKKq z3o_~!n#*NnSz&2vob&mto7!pITG6SAXfBt95Gaa*qA14WvbDlLwU?G9NkW!oV=U}N z2Qwl<p658{Xf~T;HnTj>Pw7pcwwX<BYUg*Loog{p9w7AszM3h}>uSJcaI;-b`eX+0 zN(cO(&p2&&3)R-l?A3;oIn!La5?akfBhKvvh6pL*a>P}Fj*@h-xQpP2n6Ba6EJBwk zMvx({Y=bPL%oD|9+6Kumzk#L+I1jOblt4H^@C~pbt~E!@kD+b>v2~(KrE8ORK{}8d zs%w~bk;WokhiD84ZSru8L}x34fXtyq)f(ioHo*+v+aPVU2#KLZifbuB64=}X71X2x z^pEsyYMh;6$cSMJQ8e@@@@Hwz>>=iB#NkOaT_jotQlO25xVeH;p^SaRgtW0lSuUg2 zMg}>aWgJ2@2mWcqM#&HiQ9;C2c#HCA#q?%XOB@!ficzQn8c~QNHmw(fmU*%@a&p~; z5Gc!%;c!S<mY2nUs`tqHKJ~rM7SL>^M6a(?mL++fljr$mBYmpRyZTw{fM)7fzO-%f zjGxpXyWn7^1|1Iu0~(FSDQyb%p)$3pP3^)r?sGYybte64tTvqPJ#BYJy}njmmATsY zqPjY>UE{R1DpQLcU+wd#elIU>KfPgoiI_M{N>uw;T*5SB%#nm9k!38dA+n2L9h`xM zHE>Fl9x{6ue&b0*71I>_8m>_iWCpSZR`dzM;Ytu~Vww|&Cy*o~mcCNF4?Q%Q0XL77 zB_S@8q;r^biEQG6CwK>CAJ<wUlq-nqV5LCmag8BnEhIE?c}^VUNSPpMK>$MO&_;_e z=z&Dk1O-AY!33qEhORyb8*AYtzK7pD0_hUw4E23fBPK1Z7-CWqM5-Xj?ZOX_Vi81# z#Qp%6DZ~Wx&mtqzflB`dh!Ba@w<e>Ci-3X!fe?^rXspN!o(p_moc&=^2sTaAab<ou z9MbRi84ib+B|w;L(J6{z9L&_uaVD$Rma5{t$9qp%mJ9}iv3UCBsw8>uDT-noI8E+} z=Q=m1c5PZ+t!ua23<iUXntRFQA=_%T#?Dn)mUKFuaoKV5keS-lrgrfG&DOGheGp#l zYb%5>K9J7E7k{pP@~zA_bue=+>_7Eqe!fBP+4kP8)vMZpxfbS99lTx$-e9{hGj%Wn zDZ&~R;A9C=hec4G!K{ZwkCO(NhiF8<g6IqyV^#4ea-24S6nu%f0?Q+`+i2Q^{u+`9 zF)E@38XY0@&=_%AQ9K82gD${ul}JJA=7})_m!m~V6cBaD&N<?-Wn5<#D<YIR;&OCm zC&A~iIe?-Gp}<@LD83)j)FIj+X+=VR1GHi^t#B)GM1veFQi3oFz*VsT7S=1~vvdwA zBGE5{HL;{w;cQAnbqOh#3FSKKy4CZ#E;h`8XVD2=9kW=CHHM6EJc3}MY9}*4!t{*v zR}jO+5wjel=bhMpUI?9;t?O;io;^JJ=%d_y_uUjl!RF>B{eJ(lR3Nre`<G=oh6wE4 zyZ4OGUi*2iR*R>edWv4JHx6btHa5mV#^pE<>$bZ(fCA`rI<(vEDTVV(*hdl(LI@XK zKuNY9vT2%*zt%y_wU9NQ+SIPJ1za!U8a#ikWLRn@#7nWQ&d9Y;m6_aU>rCXi#_2*> z@l^Gi*{dg+>t4Jhnt-fSfe7uYEv)n-fc`obS{0bz7ZoM5UqNVtY!YLFQzZ_Mg0zU` z5Yr=QoWasII#?$5K+-1WSHLYIUWpt*-2!Hgm{dS~bql~M(F}=!&}f47ut9*Vi@K6P ziH3k?5siWm9-0mUge1Ydhgc92L46N(En*pPb6uo8i=8-xW^E*CLOcesB0zSo($R5^ z4$%UXJrKpBjR*=9@#_@}T5BKLD~OUqEFgN+?ZJv=jCC~GN7Mq<2C?rUEfFt7i)dAr zfoRxRBy?1{R%$+iDnJ@hFrXk&Mq-|k7jt`<Y}dNwmRtDjXFtm$k37PT9Xp6IlIJ-^ zQCt?h+}8C{?=3HT*~`vY4XRt>I-L$nOG`ZR$Rq6CyO$W_xWZH8X12Q}w%!AQG0D{4 zy?a?$SQtO=G>~~|S*?dw2Q(LB$>hb#vV7hlQe$YQlWS^I+up;c{&y`U3nr@$mx6iN z+CFtHjnO1S*>;Z63nk9^LXXp>&ZSEVW{OBmXHY4z!obZSY@+%yf<A@$oJgD4-z00! z6WkDV2hMF0f<a+eI>78Gc!wo@q!6sJ2rd#rg*Cy0*)aqKO(D$@Um(&U_D_;@7O`|4 z@pDAK38ml~is_J;XNV3ftrhE1mP4dCj!PDZq{L^BA_7rC%RWIGNZ+BYh!iE|;3x?V z;-+9WfH()T1_rS#(dG=e8K8t@07XQ!iZDcCMJ85kQ07mgop~rr2stj@M<`EX<#CXm zh$|}+gM5fI1~>zsEFi@(#3><<I91HzxZTV`MZn+^M=U%d&$Z^74~zjbb%1jPxG71J z@bJSA^YqhC^Z4VB)9?3Ru(_M2Df{>D=bn4+q19@gQ^!R_xcTOrSy))$vBw@`Wo6}( z6Hyo9z|POlbKiaUv48*mQ$(Y$7;5&Zy<l^puF7nSXlAF=!Fx}m(O_d^<CM0uDQ;$J zQ`<f#ZL;EUt=ZN#s*4Ty>hCWW5O^h9-I8}cL=opZUe{U$eX`<oHV5l+IX#9!;t(~= z1d|MW9~vEk41tWq8H7HP%@X}8BD=BX3}N#amUY1jB(7Fqc2}_oN7m5-q}e11vy}Nd zjvU+)Mib{eR&GK%gGm9q4&Yax!MP^UhD7g3G9jAb(hg`r7_>2k=sgmiMYKs6tdevV z@FbW-q%2TPkf2y%NZG0w*9=r<pgka#iWT5w7R#5Btb@~8LVpv%A<f;ycoYkvLZ?Kq zk<O;-fH*8sm*AQQC^x=>rn8XjK{N#|h`B>u4{>dxrr1Ug*SZb{hY%-(7*G|=A~K?e z*7^pusHa2-BLN^PK~b~O{D}Ut&58462&?Dp!Gj06{r1~m6bxG(7@VupQCGm1mX>(q z8{hb%>>;%*$ac2{PVMU3?=Pjh;FQYDWDnz{3i*ZhE>CT0Q#&`#VG`tgtvTv71@YO& z;B4cxmEGiWI;}7E7@Z4Wbfz(y#1mbMb7`{TbiNMdcI(Vw3L&qQ*IlTnfy*3`$3dGI zS%sak0;7q9HEiu9NCznk%#IV)Rn?0CQ4LWghD~%>V3woWs#>#rfuu&v6Oaxz>=Bz8 zlpak4?}t@ICi7VENOwOTaQOz}Am&Ad?~zIv6BWw!lektFvjmAX)$}G3Gt31f%;986 z&~=<OkoE!+mx)2Z&7p~-EY@LhCpH+On<vq1k?7Z}R<|fsWyHXIghVjc!uP+9(IJ+7 zB<TP>Vvz$079w6tT)G>TwW_e9O(@sF8<855Q-S==D!fij4IS%13ai@E>XtOovF6N$ z=vbX^5Obl|sRN1{6ZvASowM!1r+d~q!SX^TkG2YZUTr#SQ@ixfza|~4<Bv-UX3UJ? za7db_V@8}>M6=m!PJ@`KO>LVN?&R02oq6hXRv$)}dLUlQV{|%4{Zi~&t)5SI2D}(& zP<8K!(+1Hkp|TF<F(MWNp5urFEEH&xW4a5~Ht2xhmr)ss$&RWD)#n}&O)8wph+3G? zfUJoGK@&fUp&Tw6Vf{Fw5uu581uc7cOOf^Cs3b_*g}92u3eTb%iA2C5D#UyfNm`gL zVg4jgVA8GVmTeQWK4^k3N~GH$79O$|sz%HMnmOq8h~|;z3=}Dv&JhX$RuFAqWe*yQ zsGA|!5a-%x7+}@~-N1Z;Iwg98&_&ZtWb-RX(j}HFnD3+Fzyc^liKsEE&{)M@W+RGd zWkd=9;uHxH8xaUpgL(Pp!i9+4ZWYRXG4_`Wecl(N6X#5#qf>k7SWR40%fMU`0l;Kb zKFNuGEjkiYo7$BS&|K?lYrCA#YqiC7I~<3}s?2nZF2@6uU=46BG(A8p9wAY|hX(3a zsY()xB(7qS(vzsn;BBSCzJ#i(APB*ih^yodEJSdM#T<zONs9OclL4j*u8qrjm{%O@ zNL;{WKpr4<B(WgU#$`>4{!t|4mDr|vOe$6{K`=2SDi#Katf0vbLg=IM2r<l~Nej~k zsu79;d-hw1G@w|)+%BB-@OeOVP_=)RZ7l6U3^<)7D&UV{=>pnVK>Eu#&9J1>uW@OB zplHa^R<{ZQZ4J$52}uhnjzJt$^EU)Y1Q9BV>rq9<{D>ex1Y*QY5F#ccCs@I}RV-*% zm@{1OeJ>OaWjh0lsZH&LvPn_dN%Dz{3TEow{Sd;KS)l&8D2nL>pW4*6>0rAYYR3`B z|Nhmt;Ci2=2stwXuig1GyyC$Bz_((~?|$taESArZNsAvl_}f_b)qHXDZ}`j;zrfGl z{(j2rz_uwgY|TnuXh1W0puR9ptnlc@$N7tI{Q@%h2ARNH_WqaLzW2YP)b?d{8YZc% zFLsPBM_{ay^6w7)cN{+c8+gBhM7U@6mAvi7-ypW`=7T5S$CnQMDzP|1jBtJHdfs{C z|Am`*6GqtfHFLIkaJkMV0W6NFw8APj_#6^EA(^Q}8>NATJ`qFx=<g{B;W!#HqIeJ^ zloidexawNbhl&Sm)KaBM4u!`W8Day>9Y8vZ=<%--vji(=A*;apF-fp~f@`EGIia_P zh9QguCM8B9enhJrhzQQgswy;G9kHD)A+ktftN5aUq=tFHG$O9~|Fie*QMP4QdEal& zwfA{e)vf#N_d{w4q?Tk5LK0wM2_z)q2t&jp=3xX5*nmwuFtM>ShVU3bVh^xJ;*kUq z#|{JqgFp!m7DfV**q|7J9w<mHtVg%{ecx5L>ePAdz1E!hW1W3;ZuPz0_fd6UedZW7 zx^ACS=j^l2+H1{k&G~&_zJ{uV`f04Z6O|pjszFw8*+S(29t`3pfi<E!p=@D0XOM$; zqN4#`RkUbjubL{53W3(0sGY&$0Ix@AYLU_wLJ28i;sjC5fHWIWvs{e<EZL0kAMqfN zz^z7$0<$dPOtd|nA4{p=Wh~>`<VKxNhwbfcTCLXARc7kCp0}4Z9GU5KItMyS&df5F zv3Hx{UUD1+ArZN^bw95@^4FN^8t;AT9sJ?xf5DyIm-C0(rW}5Pzx@@*`MEFrFy}Vj z!%F`({NYpogzviJ$4KSf;J&9qK)YKkF6JY1p~o-OBC&r7tFV)H_~nPclQ)EQzWjmz zjo;h;Aiw?eKV_wLFSi}}KK84FyAfNt*cj~wz!w^i{Tic$aX@>#?2dm(r~N|y=-hAd z(KEly%A-HTn_l`y+}(Zw_uu`G=@z%~shtn=;irF^qmTX_{?otk8MZC%88F`6KYuA> zv{#%N5C{<^U=lEogm4fF!{R2+Dykh+HnS5wj+<q&KZb??$c)hLSvq*;Qt!#3EN7l6 zlKoWDStt)6!_)X=J6qfM6g+^pv7qR|`(g88+!VJ}+{QV-_ZgU)dCt&Y!Nyyt3nqpb zpam9pkiu|1h7<6(0n;h8j({o2rUXi`LDmPeb4alUHpX-ZF|d%J?8EddR!#_$1ElFT z+HQjhCK1&RsRGdwFA_l<A3T~XQr5*~it{)@+nMvCo?qJ&DhUs*te{q%&FyYYrKSL) z%+$`ZG_-pb({LQZ{sEC?{<Dl_?9*|g2vt=PLbzfZhB=sNwOZ$C`Zt7}y>|3o#xj=i z#T$4}fCEkdzU99EjzYWiLziDX{m(fveFXE0H>`gf@9O+4|HCI=Mjz$&7r&QZIQ~vv zf^qlJA7m;8(QA@T_Ov>4H7aC_KxjX!GeH6mjX%lybd!5-|5jdb@NIl;_sjU7PrjSM z@Z;Qm_`5(_`v!FPqJ?T-#>gXYxa~(Mw1Y~)XVW&1oc&eQv(Lv%`>*D++T-~42iX{X zg2PhqRd@UZBd_<=gMD#~F7_GsZ+<w`0V`vsa!4E3DP9eba1?BWQ-iF5ZbNE-OG2c; z>WBtIy}*1%PIm#7YyfF99!NEl6;6&YK=cq6CxlY)l(49od!u9GnTIJPf%gy};j)gW zO;kp>6%Z6@A4Y2>m4=MZ;@W~>cwJ|J61P#Uk=C84J5CQt6WnSfZDZx(>~)hORA(T9 z=qi$?m^iY%gZMT{yAX$H2x#hH(-CSXp)RmALW(JFf=t?Ys|7xRiY%DGSs>(!isrVl z+$L7xv=BXvS0hA^;PGjgJuWfxXPU1E8slLQ%VW5o>-FVUPnU5m@7HDA%yS~8M61=h zViAC1@szOfa}bfadFFIFos)Bxv5aNxZIZTUivb`~Vs8A#iT{y1cRs|u{a11SvA@B9 zz&l>?=Zw=f{jkc%Mh|i7#Lx2GFZxa1`I&DZj6ccOAO1dGcGpia;>POj-tUc1P&VsR zbOlU17*0R*nF5~9As+V)%v?>PbS=h7rNlh(<m7WabmE_KhZKDMi++V|8`IGiA07Mw zn@|2ENrV;cP=uANM0Ep?)8!r#(76i@1Coz%0Tk5wcz6NgUqI3Zi8ku1xNPGTv%fS{ z0~Gh*@dP4HQc$xQ$EE-`qC*iBkD1(VaflWL8hUt2xGNe~2pX}vg|?@Vjsn|wQ6piB zS3Rf`S~ybPMI4TB8KdpP#Ezr&2I>Wl;z1!s+=pm7i4^ydsxKgA7n`0#rNrwqNc$+E zRIEOL_!iVP);WU44JZ;$iNr0``njF06m;CjeVi5A%7}&oq$qgUK&$n9<RYW2U{(o~ zxsoE5fLxslVFhFrt2fbNjZ_cN@?NZZ48btByxIwwALD7(4k(D^f8Pk}`Vz=o<HMI_ z-1K0k+wC%$Os<#%dY+nDQ4|zKL0#8WRW;|)EPZB{v5Y-V6lYb?JyWwn7}}8EJMm7A zpZWz}fA~B3>iho%+g>AHlf0r6dYnz${2z~e7yt0ypW{8-zsu{2L-bz!Z+Q1ZU&BwY zd=;|(R^02oxu!kvn%VDl$1#qz?&2d3!A2Ak*iHkw0L5Wk_Rj}suPQTpJ(n7AoDe>_ z^#Ok8vA@M@TletRmw$qt*8N~(YODDE+kXtd^T+t`x!>mlpZ`w&mxsTb|LRpkwwXD& z@6i}ti+OOddy48L$qh$A5+s3gOt8<97-O^$o#F_|`V{2^bED7>9u8q~2QQDJ@g!0w zJQTSa6C<b)Wai7HGoWTlN;`y*ThLs9xQWRDOloA>hp<U#8?n3%t2YTc#EKOp1f)6( zodQ|?QqtMa5!!u-cVT`8@hP5kR>go+4+*WOKmuu;4Le=3%yOEXK-#w>+Jji)oPqHc z6nBG-^8nc@Fu>{rwgy^&7l_ngj<pXWAwfKcmFMv3AcHRpxH#GvU#cQzhzXVo&;cR` zu;K-1{48!Ya17CNK$R<6A>dTtD`+UO`V2N>EnV+eltW$un`a(GG*Z>eoN^gWG~E1# z=5i(XOtE{SH6}}qan0_Vad~4dV;Ps1h&>lyWG|8~6XAb-<og+&`yC$aJ&3j+;NKnp zCp^%5HHTNfhUiAb_`r#G^0t*%(>eThMvwk&db&n893}#_O|m%CH87leE}xl8d2BBt z5_w7IL4Lh^7yt3xzoFfE3BSMnLGDpF)PMENM`WM)I=eRWOYu<I4TPR;o?R6{k{18= z<U4uj>7U}5lpI`n4S%@tUe<Jlmmc|k{-4wDVkK?TZQaAu<4+-Ji#y7r<P&z^H&v<U znh$%$naMy`fC<n?Yy=_T(!tG0b`F<-hGJHY2?VK-xP~euQ-mQB)}h)#!fgaSM@l=m zmU&-AP!mvqoXm@R1{HOU`3lG;!V0jBcpsN@s3=yI1fS%VtJFhEhdKi!F~!e4frb_` zDj-z2^l&0UBB?fL_XxU<TL9gHXk=lqtQzJfFgk&^)^X`W9g%PVNdiTI+ZK}6AoOt= zL46j{!$|04|CuDP{ZzglQM?}DHiD#C%35apA|Ry-u>#c&ZWSH_x##Q)vrMN#NO<bc zTJ<V0%b&X_@H9d60G`feEF<U7g}qusF6DK01DWMP@P)z5^^&Y!#*LXLHQ;tU9<#c- zdPT2OG?T2ZYeERLTCF+hay%YW6vbR!U^(%Yv5dV-;`cIYoQF1khnEUGJo+>bkKTa* z<!wL0vDMcRF+Ml^Q^x0hi&wnx*Qnfi{m~!bUqAYN$fw@T+YWy_E9>9H_C8c)ZnXBP z-QPz?+x*Q3-pg-2`a?YN_}^zWwD?c%`5BHK{0=Jiw+H`nu5<DEi|g@zjFE}(nXM1d ziWS>Z@dqb<9s>>)tGx2)-())t_{fQWMqxt)c-89bc=NsgjDg2JtIAye`_{obBpsvT zh*pS|gwP^Z5pM}-1iPP57R2}{=9<;HJmS&=eIZ&rilr&$y;=Lj5Ii8}n0uBVcEK$o zp}++!Z4*KZ3Abam1Gb4tK&3;nvxH(DADu(H?X2iEsnG5n)b&}4D7e&!9l*j4Fr7`B z!z4S7wtB!pEDaG#L=NCBLE^a?`_9pjy)dQTBy<wiK8#o&(;cV>sH|eeCL%4=4`jtL zJA>P8P#%V~iCaR;gpIclpCUyo^NAb^bf&aiA=*Prg$U?DupO`|;t7ut)7&xQ^$0kC zv{E)Pl@>@uIDq*k8jg^vC%%Yg_IWM87}#k5&GF;MdF-*r=0Zx#_+qqLE$+ViZeIAp z7v7S_(aX5J2qEC^lx2CvGUi2d6E>hFr8GCpTv=Jc-RFFoWh`SES0Ac6cU*2NpjWlY z;*{?E%h#r7C~qaNnR?z#U(){y9(>s+i8cnD7x!Mt-+TFIaFpaVTRz>hM077WAd3o$ z`weRD@4k$``?8O~ESZa5QSA}1doD0@wd2$zP<tuQ>^9{mzV!DwPabME+qP`TTkrS> z{FOU@a-KLEk=my0b(>E!53Y|ZxPWaD{7$elxOY*HSXH1QVcx|jTSz!Tf~-sy+IZSQ zq=hhn`XSr|rzWV*+Ne5+PY}^OddZMzSjf7Bs1Zc*coLO>(!)&&z5~)m^%!w-iqP&s zU8A*-WI~!eNg->PMbuaDVu*XBSa}g?`UK(?$?nSFC~XrC-iwDd{Pdrq?L!cIm^_iw zf(3O$n~cHMp*sLK=-x%#IZja?!QyEo6i962*1_!wsJdup9b=4*M!79b18NCNS!y{O zhXT?eNFYt>?8j4|M#^=JEr=}?153Ex1Dr+J#NrA{jmI$(?t}6mOa~~5WQT!kKUa3U z*gx{fBUDwzo8I)Mxy{8gz8Is?h(G(YKjYJ%{xq+6#VfAkJ-&<^C1Q+}WqHMw)cNjL z6va#xByS!~g{JYCS%R5mEMxCBzQtsAuVQLD)VqGnzj!KWZbTc+6HdpdY&3tKT<7uF zofurxYrv^(JR7&+p7DmB?K3X|zGrK*yB>21SQwARpInJaUQ^p}{{NFr*blzKZcBh? zlV;wZlZS}d2C9bu#e4`dB6*3VDH_&rAAnEu$G6kCv~e-4cHAnUMinH26ri#S-o;3m z=eBMSS>a5~@s#pdiel*mmIj#iaSgbig=#=3SMe%lev2w16-o<B4xz+-3#Ue6q_z<r z4fC2%D5QQqP#K)Yho42tRj5m(5VW{Ii-{CU&>7D@tYLB%>IuYg<~&G=rOn(LR-eUn z)_&%aD@!s!(l#Ok9L4ZCkO8uanH@x>o7+svgLoQ|Mc*PKE4WuA?Lis=Bi!<M<pz)B z+;#u}AOJ~3K~z1#wZQ!>Ry~4vfmwuNrWm(J^W#$1qQ$u>BAhyPimIx3-RoYr1Tq&G z%NQf7%9nrnmlI>;i6@@8VmaPr+!|5W^&HGzX=~=3Gt->x6-7Z+Rg`5p*L_~xc$c7N z8Ozw4jqp~zpBAesi#_De1z;`}?A$7IV^IqKYUj#cS7vU+Xg0fx&7HmWnQ?arg3A<> zEu6!sr<sD*Hh2at>g}xPl_C-nlD4pLFjraJaZ1!S@zz)3@)Vv1h?EG$tQ{<o$THyw zs5>zw)Dlv*@N^2K23f^rrU({Wm~COHO;H{OKZ3;pq60{W5M2QuVA4f4A4kg;BqOB> zqU|i>oOXZ?#C|rzRK-(4;BH7y=6g3BMq-TyAx$9!#daP+Wd)zL(g{7xwh&o^a1hlA zR_|cd5Di7HSb64AWi!tyYDYm2;IfSnuzG;#F-SW&8;Grdcaby!R`BX^#Cx;qOHJ|) zQX3w25Y5VPB9b{Z7nvLTwVp4&hpO_}V~_Fr*S~&WuHja=hwHj#GMO-)PPylvdwA%f zhxn2&`4Un}bI$fMo?m%V2!UR&M~v}`tzhQ6UrLE~yUlPooNtPaAiz?Zc^S*tyBqgb zCqFi7HCOuio-fj!jcUtYjMJ?;mzp-r>y{8&Ktv&p5IGIu04`3p6-|(eEDa`r_GVR; zfcOqVIrEYkgO{ZGQKZ^NX=Q~jpCBeP0AnDAiOmc!4R^sT;RM9aAvVa;&Y^=<8<0SJ zLW)m=MN|*sW>_3zwvEvR-$u$+Qmk+a)K4REh)ape3Q`5&3{tLP?K=R&8IsaHP#!|e z2%U8#tRo>}smMYEzC(~hFx>(d#KCNvB2;)BK|RUlp`K6-6(#qT)rj8(6cDzvnpst$ zp@Zr+&_cYA`3R8-NP+1X(Jsg~76L+r*cMW>zywK(YQUugeE_bbynJIe-tBhx6ky*< z`(KQa$z;OL&dwavG?pOCcz#BVaee@L)ux$cS+c#oO}E=UPbSUX=dEVTSjIB0ezV(M z>Ackz@kQCqD_J*oliP2_F=_x`jPa_+=~kahi;2*+&%R;?6DaOeT+SeJ7-1U?UGRYU z6tk4gELq2N3^vSC#oERhBE<?}I>194k#SDkJxdffVgo+&TR}AQY1DCZR1GsQHt?{9 zR9l3io!hx+4jxZ~-iB}+$Oc|*Abt;09Kqt_sN9LAQy>X(BP7LwK`{XD;$9&tc$#8` z6G8<hcn#j~gHF(@h07E*B^3uqqitLVxh>6mNGniJPl9Q#z-X?-I6z&`%&^vQZQ+a& z)}eC@-}x+F?4Z^H8RFhSwZLo(w;rKzhy%=eVB28hELz|Rl|F=x%wKAZNpGOU{kd8s zpKoDi#2Bfnit%_%RaNsftJyb}<MjNC=Flp}c*Q*8Ihd*Ins&QAFZDI8A|Zq&YF@@N z_6gM7YSEmm>~1mJooHW*JoRo)$*r;mHL5Mm?-wJ!UXE1rt$L3%2Wr=i9Go2)bHznV z@G)*@kZ=f+VlqTckR*8FphJ}QOqqI|Wrejvsz<1-fK5sD21r0Gx70`onGhd}nXt8? z4sKZ-8Vg7OT+q0U6G(N;eHB5;-E0Pa8quROx0Q9=+b9v$72HlEdKj$2ZHr_hRF6VD z2r|grp792*0rlH5@Ua@S4Lc|BFvYD!pq;OInlR21=!5lft?}t`#0$VsOSovhu4I|# zqG8tlW_YR~jvzix@`{ikMWdia(or4{>)}>m(GeR%8lrj#HwB&MF%rXBBj|+W6-+)u z9;|1AiYr+^_Uay6Cg{(U%1$X=vD^DHZoRoN9*?goFDiDUqv>=?S(cP#IY-dDC*v}f zv5c$R#CG@j-%5uCjlANeo=iSlFZ!)$JlB93Gn)gx=K?g(HAc5$!lbH%5UA_=JaGJM z_t>8AQKCpF$WD{s5hRo-6HFb|+aPpMdjw16>}eCwK5pBfvkIg4F*Xp!h-;Q84h7ik z-WMfHLC+AB&-fn#o+3hlsNx3ViEK}!*_@J;Tj6{PegX-{py*;+<7tOfRcN~l>1ia~ zhfw1(#(k8v>U5ptr;xIXatP{Ei0pu^AUeYR020A05CzmC&L*Mg;l6@|2-VZsWYlKK zsWwv60Z$cD^ni6dZf3t4DTr~C5EN}Go?0M*7&j0(2)2QXpz2^lTuam=&S^xB0d?jM z6$MuBKyd&KQ><8-dmQba3s*8PF2@h+V*me2IRLjZplQ~=rZRn@^==u@pE=Q}m^GF7 zt7<cYT%Bo7!y3e_s&k*2Wh`SEdz2&HqOCzq#o=Pa|H~btX0f}K#wdjF4D$b8jM1$& zPK%tP>z3TOAj$9q9wMSWTsm1bOeQ3InjisBiil?!VFJPcbPduNQJb|-4S@iXjWKb@ zEi$vJ%;u8rh&sdu+)93)Cx~@^t{GYuGr@t7Te&QO2dGDo1h;Ke6Rdm*8a813G!hQu z@eAND#4R9xmgGY;-7^CPtC*igtTC}Wi>DXjoX*nBGC^zrGA4vWND_<^OJ6{fW>7WL zD-)NQp=U(HL9ioOJV|K31h-A3+C+mQmS$~fC1y_|x=OO+lzx=t8@P?}XdqQK-~?iP ziXz+&bn$u{p~g}xx2eU=3_SO6onFTNAMPz<IWL;St40LiiouMkVrFxR=E-D2S(X$< zu^j1TEMuPl&8@Uyx;yQ5`#Gx(mzyx$YA)Ih!ErB7Y;VP+tFZ^Tu7JjCOp9D)uyxP^ zl_6*kv`=9Z+y#O`0`(5Y0H=jBL8K&;-UnccW4XdYn%SYui1FqiKJ%b5P(elKQpTig zZSS5CAsbS<;O6-`4&pUhtdV4hh=Ce1-N31`qM8pe=_B?SqDR04!XYf3MfJr<dJ1(g zw()e3#GQzqB+!Cl1YY6EaR-$V&QaVxlfjfH#63$Z=RUXmS*44m4x$yRZQQpoi->`1 zMY0|$UCcH?Rxlf(dW7gB#K)Ne6LQtcEFmEfLW#?1L~g@O5c*&x76d|PUYWTO*25)d z=9%NM7YAL-xV7@2#unykR5^>q4YuLRG-aO)sS+(G;4+qRX^G{tZDPBhb1Sq`m1Q|6 zwKr{Mm%<0RR9WI%!6{lq<`sv=IQ3FN&9iZfZZ*TXcDp_QT$eINyDL<Ck#qr>#4n!P zm}G^NHgUZlm7OdjECIt1X``(YODDmyWHS=*G{}B01XO2ac(L4)h0W%)A?{=!8<3#6 z%ghW@%|?~Zto2MVcT@z!5os!Nj)cQlazbH56!j9blZY9v0kaM&H7+G?TcGQx51_mc ztB!*QM0N-q2JIs03}RqqM7>6=kC%eP0;7edhcj?!aCDF?!)#y@GkD=3$`JEy&{ZUD zA}NuyCU_4dV15c@jCdcFqqq$aKa09z;#mpJ!9uQJ5o89S&Y*gG21mics|*U+d%5ms zy9XDm?3de0`+Nj67uy@3tEF}sw`Q)?bQF|j$#^`zVsEB7m}%TM%d(`dYeEQ2CKEyk z7uEM)#xj=i+==?-B&IiWES{t{3Fwt32p3CMZ+6fZLZB#$c`5yJfXv0JFN?gQTS2N> zMCKJfGkZ?&iGBU7DWSH4p)-l#f>a+zLP3y3tPG^Y)kzExZ-FH!){wM?#}QrxaL1+z zS|#cQo`g`$5`VG>i>e|S8bLB_Mw@ZZwvzy6Gv%`ckXyNwh|5u|ifDO&R2)GkCxC?2 zhROsjkKpxL2nkOG1c7=3ZQn<#9>+c5aR&*<&;VX<1B!$i^avjAz_vezgd<ssx_)wY ze+wd()z=)%9k&{n9zl;`wvGE%7Db3-kPe=92-*Q6l6G*WI4#uL7-tYhxQCgjf#Z@e z&qkRlj!OoGR!=EfliarF32ncalpf#nwfwnwdzZ?K+{<}-v)<>sMF1|xZ)_R2Zmtw# zoMVv1`F%N|%^x-noWtR8zJat_t@DVy%UH%T_80uztkJZjE>;}&@^jrPYf!J(I}hw# z>Swyt#r<X<BX_6M>0DM-W?!S|;JOY(ydHuDilWLA#srFP2PsNKN13l8U8FdG>Lz$a zQM6DOf(Tj!6hqP)!a6a5WhjHFViqxrneZQUUS&XLqH3P26hhO-WgrQ&BcK8jAv!_2 zXaKP(MNxwEAk~=m!G{DXfrE&TvG_Sex~OSxoeOO+gW!0WAgp55S$y&kLAr<xz@A1h z8r=d>$rU0o#1kStRPQ3zTWE+NeJr%|YuOf|TtQOAWei~lmsVCy(<#ajG0$8Yk(p_! zpeh8-zxzxyArwbYDbQd@5fDEKzQY$wMYrbK-Y7qfMx&d$BD>5fm$7)rmr|M^_Fb_6 zKqIHx7-Ys6=ZVR!?kc^EWnAxA)Y-ooH>c(#eZPRr;=*<_pGbDQT|{KwhPT(>^<wqv zW^Fwyiej#Y*Zf?^Zw<A6CY3YEid=P_!GTXP0jmvUg1SSoh8ZZ^xJ_{nAYZ)xTxB_s zN&hm=#Q3;L2!@$wb+aZFPYH8FX2Jq##*4`;8p(je42lC3g#(+o9KhoS47V_Eq0+*# zaslQW*;taJ;45f4iFu7zRp#o17J;Kk8e`_TM1+7dLZu6S7S}br+61W(QPjXB<thmd zmN_!$VJw|NWkRYAVGU^EoJB-PaSK6n`<n%VcOZ>$-OOSDDw*_;<H=w)pVO>DA~+%| z7!}cKR6AH*5&d))L12H@o~u2G*<G<8kH-v0V^;b-`kgi=deOfhjYc@aTCa_vOr}Fl ze(K|F-}lwL_MR1z`Ax9~K38RC8PDGws4Pn+lga$R?~1@oQ<>@YdV~<>fTk?Vxq0T| zWL(BFmT~DD;HCJ5xcf8Q&Tp0^y;(Qvx;~FDb2+U+m-?A+Rx)i_mUADkMKE)zUNV>S zc^65PH`6$Y$h=>=8K=u_SKLd^jJso@Mit!qS)r?FG<|hcTVJp>R-{;PcXxL$UaZg} zp%izgxNC8T0zr#Y+}&M*Qz#bPU4s=~e((F<%34|Xk8l&toik_8o|!#X3HX@HDnqOW zY?s<$xF$%da5ABxR_d`dk(CJHhomJOurisk_hUk^!CHSSNelT5G0laZgTSo9W4OOy z1B+0C2`(Ez7v*O3w>&sXIM^IYK$*#6<decJYD=SD2PA#)N~uC5Q#RVZ0Bv}>r{&SX z0}}njg_#xLcfDe~m|)>e<a_lG);slBM;OPzDSbbS5>bD_P&%i=xjqp@L)y6sR;O+r zA)KMnKruvyDSN%_7s-0b9cUvBIlNdrK75n(#~qQ>Wo)eBy-J&oHvX7|ERus}6!FKT zjor7WLZ*imDnFEsTj>bay@NmQ5(nHBtY5!cJ>Ecj(iOXJS07Glx^g^9&2RFh_6N4K zJI@15^#8cNTPa}P|DYbTHpFNGrp2>?#Le&erTaRsm+?xjdYwArbfsQ>-3LwA=-Kbs zr>55EO;)m;ExAjea9JwA@Ow&qvD_ByL3xuw_SnZK`vdtH^5cAfDMdnA2YWh}oCj@_ z#Otcs?ApciN7*Cr%hQX$_nVv;`@$@-Z6D-fwo!dW0y*&vWk@%NaFB-NsTEKKGByqO zb(k+?nfnyVn)__C-^XSrehsP(SJ8Rk#ToQ{yqilc&>JxK9S+o_-l_&M(QZ;UNT-XH z!#5&hZ7m{9ZB>)NJ(4nh=ErXfUMm$ou%x!+KrFqbqG`5-h?oape~8ADo8I)mM?-uM zi?p_NjJLf+LqAP-I@${ovOJG%BH3-Z1)YIix7bZbr2Dq9IMwqJ>cfFVY8vni`?71{ zNG$ck!6IeTUsgyJz33v1<>atGaDZCO&~$rgx8dho4{R-U=>i%@1t48Ss->SxcKH0Z zLj!vidz`a(damED)AC*wDoGn8h@H>Z1Pea2tmZG-@a3Lf-j+&^NA#0Dbk~T3t-1HR zd#({X_eV*;4xm|0Wt;F;F^A5bdFUB^EsT!(T&n^_}Pr35DL*{B_%gy0#%_@e*x9 zH!%vV>Y9-BbnW@4+fu2?;o)KVic-aR@~tVc3v+k(yAYIjDl_%5L(f~bEF1@DaQtIq z1t=krpS1scpW`qiSz^w7ohAF1%N891tLoI4$r9MrH}FJ!a&(iP|3XIk?`5J&(BRBh z$n{7eL8n3<7UI@)ojwJ&V7U{W2=__&wtcd)^1-0lM>3?_j-uyCB~919R0HFElpYrl z*A{-~7=9=+IAuZ$tec?Q&v|Jv+|dsr%@tQ+VCr?StOxD{04iht0?go6m}=EcliPT3 zHQ&oI^~xmY(K*8%Pg7TgdL5d&D51(4Ah{^YDc_-DGS#^O<_=trOl&e&5BU+<#amKD zKqK3A;RV<}sK2MTv^HH3w)BwMPJiidrzyFAh`}6e#yP?Lo!A(c<{-|n*1##FBWouu zQf5skJ41)ck?gp63kX;G=Uwz?phUo;?SlXXL@5;%gHW{PJh*$LahYF=ePi^J9vBt) zeACmXsL=&N83_B#l;FCZkA0nM^d>>MoITfbz~;3YcrW00=&EsbSQ;39@z^U`^SIyQ z`b^cGvhmpd7G>mRmT-oLebs05CIET6V){Mq4tcrn8G?2nO$h({OLa5x_9Aq+4uvbF zd=p<?8-Tub<!$!;`RsSAyD?PbcX$(<^8Hd<3e5F-+A<e&l?*?bq9Hk!@Oqel`=QlX z=tFFhXV3F`=dpH8dpHVUqLrj@YmDD_Q9Bs4{*qC0AX?0yKK7r3tqY8@a-|Y1ep^2u z71AnW{TC2usHtzywR+)V3uyq}I+{z*AGuk#tR6INo<Z*fU4PpMb<D!60n;igE5Qev zh!2ioVT$8~AK|}HM~4yO>fj*!WsyVpRIpGaDx)Xsj*=c~eBgXx)n@KsrcW&@|1AlZ z{0F`=S_mV3qa_@p)eURg(8mxuE%W%;O4@n^A1oJCc`CiW0;{>6W*3JYm&lWk$XEeP zQ@}>y%zxjBaiR&<5Uf8d<H)J}`rt-Z7@_}xI6r^bHZk!hsvIBOHGYyQLrcW+Z_wN_ z97lU3p<+3DAK93}=#E(Eff8zYbnMjf7k|O+Z@Uc}!_EEYNd}ZdA0~AFQ4)FY}QA zR}_FBqhJl~E&0WxqPHR4TiiyJHLyiY7kY+C`TCbBqx;ak^Lof=xbWm+M;2D=xdv@t zCCPdG9Pm$qYL6^%U+AI2C?In7H`gV|!Rm|vN)ve0bCAB_AvBT@7?1rDk*p3VNl}x$ z4(yIdpnBDTJYV$0@de)2Jk-2p8Es2--j;g(vd2;6c-@9}hdO!5j8SzxQ(b<&cm{Ai zmQcLzJqtc2z5Nq<yyrTq^|n>&xC(3=oW4(M>HOi@b@J`yA>r+TkCKls;PoId_rFP& zutNApz0-S8+aLP9beFxl)>0!FifPD~uAX7{p<&OZ<(vqCfxcpf6y1+soCG`fDecQC zgtWo{dO+Y<(b~jrkin_>`N!ekZE0jKpYd^gx+r0-ypob?1p#e&cOUo4vhLcMqsf|A zmTa32?|g1-!9T&p=>Gd%O49Jzs5)CZ1)^D2&G3}2^0Xok8D+V_ag>8|I)c8bKi6yt zS(70NdYD%%xbF(WTSI~g@z_I35Ynah*O0OeFu&`5NLpP16KIsq@><|cc@g`e7f|QR zM$0zd(XQnMwf;DKe<}R8&u@~3`so9E0KE8CUBWXkr1^5$ux5|=3e6HhCkYkkMNJBl zP8AVR3VwJ`*kVPVJ&z<3`zTW8Ia3?WhwROw@09#v6NalH3r1<%#^qD`K7GA_*&-`$ zQlgjr;Y4r&@%PGTxmD~Z2{=cuN|(>Zv5y(2E8edLtvcBt6;J}^Rp1HOMe_bP)5Ca6 z01AVI;i~}lHALzaQPA+8E=cm9rbm2NxKQUdU|=h8L8L!8hY2(&mx)p5({HV1MVS<| zAm(@eWzy(1S9hN5qIV1Bq27#uD$ob4g2ikHg^VD2R`IQfD0`n8MwcSro(G~!Jv2)l zw7gv<Tz{>i>%0<sL*BS+Vq4C-!!0alg}m$w-Kg~3s&w8}Iqe<J7Q$tVdnZGC-eBU6 ze`+kbi48m|AiUFlukr&Vj+G|W8GH?1(Mw;fGR@1`C-!#rVI(D7qQT^bP$~Z8q<`UB zAPv&u;^O|&-!J6V`}F^8Upb5Ubxk`p%du%c^laoA>BhRKA9hjBmVG9a=V3zIK-ElR zfcXyyymPUu&Bi%q#Ecg6Vp4kuEe(t15c`>VL3;uY8ohh;r%(wjtxcd01{%B&lQRNB zYg5uEy5mo5Njx9X(U4dA<{1+Sz!_Bb=GAelSor?$HMQOuR&I&X76l<WR{-qHuBHKq zjnu_E!V##98M<Zny^4`VYpg`*^yGuf{oi;&8-AACN3K!Uv-XQDShQ#?SUdWOrt&kA zX{^5n{Skk<t4?hTGAKno544qAR5UD!rL;*cBjP8Kw5Z4wPGZOq(9;f47{9}9&R1=H zx29`pP<-mNV-bv3w-9VvpKfaDYf2oD`zws(>*^|o5Y_%o;Hx*~+l$nuXK3<vMpf;= z=fJbC!ks>mKF|0GlHMU5MFoG(f3Ys0+PKB{ZO-^{;Gntrvfb)m?&6JzbnEbuW}D%f zbm>}3i`y;p@vV`^2<)^DlR;k1IxYG4k2Jax@}5C&X{#GIF@6K^W|^GdoXz-2uQo%m zubBd`nL6*AYTj+`P`wGaYy^mf_HB|VAI(`=k`To(P6G#NbdfAcFXyrm1XFsprrB4) zFh<Z0Ju)-ymnKms<WGc7g}dRkca;b=5lj(cbE(nUVA^`+f)mNSdL;i-g9lg04q5)n z(vjOf0mzbaUFpoi`?K4e+mAUWy%RzDoN&Eu+eox(yb!{o6;yn=yxrY3%vl7j-oJA0 z?@ZNV!&4b#@S_w=qswJ%r+3qYaCpEu_IV)hbG;lkT4pVYxCsiq46O$w<wR4=xexTZ zb|IdT&F@svzN0RY#=zGFO$a{N)KW73S{XBzfn{ZQei~@com%XS@s9QMZT+4aPRG3x z9)E91D5C?Q*m4OQivBg?yxv>%qm;!uAvVT?nmpu*AJ=~PPab>*>pm2Bh=V4;xWw86 z3yK?sWkIF3X%lISrc-E1&!Sn9QBzlHZJBW1C(n%+QvdI0qttI_V^3(~N}_TlwW=ZE zszM5i1%bZhY%*;;oW1<m@I!e!)(yyVdWjZeuAo^*=}Ggw5E<Vek?hawS_4YdeqfXS zpeOMi+vy=Q{d&sCm&-G7<m4#t0Z+0N`x@GF%bbJP#U8v)PI;@J!8Tti1@@KnOG7dA zB1363-|MB(5#=!czKnuK+Yg%o?mg`bk^LC8>eQ2S<mS^SVFJ~I(UEG}ma|6t(Z!&w z`40I)F!E*@tGp(=q94gb>u_D`UoIafg9-B*pf&0F$d8ra>VuNTR+ezUzQebrolH_( zUpn`mEETt|<lFUMHNc%3flF7<@%p0qBQRTh%*|0a0<Skp7`OZf6q>#0n0?kCK8!0J zlrmpA!uZPEEs@h3j>8=b3N}9{-_O?PQV<TG($Fo>Xe}tY&`G7?xKy7K^YM*?`f0GV zLUL%8gxJcw<tzxIJDh#-m*6cc!uW@p^3>?<=&WHvcAa4h<FxQvfL&rvCKr?|?GXD= z6=ddIDRj<X$#LvWF<-@WtNI;UbCA_g;qxVKLX^F{-oK!7kC`GNtqHmOMlHx753UUz z!iff#OJ(-OzW;!dFYOnd1YiN2(MXP0dHgWNb?(C6!!P16=m4CMedlo6Z?fII%$G!Q z^rdimo7e!)Hh<C$4jnl^SnWA@_TDJ$A5TiZq?5W!cvy%2+wi+h$Sd$%O}|d7F+AAY z_$TYP(enyN_0lD^`O^qGDgLnEVgjw%p4%7LxR-s|t%KfNNM4l|y-K|Nm3kti6koAo z>Wr-MHJhAmo}Z_Lc0RCqr{J&oLgCL@rAA7n?u8+eqtMq|v4@z7sIkEs>pWZ>!{?Qy zf^t>HlpCZXkAyzMFCA$vCwro5Vz&iqLj=Jf7#S!<@%8l4=nJ!ca~2G=rzawCWOEvv z{i{C=fvlZQ`ulJc%pc9bwk-rHru0y^f$=o0raRL`U;OB+eO!)u=@Pv%tZU9Nj;F!9 zW5F~epozoFw-3=q?px;PS^$E!_L<nF9i(I9V&1lC|9O0S+VL_#;KrEC-!f6|I_xi@ zI-Ex2g7C)~EX&o_;0ohpX4x2g3iB{;PlatRz*I1P2D;2g<HWCj29=uQKJJf#IpHw* z(9EZ6I9U1Vqc9vxBHzX0qKSF=;QEDpMDdH%3<)g`q5kTn6^4M#P%c}G5c9dnZH+*K z<&EQ{HAkUQn%yFhoWXZ8V?R~Kwowm70yTTgkdLoAI+a5ls~#m5BZ&l#f4H@>Ky=Wa zmrdkumO2vKio>yCDUp(pTtlD$zErL;fp2m{CaIU;iZp4&B`e6|dj%yy%y&!Qrf!3A zpYDf;p;%tNUq?6E8+QXpxG7iWk{8%L+i@?OY(GR5+7%7QTmJR3F-He=XzCKw-N9|Z z^f$1a(4&i$t}phBb2C)!z_6O%lQ&nx$FvZ8KK$RunfJ#Memg=va4ng{IiXNL1}Fbu zQ{;{7d!o<yCa*7JMeW-<e`Bgz(&rVLZ$aL#ut@sg%BaSiGFKO5qf`(_+)JBaxop`C zW0)ZOE$KBDmN&kQ>?*MOXM-$%se&y&e(I9)a;q<9jzyTI%W!6~H@4qvmgt6+w6&kF zbJbLUz_gnSE1bbK>#*mc_n6!@tpZV_0YRAxneD4*Qyac@xD7<dj?bdQmd0k{q?`_N zC0@s7^=QArW1=`hvQ@JE!8C+sI)o{NgRZTNm+ucvVx^br#|m@CegZJehc#?otm{?i zi$E)SpMT3-nzvb~F4YzpuS&xqTkD}v$&iM6N_Q9wq?MFGdANA8K7|EoNJV)ETSWrR z{;w7woN(VN(T5^EwAI0UGZnXwA3f}6d<hPr7%C!IeWw7`K}lB2-s<Kf)}~Du(g?1X zTcc8|uJN}Sv?)PSnSN2r&)M&<;1>J*V{4;#=wqx8x9^ZpzOb>ATBEzdmoPI}%N3f> zFbFN`zp5JVEX<>I*eS6r#_l}6K`2t(u4F6QGqrT5k?`kj^!+pm-@GxWd~@B|)3QMp z(wrr*o#$Qcs%>kjhAusCwBBh9OY3IBo&@{O6GH)JkhS_!)_?UkBx)))h^eGgBc^OK z1>*~G?MLi}MySC61Q-N*6{$uJ<2c@IS^ckMom~2ivXHFC;`pVl(JQB16za7cW2@x~ zw`ki0)3<Sz?tDH_pe*DHIKqkMq?dII8Idelo|$3Cr3Zs4I?B|8Sr|F^-85O0B&9!m zz%W3ZLQ0}6=c&l$vD->USmU*l|IU`hf2NCNh{R5kY=56&S{-=~&>MhtNI$Ti@0`NZ zNsND&OBP&sS0JVo>Gd7PKaslHWv4}|!cw>a(Z8UUARCfjG}5T}s6bxh5d5J^)A?}% z5)S8!!hA-dfjtl5n>E3bd?boJ9lqYClt(UjQ&HKO!pQ8&W1D2>BdywZ_3DYzjmq7I zRH2j~V(8k6r|@hk3~W;oQs6<KT+P<)CaTlW6GrYFHDPsccxvv3a{D<1x)_#U+^ZQc zhrXBPTK#JKZ*_;4iOD|A!zB)3n)2iub_QmJbt;c%u`28+&Nb3%Yr7lv`xY`C5`A1G z8Yv?w9pYK}_xxkH42YPuWIb$;BPUo>_mC?zVW5u`RQ|DJJ@>5#J?`^OOU#a2K99aV ziFJ{nCt_EYsfKbJj0yl8rBIv)ABLG?w$SvSLT<uh=mZhT>@6QR#cj)YZZt`fRFjtV zERD_Eer?91z-X!ct7da+^R!wNFzetu0vYzixi)*+-x8?~sL&*>IOnvC6<F5sDe@NJ z8S9$37$jZ)Am2-<5lY!xfho6SMeu9Vuj~j&fQ}~@{>z{JCxHA47t_=1s3EeXlDEV` z9Fu142T}YGyo?xq0+N&2;*dRhW3N3P+KDk8fWa$nzTf@hHI^w3HV%}~aW%3Obey?g zC%~{w+?d@|v)&3_yJ;KP``}<c5uaxP=gO8*!ggA|0M1lyZr##gOljK&pDVZix5E8( z>Dizdhxe0FJ|B<7jpu?=hSauAdoBVd<t^&h#~uv><JY@(pLx{PuCuj7xwZ^nE`D^k z3|%-uy*PBZ2=Q+JiTbazO@SNYG!YF+jq6dr6FsI7WvUR779wK^?bL5jTh<)RdDm#7 zQodh6<Q@dk4v}sHAIDJ3NXy|{1nAGeou8UNxq#oLFY86^k4J;;&$V${R2!$aO+Z51 z(jS9@EY)S3Q%@}$rnnXCW2ae3Rz&%IC50(2;mdOjczEl9OrL*6@JV;ZoFJinlZ$Sv ztZ#M<<?omM@oXvBa=I2ilmd$7S{{CflZ``zq>4?)%UI0x2?zHbE211eCc~7n5@4J& z0}tu)y>_rOKy5YBqqn4$5UJ+Z;kH0)EP%?qL6ymOBMd8;=6Bi)2}AH=r0%9ftt2o$ z&dR~6{n*>(2g;{u=!*?h-#h<GFMj^!Cb1bu#1;#^h8WCW>ZoQE02`OX3j%8hrlb16 zfY{5fZI4hm<8K311tN`!tPxM9;trvd_0r4du1CWP9{m?`On}W|!_ZaxUt*5#VaJ1G z`9#kKr|!uYAW~q*!TfgA^3eX=(C|?SMWNnKeoQGmW60r0o!5`Du%<d@rCC5l!$A}! zoEX|5hBJ2v^B87~fK0t;M%(mYI)y_}{2n2P2C|Z4;hgxCvTiSKChvuU9M7`C3tTRK z3kwqB2`%qCs!-;A0>==Q4}L+Tq$P;&on)frI8Y0`%IoMi8Oo_MmF(%<v9T3<r!3WD zU=p3^QIUT|z`D*<$y&i_beE(Jm}}U(h(s>@?-hPz6l6y3hiwAdBavXa{d6F`iD<Y^ z@Js|hwYR)=unkI_0GcxgHyO<rfKTKtuMl(2#Ic=k<Kig+s{Sw^_73NQWixrj!9{ji zd9-7Tm{eJpDfhhnrTe#OApvcMVc~SLZ~x^3c0!np+-3}wz*!qaLecvh=>^@c74YDp z*EMv8g9)B(aqrgym_cSmv<wmhsUMI^r?kc?FTd<KmQBJby0G7f{8eB#%~j+6JpRh! z*wE~ds(OZ^IfgrwX1vI0DYqsQT0pAAlWfO(lIX#F3(&bwd}3jD`?MH@tBv9~LR`QL z?~t_ZH8q5jwZAA313(_d@B=Jro)3Ew&$1-zD=9U+A0hrjfiyEys{W1si?I<HlNa7n zw4vz8YzWYD75lc+nlqp$%i_Ws?Myr_P#F*l$Y?tMIrv1r;=@B);w6eEPo^a|5oSl# z;_AhEvl>O0`w26WtR(y)LoSP2Hjz{4z0JP<mpms0fGeLfSGvntA#6+&NEOy?ue(t0 z53BN*eaVp$J}K@2`s}6G#U6<L0>1ofTbZb~(hBIpQq1M(Yn>go7D;yuV#d>Iyt;)o zl0mLK3`TMepxIbZNO~e4d?FJ3KKUSZbTaceuCj8oxr+W+numDWe5~hL)6#RDXICDm zZt)&m-6eMamvSsw)nYb{fL$M`Q-t6;B?BiD7IE7@x$ZypI@^+YmkEW(hQo`jo<^a9 zyI5cKZ*N!sQ`7$&fo$Q%qYt?=<{Iq|$^3|3#`qfXQ5vA&MYipaen9~tt*jHixE#jS z<FoF_#x4T;A*x`wahHTLjRs4)KuZ3KA@F@b{!8840cR$jAv!GAYL1L2M17LfjzmV< zYwDM)eIpaX)W5Q(%;Wezgs0PP3p}rvg^6r(e*+Y)j<|w{{JFjn2ZmrCw-p*^63_V| zV_9;88xr_ff`5SD{opfkKy3^{UQ`e+x#FCR@I@9-6^zl4keTUiK)Ik84%4%{R-XZl zAQ{^u9y}ReFN;G^HhqZ6OdVo91u9igoJ&SrSEf!y;4bElF1;jAIpMGAm7^E$xSAXj z2)ewACb|=D?SXoP!XmA|5A+Vzm49Apf0^wMeu`-`G9354E5>aS*STGe>6$W=Ny|ME z;WMT_OMWNF#ib%@9P*MKUbCfktIF6P=Ka<9#040Ag)_XwT^)4;4<cI#$$F9Qf#$+p zdZhM-ncJY_#U{1LI&K$=a*pMo`5|zQTP>M8T+%R(T0w-Lyi8RCzZ&Wve^Ao;m1bpX zkGDj{6nQOsEi*G>fn|-0gxAYH{Ntf96p9lr84e)x%0^et>H7=khq=Q@lhMnK$VoR~ z;wO1Jx9LnmY=a*}0-oS$t&H-d`|FH9fDb`xeTA>ZlBG&l3p&|X!&41%XIVTLknciw z8OHlGAcii3ZGdSv?6Qmj5xC~G#mc^r+0Xk7B2EK+V^$U#b!_>{-zRK%m2z1Pi$Y+5 z%w^FF=)DzX;KBtIl#@f@qkdDHLjr33jqNZllU+VoSrBa)0N1vyDNjK0MTsW1mT`dZ z-Ib}|Twf-@tfZH{e-$m;$?Tej+sih?nMHCv9F4X%rndV>i;U(!^U%&tu;Na}LNckM z-dDv;Ra|*G;e#t61sQ{|U9BMUP93LILvo9xI$Y=-+8~c4`V}(oJOek+1Cj>H4kI-< zi<NA3AS;Nv*;^-)G1v&HITX#5)|ZxZ75gZlv&O`pC<f6qb~OquZPO1gMBcchmX~>6 z4>qRY!kjpj!AE5Npf6nd9Ce$FSn8c{EE;$4NQNL#5I(r?Npf(4dzm=A^d=rLfV*-Y zimHlfRpM;P^A|bTX?qe$W^JGjfhZP%%W+T&Ll!1L4e@PX=REVsf-N4>j|4^WVllG& zXaDx~^K6hY0mX)%^wbfR+Qe%uyS<iTH8!G3M`JW=d09a;t0?Cvu`>zeYbVOZSG{B5 zbW<?%@LeAn#?`M=*1l)X)-G=$E;|=c-(Ss2yZx&8D=(A>m&yuEtRY2X6ozlr=s-+6 znj0*;G(?K*)f6kmQ3~XQcT(>{PZOI8y_RVB-Lvy1)2C5~zlKoLxT>)e<`sL1SqrJ5 zQ^lIDqate@TXA>i3Gwz~W`=N3@?#PA@%*rO2Z6c-r1rYGNcIUQ{6t1(G|KS|J$%|U zNJ5hx)t4r6A|FN$HRX=s$qfQ#JMDI>%=JB|&M<m?aOQ!Oczqt39pFy7fh@W#^fldV z6<Lxdlk|2gZ6~K|Rp~cHKc9Cb@J$Ja2J~oD{3-Zjn^bb-k_Sp+WS?7<jHcD8G5q$f zCEgV`j}BvijuKh2Gz*lA36q)DsgPj8%VhiC6)Qi~bF+>nT#$t4jV1d5b3}}sIYZ%Q z!o4C10yMdT!(R<n;LV(YVQ326K(@Cos-dq56YatWXdj%9KJOwjVGb*pgH2V#l$mZS z6~z&{g+?=wyoBPQm?6KArxGomYh^HZvf5nbL+W@Q7$H#P1FO-c9CKp|K?AG+{EI9= z?9MX^_aY|ipq8_HEU0gOXuh|W{9rX~&}-+aJD7*ks$M)s;E?AmdxSWFL5j)T&oE%W zbL`QIy;VHr$IHAZh66WdrCkbqyf9U@&GX}o=EY?n^OXB#5%ESpcZes?6#tDXF_$B- z#x)+3Owbu7Y~eC30j;%P=B;Ok9XJGM<9iJwS$u`w_(<?mBDPJWRyppA*~ty#bt11y ze%K_<eqSsshlydyf;fdx$Cio1LuQy=>Q^b?%m29qN3-g4zj_B8fIG8eS8pbn%n%Xm zdaa5;C}wD(;@?l|F`OJAoVqoW7Ut?TBY-f%JPYBs?aQObpLDW-a6R6+g)JVK@6Uwi zdik}wX8_Yda>R0Ll!?6aUR^hXDgCT>U$w=U@EEJ*&Z3GEiy?d9tMFR;+VhxT5UT2s zsTN>!S7QqHw~;<1&IGmO!l5&Qtx5r#IRoJ|QzWW016l*c-*~?=H42EUbvhW=W2CF$ zD7eqjqg+7FMtnm{6K>oqC%OAjAuWBkW7$lN@WLAV<brTJidO*`C%MB}0A3a2699Ny zEo_XpHdGeM@7x^k@=X=6o3oA#la}5g7D8vFBDEcj2+~i%Zgg{;L0Bgy$1>w+3kya= zadlReBpohh2`5}s-|QlZ-5wk5*YsOt=uMd&{tLiU-Hm&%bSab2%f)C$7;^Oih3W{H zUYNuIZ+?*NiY4ZGz6;YNVf#46>JtuoCQLbQxG;4dRv7?(yx|}F;|F?BIxI^=OhO`3 zV23}YN*pdP)W95l2z^G9k%pD{SeEGPewkIlEYrQ+PQoNl2slewyKMT3I{oYbd7EIW zySdML$kOmjH^1_MT<1bRJ@+X-4mxNAW1>~jH5J;oZ`wkh_I2xdzY9AlTT*T#20jyT z`cFGKLss;E_l55K4OkDaZ1_p``k>L~{-O_g>saDj^p57*@Iu@OY@7fsy|Fq;HH={f zzQX5%6@Cv9rh5--2&W76{8P*BGDS+DiO%%fn}$qxS-lDN1pd>nUpT=G7E=K2&f{-8 zJ6l6SJQGU*#Jmb<v3;$A@u&vaWbxYuA!vx%d`OlUb6CT}#GgkjC^d-sExh=mw`?%b zSd2s9cEss9V&C~;+EGum6I1Q@Wl>`|E2|zK1BxDLyj=KlMp_v`z_25C*U~XE1hY{C z$*_4ZY|bEO7GOOUQJk!391jVk={i4`P+X$(B-Ck_!C9G#$h_^woHWB2Q_>$JFW99? zoNrsLn<#sLER+g7$}^Sn$Zk~Z>is)=k`Fj6)+uDp=|sQDr?Fky%SD>H;w{d`<A_bt z@BlWA9cb<R<Gx>lM$DuP4gD?a5k%CH1<H;A_5?^|2|00w^!-`hY0D|EXJ^Z#|FS+A z?*sz$6pFV#MP`He)ne*-L0oj9d~EO)Fc%-M9Kje{wseA&WOm~4*01RFA~`#jeu?hn z%SM#F*>*R=bLSJsP--|mZAj{Jliody*b*33<0KpbH4u&WOxxFR%I~u0BU_A}gWLhI z#oJPJrcHK4Cl>R@NXUkxfwUvc>5(Ux3JSKjo{#~e*S(mvX5Z9`z$1SH&sY6Su?xC* zy8bKO%k!4(zEcgSgA=135Lu5qp;gy&WoMBs)PGH+A$iH5JKo-d3tQ?1wWFj%dUUk@ zF1zj#iFB3+b-!}5&(qrZp);8^mb+Smn3TKlp_?v}eQK`_k<2SrNKP}3-W{+|+l`q& zR7|tD(5q%<&la&RBW=uXZahGlA)n}uIw0f0KpfhasCFQVbfp#RVs3+{dR{4f0h55@ z3l9<;#3SbQv%Hk-Tj|?!U4`QdHwmZySl1nnoqn+Apot9XTfsPxjm5rhUKlpcp(%_P zAVDJGTn!b#$%P9+nm}4CX{}5Vvq1LSug(9lfP;)|g*lA5e`;L2xEm^p@-}sFhCxoV zVmwldWh^!rUTKBa52zfl0zy9Z#_sri1T0=7qjGvF2l4%Wyl@k}ef~#xK6Cq>X>2&s z?6b+_&QgAo)&QMaHdus@?ks~rJClA)I&U?4l|Z{ux;%DK1v62>jp_|I&&yisDy_o% zV7e<DGlpF`nUH6#(KTpnoqJsaZAT#6tsfOaQh9bcszGTrR#E{3iH}A|-2ekb#rjJ) zDwOUW_7pWZx4~~$7=BV>;qM5!;b(8x{q~2ko>z7{x4vEMmCvVbAy+x_AkPs#-=AAp zzTx|KgmEx&j7`hxjokZEl{7u!PJs@;zqRxXN(GpS*-ftv>hVtAKYKLTp4qDF`C$kq z^8`3sOL2udQ;zPgDMp`Yn1mqbCI(?#&}G{M<-t=OM4UCC+6^nuOPccmIEO3%tq^KD zoSi5C%CoJwp(msPV$PhYRgz~LUMYC~AY|am0B@F+Y3!I-w70B6^caF_Z7RFNKGqM< zO$0x<2f#FHt4(K12J^5959j163pB-VSS2&vp9F6wS&}h!bPnH6{4d-EUaYdql=0CH zd&a_+J)&y(gwJ2<(TVG1`$Q0;*?>41VrT=u%=sdQ<N;!q5Cu15-hnKir_LN_hM!~n z9dK4~)k=`+qwP*`1Ci{auQI&5i#=-=w^Zbx&ho>DVbwXgow96_qYHK`v!Vs|_#Ik# z{T%qRvVtFMhqgWBnTpd)dDkcV*6Z%~d;~R{D-&GilX}vbA_yspQGMJEXAx_Sn3p7$ zSB!*94wO~7-idkk2_kP*WVL5hwZ0{?+#bB8xvn^5OWi;Ab_D7TpF&3GZoIJ*`sf=@ zRd|P|z3|fW+7Pme9v9sG&QBXD_sNXBi94C9xGa~wFfYUfbGFY%?(1F&mUxoyL7-*D zEFM97(KrsKO0&uG;=%hz-|z#oDKMXoATe0I&MO7wvGeEs043Ek`I;5Yl(0R2^ce1? zrld7q1U8C=jxsu)dXNncG9G<*LKD3Cw^|8Qg)z1UT5+|=VP{z6rGjctl`!NRI+@u@ zJxGcY+*b;OEM~y<Gd$ErxMOa@Jru((l+6(Al)g#51qvc?!j8R*&y{1`Tg(eWGS|$B z>BY-M$TC!9oJ=(R^c`rZSD*-Lh6#*(Pjiz<9+qKMW3U^fe8m?v)XFQ<J0!@jwd}^b zL0C$71NR^ft#gus)DAIr%-In+#KKq$RrJAlQks$JijbYART46sVa-sa%vlGKVscf9 zx10j!BVX%$`Dw0Ol$`{dyO~S}VbekXNg2;#Wl{9gP@Vu5wAI=0Q1lH(RboOfr}JJ> z9KF8>Vr9k>YmK1QJbimTu6cuva4p9)N1@#OD)cYRk-Y9Lm#V?@#eT{V?PxB>YvhE} z80a9h(Q~Bm+5>&Vd3)TEDzcD`_b=OaiPO%mwa1x<zT#0mzf`G~hO%710rMa$LN`o- zuWy%Bfd}i^g6&yO0mp2o*J<W&Sk3A}t+%^8ysMj)F#+K!>Qz@W*ga#VQnzo{RBtyC z-p)=38QbAaf>g?z*Ef>GiB=c}$eb6KAQ2SG&Xa9_vJ?^nAGjT>I>Fvd48_ceJalTk zBr&uSnY6Rv2drVnP!Jah1UkkWI#J?+M4WD-8i}2@{Tnk}<GwF8c=|F_i_@ytY?Qd~ znUeEtCmGmj6m~-*Ims;}w~be+jJn303zrAHT<?R*)>p=;G@J0|NqM$JKqWdu!NuOI zJh<d6kj6fdN`WGX>8V1k_dLRZ!kB8dqF&AbgN-I(+EY{~o_;{Llm`6cO8|0;&<E6O z5#gylStXYgucZ-@gbB;hWEO+8V3qH=IHm?v8-b+tNH@5Z^d$QR+JUT!B?ZCWBoCA} znUpR<d=+#kFi1p_!9EfFrYjrwUkGGIR9d<qWH{*yxl<5aKJz=r%iFGKaT@t?B@Iui zFLrT|mbW%lnDR&><Aj-?x83~Jvu?XUw{}g`z?G;YB*kl;ta|Th$!H3VZ6u@pLePWJ z1E49D=AD`pZ@)!x;Vo7pX(o~ocyZ%*tRl4)gpG>f{rK6A%oE}v<|*~?+44E`+|cX( z)GK;1S<Rj}?h@GVCT21rU$eh*QoVQWx;V4Z6j$|}H4-~uRaHD|U2FTN{DlND=8E#9 zPcKG*FkQqxK#Ni~2#tKovoFkxYSTZQ&m{NkQpCAMa44g*xPi&jqf-N|A5NCS&a9t$ z@+<G>0V`z)2j@C+WAC7MRGPqpv7htQI$j3qj$$1or6qof+mhd@$DS8~YUf)BO>Y({ zRw$+|l1l*A$Yv0=l<T}y(DW1W1$T1}Hc}Jej#aHA_97B7ZmrDgnqEk+>5GTb>R;;N zFsvQASc);Rtaru(qL5f)38VmWsY9@R5lb)%f-GRSQ-HYkG4YeCv~fF<Ai_KoDsCla zpF52mE^NfI03CMw@E?OtSZrFttoAwERnIQLi(Iu#qEMkw(=9#GmG^r<$;T9(FPicr zq;359t4Fx^d}$8dAx1t<qnK1LOx<_OJ*CSpK*4*w_I1jR^PZ>#Nu(}z<MrR^SHmZq zj4S?Po@Z1C+C<es3uZ@`^Q%2$OCA)|E|f$Z+XXEz<V+(h=NS^bX1!uhIap_9vV!fw zuo>e-zen=+OS0agdRFSvJ-Z*x>*;B7I)9Q$d7}W+aJVEvLT~*iz&+o!x;q}7oEQCL zne#R9xldw^-wAvs5b|O-z-Bo4?j+5*a?m7{+IY4=-X79PlDRS5hGQUDraqcr2NynA zG!0ha!D!FE3qtnpsA6^^$X3T3&O-{7NpHj3jYV0aX%OIcH?Trh%`oCq>RtNI6i)r7 zo+guF6;m6}j(JTugY10vg6&?*lOcJFY&TZYR~=zbC=9p7{6GluG`2G)k`YCd93^Xh zl$;VmsVbwe5rXG~UzAxH&znese!+Tr{MR)dc)mIf&UWDzMnW{f0FwDhTS~O*Lq0C= zLPwwFJNi7qYvJa(;^>5Kz3~T~;F6nvaqtaPA)*gBO6`MmbZ#Bm0?IHZhEK<uo7B?W zJd9s0p)(7_6V9&&lWcO$CRTnvB;nJxtu2VgQs29wCZK>Ff+%_Q3$;g?o;R;cZ?s;D zH7Qy~zBoOPBk35I=>x8U>95$+`s5H{kF^)1oS#I_i%9gq=o*LZv!1ICYl)L@;VOJ< z=%Y0U87hCDkY6YB{DX`b^C%Ei+F+j;`gt*$15-i#`g&XQ5%lxr0O*Om+FX+T!e@te zDNNgJ@QM}i_S1D$SL`4U%EveTlbytjn2d}LLzePsjVgpkPE!eA0cq=3(dDn<MXELL zY^YfH0M%1jkJ)}(;3Ho^@DjznswMoi@Tur4w^tv6ml(8Tk<`{DZdfVQQOI9?8Z5ry zQw~Gnp6td|7H)2-{Ay?emy!2CW}=h<AznL}Ov`=}_5o~YJdBVz{QD(!D(R<;SK1`} z&GIMd6I3CC!Bq`?<@GUVr3BaIi6oV2bISd#tm*nK<AvdD|H&-9HWR=2n`DXs`{Wy5 z6JpaU2GkH!tdOSW<MYSlv|X$5-3lxqfwr4{qPgX^uw*+pR+ytnzp6|-rl73MBn1oc zrzs4MM8~6l+T~Eu5C-je@#-FRJ^m_;BdmLDWDrij`p%2ZOC(384b$L;J4%0o+zp*3 zAAf_LfGT;}uEb{1BI$}Be(;%9F<=as{!J0)EBI@XX!*1F_y4==ZDpmp`~Z0-yYJ(7 z<@B#qarsq;KLV|^ZTw(HLKd$|KH{p-PyUk+Padbsu;$Qs@#Jp*#oo^^8`gU~I4D<4 z4qFw#@E5W_(fbFQL#00^wB)(s*~eyNqsVpKUQV+<YQTQUjfzbsAwy?@UBUx6)=RNT zKTf?=78c{4>HqKO+XlBIElS^09@02uO?>UFb{OpibNoBV<hp`2|6L!p(U_@jIVlmr zLgMHWvj~+Tp+P!Q5)u|$^#N}7j}x$f`ed=n%*W>`68rEA%<sU?|Ns9s!UVK~saG|w zI_OjzL_sOdz}a=&5i0VQj2N=9JZ>H9+rJ7`cU0$7eY&Ow2a$$}Jx>41ROuAXTH|m0 z7o6or36I*B*gAoy>Hb|rYuwz}{583a&UGN4_^z!fKV4j1Ze9U<I`P@A^vbXq(S!OE zPj@F#JFSPr%SUdJI}eB9mZJZudGnKEhEV_dV>|iV#7;0vPE)RMc5~sghQ&s=KX_^i zrl@?drYG3xrGJz3V(6o)A{1(p$7a-0sdw8oUJQrwZ1_ld!%|1r*8SS^s{WX{cQH0S zz5!&W;)hE<AwSLmw}d|iNNwDVL-#vIYV}92J+bcB(18bj-}B#`Vp(>p{Qmu@c9C4> ztf^afq`Kw18Qbggss{vMuWFz#^PxX3bAt>=eOV_Cc6aGr$QzuFe**un7Qh#JE;|nN ze*M!28LDkM@$3e4@!AJYF*zyH&fgsUxbDu$&K}hNIy&2D?)NtnyJR)|%JHu!VSNjB zNd;kljfr6XOIzsJE$qfJ0B#Wx@4vkMwVqzE?~7cYzZSE{9(AR7&(4)v8c|V5L^~g` z{pSPZ-_}afwIuO9G~fQt^@rH~>2fGf_<DyY70!8v(*^l^Px8|SMVL~}TQ0UI7@CdV zM}acWHzIaU+<brV-jh9SgNy!r28t09q)^xwj!6a!t#5rKf(j5+lj#(bb6CPHVa%(7 zqT)f3Pf>?-={!q&))*q^xAs(vi8LG}nXOCVgXn1spaK9%-Y7ssoQ2Qf>7S$wAhCo6 zX16e4GVt?Sx}NYc9@=e<SH<^XrEFAS*K;mkZABGbb}tid-LXY4=6stG$RhFe7mSa4 zDgR@OB*R^5VMRV7FN6%Vs##)N<bqDu+fS{yeYGEpj_R-aV|)AT9}Dwka>?}5J_=V} z7VGttIMpx$$fINEVo>vE?u!fn3~cD6^47^%t^T?zeSVhB=EW?v)R|SoueqyWE`QFj zewR7PXhKYw>zi5Py2yGVhKc~=m&ql^<$znhJsVttsxU^?u!iVl?&MF_oQPtVVd?4_ zVV0`rE#5Lw?r2BaipEh8{e@Ak<~@>hGX0Q%d~T!PA?L?o;t*<Phz3wIGWgt0biuZX zwqxZ28YAmr5%kBgC1#qRG|p;FoqS|yjb+)hUj>*|DPumOuR=cZgVSYdGAWKZ8dgXF z`;dru(m~?Mm}_+Q5n@Qa<zvpJ`hEPR;zZhLt)GVCy?nELyhUF0Hm9ds>NFSydCxvS zKzBO>_I=xY{j&eo*(V}*TCIC&d0DQRPd+9WJ@km@ji#KsR27Ep=8Qk%=h`jf`Tuon z`Mq@Vqf-T~-h+EDw|)smz~uI@&%@kLXBrd{?490E1T@Ml`N3{O!Qk6kiRaU0=;B|; zRnOU0(#&xE%sVX?h~{KLndPVMrU3hwIw(j;Kn+fN5);oU5-cx^CwbE@X-(0cXn|op zuzN0Xcz#Rq%%UG7f2LVVhW_^E2Imuy{mN5=#EqWR+S|3!M0?PhH|LxRB*9wNWLj1^ za%FdwcUxn{<nGM_DKR{)mx0XZGwpU6c&t5C;bL-Wa?SFAsA&KYJ|zX`IRFv^nQxWd zwUu0>xlqlOH<CS#s8rs;;+Vglk}DlEB<f(gk-dGLd-{B%>Q>y;4A&mfPf^d5faDq3 zz0@ij@)!{#CP(?s6V+%BG`Jr%m2CBu`5a&v)fpu@S|1BbeEFujL<~QyXeM5ay7R}2 z5uY>b=2&;pg9w(F3S4)e`ghnT-mlG`+`+cc&_zOHvCrjVOZS~rw$JfzSHp5>u6~t{ zy}?<LbuHcd=E@g2r7#+VFga@2n$leM`#pBqQ@ZdLFlXKbweNmFyrNfDN)G$)FHCV} z99vYn47pOf1-Dm(CqxIS4?zg})^03Ge(D;W1T;8XiE+ijY2b@lzho)eHBJ0UoDc95 z`dhYrsdh&K6Z%6YWQ;}ihQJ159L=<XHFLy?=Xq*f!Nf~#-}7tAMwj$J^jbXb5`u;R zWN!rtsb63#&5(6RPpreACxWDLA99;Mvz@{1t*rc>$y>URmgJgdmYN@yF_%Fc^XO13 zoQ2E4qn`;k5|g0axOPo)b@{aCy$87_!5o)oi8+muSyJ%LK>WRtAM}S84xb6QD-WsY zq~mcDy`~kf{9{Y6tmUSTznuPj2)U_eY7|E`{)4RN#buYW5%UrQwq}wy*FX^(G>$x< zS5Mf_Kg9hPThKDc&v9RUo?jDJacOklbg1M|2}|+D#u!BAa(XT&AE+mrV>yM(7w!4h zTiyPX_e{r(yOb9rp@q`U`}9O&xlIvFbt5lse_A@Z`yg4g27KjuS=>~+jXxwl6SwsS z0P^FiAy)N9NM6cB8kotuhS$0B3GV?K$whxd`&It=(GnGCjKlZT<D~nS^u-*q)}hhT zSwKelq6$}G+uZ$dGcJBA`s`1TJa!(wVYI3p*>4ITZ_Xr}s;}dIiPXpi|i@6}R3S z<5t=G=D$3cD}#<lp~C~t5uLvO#9;<`=hKz=FLVnFK7rKpu#5eKc?WBfjlyjvJ~7C$ zOL7uhLZ~)YER1WV`p}=glO0ii*2zcdH}ZNt<D_EM^Zo$EfGFy{j|6NZdsVqaoEGw) z&vY)dD@nHuQ<x^mX}~P_QfcwqzAK4mWUNYWb*vaYaSLFL#!FGM#zOlv{x$wm{x*9P zi^BO2JVV?~7}Yh&R`F;Ak|WGYO-2p|C<<iVdsR?~!<JmgiJnJ@Wh?%$o-WOcd4SQT zgb(yuJRI`bV2xV;X|d$m!2Ob7@+Lt@Hs47nsGmw4MaPv{A}fPo1qB%^<*+CO!rlB` z(e1rsHAaLYg4#}LoGDmHgbE6xHi@-It{QavqH}z2UPUVnGsgJ*G~ZEloKLLKS@ECl z@Ize|J5jZYnqR~_P<z&lUTfx^zhirAAe`<3<-8~M*$^o)U-!O6C#smMAQ>Q%@CaML z<^Sxo_rX!R0^bS9w+{6IhCatfr>lhVOB0yUepJtXS4BLYWCMFCca1gjG4kfnE1P^7 znu)})Az8v9tHNMFr<pZP;)*JG|0e$`mvnggYijf;vaWN38uh&y*EIdons04q_}| zMCUXtJJhgj?&j9m8V>j6p8>5HZ3OO*x$#EB8a#Q;{OsFYya5jB&joz6RM+YgKq7C; zGo@qep7;;w*n3b>KHB;cx?KGunCa|rNq7FSCGg`wWQG4<yAXKvUyfQ@N*`u}Rla&D zw3T*t)Hjqg)X}2Qvei@V`bXByIzaDoITh!cUXH-OJ-h^r7oiIz+4U|9c8SwR7{3nj zUE<9(qSbJcBa1zd8rTcxkMPxF4(qrvKp>Ebxp~oFJOqCCU&@fEAiw1-+MT(r&$k*d zOl$x1Mcuqzrvf&q`F(d31jidchwehJU}jILBfe<7VO(qmCr~0wCd69?0ISuF4z&A6 z@6iCe_xDowywOHD{8<wO^$D!F#j|V3@!b=-Kb>#mx}%hehK)bng^pC-Fh##v&NtQ_ zEdRhN>|4=@Ei7PqkWgFt)RgsFKASKS-eGKzpHA;J_ZrR9w~xvbt%d83MBf*z`S+3H z##?23(7mM)q=`brZgW%UP?B?I;7#k$X%j?G=)N0zxQ%NQ`*5YXL@cTm=*k~_tW}b# z@DPMK)?hWaeMMdCg_ApxX6anDX?^w`EQ&JNK6f^RgH<{<kmGXL(aw{ipFG>3e6rG? z09C@QbJTEodA3!yo?kSm=*(Z_q0GH;v~jfCLrLH~@pK*b`=%M5b(~W-vHE_5yes-> z)(yTiv9KKcbsPzjOMJ(ESmxSBF7NA8py&2chs~TNXO6PeKm{X7Cxet3{b43cMzFF{ zrgWa4dPzOT9`Nmh7U$#4xT=^h>E_9Eba3)p`iWvw;`lH@FMA%r5EGdak^z!Z0gC85 z3YcBBx*vbi`l;`du7YAd*}mQ^p2cjmRW}-nd~PB8B|hlTM+tLuH`n5wE@#cmk^kAJ zqsC4+On8|mxNc5&oL8G#)`&^DlBS!ALW=9aoHN{aoEMs<%NFa`_M$!|(D<qM)`+D& zOwrOPn1i2={TVuEi-}D2+@FBe70|?~{xRPq39X7h`)i6f-xQ(aQ_X3f-jr?4%n#r1 z)$SpOhlk`lzv+BnDOAH6U1ARhVYji!G?FCEe`|{?9}bR`vf@|LC+ywKjZVb9g|zmW zdzO;izp*k=%P4N${i8oFny_<g%kj8w)SMkiXnHyHtSW4xoo`pwgyaYp?kVL#din$5 z<t#2sWJ)gO(i2nd#@v@n;z>`~%RRK*_hr*DkEui9#B$J5y7ZfIlE-F>S@*Q`G07)* zYeEC}=6KL>57~cRe!FeCtjh)xJ{P%{V|k!nYzuQ%7sJO~wvcZvSWvZhe%=MH4t@7- z8Ergu>S}R2sub_>plqZh$Z7_xX?ldnb0T?;l1?yG)N9D6+pOiQH0=JfU8Bh;Aiw?7 zu7G0fUh*+?66V*d1{x>X6pvvxY#{k<n1Z&Dw!va8zk-kd93Ya^MSY=!!mx+YG}^V_ zwAoS5$AjUSy5~ZCJ_Ahuv5B>u@ZBF6dMLngL+WY0sy|He<kPRaeBwiOyxDvS{D`=x z4@38v8a_SN&kVdAFEB7<=3EDpPtAumHy77K$7NI<R^63hsi4yf-gD+vqcdaMwXJM3 z50B<r2J}fV{#2|7y<4NIBL6N7XxI%OWy+c~>KN~dy5)Ran02iR8^2p@7cckIE31s$ z(}x`ZSt^LQIoop|jlz^LV*J#@K03|Sn-$u9o{0W}SbuGauPEpA{+l6VNHu0{{FkF= zrK8aJvXe~3NuzJj@`-7;R7J%*H}4+-jE~s?38dho1?xuuDE`ag0a+RX0f>zXz?Kd< zdir`sY$MMAWiNG;e?0MIfBz}A23dNAJC&e_6MN=YOC@_#5|s{L4fKNuZ{?m*X>gP3 ziA2$!%tih+2t`eQ>*Q2b<mA`SD!Cs>K}uiLdW_)F+Bt!{pC*znOV%ByU1l123HBKM z<}ZLf=oF|k3`i@HCr@7A@@l-lNY<2MHXjNnaZ!xUJ{yTK>s#57%mBsxIX~=b+!!iu zhvkWCmADs5ex(kV+cmVZZVaCDBLK~a7P2eu-JtIs%#+BC4Ig4e`IQ(X7)^a2>t>;% z<w%$QnPYjDXuDpO!}2Y##zG#EPi;?2)nV7dC@Ma!@`vE-cL`turxYnNed7+z2@48G z<7BF5eyCEW)Cy<`PV2lh=gq{*tTEI8%k+3ohhqeW8AJzYpAC(SR;l1C3qDU27sJp* z^N2p@gs3abas;bl#RhZjO08hmR-3yAD<H~nv2jdXHxId;U|zt24B%|nnyfreInRa7 zN+f&>Ypma<v)G~IFS82(=3MhEW@QAviTVk*?ie35HDb=(yAz)iFKTK{G#+Z6{e?;1 z4<lrbJb5?0{$Ut^K^E%YQ-ro_`DdOao~fa$7HgWr+9(4QK1Q%W^blHnmxy(G7;dJh zZCQdnf@U_sfO8$FSt}Y-AR*EvBj375+Ade<=LJmH{n=-;+?zhFeHfXm-f{Hw4YQz0 zE0Ksk_77zj^JfYc{JpP|MEP%vpq%Sq7EB-8CVd+Er^Le7T%FTvZwiW;{*uD*r^^OO zw)_du_>_8Es;Uz=#oZj7M(OkfZ1L*;kV%h|?^2A5aCrB$cgm+HA5E4Mbf*#?+Q)MG z&ciun@M%ub-#`Bo+0$q*(j=FsIAb9bu1a)QYrp(VH8p?t@FcpYR9UV36Rgk{6B%D? zL#H4AFe(x8Gdi;V=Ut>J>&1x4vZTZ41W=9QY60ticzVmAxVm6#7y<zjoZ#*d+}%C6 z26uONcZcBa?(P<x;O<VaAcGIid!Bp0`^}H3si~P=XIuB`?$zDt0h+p)B|8co-D2Y` z&B_=!33;c3O}I>_Xk@y|s?(Vk0+xd{!ucGZ3hP`(egsiB3e*&t^x#rkqtwdCxa^8a zOHJSuH4akvtWcnJy6NK)MAm-IYq^|-#JC`ikY7xYreAoD$>NxO-adpu<dLcAuS7z! zJfJ<BE8#dC1Q&+8+^InE61?G?&9-bMPS(PBcdiA+$)2%bMfO?|m&qg_YMMr5>*(J# zEYEfJ2ad&!rP^KP6DSjCEUYYg%LKdl($kkUD%=+sX@)0DoZ1Amw(xXOVnB6v1SO9~ zB3Nukze<G(c`&q#dQ{mqtFl^bXfSMKA-h|Q`T&OxQQ{5^sPr7o@9s$7^u~SJP8J@T zH)VwYb&EfD?8NRz?VgtyP<&z$%R4?DP%Xakvmy*TjQ8#xJ!96Kja`26aI-VHI)=Ad z06&b^h1&x-Sf*MBNMDjqsyjvqIybKr0XfG)-~;@pxv2=8WWYo)1|0E_89?xvYVigE z*aC4uIQT}hKy)w8a0_;#U34N!z`M${Q^%@u=8DiUBZK3zb0TJ&{27v*zhvPtQF>tu z)5S#+N>i7nq=@C2_0SFt7hOh6D{T>hmr3{XrkM3R4?S&5)_i0sf|yH1$hOZ-qBu!J z(46%`c$VqG1V}v6x}<mp;s?2ww2{fG;#0{P$kMc&)#%xw2wNR-k-V`m@K-miu6hl! zmt|<#3JG{+IvWPFb5bVH^OyBWa0?5`Ps)+;dzUo4HMZy3ia4ZGJEOy<Pg;b{pXQ_d zG>(KN+3yX18*T}^RD{OWTK?V!dW-?4_n?BVSqYi=VR;i005xKh&7{J_%!$U=zCt!N zN)TAmrWyVd-M`Va{q<SrbTZIQ1TdhHvZju*Mf=tx=aHgoiBhT4&*uP`a{}QhU`y?S zDfG})e8Qej?@qAj#9tlOi9ZC`w$2a<ItnY3fc;cRE+;ABI<9+3!NOEMDVAnoiJ}3c zt=ve<qc#7bl{-GiVe1iYn*4XYle|{Pi*|+vRE59BIN`!QTSNf+UEy0tvUM7(VCSL) zJ{J8#=Z|PYgqot}b<`D{cthCA7UQ2)OXW*e!%qadXrv&?H20MI-V?2kHi5RXiI+Rx zSzWe!!>7iJ1%js#AXlK0b(#n2dt+suW*Vm#=)cuiKoJ9JB03!Nj#f00dJ$-qwq*aO zm#x^bdC@Otae77fkO;0Y_=tH<09)+C2Ky4A9)G@^rFaC+4FSGp-YV7HR%eW4UKy$` zHIJx6_;k=2apkJ_T-7|bgo_e)dy!-Kw9P+f#X^v4Mb5M`;GckNrE%9=WZ?jmHWV(Y z%0Sx<x6zt=<H~1e#6f~is0yUke>e8Ayv+mv)ZAK9Jcx4|T?7=dd+5S*MGUWt#LojH z-NqUy`$LE_HyYQ9l4a)3xs+X`FXt!x6*(fYykhU-%ScqL#sb%o3Xhz9PgCMswPIm+ zkUTvJrp!}j&how;aFI6BTmNeLRzzzVQE77CX;$3M8ozFhw4a~;DVT2zV!-1>G-(N( z%M!0sTFJA9l?#r#38WxUTim{{=cw%r5#serv|Dc3^O{<xwhqlN8d%5vH;q0ZlOwP= z$I!FZ91ta(1eaM$wNygUDbT)|P@IiJyAqK4M8(JG{n6Pilg5@@gznXJW`=M>fXH=t zeCR#qneDVJb}NyqzcP{bR6SAQ($iEMj&)E(V095-y|y4B?!G&xH0-plm-c+>UR<Zm z@MS(6g*_nCo-p#ND*J6wNXA4y?f#^P6t>3|S~-m)RlDk+uRyg}F;EX*RW`ZQ1e48S z@%IlX6#D3OPwKQ~i`=xV#FMk+3B$YX#S67#THVEG<q6X#{s|K0y@Dgnj&3PfQnq$_ z^Y)2Dj(slRCfL>Hvwp*cNSR1+k!#yFHq9yWRP*aQ<Q8AYOqoeYzAyF*H`OhIayy(> zH=;EKS>;n?d?uKj%h30g_>q=;5)eP_mol>ghn-Z4`f1X&BU?}5DaO?EC=@0mGwm== zM(e|>V*wJP$9)_}u;F{>tBpp5-BWh{mD2B3rp*FY&~vxQS_5s~_XXQ>SGAzAC^rN4 zu<r**HG<<cA?%mbZRB~#?k855Z@oyc?k8xRz64*;tTPr&FVXPl4{%+AVJ;A?Hni;C zi=XOTH$@!683Y%+>wKoj`Uwsb;Ngb});X;7kbv`tuD0=+V0E_BNMN%7s-u&luht4M zWr#Y{i1TZuXV+?+$gq6rr)YEd|GOSewEg=xe1x7Ox?OH_c5SCFU7Jp4w$3yb^K6HS z(G10N7K&9%8ZA~B`ap^3BOca5RTs}FnBc^>)fQ{@0--y(|6&r^<O@t396y<j30X$! zUC(~X^IZ>-{iF5ozOp!;&Z*YvxQT#?Bw$P?|FW>KP_5ChA2ESWQ)z*%X}#9zN{h!~ zQ~p2Uf*^9PHM=$(JUrvW@f7DE=6yB=dHJIpOyt3gFZZy3?q^mJl00h$ciC=m{H)gK z9~v6MxBo9JVkD0~%RPE?I6-TMAJS^Sqj!CR((M1?2mFZnc=Lz2^N)4SI*o=xBMI@D z=-mH}O>Ac**xUde>sDKB@u+e=_Os^~okq<1(`DXC4%wa+>)lkdozFKrl1gOK8eM?= z^b-32c(msB>p;{);Sk+f93wu?tWV9SvV1)lL+x&UN5K%g(eXec*XQO3B^8xsgVAu) zv@!w1)TtR|4wZ|b#dV>{i9*Uq9S}bGZ_WPqEiR-RY_r*(0GQ?6!7lO5^Vaei8HDoC zlc!&LjYpA|t2I@`vuG<VAQQrAGTWF0)cCZp<7s-jm<}}lD2u1$0s|R`kBp9<f?w$L zx;^Aar^(#R?i@(??_~TKY@@5Dbd<#5q11r>zU75j_8=hW6ipG#C~;M=$$aVXFcCc$ zAnuM`eezhs6$g~E62EOY{yQ0yiwEiaqAhbaUwNkZ{|Alcbmni%^`ycj+VJ$slN57% zZbUvq-5FT%#{)5`Bo`T9`XtHo$&-GbUtrXgw?DLo|HX;^ccQqLV`C&{TSBLy1M*(A zD+Nqh0TR9^&!Ku%ueyelQN{GPb0%kB%_S%Y{y_>UTa_-9s^Rt(Mq!qgSG_rTj8_*1 z-<IvqO-QDO<$yf7dv{o<JxL&Mo!{_bH-Zzlq!ya7skyni|Fqg}M1Az3pofuE{j4#X zNTr9RUqKy}fkA82q6aqki<!CkF~W;auO|;PbN~0U?14(Ps>;f|0}cI&-&Q!&o~ju* z8QU49mdrJ(rRhHh*MW!sbOgj8>7Y^c{vla*Ae>6Yf*bDiT)rf~zG%4G9C^1To<ghw zC-}d1d-F1kzWp#%-k?*rF22{R!A-xH3mu>9;bDk7!#MR+Q?BFm%*_2jfLOEXJYzbQ z$?lvf#GhyFI^6*5^JVv~{50RK>~fvHJ~!Javl-yY=c@BxoSqyTlPb`#Zo%DtF}jrf zzs+#@D<6}5FJ-B~z5e0kWOXz#enMTX8h}3`FW2F8_&X5le4{PCs;>9>v%V+_bhh8~ z>83ZRhwtfcQnuT=<;;M+S51#z{C|Bgt7<!==H})+ceb2+em;2v_bw(r-uXDkz0u?k znuLS|O{gP&B6BHMn}0ESYADd+M^_SO^g4*46c1*y%`^Ax`?3*v*p@p<-%8e*1!p~n znA+QM{|`w@*JAk(JpmPgRjwUg%o2LMA}?5AC11G^7?)flzX5#;e=NA@34J)Z{T+%t z1HXtL7jnf#9;6e)Ayw|gQ#3B$0No6o*G$t84+n2QLzfKIY+THr-D~uCv4c0Ak<0S@ zp1Tw5K>PqjTRa*QLw*Q;ZhI43<vbh+peB+7Q($FhA3iy;P+N1z-WTSccPj3Wt*2WR zMnM^MEbsuLqtI6dc=OnUcXtT)2{6X@xEXm}vl$thg<d)0WT}h%?pdTi&@yW<0Y}E% zyl-GXXag7%P3yLLr_55iZN<D;iL4${vMDx^ykJEEo1nswtJAt?Gf=W>sdV9DUk5-| z=6{Bur@gzoo6MrwChA8FY6_I<l&Y4PIIsu60#iTJ=q6N>m$Cod<Hl+s+FS(*>a(Zq z9zsdzTjkdmK7lu7Y^P(OHK0v!jREp=#)8GMhX<ojAT4gJL_ac4vU=SL{PAVU`67W8 zvNTf-;3O+CWgO~F@h-NMu3IVkFF)Y>g`2nD8%^K<5Uc3zQ+$zp2<2i0I#T)d=_jA4 zJ?uWZm?5>*Ja$h5p==<)*0e?*MVjqA<ftPSk14{M6n{I1CotjJcjMjdwb0m+MQ?k( z^zlGNp4Jnu-)?m4{OR8G+swIFNc`rNIK$KZ&cXP%G`=(E)4%+$r!RfO_x^W%&U=M$ z>P|vPHa*dGf~)&Wf-hdFpWh?YQ^~)-5cP%D3H<9gvaK^_);yd=z|e^Y5$)!Je1r2g z?}-&IGELu1?e}+jz+RY|l9?sVZh`~Iy|?_Aevdzp?huM5IIm0H`;ye{H4!Nc!O$jM z_6MvVce;c-E#Y=X*qW^gRsQc=I^OR*dM9a$hyWPPh>Ek<MEjje{smY9t~eYbBEie1 z;dyp;1kru2BjCb_Yj$z*k7gFR*Ox*ts^Sz(zq|4fc=c?fZpqYvpR}sDlzt?lPph|W z)FiJsRyWnONN!E@E#_})X=i68NJZjXX^$Zy7zCpj(`|FF=P($eqlH5nsvZnE>j!E! zrR$Xi-^R`2CXx?oiPFb8ZqI=LhOQ&NQZyM;htWi1j9#5WX345>X0Ki}b3i{zNUC0$ zOw-zcmS_(q^0HCH=uf9TjI{bn!XqJ%D>}{8xeKr*$TJb-cUETOw?(VTf@v5O;3rtH zqj2L21L=s53iAZMwUK88QwDNH!3_rJ^(lCR$zIPm%ec-E)$7X*nT4e?T&KB#WCzPk z$Xx32yruO3wh1S3Xl&%^7w#FAE2CfBO(Q7cB#!8YHcS!IcV9lqq;?p+-D|}(2s?tv z<(Q!kl<HQPgu1ej=_|!ibG!N76U|~ctUM5U^z!@?4aP$2env+QMA#TKzq~<TL5X4@ zX78Hg*;~^a#|HSBX}Ye{YOs5;b}?ZaLrT)eUA=&rFlr7E`yM4yS2{PrTa34neUA{= zd9QihR-qKGGfeDJWFxq)%Q;|NJ<oj}BhCpZ&JTF~_pA@;J4ycmJcSq_jgd(mpf@na zIHp1YH=@nS<jB$L-#t$>7Ngn6`<uAQ&kyeHoby3$xEcZ~N2_sD5PZjS0vF4^4-aUM zX{BoB7r|+hy32VI8_`6AzmM1oT(~Vv1~VY4z6?6-iN?xa(wbNfOrFzi9qAFi3K2ZT z{~s6N8ob(ar>y5XLi+p`vs%Ko(ZqNCmX(gbHIV4S3l``NpHs`~IFFLS=5-+Y@Veca zWE$yE?~R*~=Y<5Zn3-wcWp#P{t>tb1`17N&y#JY%;kYtdp&x1*PsbW>=jGVj!$yCg zatiCZw2G1VF79WUOsbj3aqj2Zg|#1-y=Rcw7uSb)0z=?^$LXFMD|t<R=}wT6-P@ln zKK><Bm&5Nmo>NOUnz$^i8^ydmDP4Xpcnas1B5VWeNizrCDx>Wexl|3p<7on~!o4^Q z`{QSI$JvN7QC-q_Lr0U4xqeqa?fgApD=h0zUnkoC?XyO78(Zx#Ty{Q%(+OCTc@z2t zP?e$m%yl7L(RKcEpd{3^RtVI7I{<G^^T%Hd3<Es`POUwr*6^ejl6wSu!ihF}qv07e z2Yoqr#^c<^Mx6DB@6~f9>K01ao1#ZSy|LbeTjDz*bXpyev~?Yc9$viQ_rG==Jx5v` zb@(MapoX_xB8QF3l-EsH^My<xOO)#J=%FhwKSRWL4wu3A!kXLhN9@r#o65%JVQLql zX{o)2>-dw7?-B)_H6JgmIRaB-+}ZY%eFjf`ytjZmyn?w_z36i9zSjF&)r~yemfk>S zq<{jS7t~Idd!~Ai9e2BVuR(WF@3r){TOrvG<@Fo^YjvL7_G2=>hgF2^=1*gK=)t-G zt%ksVIwtuQ`#%;|)$cVvpURapI)FXF@BJ`&>h_?MSL542uo23klsNMM)30nzfA8fx zJ=quRtMGo3STpEofaDG>Np;#}e2fGj?~rfHtUv7$95CSlj8t)ccrDj>e0ct5$SY>L zOCdt%n(Rbvo?efP<)_fKR=kwEzg_1SR41T$Fwn$dFi)rr>WP(flTGS~fl}BWR_}W> zz1-G5PNqLwb6!b%dW|L853A!Jdi-PFFnPX5Byi)IoBr>pVxhv;=eQ~F??{$=)8%<I z_eV4Px##(JGyYwY#)a22L7!0FA}Z&9Bg32E*!b%NBEi^}u;!LDUOyM!q#lGtubP%c zs?-L{1sIW$j=R{E+c4`|qp3okwQcREM_7TWw~NDU-@OiK1^;;D*Lz7%gOT0&x7VvA zqJyptk?D@RuMAwq{C}qNfX5%Tq^cRIPoJps{<hM)M<cJp9A{{!dp0?Vps@YSE%1IH zuF?7A(^?(f{<PpfYVLnU?0ftp38{<l9g^r{a%$+fJ2%h!fYx%${hR+&sP{?fmx~PD z&6~rSs|=!ZldUx@=W*%BXT*;jMn0c_-$MRwjPcuVu6FI$3_o?<2-I`hqO|+2NCZ4V zbR+Jb=dk*RM15VcEyvwK6AS{;*Ovlrt*kop`*U3&!xa~Q6w5yra_`A`n{Vh_<c6Rm z_nRli_jHdzZXLJN&}^oo)fO-W>lCFo(G#Wr$0;bWmMh13nlFJs@R^S2X@821l~qSi zM`9i{cSdExkcKx4f|+Mi5S^KvoXy)(U}dG#W#%|`{;Z!w`0{XJ4*qNRAZK^b5Asj5 z^<&4%?L$+2z6pI~r4v$ot9W!_^QnAvuo+8)_yhFANF<k)l|>h>{>P7atX}ie7@%$f z?ahUUMV=G)S42$DESgx9y_T%l*LvS934PBU0r)IYwM1vLov?l2fS>Xi$ggtqz0^PL zzD7RPy@fr0LnbQ7qm(?qBCzRM%1djz1j@A}mhdJbjf<N}^wO1>?vDXcezDI;Jzsuz z#P~ULg8i>4dt2S%`|i8?hQhQ4YI8iLwxzu#prWVSBiujcH!NJVtF73cy6^~(us#;- zoz^;)9_;j|bIa^^TM6WT+DEM34*71rFQEFJeLUxJJ1gmR-dC;waWlg*=2=j~yZO#& zU9S}xYtsu()>=PR-wV^$#EKCUw)NP2vRRXYpd9R>nrl#b|9nYwLq7tZ{MzK7(wV>S zIh)TJbxa+v?5{*1?{D|=;VKGxu^(A|hmvh}$2C}!S0`~uW!>O=9hVVor3=1VA6wa` zwf$3y1MD+y$6Lzfu8^N)6L&7~V>1-o$3MJzI}Tn14^sp``fjFaIp?kP#>8fi4tBa@ zs~EYySR)iWjJw+Jt-~u6?3`VP0gP+^msR!lm!&Mtn>(Q2jL>+O-*Fn3y?BniJ?lZu z4}teJqT6*rAN~UNcE2Hvz8e9(E@qRDMbg^dTTB6PO}NJ>j`nJgH}V0N&P3JpmaI;l z^R;Om<>~$Ed+{U`lk>c72OYGFnfrpaFORy82PG{fZj6o(j%H%LHMnT=Ifba<U9E3m zqmDPadckliF+yR>171PTRe&lk%P3B%M~`Uz#joAT{XhC$?$&V5PDkw8;mXy6Gj2P{ z#Y;@XkYQ5R`x(*gpjnKJgy&Y>2S*x%TwYVyw;A&v!hn4OC{V)eRSPyG9Hlzyl{5fA zXJp_2Kq{NTo-w?7Qbf89ppA7=fgQka$X9RLpreW{mAk}b;`(aM)(BcgzAReCuJn|N zwEkZ#-Gh#`nER@9e_yuj(w6(Sg?*3N4xm@<cjCABL-l*^>hY_r{8eA{c?e|C4$C_; zBKHBuUg)P(J2QB7nlR!MhfyrSaT6C3|HsjfR5?V+I`t?Ah}B<9GRrK4B8(Fe`(IM4 zwMR1>cq~(eQCR2U(yb`4KOvp(#PUAr$m25)*O!?qgL5Ytj)U$GOf033=%OXgptqo0 z8iH^4JzoZ(Hb8$z!RM3_P`I%z*&qMlVc>5(j{n4jZxa%(9+un6w!h)&m*nwegNt3$ zb2jCh?|f>z?@W4MpOCNmc{!Z+!(y}DmOE@T*b8H{kValuwL6|9k>_1=sqqhz;Ta0& zw)>I#Lf|>8Awdq)O(w&Ubk<wbCY;8fch8~AYO;UxhP&rJHy+YOfp2F`#<^L$EW+4Z zcb-HaLSc^k?^P0Q!40&&WbF8s?U@T{u<dMvs4UF51Jh87`Xf(Ry1#=t-&p-`7jXfT zb0&3R`frTNvO&6J0N>C(43%9+0Aia@T>MUbmg||qZnBE};UYcNffi61Ht^RW>&DZ2 zn_EIDPAzBX+4<gS1`_SMg2U~_2D76Oz1|;F`}V{V4)0RbV90LaGzc?IiKeB}rOg>* zPX81lklsMuE2H43Q(gjslHW3}gv82KtKcJRt>x6sEWQ5T1ko#e;m)h*w%4|DW3zJl ze<>@s_Q^@)Boi$E?!7)QVoE*XOyUA49*FF__;_<8F5y$c0|~v3ld^TAk{_p(y>Ch0 z(J-9b-Z3rbd3KIF2MV`KM4KaB+dhcux^B#YmFYM~#Q1U$cD>dfpzFY4sDu_E%bA~! zlbH<K;FfiG+gldJ;8V2Bym?Mh1z<Sj9hByJ}m<w^tP`eWE0o`pXozDfaQQ3;)R& z*M`p*{$Q)D;~;MIgcn?mJKlXxBWS=H0reO5Nv`5Ld4}1Jyaq~FI<YjAHL0u+mWV*M z=6<GK=85uVMu#rODu%s~?>4Y(LGF44bE=^m{1o`i^xFW=Sj8h+3A^!fpYwJ-T7mQq zk-_)n<?-JCmV;rtG4l^>?_juq4^-R5L&!3ETPufw4LN1K*)NF+2aew`m>>epbt;+L zMCdeAY~#G|Kk%9vk_X>46L<flh@orP7{FCetzc>Fw_x2&yX#G%CEX68Z;_xAIWZ>2 zV(AXP_+9k8PGTG@+S?vF=e?rncY`35EZ}<qNteh5<X(B0%gA#@yT7g1-8c(6b5~i> z_r8=UI2<4o2K9Fi&Z23^po<R`O?14*t~igZQ^dq0d0g`6*abB`MW@>2SI>E?Q$LzD z$#ppgQ1#ww_PW^*WceMYaobx8{d;W+>yTz!^c3|q`XZBBv)4SaGlo%>$>*>kdMA4o zWDjIv1IcO5X2q&f=Mv)ZD;WUsluZua{OS<eCEV0<p3M-H`=j@v285z9k)h3jDuLSL zHxOki!+pCbSFPWa$mZ<9r|k|pW)yt?Z1+090x!!>m*qq*FXDM8;n_3I-PuEk?0*-{ zcgO4B|G*2Pig2#BVE)W;y}jW4J>KWwh41myzhKK|UsD6eR(!OL3<@2CPg2CW`QrWU zMYGZ5#~g%^*$hB45y?l^YCFZ(#B4lO>l<4t^UvseU4@Mt&_8rFuPyyslt0_zBm%uS zjd4j`+2A!LF#y`?-%`*W(v&e`u?OJeA6BgQ4C}+Qs~IkCt0E0}8IIndwra3=YiVAw zOEAj8^CXA)=?Z;I<Toy3*WW8;*4eIW7>kJ^lb(P(p@qxH%?cO9I+9jre7nDt-EGRv z`JNVk^BV{#h?9)C-dYcb8JLi*=(IIRA@U-t>`^XXu@ib<p~@3zOV(`}nSH37=W#`* zkTGjc7^ELPz_wkFCt=Nj+$`+;Gb=8?*6uJ(E4L*in7~#k2<EY-uKdX!g@OELTy&Qh zqIoeprG%bqS104$DaX~B99u?bIQ6^~0xK{w1$fBTtw$q@2wzGcSXqrvTFuv3+2sVa zv)UB1ZH<DJmhJdLOK4Z>o0pGokuQilU-3B@<t;gu9p+5Sgfbz+=H_4=@ds9)x}R*1 zvG~Gc+}dQSwt&EX68Bgl;l<DBIWMWY9rM<Xc*(x^AH5Fdd7SSfeaA7wI8$cPTJ)51 zDy8O`F>JVijq1XqtCho0Fty_==$P(;r68xh-#`)4&4rqe#d_mX@2NN{z1X;~GF(&y z8N-;$npA3;lEVEds<0eR_4HqK+B0Fc!sQXKdy*+IbW+!4PadPsSvXE2n?&CG@u2 z1^c9%iaf6;lzEO93rsM$-W%li{-Ba~-0DqOm{#obfVX4**14qP`RB7JK}IN-a=7#R z2zU74?d*<!?unpJBG<jiPH+6F{To)0mQF}HYZ~ejDdE$j9CY7{J2u~j|2vZWQ`U~) ziMI~i4vm*5Y~WBv>oTDuagl@B08_DE-9a`P+$Vs>$GmGr5;oyozG4mS5yWIPSOVHx zdEvb3SMZIR)AvI@uCD&}IaeSIAmG~YPfrNd{F30GCdeR_{)Vb`VgOf^o;2MNLVMYj zhbQO&6|d{VLtBWcASdsz)ulHh)g$qnb#0O<s$3EibbHewK|it!d%D3#djMNvDvVP9 z8ggH)b0^yST;gwfRD5W&>cpYmbBxvg!T6rg_x_vw*k1F;uV(IgccLmr57@fRD>(m` zoxah1ATOk;TpoPd<zaOWz3sP5^RrdnWNnPV=P<8tsyB9m>oBHCqo@6PQU+=SGiTDe zjyDO}|H8Rg<+x$~d@nAKub+139i*Y$bPgF*E)1@<zp{L2vg{u0X#;HWD*qH`tkB{t z#$9%-?I}T@zsA|_+m>`hfz!P;e5ZAP{k=eIZ2O8Swx0W1vh-Ib+bHdtepe|oS0?7! zu2pHuXO~CQTl~`>8TWL0_zur&RgY=*e&HoYB9rfu9iRl;y93q+nAV*aMxVDh4m^3i zQL)**gf7B^5E%y3)BRYT+gj_#jd;J*cml3?xhe@M?H5lgtDv^t1FdCwvCtSP?mQV@ zK1XoPs|$$D+ub!?j_|Nc-<ghkQBfLjIZo95qp_+w<cGi-Zs=fE25UC3mxW?8q_ zsDgz`^eEte)#n@7<OdpjeYSLX5%dcJ5k+Wp*`T^^7;e0QoBUtd{7z%dQO&;pnb5&W z#uzLp)O~gym7)BBcN=^yCHbA*J`PqOMR@LGW;<*2ht^N<{*JqURb`b|PVQ;0uc=u& zjsZ3*j2NUaY7o<|L}BE}Cb>EVXTQ#r(~^SSWlyBzkDFUc%DHw@oh0kc-)C`AK>=SQ zn3$OGnjU%=A1?a@y`~2%+NwIMs=7L>D)T_cta%xywO(nr*~fh5f=e!YT5;WMNsThw z;uSGdh+?cPCR(9>d~Xg;EYaq9{)9X4bAykkNi&1@KGab`qsW8<m$w`THEnwF#4*yH z2{rmXXhc3UpabK)H?+&QcZFXQ+>i5|{t*OOocT>fzU#d?GT>$_geEDat8=g)!ke!< z2^0o@<(H2u6cI)dJDST+#6g8taBLVOZGJGk5Iix^i!-lqlC3qvBZBXUzu`-_L~$9= zn!&z1k~Arm9cB`|4!gf$fer<HhN#zl{4?J;aq;oR?Cn7@SWO57U)k<#w}Wzv120{9 z8@?xvI-9fG2>SD%&q^M5+G=cUAn`l=I@t)j_q~`!|2>OA?S-4gQ71aDm~Tx}C^Z~) zuia3)B~o10a2uqnk%q*~!58OaV01CfzuH@i_d^9L-}wHB{zUdfQ4O&a4dT=<yRV1n z2O?ZDG)HzDj%5#9sEQH<S<_eT7v4RDyy3OEPxC$2^<G;~?RSYa^*N3)F$x1JXeS$P zs1KKV;SVmbJV^mb6Gkjq;qxs7bsZOO=h`JAmfEqlRqMZqc%qxgkUE#ECGAHTC^}0G zho84r8>B~1uBh=%>cP(&4i~+#ioVE62ZJ7$*XE9U^lgSoJW&hZP?teHgl+n5c$B0< zG6uI#T@4*F!;fQdjq-3+-mDM$y|7j5w%9Z%r?#uzzGR6s`DZXOv%%|4U%J}rB+SP} z6w}4rSYRcm3_vY)qp@8-iIowm_4+V$_lS{*c)w6}K&tDxF?)5Y8y>d`6sy?IzVS7# z;eV|Sa($^Col-v+5sChFxfR#L>$Mk$Y|M8I@e|AKaw~f3O?P&wy%7%EE26-7l!;4I zsM4Kv`M#CxE^5r$+Ho!p11<`w`XS{+F3jQWYSVC+*k&gz=WN};N+{pm;B0zJBaL}> zdm%DpfAH2vOzSHiLpNGm_bEqq+Lt|gCs+t^C9x<2(gY3klBBk-zfA?wDlA2ox<TmT z8Ap)1bfKyXY}wq-FtqBm)f0vzb$?XQxN{zNd}!P{AoZ?05TnJ5_Vx^2TwE3}a#K7a zEtKNYxO!-==Z)|<zJ2><VQ;UmT#{loL7w!d5-&%pyS)scVCPp_{TP2y76nG;_r~n$ z>0urJp2!Te&**=+*pT@vhc50w0IUCa<NNr?58m%c3Z7N{yxx&%GJ5ZDfx#Gf47-4k zP~lCp+G9&b=(~>toDCxj7yLAx`foj3Ir{>=pdt;rD0#0n8_X`Z3mR*>S?9xBPiWzQ z?d@$#@62Tr4;ScfpjYqaJbcMIvq5SPsa~+0LtO_%hc}VfKXs~nQOHi#Sv_}(MT{J# z-kWbO5-@BFAx|gHV|qRCk-ZqCNn!KM(ZhuvN88(a&24QmgJv0l>%WpnfXq5dN=h;F zrld0Yl(9f2goe&OeS{rbYwN-OU|9W_N$RLi3v9!`7;&?I_^Th3EU0X)eq`bWQU?%) z1Q_jg)7lNlQv?x(SoHm)q*e+chHJRI(XLmD+=YcC6&Kc?!R$T?vsDQu97Ktli;J%7 z{bGgw8<~tc0_B8Y)phv3eRsS9D|!Gz7@Jh~em4rwKK<FBiG7U4ciXSqu8c)3X1f<@ zWvd%iiRu37wCq<@3NOQ8O;=qy=}#15I3401NX9P1+YVej*`*F>$bou9UPfOEH_Lw= ziT7}ZD8Fw%i6sQR^Q-T>Vp;AV`zapfR))rU*Nvq5-Z7AT+6l%JXL2E+Ar*`C)A1XW zxoUI<BLyq+`RA9`yY4KlzANh;v$!%k5C7bBnD9In5L9DaXaTW%1b=<>3)q&!+F#NJ z_nzb+K|${&4-`^%IsU1#8!S1t(iwm=dRzD6*gNF3iJc=uA82#l`s^_^(sMljr}UrS zYkp9;oZQ}kwcT$4dN&PmNIpTaou{<DRQP5~`Y(mEdAJ;zYjN7!_3%o&gUA7snHL_z z&$s%j`9oLr^(7nvGlp?Qsn__&PUD|;M%h*ZOF<*>c3Eo^dbOYFKC=8v(PG<KM7K%N zD(~Ez79wuH;?OU7$Q^96?i1Y9w%tGsS)G1oc28C*&&nY>*$K1UXRqu2>icGW6<X(K zJ&x*SXP=FO-+y%i&BJ1gf%mz&rR1vet?T-=f|dFR-s5%Gd9}lJu$kJKzPajeyOIkc z8TbPsGPrEckTTy?x7^+vV-eg9sYJrdPW|otJvV;RHEs7?zZYlR`%>7Xy#AKqwF@NK z>`p~G!}yZD>5-_B`?Ae86<U!&0$FW|%Qq8jnK^cRJ7&UCsCHXjutOb$)%gm0#gA2( zz(Dl(Z#ac9LJ@Vq8O%a2USBU!*ww`5y7N}L{Q2OQN02!oDF(Da(C@rbjc|<K;}?=~ z0XU{5r75uaH=?VaQ&1r_4a+Hq#xu8l^l=K2h<G!#dzNK0H0e(8E$LZ4DR-d-F1<{; z9Sl!u$sPiT=#hlRpD%=WqD80dPIHskqFt_25!R^#4&j6IBc{}Hpz4P-rQp^6c+asX z#W>H$v=Kf7d_{XQtHHiB4?!jyN_r>z{EJgba_zy3-xoQqoPVBhGm^p;N10-H(<-m5 z*%GgB=2817zFaw&GD@2NGBch^pXkhoo_@XWP=CF&VP`!=NN+FP-r0zCee3bq8~W~Z z_<}qz%LZ*2;!_Y|9)~|zf^|uwEh=(je%v}WM(z(i<LL1CSkV|J%l_h5I&+hE94&5v zOe8`IagL(++?BuM$m(;L9dp-Hf$m4m#mR(J04f5zt{DCmBouz$JBCyXz27CFR-&fy zq!sTj5jF6<^cI+z2ft<3su)eq4jEPEFe5+#0;)n)TG=Ndzw#^E#oOZ)*dHZAq&=50 zlC%etBHX*9;!kI7v>+>i>NOnH_tIoLap~{sQfG#Xbj<^rb`FL*6{<6?>qX1)O&G1C z+Ve@u{VRdVu2C-R&jtM-S1vsJ6f8F$GVjs}IL}$z8*Eci6_(Mq#GIJ}v<*HO?9*6L zg$6!0_~G$A0n`X{3md^%wQKSAn;$5-f_`5a*LsZC*?o3K;|T%wqM^~?x&ZdER-gRQ z4bXa{T0#Oss6a!=;|?KFu^<$+kiZ(XI^D?uuQYNpmp<as8*Qv(wzV#BJ|pbw?>3je z3>x8!qT%@!xNL$#=pm*#a`#-w<eA9t9Z&HsJWSG^8FM5c&s-@+Rs_+ocT8Ofd7M<V z8{*==16RUk{exR<s~?QS;(5vQ?G1}#-_;y(htGJZrAsWeA{&$@_A02O%7b^65G$F< zOM2!!BNrlab7J`HelLy7uw60P`8exYsrn^a;Op5^9JG?tR97DJw0?>p-E_G>^tex9 z93C>MEj%#rAPr~Sb|>Pf(Tvn7h@g%VlU^6WWAOoUeFHMx4P+^L$;Qc1|EYLutE=91 zznO{k&=vq$U)zmDxfOCHiI5Hp96q|C5}=szoTXysrfy+&RbiChY*U%FBr!P3X64Z^ z1VUkk`5JW6W=X#^{)*P?G<f+Cs`CFXLIl{=7BkNxI%I@3`_i4ImQs{Su6W&&s0f6I zyHhH-H6=FOxR3$18|=v6tHLBU>-R3)JZ<HwzVFRTW%bEguxmM$Y_Z6>xSQoy(#U5M z3Ki@UXEZkyRuxs}mQ>QT+HXTFJb%gcx#Uun3#}}_3Wg9J6g@e;)SJCD;EO6g<++Qy zQ_ZRV6f&43)EhA-E9aW0hEd+87bv8(7fvGLUTLZN7uI1KL7`;hY(zD(zr(I&37cif zMJd^W-Z%_Dt|d2*A^}IbfEc;BvU1F<sgNwGIiG_3$d7tb@<$nv&JUd!G>!b~6*SP> zjrA%*U9cpZU3>J>?TyDzC5OW3Ug!1QkdLodk?qrwKI>pCeeQdSC9cgzEq5WOz8=jA zrFXCOES$61zC2vyKc!l`sthYLnrq$cV>LOTbrh}R$4p*OVR<|FJ#RObvlmS-R4b4= zs=ly_V2j`)eG&r_A`FS|ZdK*+uwS(OeO%^h1h1|py^%eQo7FLRtd-7VW10B*ff2Z` z&x_3M;R?ci7Vy4?S}G+>2nhuE5?5pW6?=Zd(9LC~M;~e@m73E}qzyiI<WAMs0pmIa zPB4F;9>_JMm@V#n9KJ;UWC^f%B#i%6s$4;_7S5-<0LMMe_c;jWTq$Qpxn+nVm{JeF zZ?RhphI#G_1l@!P0J_j98t@rg{_W9`DE(<)>++`Z;^j5S<mtVeg1uTzQix_KI5d$_ zmxNue{ny_?S#;$?R9aws7)4mE-(@Bo)|{H8ooe^H%Z8V25E@-5kJ{j|&;RRF0&{to zz}vYp#OUqSfS~V}Kl(W#71j}7KU?&<eJ`D|`1Q+x@A5@JXC?H2i~YKBmq9vX*K@~Y zcabMSMMR{KLo}=mN;CEIL}RMX>d;`H49U0s;WP9MKw?FT8U4v&h*jLx`~DV}*+qB% znk2DD@g>p=)GzJ7Tzxs%o0Ekaih48r>3uJ^?jRhQKT3xIJ{zz0!kZ9gI(K-FOww=z zv$Yl!e)gG~3yER1;j{l^E9b7L{|%Ck@7l1#v@3DVQiAgL%x~?4>x_L6Wel27TZp?^ zJU{t8px4~r{5|%L6$X?7g;Y?=zv5F2tQ}A}o<n_nx?R{256=nt=@95zmEZe*2&da; zLz6xEm@vyGcfx-?!n;&B)XabxEk%x2*rZ9BB;24;{j`sUhUUyGyMHPaDOOnUps%B( zKiLVJt2Lr>CA(1FVd21R(TwhcuAo9LTADz5ew`t4dq|;KHSc8+%6|C$m&o<J>gN0U z+0|d?QD!EVumz~W$5mbZ;is$>qm9lKsa48GPuO@tXY`^D()WGczQ_rN?chAV2LwIu z3ygM)V~+HZWT<u5t<O~%-@(2zOS4Z2yi5;`ytAp%5TcUD@wxqDjDjJ9FPx$s9<=BS z0pN4T@*VF_BY%|c#CX<85wGyE{lPDAo$Dy*ITf85G`T9vlXQZ{VI%#E|B}&1V$M1N zQ33#fSyzHo(|%Xoxe`gOSv0g30)(Yq>8zCh;{y1lN}51K$Zd^z*Di~eEoWwU_{JDw zGa(ciS~e?&-{@GN*O7f9{%4GvAiw#m;{FM@!c5}mm647htHO-3He~orRPU90b}n~B z^8GyL@eS;ceQ>~yPCyj@`j4CMrs`O%jFlP{U3{1yycO@>{RHto+T{<MSvX*9S#)h) zt{TpwO<p_?E+P(SDg3s#1qy#D?F&k9H>{xX8o}4l_eNM_6#OLk)xerYR!uV8iWH|p zF&JeX)*pG!)q4*!$`t-%Vq4)d&lGmWRlG*PRV9~pXqs#WXxmUvCj*Bf?VRxISNRUf zAC;i;2;JohInIanLiz1%3IEIC7@c9>-2|o0F~ZBAXI7LXN;wN8LAJP$$9=EHuj{m6 zV>Np$7t!!zSO<PAKkVO3vel>hk!rN+5Q-=;Bsw!$OTwz*a$hg@YZL{+`ly#%pF$vI zM<vsY3U{Q8Vlzgp*dqn>CACRH)>jZOg6(17ZxN|^;@ITL&G@0BhDisQs=0%O#LP~1 zn{2(cypOctoyf__&31;ag@aQ~+10F$jWAqppOK>oIVW&$;k5Zrfg(c66Pf*r5#BA@ zhus+${QFyfkMQ`T{rl$cF<GS5FSS_Y%2j*Sqc}n!*u?v_?RyA;o>(k=?&suTBb2+| z0tlj#_Ucp|_9vrJac<DnqT8|r6CRT7T6t}oO*Bf-hw~ST0{4=Ny<o0F1%KG_8DwEb z9z_VTOe9koqGnFL&xgyjyY^aNRvb}s7pM*raJGBoZ^oTC&qWJve<`UnF^hi3%RLre zaZPYboj5H0P7ho!c=uUHdmcG`dk)i@TzbDJNI67lTz*oOO9D*NoJuV{tC17J8rvR= zMX4}^x(^z2xLLo-Wt2m9_rsW2rzuQn81BXwwT+=d<$ucbE0tn(hbRs3MQ{Z~`BnU} zX?pd>nap4FjW&*)Ui^F6Sy{IS@AI3fP`4V1o~yvZcvHgnP{g0|D}>Z>{U{+BzoPtw zXUFqIn}BCq%{2MwKAO}>4b@?Q9c0?&LbBPA;K;%donez3R8ioks9+#rh6g@(x}H_? z;CnO&J{UHAcQgr^YLTG!E1z<Cdz_v1!jZo(Rnoc6ibiF_W4uPPudIw>x8%?(<e7Ss zXV#}V9<o7gcald~|L9)8LrloJFo@SL+iZEXscfH{K#aG#Bmhxk$HPn>YO&7MD_NOU z*02|}l#7q3u~1gN$y4}cMl#ak6fKS6Lcq}>4)@BQr$J=z$5@YeQrh{bMe+S;X0WIs z7!9nfWI{0Z8<9nUmMT$p(8cPk9lYfuM~h74yU*cum!?emRsM;ukUNW6)VmS~5l30i zgJwy@YkfZok^5(6f`l-N(8~R1!TO2s{!`;J(Ws}^A?^r45au(v!&g^VY=cuw2sZ1@ zKd^tZWtmeJ6)IBi4n=+=rO1vkP*Y2gFKh6+w}KGj$Qq9PMpcS~XcCZK8u|Y2N1pWK zq?5snY8Z6-;`fLD33Q^>SzA<BhnyiR(LE|FElpePn*H<o;pBdwY6raMnR}wAK~I0+ z+~6T+)Pn*I3Fs!k6o7He_CuS1ZC0S>QHiFbJ~cDTH2VWBpNTF9Tb#{FMxwL@3G_X& z!=T84C-Zs_z1$t<_mJTyGbK4ujYp@sOkkI5sz~{?U-I<#owJcd6lUz|iplSxDKCXh zD1XPC1;@qBZJJu<gs1jwe=>vB<8OlGF7UL+!Nk9}d%OWQ^jC=Av$H6Kevf;N71ezI zI@~U_8qzvYMZkA_$W#isL!!w1s!Cr<k~OV_=HOV<|5^SX+F?Wx^~i-Cb+o#iRizj7 z%ncVQ2rz1(jtQ|kYdO)hv?w_1be+3z=VQc-rpAm0_Nx~p)8mvu7FC$2nbsn7yiJT& z*;xx;61dJPBPB(5esnmlMLX$KcrqzMQ^1E9h|p^$@YvqwTW~UDSzKwgaEs=jW=4;c zOD{JH_658VgRQpc(ZiNsk635;g5epv>xa^*)nCw{A@N81PZ!F{a9Dn;Hn)|P!4B`M z{)_jvYd4}eTn77Q3;5#d>gt+?XC($*b}}Fl@Tj&DFoz#-IpCL_=CChevx&j#uIzEe zX=M2bFuv;}LqP^GWsV7@pUM`PAKqlf>;v-@DS(){{rB@j3QPk`ZQ7M5S`vaH70ctF zM@`EU#U&2Sd;ARbZg|Q60L0Q{wP$Vxc&pGO-0PD`S;Ew{qsbu^B5In2ufv7Tf1>jy zY$BKtLcdk6d47lcl)%fM<`pbao>5`eGgdxj!U8C^1@w;oeqn&-8hrwzp4y>&;z{V# zfe!-<Teb!4!rlFSBs#g><fQ5hD;rx#LjyB*m{Q`=$U=sE4o_%*e?Lx9jLGAbOW_)+ z96bB0Bl975Sy>_V$?0kTf`VWyy>{zwSKYr(+<$MMI>m@RisMOXlc%NU+MQ<P<E%GY z9dCg8AGe;UTN&BeA;6wSlPCE7=tdPsRjxosixg91H%F@}qxviiG0`|Q7V6n%w(LsK z3mR;_NPM06|75)&c2<SACc8)^@_G%13Bq-`Y}FWXVhdl1J0*{*s5?!zeF`;?f0>y} z;ndGtQAAuGUS4J{E-u@?_S$G*;>8P=>80Fq5-7fanYOx$4RGqquA^$t0H<5t5q3J_ zlMkV&s3>6m1DX(9#Yc6pKs3B^U+!bmVblY?Q3tlo3`QSRqusVYCrR`fqFDL6M=n(% z3Vcm@+F6vOx7kcCKSoiXiE3+03rULf-fn*|urz_77YBUUP?3V-O@o3N{(Vuog<VfV zAZa0RdRqRJO}}*adxj66tlS8K+|K0jZJ{{pmC*#-moJf_ygu!-b|r7a(VNFAcxd41 z)~J3-P%DaU=7HX1JGd7EiAxJ?X0xPo>S>vyswS?kjs=KhfxNtj%c7zpYV@xI`McIK zVKJZ=kG)W=kiAh*jx43&Ml1E-x}U-kg>Yr^IU@S{d5;1(ti2#(4-ag>`>0lD$euw^ zQ{27Y8teP=u=jX<z~yp+a`W_BxQM56*9nLtUbk~0b#--3(L}%-X|vIa_@CUHE0Sd9 z;GiUxy3Y+Sq5jIl!&46s-mCTd2muN2J;5zL0lzpLV-xS`%1S0Kri70E^>YLB(K<*E z0MB0H%@_oq;n(C-oGi5E-s#9=+tZpbz*6j})n=b?fP%Ng2~znzJ-(UDP!LH;Nx;M` ztgUG`E~pShfnfkot63(hjGp^MqqG^9>WdHX6Kq0432p7Hh*o99vERQTUNw($>C}Ir z*==wDX(Mq!4h(%|Qec^>lc-r~i#qz}x3@QqF1MP90LHNH!x^5m;}i>i>@X61&K4d{ zX;RkztWvoGlZwi(qmHE|K2lOrs&z3bDgqtM3s&AylICWW1nH6T*M$#SpLL1`z`k>? zHl@#n8CFdDqBmN$<;?c?+Hv+rjmMa0o==^V&{m5EnUtMfU5-F)C(E7h=wH**(}ldf zyCSBCtjXgD`L&jrme~+bT{?%-Gpd9=p6@L09v-6hHv#i%;*g1tkB<s>MfrA7>QsUi zkt=8FvcoBA4+Ik66;bf_>E9VIMustRA0x@|jy{D^q|mk+L}XYqoHot}#)orKB)q zNSTJOc(EDxakf{YU7qZ=U!+I7YTQDgtvCZcdu=($$_!x;cpTouKjc7yOIeE=A+VVC z_I2q`5<uZX7APnvQ;_L~+mERUo3F0j96!|500NqUjSWJin8>EHk<q7vgM$+3p^j4F zn%aQrP}mL<Le4R)h4hLC&!_XM5^PnP*z`lhC_Uxat!`4*?%l+7YCv`mGKCB?kdQPu zM4baZgs<q>m59{1q!4~5q%k_w5VGu$)VKrGK}47kA&Lbe>fan@-uehXS&<~q4l_NX zmmgb{<rd`xQ{Q09Ddp9n)oVyJ6lf?eR>WEQ{Uw8oR>aMgh_yPg$b=bW`Xya5yS5ey zyb{5x=%0b<tkxR_OMwfe>`<VAusp5h*<@dud|84NxtL_*+HY27xZGny0|SVhoE*}r z3*bIn`RZTcA+FP*e^suZsTVxFm6lRX4OfjH9mSl~R6q$&HjKy?x0;arRE6QZOhKMH z9#JvcZ2b8v%x2PKSMbVyonPgyzo5<T*dH)iBwWYX@D86Z;`>qA*Go^IZ+8QA5D>7p z@dw87_Mw-2@#RP$E$f~wW&H9{c-ZR%{T_7xH<iyHcT!)=W?l(oLtKx;pJvOmgLDLq z6#~C`J>E44{?>n29hM|izPc({A;FP_aAh-p)UzyQEms~_&2D3t3$8uW=x{RC3|_qD zLqJ6A2N>#C3iKY55)xuXx$TDY3kzfj8CJ?1<s)H&!G+Y=xVQsAak!f&KA>z^+0t=( z>6eXGbDK6DdfQBKzyHy<y@i-}=nc8*P!Kn*ijt6OYN1M^SZP1ILc}g$4Y)tMkUS)P z`YaI8$L|8Mk#l@~(+l1o4IRB+O7ag)UJit9b}RoT_&ZO>1D%NPfguLL?~|>yU<gsp zJCokViyQP23~?0ZWPaod&m@~<=_csu!`#}j3#FMhMEv!@8P-9VDUiSF<I_&wD?{(= zfcKR|4_=OLU0v1>(cFg&gm&rwJedbx<7R5iSCI!GA+ARpoh4t|X<XXtx26xc8KU1U z$G%wK64bGh!n{u^OXiekGAdf%7+l#FTnQ>vzXBQ_8y`R0Oc4PAA-}Ir9~)5#y+D!L zz{JEvi$E4#9FRq#EE(t{2%OLpa}f`fmYKjegR86QkKG4cT+T-bKWnr?$t2@st19Yk z@ls9IHV>ScwZ^ATEmOH!0l421oXzIrag;qneK`fV3u@1z3?;~AbyrfdG(-yJC8m7} zzT@V87l;<SRM$xJ!(ll6Q0cbX+BvX+#?SGANF!(b9nyiO?{RrA_18b{GVbiUrC_FT zg+FeJ78FoWR!|xFId*!IlRtu2;ooV(3OXVzyh8sp(O_*{mZRfN*Y$V{Q9m;gHsGtK za5{4Xt%bo&r!3zGefn(vMgqM?B)TB0)ABIb?lh%O#<H>>xoIqP%`G(duT#OSP=(bT z@oGK8X%0tR=@%fH1Oyn&`sRp78X6iJn@>(o0xUBNuljJq0|2-!_YFX?2zn);n3xy? z2L}{DK~c<<o$<_{-o+$jc#ZcAOVps6Jy9jHGov+K((A5-zA3@GFr=6FvFfsA$VQDo zuuRE{7#XHChgLc(<{SOykBs>gQW+|wG+S%>>odw{<5i2hy{#@n$$laUt%=<Z;%I#V zFy-r?BgTDD-iND2hoploh_~KyDTi8Y`Ub5~(Q%nSu=&%Y)>pm1MY<FD`4Cs(1!4mE z>CvQ<$Ii1W>H@UsccTX4ke?uC7o=!lzD7kch<|=%Rjl_^vRIJ5r7AyBTX99j_)(%f zcIZTrcgu%NMn-n>?;n~3U;{AWk7jUaQzl3eC;drgH#76b<T+NUQ2mi0$d0?KM4Y*v zD_xR06u2<vq&qF8sdXGJcH0m3HS}K8T2`K)qDztfG9k6V2EeFHEgoqpsY$yrx@5(8 zl)}LiVblP$PQ@aKCt_qgh(+}LbfzV8x+X*h5ufL^EC=%)|6%{Xgag9~@Wz8wR~_bc zqp*ox1tzt^==75akx!VdQ1^`Qz(5Ncfkx2fhNv_FKEHy$2+ggde%I1{G9V#kh5sXy zQl31!jzWDL7fp;T$!aLEr^=>qCK6K4U}<(=&S=dR9M(t*s0U#0*o-BV(19(DAbnv% za6DgaXk;rG@Lym%F2?>vYM4n0-~gcR;dkZNath~H9)5m)(qUPevJyVpB9x{)_(XGZ zxKvYNC3NOKE4{7BAY!2g4LU<M0R81N0QhGey}^qt;?sG(`>vfchQy7+?$}t`RnhA= zjS>ig$XisaQ)e2>5c}-6o%ZDuVQ{6p@zof}D6a$QB2pJSKA@Ttf?&LRVTxvnT~&pA z@}mcvaGLmQJ!=Erhn<;&(+%tiK^L-M?jzFADj^zA64G?U89~=Px;VJ1yA+3u+k7nK zy^KKrA;Ti%QlMh`GR*I77_t7uxnk5anxh+86RFkK*tj?(1SBMRXJTc@-pWcqdx&ym z<+w3aRcbL0+i>s<Yl|cQKc2n<DysJT8bPGHySuxF?rxD5q&ua%J0zsL6%<e!q?;jB z6p)4ikr=v!@9|x~|92Nl!R2u8+<ESE&e?mPeK0Yzd{~n#YkGR9TwPsxHNBtP+rLi? zVVHiKcNnnQ;?Q0p$9}kzl2_$o&NcVq1cK9ekTX`1pF)OTJ7kar)qI~1W5{A;td!Ni zeRN8SZZH()a_~Q>4mz3MdL;9s3Z*bWSbXP?@%nQ02~Ym*)W*OYQt}5ux1T4D+ZCv} zevjh4@BykXd%5uZOXu0u2Xc*Q>JJFt1a`7&^9ZBzFiQg`3Q_Tvz7mFpEWqHuUL6kz zK>P5>!w-ypMSLr2iW9k@_3iL8due1!DM>=k{i9`IlwvXT>6P3tOzU3z2fByVt)5xi z(W^1JC#-5M(Lqji&{~tDN$3j@(E0G)eJNw<Vq;@pE(?PK!Z62gX=y1sLe_lhn)cgI zLM8G|Rj6*=ujcxCdiGcO%w~(`Z&AJT>`11+B821AKMilOhi-z(nMo~wh)`oeAuLS# zd!zZX#{uWZ>$}AK?CW037EB&KI|!7Z%<;%Iqd@oH2Ju4toS6ML8U4`buZll9w?^e| zo)Z%3>)Ta7^s#*;pzwn{rC}#T=$hvlypf<Lx(h@69ZAaX({uAZobx$BI4a&{rDZDE zM>xug;>6n|EW)*16>0*tkFfE|7hfc-EuE9Se5D`~hw`aWm+T?*8|lpSvp{L5xk8XJ zfG;SlrpE|W_MilA{`seMO?N}O>aDKwd<O(Y62wx_*?7?^PPS=SpIvr0CV0M&*ReI4 z_R7bHFxMiG4cwgVGLi~?@OlDmNCYSj0T_`eri4F9AZV|oo0T7Dm*XR#Z)k|QQEru| zOE~@v0iZ>kvj<htY&vDE<b;ZY=QlLyghO3SbN1huYLxH4n7Y{d+AVS2OL#{$J&&^c z=&UB1lBKww*RH#==V+Hrxbm}8LN`CR@nG-xm?ubb)RUK=pZ;`0408}ymu!$%?K+}H zYFeSe|F4#x-&HHLp*~TAIm(9LICDlgH{_Rwd1HM*<25xk71i+A7;0nhtrHm3oaxiD zb02qX59+;frrejo!IYrTsPEK`Q8<V!WIMNSWW9-n1z6uQPv@cy>by|<Z(~22(0JeH z{`{mC-KdhC4XtG^LeIi9MTAvO<c-UFLHlZB!rQ<<Re5?M1&*MXG0QDy+$Me8280|b zE^~nrXl{=ieTEEsHvR}Q(L-)fb>6OchAuJ!&`B)(_5(`?<g+fz!~%47n^2S8DZ$JP z{nXb2hq{J_p4TT<f7bfKjK^*}iZQk$0K@?Bg#uyM0U$s4Xf+s%FR5=Gu&*lUt-c@# z7My;T)($!n_)Kqs0=BszFM0^keI*bl(j{6x3HICQ?8YhdyAv&$L`f}Xlc$TKPQ5{c z#KNX){@vYOL#iBGVx$H$((-5Z<UG+d19f-u!e76Br8G8j&jG9y(*~d`zP{Nj4cS+} z&DJ#kE0QvREtL4_pMr9L?EviKEhwD9H-zYNS6MH5yMbe?YTcw+*{CFnATI|hqSaRq zoaE@}p?fe;&-!a(k=Z7}s56n9XW%FDlraoLj-s)JpA+3f`fp9l=@{kZ7Jb1fEA{G{ zKM5>g!@WyN4qWo`lGzsoK}r7lcr^uJFwMgMkuKr3#())=s(!=DGdQ8xpCiD!FzRbg zh#r%<iwDVP{dj*Jxt(^<DI^9{GZ8S&K?Zp?6c!`nO{uJ8$H@5G=4&gxk9i5-@Vm?n z{2J{B>W39a!8HeYjx)Tp6Cw5Oy6<i=+X$uJi=SP=6@jp4e4GpN^zYw=x!CoO^6dB_ z*8;P?djXNOxK!Gz+O$1Z+;^S$lH}QGB){`2BOmCgYLh|y{As2pN7}p{UH46lKAEf& zR|tXDu7$H<D2P?0>fcTI_#D{h#qv4Nc?t;$K$d3Jd<Ap~69N@(^_{0RIL`3d7QV(; z>vd{Xe6mYz+k1c6HFS_)-QUa!AfntNu|d38y1>9d1%;Xw(ipGvyaYR&*;yKXGY8EH zUr3R9$jeWkgi`bb^rt0e&d==lM@XWIS4!CyxwOf{Cev8Po(Pm+Hx0a{iyA(IyvSkV ze#bh|dc^uK0jw}1X?XtA^6S#4rP?VMAA0gnnfG)&U*%X`JuRG=#C7Rzy*$f@59~lN zeQErBcn@<rrz|qqY1FLIRRGqN=bzaNO(9zaUaDeDTMhWvLIu8>zc*%0W)d4JQxt;J zbWL|}PUKZZ1SXpmK!)B6YUUrGx!AbrbZg|Bv+1#OY`NNvK7Ffp7{%&U((NS2GHCl) z$d5Rd&Wnk3cz6h)k+_3S+chxC?fmMBAx~qV`5hUC{S9T_HH`HzV{!Q;t0fQ90cgfZ z7rrNiYF(MSVb9&XZgcj{R|!<f5^!=V607v?mk;>3?MNrfM5YbcvVQYJ`~1J9HDB3& zhmI}OI8|xhBe-O{iBw+ea?IaUm$sT9AxJGJ)3^y#kqb`*@kEy^jU?L|gN7Ip^cY0S z(Fj;Tq){y&4$*c&HCytwS8FNjBxv*Zm=;>3&7JH&gY>5*C?I}z)fRx*m5Y!`e0JTM z;Am3d&Xxc8g0PO>XWH&4@Oe^U{=soh3!gr>=JR>S8~9UXT@~u-h5|C2iy`?@M#i1k ztn}Jrs~=Omnk|eZol9f#LS9vd<cR4}@mc3iHB?Z;OJRv3mu2pas-M5P$YmYP;_prk z1eQN5-sajGGx@CVJDk^;!KM3{$>z>O>WxZe^B|r2DI2oTktSzj;sIX5s|sxAZx$`O zu&Jr)M}viJ8@jcsyqygV-_ZF|<6hK3ov+I?9Q^Vl7*~<H>UKX_%;m~^2YP-={?5|F ze=2JpTQY1aByu3m@@6~}@yE^7rlX=oVmT^!=ZWQ6q(jr6ch5pB_@C9<3H8?aFMf3T ztv4pCs)Qp(-F}vdS=n)dvyXM&-D&}Me!k`CDnwO59`){dz^-Vj3XV&4{3pTZjO=9m z+b`>c-kZS+qL#Q3am}YqxGcd%%zeS|DfoDhQqEfbJXS*fw`_%-kX<<|e(~kaHZnBk z`Lqg4qHtEy1gA)z%!mvVa{6S76BZ*s_h$Df^v0=4xr8OE-pr`==lr)EB=#x;vD7HJ zGSubI=^wac>NKuE+~ZA5hg@}-aVL%U3(Ok1$%S>r*!`q0%&mH378y08sK(d$^X(H_ zh)nM>5J5ZSGjlS7bn%vz%V!q;xqjN~T0aD-N-N_}t?g$Gp$ReV8wX}vr3JwZaYg<d z>~l3|Djw?M6qa~y#+CwIU0QqcIR|cZZHDe+xweVo27!<HK{MYYTpFR0BvH0>J8}Z! zm+gE6v2-INEFP!hcknaV=!dK7wIQYu;(K2F3m=G=u&`9*RvILHPP6HY?{b$FixA{t zC#>J^@-Lf|k2&Jca+Ymw5pKuF*-v9K)pHaEO}vZolp?9Xh4T90J+q-Ux#%R$*SFD~ z?9j=#bk(oTjVhB*A}Ngp80h%?hV8f$U*JC7^l*p`QF6ovAPeihcU^W}jMlb|W3{}t zE@6hnh@--(Z&|jllx9a>tft;a(Ye|spJAm!0fy}6o4F<c5@(qn=k*?Ra-$FHLT;v; z*3bGxBbB{^J{<QL(N0MK2?A-!l-z<Kqbmm5vcgBv1pB@#reJ3m6pNl70=Lz{%Qb(I z%ci{{h1LGCF;+@woTEla4Oh0p+yx(mAALbE9972v`EZ}mM{{uO2jgif#`4#U53W9y z1gP{_-es2?gK+@5nwXK*BSZ!;3Mi5QkI%|+4AYNdoHMyA_E%Z-1pqvmz4Nrwl+NBy zPfCE(0!9FO_A<YE44MV#Na<RJ7Zt~1nhOBGiRR63U<r{LNGl(iE`0|8NX-Q`dZUX_ zH!m$b9wG5|T@9a1M^^mz)`i0vlO*fKA&AnD`PjDJgXh6lEq+_@xm+uCgP|{9jFYKD z5lSAnN#NJ}l>7ykTUc!tiFYNEDHYn?BqD#6QMmgKrL6{`(y7P2e+IAjIPl++ibtb7 z912_yTouQzeI|Bq-}>eMtIE`4_XY(XCUr$b$`R=KXI6mq^I^Zl<F=LyZ`{ebkyL70 z*oAI#Ao=s7N2K6OcQ^U@s|H~QY-&in#Bn!4ok9JdV_+mIbu+HLS;Z4lC#c707hTQ@ z(0Y}c1@J{mL(}x@EnUnIFQ#ZJgIoq--9Li%*seN6CDDO_qb#vJUfzX!-xkBuvRDnd zv<!=Uviarm=TfLODgThVLWPougP^87z(aX$h@+J7@snI<XZrwQvpvL``nbub@h*Vu z($WJ@i+MGQ=I@^Id0!<`#|8^LChR7xeOvo@gr)IC$~b}c)_!-)CB_5NmBmfl^`8hK z(U4oQ;IkU)0am$>qN$d_`z`Izu4j*z>oC64DDCy0urp7W7mrWQ_t{6ZNj#<{9x=mu zB@<AjZj`Slazo?&ETj|D{@&59`YyJ4o;^dZv3MJ;I+w}5b~r-eK6HI8Ds|nDqot04 zK8Sl9w08GzZ-43K)g1i{@>hdg1iw-q)L-M{s-DDOU8ZKs2C~^EUU9UEF#$gKIkWRm zf!4?CsT`%B-Zm<=^@#@TOyyV@x@)|PevDSipXjm(R#i?Dc3p5o+WSQo^UF-ulI%j$ zz3b=vRTnQD=X!1wY;)9P6Kkv{y}dTDB9%gOe*Rt+bqA3%8K-1~LHjN|!}9;M0F?d3 z4epT%g0Iax(XJ%Vk<5bnxjeM)pEC3qtuJ0S0X!Z>{JT|*AEox)6EOUu%t)bkuh+q+ zearte2GQ;Bp!4kEPP%yu%H8wTBoyuKlabcM)M?X?K?`bx-u4-0Ekw6GN*OOg$ShhO z?XO2h9}v@g-Vf|Fbs#tWx!Qn6d<R6Ft9uZI%koH(-)aJ&6cD}u{6Xq=E^YI2*<D$< zfUCew#I(V;BP=Jk(I%hSz>p{^6J{tNe@I|xNF?SAr<WaniI4w{%Kxk`B%vI&_c(Wo z(J{J5Inh(Rh}gRh0xj@U(|IpQ9~BFAbtD8VC16n8<?W;nwAL;{ED5jmB5WB>GOb7f z>_u>I!NDVBve7qm?>PR*X)BQBg!R=4HWh6ZpOB!st(3O;(^4vlK=~0R)H4@bL^@JH z$75Ghq;y*C3rF(SpPyFIR(REpvbqR7dbq?aibZOKPjrNSyhe<DmW++H@kb_H?lrzu z?H6Gm1q4E5)N*fM2dik_lXY?mc(wF3L$`+)!f5d=^}`KPSkzF>1GSM2V!P}Gc3naO z8l|WQ0vMAq=xljsg7C$t@7B=l^-o)nP8Tx2**Y(5(pN7Rx)d)$DTaNc%p)1Wq-xKx zMdKLf#k}t2Ax8j^KWF2B^4;uNHxtQuWiX<C9X^KD*pv~jS5)kLdk#5xhTqZYV-)Rj z_^FaH!U*B>dVo{}_i9emx-LMKTr|_-Vkrtz#f~YjfPfx%tnBmicwIm2lGuix<W-dN zNle-UPw?F=@59TrCocB`cOF+^knqK0OAIcF@Xh*PFMj@t-LRC5ig4~MJ9ws{iA;!` zSNy5{e&Eyfo_%jJ)p0jo-Bubv=S)^Q-c#&`V-X>gvytU#yhSkBw(!T5_Foz;E^7FA z(Cy1x#BkzEfSwp%?xE$pD~kPZzJzx0Cc#Mv4d^@v@C8>x`iTBCBV%~oJKja#;SRB; zv1EYb?UlSu<v`KnRafDB=-1lU2kIDbFLW;n6(bz;nI`NZR1RzsDxOiXyX~CAXF3yv zlJebJc6D7Y$g;F{33xnQ!Ul#huFKZtk~GM(?6Ju{_p0R2cf+tGe-TsD91dZ%^-@y= z&7V->>`!rb?|-I%L$$H!Lk1^3V2{B(QdbE)o9<y|GRvJw@EqxObff$4%kU}bVB)Y# znDiGz_v;XsHE+C`V@;WF`u;cW4|M0}HE{RGlPgsI1Nbt{^((Wlx&4)$#LJ&ul?t9P zUJ%|cx{U;w`o6RH89@`e&wW4HHj1|->3?zefY|g0Q-}3y@lwFwi^Zg=Vzt<0!E2_8 z!;AK)_r$%pBbWh4wJ!w|=>hSlXKv$chnCPmHFP#z0uwL<8Qq05VWK(ae-OFic7<7G z*>}N@F{OBPnDTT@4twPXok`ZLd!4BY^mL~oY!f=pPCqq#@}b`IWwLnWf!~Muo$wQ$ za!#`IU2Y2IyPN#d`#zNw^en*Q`{&q{%9H03618UNh8_82n$Dw5e}5{MDO00&ME(eK zwuBQ0@0paYUprX#(HuXl8}edO>8@A2VEv+bG)(pAERAU%0~0@ihyKB#+D@XD`$T2* zFcReP%e_DcuiuxF&>Sb>=<Gzo?@z>W$4T(Zoq(nRi7N+>9#p^kEA^M8;syxCrV1a| zXAaB&T_yD1UCfx}YWj5PtkQC7w2Ud44Cq%hnALCZ?s|E8H1P3##qW3POLf()7X+Um zq;7qs%q%)A1~gutMvkcPZz9JRtmJcjjt*w@8MvQFFJ8QIik4BrbdSX?VOmg0q=zwq zLZyC80|^2{nru#2VH{eaSoBqQ5VRcZ#&fo-lzZOQPemi#@l{CRY^P;Ebscrs?DY~1 zQiA{ufIk{9=IxSBYIQO#ayB26oQV;hbvUk#@4P57+oL~tGh<YE`Exi+Hv2MV=oHC) zPhe5De<2wl9qXNLs&jp=%LucC0z8b2CVxv|8Muaq!)Dlvz9d8KI)uovR`H!;t5q(I zQJA?VtoSLIg8<)_i?Bc?ha0d-y)Rg(&Csvj%e&zu_p<3|lsLYqiW+O?1eIRr>F}fA zWMQevs=0NjR>Je_WenR|XboAv9yty?pUhZ<pm|=GcS`ibHp1gpF}V+mU8YRY$ah zXQHGLb#_!=Gv5+AFEzolimtN)jxK0<P^+kP#o5SI%v76ft^ewA9Gp*`hjwd4agcht zTZxgwpI->R6s0yVy%QRIGL1#9#ZsTNd2BFVpypF9Z9|I3GxtPs<aNuOgVeJWpNDVU zYn#DLb0!BAxu5Xy>+1)aIXzRSIQX|jQ{N`YkocJc>438CrrEyMX5ti!`K&&LUk3 z``-&v3xDfu1s_EYT^n6a!xk%u%U1qG1hOigV=FM|eYP*hGb-OyBU0p<V1r%MzNz&) zL?$CTmts5~=dH_%#WxZZE2<4mSg0=UCahTm3;m?!%`QyEKv}vTd3!>mV$Qu0%FyL! zSgl;u!+tTf<G8K&w4@oyNf;Cwa%DQW#P~bYZ@`o@x;avGR+4MNd?u!FSfO6!r^4Jf zP7wbZj?P^<A{(AcJ>HU_^h_-!tQvwE5|Njig3K``%KQ_Gz4>`YVm+IJ^n<w+U+(V~ zmY^ehU;lIqk|5=ai>p?-xSdyYzBiF<0WDY^IT-F!Sq1V8A0ao9<SIZCu^<%9Ctqi? z;;la1m&H#DE}|WsjYe1z3Ey7*8!L>-d00!M`|VrI&t7<M^Lo`EcTqeV=Hg}c{VNNh zN(}rC6LZcTtgH|!0Cx{~Qf`oDy)C*rz3DEcS(MKYk>;|^?NQ3=pVl#A{n%crfndJq zyvi}428U=@=4G_y<|DR7zRXB}f&C1N1Q9M+nwPa$_13&43&n{`&`A-=PPn3arGMU` z`>V<bruO8FT}$(7s~TwK0kW+HLB$Cdjy)=P>#v<qrQt4XwO2}!{!x)EXKvF|c`4nh z1_A=6sTI-D3IVq6Y**?G$KL|KPqm__kne~Ulx-lvDyo7l5;=ih$wfHHhCc!9W6)`1 z2Vp_Mr_i%>t(q9VAFSO*&RKk@i2n(Ca$Hng84h)wp6Rg?>TnV()=b^Z8<*b%L}7+G zi3&G8L&(aJD+&bC1=3g`o^(4y0Z(3lx0(vMDyOvavu{N}${!K&<ef!Nr_FYR0vqTQ z;uRH*2dMko>YqA}cAv)BG#7?2c}G0~+BE!_+pxlb6qDR#{Soya_bsv0@uB<TNuqUN zu}Ghwz)Pnk5k68fq2SZ@=>HA{+gGvl0-s%9d3oUj8hG#UkmzO|pT`>fsGLTvXlhCU zI1Y^km)d6t-sX3#iL(Hzi$cM%UZ~at5MhTI_Dyi8?5>$m7vI)hFR9I+J1L;PFfz(r zA<=WonR=V&Cn7Lm`_-4K7}oz^;%;XG(ujY@R4^+j#hi3lSXllkV*auFVp5Y-_4S*7 zezpL*RgOPTfjv9Y*0?;%Nq}6yV5JurP6Dq@0)%iIel+Nrf_(gQmqtA<S1@;(`qYlT z%kP+*@4T|H1F{jY+FeMt5NoGL&G1)K@~p#`i;j-3MULTWas|6Ha86Z7<3(pGD{J{) ztd0RtxXQ?arVZSEW{s4ZRt3~xoMI9gNJjZUGv;+;60O;N!cSl6bt0l_SNSvuAteqT zA!#hKxe;z4wwYywqp42+??O46#sdaIXq8Nx%U)SjISDsf3b`#bquh=(wl;U%u0=HT zUKGGqvvYI0-gk3$xk*-}^d-<Opd14jCJ+|?BTqpTNYr2u(}qo$e*Novb@WTr_ctLB zQ$@>_(NZ7`IoK=<1K2;wb@?-0hDto$^y!pY@qOt*C#jPp&p-MJFXE#s5K*ErjPNEq zMqL9%XuSlGP^Bu>6K{67hhY1Kz;qpgRwJ$+zY`}*Uzp!t*!LzC&ZQdl?HrClyhM&} zZqO8TfUscdwM)?ch3Ls|j9KEC_|h*>>Jc!d)Yt61daWP%@B8mXYO?9lv0))=aqzQq z-)r~dK%u1y&)~DOlA$&lilJMhzuc?ci~Z(dS52b7O+f=*MtPa@mK0_Cg^A153;mHa z<Do0*Qz=O2%@zEp;C7>H($upeA4lqxwgmc*0|1;TJ-O_!E|Z(!Dl+~UxhJ661^fvD z=bLd5JHf{MFPgj+lBoUe4;JB%-jFWRc@E!Nk`$9o3@3CMB>k%XHi+yK!XwQ3@was9 zc>|@ogtCT)K+3XIr3x0F;8uTKJ-Y$Z!1}_~)<Vf6apFE!`$LNR;5So4$Z0&Hp<%j3 z7*pdCGURlyWOE&-FTCmfO7hx|+(;Uyv7QrDrKRuI7ZZft;|rpakSB{trF+lxs6zG* z_~%yW^&;x)W__^wx6y)+SG!K8qv*JMZ>~<NIofFbZgX|AP_67(+`63vm{TQVOCa~I z!Qws0H2#CwtYwJ~*K82}+1T8bUUF6&K7Ts|0%RPp3N?Jo-4#(VHH}{fD?h{X6>H(d z7`Da(&m9o>B=MJi#v?Q;M<(O5`SK#ia6Ywzh%i(tDY5gd>Z|Hze0A4++lJkpASHb& zL+~^K<@$K-H!*!Ce6)-OAbHcP%d+7{OCZPbNKi7yr8>e`8#RwhqhAZba|`;V*<K0_ zKM34p$p03bszs$LA7l4U#yu{ARj;(38(TUU_wZmXIeUWdel6&ze~TsL-HTrd9@e<S z-<n2)R-36JC<I%$kYu8Y!>}#;?sOqR&quRS+(sKLoAFTP=4TPOB7B&UDwj(e9N+!c zLclAn#hZcL2#$1KZf?5KK&7s+?w3Qf`;RQqmZ4UJ2k_mscD#n=6k8S)71^3HkF5Q4 z4d$BZWrwQ#h-+SxhX=4l_SJbCH<0p!<Qsi;=UwlF550-1x&Cj>-s45eI&MdOCCOsI z#sNsuie|<i0L}s!4jq>D6}po9g1+VmiRfW}c(q7-+BZ6#KX}KWEn<{X;0<^$-H-JL z!JD*WP>H_$UJ4iDa8aNu6^CxtC=<GLxe1&npq!kK^X*XudF)SGMt<T5O8-o7VonqP z8>;SW$V!Opw1HU+McG^N<goY@hM}>jh>DCyFZ0bR`4RIf_()elH~x!B#6`n$Su9<a z1HLvyAiOuX7k|Grd{m33|HE490rzT}YlBgFLkpE^OK4FydC0st+gW8hMJ%0@-sCs5 z)^a|1dH5cV$V-(u_o1s)iahTCCF-&a?8cwaCkZ=~NPtw#P(h8VCeE75E9>2BbtF=Z za9y74tSSZJt%V^v(<}xXhS~cN))#xU){C_ql<ChW!a0!7@rd!TC&N>Gy*YYPhk~;y zVHre95q5^&E**wj^X{<yy`_AqS#kl7WIT_g7cTgSRe?+JyY_8OFg5vV025KLEjk%D zkIKR5lr(Jj;CfSJq5Y6(`6U}{mEC9Koa&3^V=l)!We}lX$nM$o<*&7Y)vF#n$yYU= z{zG4?Oa)Mh2qZwaai939ImCahZz~SyTAf)|Pfgpb^=m%4h^6m3>UaiqkM(?m8U<QX zzc<lR>-|~+P!GVV&HDE2=9w{N<QcFdL(fVb$(w(2;wMDoD$KY1%TWqHC#P-aSPq){ zNk;LkoP_|lw_hoy?tMgeZEaDN`2w%el~ZrVP$mqv`*{#27^&~}(R|FVmtWM~oU|DK zShkE=`&C0P?L)fOe%vK`d-7NGbSd{`93HKMT?iBU`X|fyw!V)fYqxDd@V&MN974)3 z(@j6Hh-97;B??4tDW^TD2vDeh<}W6y8=axg!Z-IBjbh<hB(Fl&pFym)KBA0*(YevS z7@n{LGKc_g#B>qIhZRHd;@665ZVeorW`5~`AZjZxMU^ZqL6_f_v3;`nF^jc*ZViy% z-PTuTgr@;}TJb_87IBtom@B@EA=jIIq4*4K-NcfqNdQuQ(|7F`e7}$SrUREl_|M3W z(V@Kc9vdX^`-r;58V(bJU>E{U@Wp{>hA%?&SeN+czD<*NB1nSn1k}j!a-ug7uRvle zn2_knF6R8>gJLkuxn%T9ozd2A?$sA>GyfXuFEtN4R!`mVGJ4RBR(!B-*Eh$v;$}bH zcrp4CscnOCmseY>D5><bSWmU6CA%)IVD+z6)_iQYl;q^(ti>q!s~r;wTLQ4ApCW)- zC-%Ee1ihkz4OV!xf-gnON*@#ZLM^oqdN4AD#e?|${tim119Rdq>aXRdq2s?dRj3Ry z->@8DkJzt!ggJGO3^n5%4@Cd2%O<y4h9`9*K(FwaKCfdv?o*vOeoro!6T#ezNb|tk z|MbNm(y3|W@c52*wUqS31+H2kS7XRo*NK<3%u}lBx{bEAt3{^c+FJeLl?;jGL8zwn z!l%EpxO4^@g?={&ANDgz7LE*lg_k+|Hsxj5XGL#wfe&N(6^K}<h+tRtMyRSRATtkN zLPO-|<OD0QTgMmab7*7I^QQ>x8k2S<v!&UN%~jD-14OW`oPtGKq8J#VH&Lgfth*$8 ze=7lBXWoaONlu^5cZ1O7YJYeQ18d;kzr)8)&p4;krE~!N&n{uWxa{eQJHAGd+U& zNgg8-0pOv+(?0O_TySgU$_?=p$)CIZjFE~yL1MdN*FmfQ8H2%X5kY%Gmxh7{js%mJ z#>7AfY_)uOZz7=2<Ksl9+G1BrtGpoiRF?L@9wZbw$OE+Dh02m$vii;(n*Y7XHgqPI z4rH!?P(t#7*@C_ZrrZ97;ks-a+^0b21>!c4d+^Hv2>(qW3v9|jlR>rScYvzgY36@- z={e%J354**19}3NM%-79lF+CvQEPk-W2N&J&>;^b)N_X#|1ST3hc!2-K#O5?iS$5o z3|cUFG1W~L7i|Er_JaRI?6V)Un#)T|v&+j#K(g&A|L+3-cO*Dr<yn7>hr>PpX}g<q zK$oU+OGkO-6NIX_KxhpL-#aNnMOo5V0005Mf@sJ5f7usEWa%@&)y;p%NRM|ln7Dg4 zJosUS*3p2hFs-tX3ukpgf5tVV7R7yzI?K@xP?%sMv43%#i!cTPP*WmlED(AvpFv2K zT#I;p#SuVbLUmCAmB)-)`JM*I_F}czvj>0=A<!B`g2b@Bkz+~JNbgTQ9>R{4(Y`&S z4dBv>4#n6*Vnd}Cjt}6)@TlHZpLehSQe05)e0SuANJ>dr0MZ{;<a87I3DTwm2>~Km z;1@z-;cq4DA6Ok^bSLHgYvE$E=UQ?zxHbLG_VXijh$h?LP6}d<p{ZRYj;yHbak@Q@ z{HCHMq^;O~PHtkqW8Rz3zY}j}H_t!+vE=M|%N~`t7}Ui0_yy*#QoM^)lO4~V3v56@ zs4&hhF0$B}#9FcLPLam)RY>wRfLP@0fXG7hw`Rf7N;Lx%hxU0I&w$>ES5sfXyB34o z_+>C@>haxXmk-zNJCNynf0a#nCv;m3{weT_!IhAcfy`o6Aa!79uj5!t9V<HEI6=Vv zwFDUNMU24@+vZWUxJ9d?Q~*VT1#H4}1;70q71UJFWkfI7lk(wGgH_zkb)8^oAFC=c z|J5=y1W+|2J{l0)1FCm5<DCiU^m?FMLq!;pz;pE%OeL2BxMs3RXKb}2(58QOO)A0D z-1{3(>_cNc57KUOjal#czc-y8;&Yv|CU~xOe8?fsbqV_=T3@%8?cIX!e9c)C>Gy^u zc;Qg6^2M(db)N#wo~}0Vl0gUOQpsA4TU+MEl%*)=s$rXZ;}6(*xWFLqkbsA~Kw4HN zOMdU*V(R77x%eaP?$Ij_m{nr4o>7LsviuUse~ot_XFZxOhymQ*-t-QJ<>R%`zIlAx zzT~xdMld}&F3(U30G)>K7Fy<(PCqd&{rD`Y**n{brwzXn(A58<Ue3|P#2Bh)X!wqA z9MeQOkc4|IA#AU6h+t^aNAtFDOSJqBV_bo{s`POgW;Zk|zVJ}iS9d+{Nl6#fF;yd} z36bsA4xYFvwoGe68u#X|P*s`_oWCh^%ujdij(w9Te{;3~bL>04V18gW$@o(tsdS*q zAMO9oL&LAao*~f7LO`=+dxb6lPcdWtm5Gt~tM;?>WAB*-PcluYc5C$o(`wmO878`+ zp?bCBS<pfk+`j5lg%I8CyyT{?Y&jAf0nT=4l$n&e6@OI~V%S((>|f;nPX_4=gW*Wy zYz3k$at!c-hm|Q1WzJ8yC+ZAYlEggifa<=eeokU<h1qxzs={r5-R0F2b%5>J@j~@@ zy`=1F!<l+fLR33<K?10GGskTbR{M|5If;i?)1Yk0XM&OhxdD}axJ5TNBTW>G5_`sz z`&7aOX@*+I@yE{dJrny>jA6SKe(8nzs>h`;mVluvlIiewm44|`{ZO7wj7%zc3kP>v z`_y~zOK|Yr7y9-)#EKlvJBr8mwYp_t3h!sJDMe2r&SoUEd7rpa2C|u8>ZLkvEo=<o zxS6QnTeli-#>p1WC6va<$?{?vJ>Bm*54nXHZFca3?wa5=lC>QaOfCqSBjer{Rqfs{ zhbJBUDs!ym$}54piW+7*^8*3JM*LlI9P(x#x*ARC%_v9lpb7=4t8Xxzt(9)YBvD+^ z#m^l?@mvjVscQt_NWXGJl@I#!O8mZ5Xp*?Yrb|*VSRT54K%B|tDDWJ7ql}WUYWDKX zp4I{$V#&JGdyFxhUW4yZ40>V*);CdDVD?%p4`%0*U{9FbdD@q*M@n+q`s}>dC#)O~ z&3e<ZG5o}S^N#buoqFP%FBN!G?@)d*G|HTnc)m)DrhCr?a}0dGNy6Xm7)r$E*m_y1 zk=g&{O2w>WH;(Sm-bB0jK@Flaqpv(dfp*irsd}%`E$>rRGE9YN##RMmme08)KXhNk zE@@PU_S+)D+&gK;0f>U^J|DtXKU2gV%tLS(Kf320SnU-n7$RLTode-va}4G=4beOx z$Q_l%%{mc;i;XiK$!sKAKoCa*GOrUkdOeW^L$AGGWi`sfkmrPE7R+|%Bpn{-mf(XW zGs4TChr2w73ns}o(WJIg9Fz|<oi$2e_98tLk|afIg(&SCviy=qLN!-A!ODxYz4VGn zVX++C_ZpQ-a_7dk(ndM$3o$;Zfg<HxhX;A**nuP07hr`|R(khDZ4<7s_)zu6+09FA z#&U^x?MZG1D&J$4eWLG)nxqNL>DZ%cZDZf3I-jZhF>-<3N#dvDjT{UX{)48^=D}nN z)@`uaap_vd>c|zgpS3}Q-%z%1D6^Nnkx-yAX{-mO{qvrvLP>A%Y}~<VWyE@-DAg3? z=fPvp{lagv!fPg`eO2}@t7Hcu8vGqY;d|d9S_Brk^V@1RN(Zw`_QXg)HNvS`w2Rn( z`hh|AzG2b;{{?+R|MRJFLHN>R63mdvuZj83V_`HITg${>4}U+9G2GXj2W~SbH@^!y zZW4yR5;~nuoyJtbyeO4XbwX)pM=GZ$yleJhHsPMbX#(gy0+tR(Lh+_^=b^2t{x*>u z#w+YQC_(`fAf^_h9PK2~@K+M*4@J@>Gp?xU%+pOc7ds4k@~{ScXvd}Rr<PV>4OAY% z3GldiG9#(FgQ<T@X{1p1rr3%UG&Id-QedqN4of;PhL2%rt+E{9m1~ZKX+`E_J?-R~ zi~k;R9Sz~Ac0})-&4(kUE1QB-LRE{^Zm}gP(EK)W+;oPp!rS2rk?BFg?YP@>L+vPq z$437_|HEZ2%df}(I)=?tCj@ahLh*|BCAW%|k2JU9c+iG}r7Y=N6CSswRj-dj)<{NB z;gGrfNz}%@%&GFLkDTi7GO8VcwoMLg8=Va<No5jjIh=wBJ^Ke3n$wXb-OJGD&xU?< zH9gUUcnvV*v}*ZaEe)>h)i`GaGa66!#0-g?KLo$vXT#n;p?y%V(%U3+gk~hy*jF5% z`0eoLW7m02h|LvTC$Gj`a~{ROGNd<kk9rtQ@KW0Q$*-c%{%SQB`mKC)?NTU%;o zc-@$=5~^LlwJcCh6_xI2G(Bx(gsIGU4afPv;kaWg*nh_yAOj(~`Y`{u!*g;6*XVoj znleah?y`F)p<LVzsvGMWDw#Dy3$1<~TNyKkCfb?m!A*EH-b@)_gI+U>+xWL80r(Yp z)j=ocL*K*D*b25}|LP~Xzp~G<XE@-s*ie;?VsEch519E1pGHvR8KK{RPBeF;U%DAA z1Kna$W(3O;g*u|~`SH3jIs{$*s>~M_h%%0xsFp4(bG4P~-{|L|Ot2^m=Gr=s>@bFa zSK|H+sK$XZmw&40QG#)aoPgcDwU1+;N`XWir+u{_DpO7(jj<mPz$kbmSmC!Dh?3U5 zkbf4y>uFB`{-^t9DwW&)RHfh7%-_{s+C_~A|3vTTVpo-!n+j@A+A1BM?1v}DneU&0 zlr}>Jh#Bz^w~Hy<I_A7RlJc_T-TpG;CnP2cp=p}P&@&s6@7)r1lttwWTXW|UP$ZPo zwW4*b(~VS?NTljFi>cOn@l;xo4lFww=lDx6oox4P9}f)f`K-?gb)4){PucLZ={Y%U zrQ1#+6G%$eu;BD8*tg^5sa2^tXd^~qOD&CoMNCa^o4A^^TBE~?N~a#j2Yt`Dp^2`$ z;yorgI1~gyj)&x(OPK|1AtpU&L#A=iHW_aFwnXI|nM`J(9rL6liIDfv{>9jP;9RS5 zi%t8T*g)6ilNEHV`eim~&cve_AsqB{KBZ)%cslZh<o~n)jOo|?DnVJ7$Y^1k61Rgm z7Wk_xqC1Y%S*c&L?Zv;2CCCOP&ui|HZCQX8Lo@{XiwI>B|Ezcl?qO?P2#TU@`=)H` z2Uk;8ch9Q)qXx(PA1&vptw#SMbtZUwPkBHxw@vBif$KV{*xw!%y*G+wBz_Kx5TK?} z4cm!I-~X`XRj3@(o*{Fr6coK0!%?zwHi_fjxJS@5ADC&a5|n}MD-OBopIETvn#7N_ zyXVX=Eaco!2SH#TmoaLropC4GzZg^EXg{UKFWqI6T5*%AoF}dL>@1Fh3?AuK&HzVE zBOSuBGeM!2rKhg+V^~e(uwZ-)XpOa@W|O-wtn%i`R?AjMSlDkZB|G%qq`Ad}3+Lvo z?8`x90#QOrCPhpHW||<@YLKBFc}UUR8RX;f9wk#C?wUtWRLSDbIkx!nW};9?3B|m^ ztK!Q+{T$U^eC=7^=ASMJtFp~>)QXjoa%&9AEFzdU9ZLK;4j`dvFJvTB7Gzpw4)kQm zIvTvd7LOa7WrU%?>2eoazpt>3F$kE!Xp3SUXkyF8{?JLr)kNWGgP3!jbB<k)!%`Ie zJ>A~KLzy(K5?sSJmYB_!u76{kr)2K;hRoIe6pnIR(B1<wE{Omq8h4c;DisBk%qRu@ zM!(qy#ykb*p#?cr;)P<`z>$m8e@)8{;MpUawq-`x%a7Gy*2nMHs99igOj?+q(pcae z*Wab%pYegbQ<UCfqf=mYLjwXvyRWm=$w5fhcDr~aw^Uc*Z@kpwu({~n4@MTa{R0t< za<1*K%cgp2yC1@9Bxk#Z@^U!DT6rsjJ*uKZl_L`u(t;W~Mq_GHJb1)N*n^dDsq_?R zmhR6Rv$oWdRiGM(F&s-P?MXEp@Kz-Jc{4PICA_WEsN~R@1NKd}V93zenNvqxK8271 zNx7t}R5@D{O?=J5tZY6YUS&rmYqllni+5vf&Az}{@oG@C8xqg(*Sz7axS=xogo#1b z2{-{WBEOQ(XrXIWgK3Mt=^k7A*o@(ub7&879Nt5gLt!gr{rbZGiFiHISEpx3iDtUh z_PfBp27S<baG!U#o1n>i>onPh7VT9a&gLr<XFVr>bPBe-75#BrbBJcTvV(sQW>}4X z5B1*?j(zx;&b@cxar{+4bi6WCKqA-LF{5QbB9*pf(j>LG%+1}biI>#QDXT?Pf6rSp zvPu;sm}7C{kfT0#Oj4sfl*~vW{`)yu@%(5{>N$7oB|Kl&;%sP#D9!&gi<+NOOgcm4 z?W7$)W=FY7>pI(q!rl91h8vmSiG!HU#dSQUK;q)t@g4R>w9UCuuTP2wETgvgYXW8o zTUT_qa39_oZ3UxwiFRtdMG4l;k%h<2{ROa}yE%ZhR^xrv$=8T<!uo8VYK0c$?`d*# zd2+`ySCnG$sx|Ae=1d^ZA$l<DK1!t^t{j{bIQ33b-d3pw9)OvDRsL=5)FJDi)bE3n z52#l1v~DpZF+`Zb7Jg63Q{#8yBY8y2FkDD6U%2LAnb8vcJI8K8qP;&yg)y2Tyv8s? zo(ZhUU%8W{ZiUZ5Y9wISKFC#kIe8&H6W6^$+vs<~S^e`o)kT=&`|+dwanB%QNB!AG zo3&BReles)%&E%!P_4^^5LXs8g7GP$%@a9PjAc>+7k*N*WO&@iCzIi-u_bu;pApE& zIAv_IbY{BL9K5kx-bffdJiHaFS`d;H_$4XXLU42kIdge?RBzgLBze`%^1CxO*v*E9 zVvhAWr)jJLJ>Hlxx&X!)rhO7*H-(1XjMgicsLlWE`c>%5xkv`vc=u=42j`O1n+oGE zRys{NiIHTXmh{FZ*OE7~V>rZ(tn;6&KfW;LXKKqjF(W?Gf?2&1<T<DB&>M#dP$td1 zqU0D}_WnNe-oMpR71bcoXxH<z&ovxE8|txezYsC~YU(By6@!l&XEK2s2M?Wt5Arop z?#h2afXl6zU}*57-J?`Kr%5|>9ey#^!vJZ`#PH^h9$}!j@)}+v(=Oc|cuOO0rOw1Q zl8sIfO(c72ePUyw^&p0ZnybZffS$$zBMx@EfmP;lG~7$VeFr3s6lQKLU?^xt_1E1V z7$SJgp&lo^Y=O#*=l-JD;}j+gkkw)i=asIhabmx?xWVTEa^lkGq8nxQu<hb^;pg(u z@hir(9_Fej(}I9@Y8n!p(VYpwX$i7I{~0Qt`2l(KYw@iT7Gzqp>u8wMEY8lHhhn7Z z=fRr<#?kBE_3a`k6O?4rip7j>!#OdC{@QrNmJ3I6>$!BJ!-?|=JZ|f<V}2${BmJ8o zWoN&9jDIg9Te{8oZjAQWtXxn6hfpEmnIGW{&E|8TO!-PoZ{%px=|M63^O^RKDaVGz z>Ix+_d~j=0vl;kVHtfn%Y-AB1$A0H7_kapwRj?a3U^VDH(=)lXPX$r%g!DuaeCEBW zp=oaPHrArPOgP65?Tt<;Siu;AcAVS{avcXZom~vrO0y6!Lj762eo)LXhz`IA`bgfJ z&r4hvg97xV71g4Y{awL)7Yn`|bZF3O92GxR5dDD4Y7i?er?%41BSiQQ6`A(&dfD51 z&Yjc3;x|E;4vnlNaTI+1FW9voYJ_B<<5;H<D9fJ=0ZfJ$4G<sUcYYp7O#4(Dkk9aQ zY(-r}ek26=3(V<hN1#pR{C%Xv{>`9TI+ae~{!6?9eMCVj_H#80Opc1eqSyv<58GU` zkl@IG6$ut~h!2OEYa|EtISU)|O5}hDl{R6er`PLg5j2#vGe#>dH32+cH?$oKYzxOo z8eT@3cH49oH2nc1(SXE0h#S{>WD-XdgfrF%pI(IBPb^mbcLq}d2A9^Y1Bl5E9_r7g z#dwJOvstK(G`6aQWKiU*D49EP*2XrR;rHAoB|u^DBfT;!9iK3@1BOCICE7iYV%#SB z6N_bVPSU@e-mlC10LOANSkrr_fDnvd*<3~Gt?u}MNs_&eA_zsIjmdeVcJ!^(cakd@ zVo`$aPX8KG6W`S{cm?A->wbwC*6V?XU;$4U-8n;dw2DGVD`3H3J`7ue`IOGR2>6uG z`*DX3p|TPll|UG<l)Fv0%^&fGp8EU1qR)@6sT4Uv_bG3k0mE|9h;1UK0DrEwp^O+Y zvw);aES4i59`vAXF<djNtum^WSN&L6_p`94DICsbc4r=z#clEyo)0skAFI4s&BCL; z3qlFD6PZ#n<mftv^Nm6`Z-^oNLK>)pR`S7XvrCL(Uv}88q`a7tg0wgSe(VJbx?2qw z7}0O?vr?kV--#5~44_fwN_M}+u!LISpy3(JOYHrMzQA_VS?AB{TN^*eZglYui6~hx z%dM;Qn>E1(o3O+Pmfpt2lq7%fuZ2!Zu(ZZ+1aZJpTq*jnDl3jwbhomuRy?CNY&}pc zcm!V$L`g}yL}uwz*zH*Dhs7O@CLAdQqR<dXpS9bEqki`X5dnV_BpDyub>AKhX20&e z6fN7ez*eg(y%Nt@#cLcGlMn3JNO@!a(B1u#q|c3sfmvk4aK6eBE5qzPC<BU*KCJfJ zGQLOQZ_WsnKVU0?qB!TRstP(K&n<}MWw`a;*gc+3^6<21oZ{EsuMHLYdolCu8`W{r z@l=f?(>y|Y%z8fz8Zus&4ZWvd*&LD=atPi)L^N}V<`UaDL0FP8Q-M1<1?ze@5lE8` ze$yFn$sg#eU3%Jd`h|dPzok;t!^pO(IcXzNtQ$hZf(?<)I+`YUh^O4~>Sz{Kc8l2h z{_Mf!d}`%ZQH}d59qyq3?nz`cA#XFKmpbjQxOZk7YDO!E<L?cuo<QGYuDnq=n?@5g z`ms;GVy%8QEj_uY*pA7B<A-T_Fj$O;k8fkRIbr)lZsNVS!qh;F<iJ5LHitN*9dYP= zWVbkxw4ncurCUJRr=e`|V!?^`la(Lfn^@gXMM*ld>=ko_>ECB{5lI#LD-xSLwyq97 z*Xey6D0A5mwFDPMEun|W$}Lg&iZDfKvYQ!V78%cpbGB2ay76~98^4j)8_LIGaxXd8 zwW+4x4&mha-G3IuZhYEdpH33CzPMGE!N@USt2J14I>@BEUy2!26;R7`WdrA>D|VTZ zx9*UW^U5%ar2k3kRzLQ>XXC_~8i(3q!Qis^yS`Kj&)L8!yRQ`kDVgaQ#)x`~w>$ZJ z(<8p!43v$QloGzm^jXqDriu=h%w%L>C!+DO%y0M#d6BH$Go^_su@5ILqbcU(M?fP1 z55z$A7&T7TOKw7P?EW4VY=rbvS0O*Vr^m5bLb~5czSooz4h@aQ%7^GhrsXP6pQvDf z3_&vO&C7=X`s{4AhktoY@hAuH{QaDmRPn0pDGTVaiy884a;=&u%sx-`Ku28E_Gb$S z4UMgEACnolf*hvl)d|*tLXx2V`{<z2AT>EP_h^rxk7Q#7_+<k`ZXHq+S9n+J(^;#! zY?_e=*+91pdOK~!;r?L%-23xq$hGa)v+S;%_J$&1gbajHPu#RoT~@-`wKW<>Dy{FX zc^JJwbkq^6B&<Y!Y!Vd}C9wL^g+1k~(~TPg#g688h)!l@X^YGI>F(coNeLqwa`}rL zmV31Z#2syIB%qH8%ke9dDn5UnhUOYW-q$@Lb9MRVva&KbN9!0rz$L>C*bNQs@9KmT z3g1)Bu#i)*@ql~GX?$)od1rDwX-h#fs&G&-?>i7wstYyP$1F*REnHx#aPD}{u$?t4 zvD>)HH)n76W|fab#)c<Pqr9g_l2ri@TcU}`NwiFQ1tEU)BCk53xR@Hi@?eIm=u2Zn zM8q9ZQqu6_I|o-+qBnd`fD6w*10_B@f>Hx^D=?(f7vm-dc;R@Q@9BQbd0LGOtZA%W z(NF~uwx`8CH=n9i;pcD~<10|<sL4p$7fra!c;*q#$WIsV)c~6oxIZPZE+8t9L_<ZT z{XqiRR(#3X{ssR`5Kaj<LyGvguIM~uf{*K^CiC)j<f)`lqgleQF24$Jvw-OV!o+}# zb1(Pbn9WV}7&&8W%CxSj9k0EkBVq~@ng4&3+FkdiWpfx=dw6_!XF_=_ppP-(WjB!E z-o0&aX-PxOV?l{27Y#v0O~&~s%}ioromyYQU?r39Upz#KHYF@3v~a-pN4DN}g@r>~ zL*~zWpePHLN>iZM{f^Md%`b0ARSxD7k7O;L*KmJ=`***qPYVzK@<)Pk2$CRXGUm;= ztGaG;Bx`XLR89EWqAuH~(_|!&e>|C12!q04?!8{iZvHstH)zd#S}R^{GJQ7I_Kq_0 z)Bhc~xTLGOub3N3;12mtsE9m4Qg13_-;k~<n7y=;(<KCLh`<l5xi```gA75og{r=0 znncu{o0;~1hmMwwe}82jb`_S$V{z?E)E!nGid2t^sXS7SrczU`Cj@Ux*0D4>gg!JS zOr2n<Vx$mD9H(=rq=bLjj?Bl#e5gSHTMIICF%6%xcMz8$`rnPm;<V%3tC96)&&G?1 zw;GQdSao$z4%XLcQ)#3vzK;iYLMaUm=a!ZdcP4Xlh2Bu6`TzV(B}gjewT%kgd0P8O zdY=LDa1NJgY)%d_-bG9Jj?jB$Cu9L8{y~XIeH0z*KNtK=Pa<L(HPDa^WM1xKp|;>b z?pY}l1ucoh8rx5CYj21x6pFFy9|E_>@F*o-V}dSNIS6$L->W##de`O011PVDa?y z3{rdwL^MELP#myJ_Rh2o8z}1wGW_IT{WF4kl_nXhSs+~2(4dZ+kBn((SmtQ*E90eY zh~3yPl;rk@S~lhmjsJZNPDX;`Ix4QXDtU$b_lbGT{FU0XY4!Dh>r5<vx^2h(hWz0H zfNRWe`aw6Y=YCc0%pNHOD$j`DKaxW65zL3Cg!tovF~IeESd}!(pFg^<Nfm}Y+&DNn z<<H%CnUkpJax1E<WBj{t1NImdM*62Ch%vUt5q{Oh#ZI=|Bp|KxV@ET&?Q@F8;@LOb z_hbA@o|15+PGMheUpl>t8eww$sh-T9p%?l-9OCHFe6tgm84lK<i$1IUL3{kriyY)p zPeifz2jYO2tFQOAC@b0fL(2oYWo;E>=`&CTH8~iBys4TwU;UG{9e1DE`Gnl|;*5F% z2O!SLfpW#9lRqs`YcM8wOW6G~ga+78froG0#!Kl6Kc+ofjS2L)R97<t=aH9SuG@e| zFM_N^UfozfKNOQM2%OoAVbW_h%8vdZgHd(Nra6A(Rs23X<#Eg-Q0;b@QFmI=;(gob zlp_CVR#)lMtD_)Dtf-;CalO;$M~QMHhc<45*~ysux43w@)kOh|s+n=HVBpI?=20SE zks&=izY%o7u$pk2%=4*8t>1n^YX-{7N#v#ctrN4p%^s>z*)pBztw5dZj6p%W<QH-y z6b-Nda2XyUv_;9X`mO7~(3AVXT&;4Ztho*$Y3o$xRqqxyWzEb=er?cG0K5)>Pyjz6 ziwqkkFosldAPydPncu+Y5wKH&no(Ay5p8zD1o`8av}AvQN!dTEkRwxi;C&4wgoD6m z?Ci$VmNRA2vrs0Xu<oz?)3s*c$%9Oor1;}A)n3si<b}TnB}@7fLZ;^}bP*47h&h?x z;!$Vm8<fT{OMXOwc`YFKI)3Q@M@-Egbnp8swsQN$qCK6wGa)YRaLDiB2BZCWo%fnI zN_4)s=A<g@+6W@%!T?dsaeZ|%D{y`2PW`2nL)*~?{QPq5&Gok?8o3c8r_P+i08#i@ z+R2>uN;pF%deun8kK(inzfdfi$2e2o(%M%?hn?K9adCWK{ZMfpH<j+s?4?q)&8~2+ z=dZ$&Ud6zhOxg3sc2G{fXqF73JUno;-`%{c71yh><|fpUwRuXsYqE*<9q0=(8R?3& zP<mE~mpWk?NEs?mH8nNC%8zu+XNYZ|!+p~s%Cbe|i&}!TqAo%uox1f@fe)}iiUt}6 z{^j#Q`9~i!YZ?vM=}Mp#2JC1XpTcEVO){Tk1wF?w2<58}l?~IoeqP1c?8zwlE>q09 z<0^zuz3NL##Q}MKSMC>ea^7kDU}zLX?X8V5_L1YVuo*O}v2ON4rBpPi7$wQ<E2*dY z{;k6&?6oM{Y#mm@jLAA%?qJo-Qsp;$7M-M?zF$uV^G))qV^%&=U4J`7`LMUrk{-{I zZb;O4(BJIR-iV~At8{x<%g!slLC7z220X<yCgm<q7TW*924CD{a)}P7(>1VvsYNzs zgh1mMH)0SmdQsL|blHtrx7Ei2nZ_o@1SXpCyI<1hW-SaQ30$WpSSO4*oV+~=3A1tI zm-OF+iEOM+d6}KExXU-_4b9PE<On<<a^x#+``u&vQKr+eF^Lwp(sCw(IE{G0-d1Ur zqs9b!$p9iO=R;;=tRzStb9@J^fiMZ(%@^%^;;Jpm1&ZvMS!flUuKzkowm9FoNDhl! z`wv>=1&(m=wp{_pUlu&xsG5>@mODvtsK~<?|Bt4#4#)d_-?$pn-8tReIo-`P)7>^q zcXxM9H=CMn(+m^SIm4ry-~IU>$IpKp4xZ=z+<9H+`8t0#8GhHX+NGpY_;w&Ty6;B6 z3-4;N<UU%aGSG4QRzE#2+C~xQ-VjeV-<x3h5Nj~k_@5YWtk*GC?w1w8!)3qUFaO9= zzw$5Ux8ojXv<zGt?q0k}b@SuzwB|#*MuE)^s?#ptx%&PG0)5vFC*+B;dKv&X!pXV< z{_tf>F3i}a8U!V`=>_MT4OZt2^~yc;zdt^2yHf|KdLD6ah+S*e+uk_J<KE1?`?uDP z4l6+1xH!abeypdPtCcjluRcmPv@UikG3|obL?->X&7-?mX?hz(Hkuq2;eV<4Z!U%Z zdCk4CNkm=7iZkmSiPt{jU8U3AGFk4ZppAhKYqqSs>i!_>zvUN_ru?A2<LQ3A<BrYW zXq?N!H4~Ws)*JEZIB5uuoE+9VaGA2Hpo9AOy(MYJWj-IAxo&Ks8D4Jn^bYfSUu~*w z`LM33<!1edNKkZnC>UWo`!}@6XBg?%`Ul~iv08H?J_d%aZUk3Y`h7PzU%ZQ);Ex;u zATRR&XlBwd``B6UO8uIwFS3#rT29^rnY`m%K8LBQ0!zB%sW=f^k5%WHUR_8~pSV|k z41f|4RPi3&9+GXHM_;;a1*2SjTQAp|R7(CDNO+EX)M0Esgi8*LBlp2!BDZVNCja7g zF8K1^Oi!6Uo;imE_!F}l77Qni_{W)$It_Kil^3$uZ7rKTqkldX#q~$DIdPCaoiT4a zJ1_Bim0gcVo0K-aqbGYkQFT3VBDZ!DL1nPUNDzTAr`P?3_kEw%>~(izQe-~KVAJGt zeoX!+LGmKve35JQBRW~{v~w4N^KTd07CXVtS?fegLQJY?U2d2=PW_IKS!M<o2ZWnV za@W;>SFEnePrtuaA^MPaqN0m@!U(v@aF$pj>TOx|5A=x;a=qEtR-1VD&)1h&qdtHJ zD;&O8TG5kFzfhd~Iv1k<7;kR2A=$dK9^}+{SbAXQD2r7^-4}r}BoZz3a=T<>&_Obl zB<p$$t4eVhq`H~=?T!7R_u9*Ifmu&Cl7WijKoOmP)FatyT+dyv&`gxNsuD%!mm zi^hY-yvWb_36h?E_&qE02rOMB^}dt#4WAqzGjHv(X`}C<h5cTiAuWcn_-sGTGWah1 z{URZi`pnv9bwu`vhLM+)5_kv0`jqG$mU<1$$di+k;@EaUKO=|Cz<0|Iyrc7_717Ib zN_Ix>3;D2YIMM8`+k=QWNYVr{a4{V}FcauDl?ov`*fJkZ_^bYi)t&A9b|xF#?0Lp; z8VkOp!#A6as0(Hs(>|L$zfyR2hKCnvomi9W#=~`*=W2vMWX92utJR7qQ;W37e)IIe zyVg-n8gQNDxs{rlfIZ@th>JT{u^_E&A*GWW&a`p!fjW;l{|wIQ>BY(Lehhu5bX@aL zs12!g?G9G>3wKNme)ZwTEjO9h&;C`hXATEPuFd%Pp(bXM4C-D+iu35!O_6%T5Qj4I zKQ95>Bc4x~0ZsRoiC;0d4ux0&HK9fwk045_P$s9r!<J8LXqb@ApW%Z%?Ux9ZkB^gL zBdkZvzW=&(3dcA(zImhiU)ScioSCx??GeK_oZS1@++X(eSst4Q7E7pWr7|PW(vT*S zO@17|XY13LmY5~MoV)6;&<~+iv{}9~Gdy3>c~|5$ijTza3k9haPB%G!-Kx@NRJqDS z+)*^?|KoWww9nUKdO+GU*wQcP`>#Z&WRfFkxdW}|b)WCNTF4~ap6xFh@E!gb-D`$C zCAkReslW4nb7du*J1QD&G+EzUZSqL@?_od{@+Swru;)yKzw0tAIg;uPvD+x=M$kw? zDWpTE0G{D867us`krHAMb7X99zn-G-#0YzAM{O+fN#4-TIfbW$_5y{lUtPUGU8?Gp zz-mj<m<43*Qpn|YKy|zK96FU5p^DPn)rZU2|Ax@(eAyZp5K;+c25z$=Nq$KzR^9tn zYDt{pqf@jviY0f$+|!{;bUa|)<xOh;iFkcmKhYn4+!0ihYUyp4PpGd2wrt?8Vn<0; zD5WSb=@_CFPgfRxZYFkVXoDwzDo6ilo`OEloUm~PE!Pw+eKJ0amtkr}Ewxi?W31Kx zGyT`wWsYsRVaqEk7P-XP4Ih;K=w=uFW@z-cj!@)vYvIjHEeTJGi?jLhk}LBGFuSv( zOo(;I9~-R2Zb*oNtE%Ow1sl93vE)+cw-dCWFBRz^zo4<BQ2!9DU6aHcuo_NF`jkgY zj-W~SEW<k(uf_`b`@(kj+<N4;*b#nUHVLwjV50h5cU+Wt)K~W>!t^oFl)BODx+-Zy z5&pyHPw%SaAt8UASPdO{j5`+t?e!oF-03Z&USHbC<EwWP5H96vbc5GU4`!U(U7$Uf zqqcj4jOag($>pO!{mATFC!Kz$>4q_j`i(_DsDf59DR4Jg^E}<N6H^fvVf@G3sQ+H| z@9s;eMbA8><y#rV;yANz^3~IB<l3A%i5RDM=F5<+zD5?WI^_3n$)Ta4gCK+oeii^? zBvq!MHq;F8vRc2hj}@Fs|C*+Wme3<bmtr}!?eRXH_Bld~XXK#d`;+pag)b(^9NG@v zJuT-LN5mbg=A}|7E$P0KhtRwytX-sAWnIA(H`LgCq}rV~XQ6yTA{$dM$9<F<RatE@ zC6Lj6mxY~7_;*SXpAt(lmO(ccn^{mE21hSE$xgQadd3IBo_lQsk-R6sl5sPnmM2r+ z_9MrF(o2VmVsQwN641eY(|snP;pdf)?Ce2enIrxoaC76z51p+I+qdEi+{)%V;VwUN zYGs%PxO$^jP6{C^YQ<n$STbteuIa7wkvNJ1DZAxhuB8^qBn_|YA7X*h2_jK>kLX*c z1%DzO%vkE4=36Nzjf0DA<m?Fl`Q8v(7@^l;54AhSH0UDu%7+UJ?sKM>+a>xE-5mP) zy-$Ne=UjUs^?Ev&q%yzolRKZ}w;nR1e?jgtH_MK*zJ11gd{BV+;WAAteLNoK{YDp< zxfrVj$9_r6Y#?sX8b5GPX*do0l;p`)EqL{Br|tL%C7n=p^QI)BpBEwN_QGpBzTkbl zNt8~l6IqHi6{O!73+&Kdg}w-6dlYJU6R}d1Kw!||C}i_nWW&wc>uuA4H-NhK7g3Eg ze!f=l`1}nv8D_O<W-(cYG3$M!mW1jCg@s=Kyife5`>QM0%l6Nu&261rlMkEaSnn!7 zz0e_-a5*B6ocW_nol@EOPsU)H%pppr7rhTge+`q6?vBWJoF16Ym}&epkSUXi9oCD; zy!K2UGX#8P<Hdb{DY@cz{=2E{0Vqx-ul4Y)FuyU50qYMu{F6sQr>8~F&F2M^&7o=; ze?hAM*8=EEAZOrw!sC;F-FdXUCxa?Hf?pBBlk9k9_;)CPU(Q|W;)^&Y<-r^T4KVWr z<V5#fViM_si$<}Yb#BnMp-S!fG3HG$W6f&J`&%*=1eMad^Z#}-U6ELO{tl@rA=jM^ zuop+#a5fDP(ktNDPx*4B*S5N>LoVC)K(1tjXE${HEKYB;8a>`tg=p$8Td(o&$H9;H zP!C^_O9pB&`2PAp0|z%gk&8^WU}J}NAGsnEWTl!l)Je}pm^>*m$V+SFV+)3GGs#JB z^*V&N?Zw7iNiXQ6L-*4@*3*6;)$afcf<JE1-5DdBt_UXv*z~x_4a)enM+B5r!B@pB zUh@k^E|!QbClvF}<_Y!1m5!JzSmBYjwOdd^%OCodRlfaK#If5Y$*b|+-piB^!scxH za@axU)lzXb=#bqrmil~tA<F125)E=O?w(lJ{BJ|NzAU}-J@2^Pa&&IP$tsRZQ~cpN zTxk!|^hidAwsyMi)>Zw(4nCjA(wg+gz1|XkYyG}i6L%~do0!SpT9=Ifb!Db)b0s;{ zNbH5QQ+53<i-E)`9eVHMn029=w4R)cA9{A3*{$kX;N|Qq90|fca6Ir7_^|md5ql~v zOyu-FEv7`;S5)a6%r+`mgnO=ky|B6Rta9Q#hlirXBt`P2Pok~qIW%fpd<<wi`XMIu z_j$?8TPmUos*d`dnN%SI72;WMWQ+jTYzR98xCz-aYDtGP$b)ph>S=!B9P&TmXTCc= zUVCqHW-Bcl9|NOxx{o9XFuRzKl+?AQxCybS>7!#K>%`M#3sf}<D;$cc->?|v$r0Rc z-Sz~)y{zzhFzZDjZ@dT!pAWqbEIAzx+?TTjn_14f@3LzUzreBSwP0_&Oi>-Ke<M>g zD5gIRfI>*csncBwy7A>R`-^?|d`1@3)qxw6&L%7PAwQwmmWbPOPzX0xPaR`c3+{T6 z8Zjvn&4}#&M;Z5)rL#W^+4B?ndFd-b|C^i)anH*`u_lD|IlgTkHd{%l6u=Q~Do*t& zwIEcS`hjFE>>}d-6hgj3W9?Dm{7CwnOb9oi*_4O6C$a=R0QR-53!D7@SZri&|C86f zbh&skb!K`<5EX~;<qSveLosqgyAaxv>kw<MbbsJ$SGGphlRNTI${_k>)PAG^!~Gg_ zsCN}_pTL@hb5U*S`F^CEm04q^+(SJk4wLGGOjlHIv*mPXn)~0?*4JL>r~Q0{^9Z`n z6ei3-mh7<6h;aOYWyGZCIT{m|<%g4w4>E7PNyu@}rC8hTtRun1?s<vHIv8#EB@9^= za#nw7U~qfb<bPlP=Dj2T0j*4faH4=SMfD>n7}bP`0g>B|B^+E#Yi}t86J?vRf-d$< zK2HCY)_tC0+SI!tXrhjcfnra7%pbET1ck97F&KIAXN6JZ9e$Oph_YzMKo57O4>fvW z9$F!FNBo!DVgm);%wa+SuQ-WzeRFBmvq>t23`tVA7d*Oi%Wz|tMYe+aD?b{(44FwS zV20zVmNi)H*)cm29r2XVWbFLCeMVjX?8JoT;6rdL(v5F-YxWhD^eCOTMz<M@!F*8R zqZG<FR{eO*51xH$T3-!>8thIKsI>_F>En#j0|zhM&*Pa)!baC4AkC|1z0C*+7zVBk zqW1}BeT3)!!uOD8uYXz3kQKg<^OY=e-|7Ywc|G6#II|UYIeYfvZN&iyhVt_&>GvLc zZ|=sKOwa-j{Mt^eJxxc>ef8Qc^wMX4rS@;*+RrRtA#lV;)|Gs>M_kNrf=g0QP!P_4 zKN9_2x4n&!GjOyxW2a-<AL_t!7xIhhb|>lNN0PICLap^@3OtUP4jbGL_5T1OM1C=Y zhGM-FMkiob^7mYBU&}~-@B8C>uUC^-+{IR=NSTsD-A*L?3^oa^l%LFT(ai7utVAu? z>rj$vZnfuQh&Ic47mEQEJD{CSIt_@mI3g63oN1I)-QTGkwI34R3oCQWrr!1*RHiqT zUiz^p^U5M?i>gU8V%q5oMN-U@Ol2Gtk*_vEN(x?J3LY*z&*#O2qa-Tfq}2=Uh{%?2 z{vkg)UESY%0<3^feK(1bV=Yvm_2-iTuypOvzVHQ4s0~iIh{kMNcSl%ENtKg`Q(IGg znxsk8Pl24^$7UxVNVXV#Gj<czr^dCdh?Fg{dHz>>xcVKPfTlWanDHit-D1$Jv5-_r z<XETUen01VoUKQ=f=uF+Ec&rD?rP0_dh2RlwLooDE*V8x6M8yqFE-T8HX9x>@R%Re zU6RlGJ{yi^!@m)A@UhrTu6eJC>s1H4M7%83Q3l<Oym~H!--)8V^XJ5mKOUJpuq^&c zu~Ak8zNtzwP4@IyJh+SzVua9QVEcrHqa1?u3!8wjgqle$&5e?eQ#5oKnpY*&WZc~} zLH&iMq640g%;7PtZX~%_T$8#j9=k08*9d(w1xcAyh<4;U*!r`B5WSelzP#*#071(^ zKOt#BP3)KH-_Isqtw`L;ga_Vm{SmsnIiQqlV{4nmJCx!%vDXFPpDrlM${<z4pcC&e z`<jmkKpS)gzF44)T~)o~%o9yhkYR`R(hw0ejh?VoQ0e8bJm27cpu%j@?W@0zY{Hec zUp=Q^wHvneEN+v_m30ZMF=*tXv6kcMdECoV%A5!Y2(yce;Wpfip{8+XE*sr`ASP(c z0;^Hi;lnQJQAhmAYODD`I4bUSL14{qs{Dxm=uY(k&&ROEsumlcNQJ+flau*w>#beS z?9iuAd<@_&Pre%#^CuYdswu|z7?dOKL-)UMUxUmGsWal7uiLLjGO_x5H+U+Rg1!|B z;HZK^n#;f69G!bC&J0|<GhSo#v#YDf^W2U8&kw!)eS3j5mA}0ojS^okHfEie<Zwtw z>xJ+iZbjpv%R|=_{9*H2MPXpEo<1oSy_{_foHz|P20Zbm``>#u@DREf?uy>&e-(XH zDYSUwZ3%p~0|Nu#%ry*Hro2vTk>D{*+V5od>RNDS6~=afupmcbU~r*NQ%LdW!-^_w zZpLo?^Vz`L*2?X2&TRX8!F?I22|+u%a>gqH^StlYhLY*I61EB<zRSmsJ)@7xFMno_ z4Xi9nM^G3f>m2)89=o`b2*S+M60Ef(K6ci}@u5Mb)#G*)kbdEXf{-Fx9mY&$dN*;b z*A7e@o=@TK3*2>^$3J#<pY?K+HeUYaFC_M^ZD=B-<@%N|#@>gk=#MIxdenf*baHi{ zr6xn{?Q#yA<73`W1}mQ&EKrQqutiB{s``e`hZ?_JsMAjHVInkVSNo!B#u`T&(Vu^- z_Loh<zEEep6(`(@#Q|Q}ZN~eP!H#659F`qoHgCUT>L>i&reH2rgOJJNrT#|cr)~6v z_i4Dl0n4s2^bZ1>`FQvz^HYwdbYJizE)}DYvJH{9BTbN}{17VBdtBhrE6B3D2#792 zye}e+><~3e3|yqGSTf>~&|t=ocZ^F{Nrv|P8kuOVcjz^p!|t(!Hdr9|mY(y<ryye2 zJ1FUsa69dT9m|BD>cJZ^YddMeEQT}%aoB30Me!9CTcI(o{BhF^S{1)~yI8go$sPi< zwL=P`-b)1Ic&+O&`kpk5ShXZ~DnwJi7Hw#HnpREmFO!6cy!&e7stS*|@pr)0dPINw z65Ci2r&U<J09~GO`gZ4R>y6?!;u<PJu`+X($(9hk+?2Q!<jYcFuIavUD=vQDD}LW; zS$hK{{9JchfB%tZFRKybT<?_?4tEe2MCRl6U#P%}L5}Q&%{x>6oa#)Uxk#)@=qv`j ztuuk>%=-7P&;ie!Z7~L0?W|hLvcA%M6wU}r2yQw=8iLS-SZkR<YkEwWt1aYBHSbyU zAx8DZ;!d5ntPPMGKhXkNX1wZSqM&_A1d(UkY+BGja9r)5qo#04M*pmV(hj5Gla@W9 zyaz>b?30NCX((E*(sEHnYW+8N2gKn&Nn8_fbrx;ot(v!SZ*;@P@{8#$$1<*`uqXL? z@So*(bq7b0C%zV$^Cqrx*0WRd*C9_|7BL{LyAGA!rNprH_Rg>yPFMf#bDS>Pxw|)N zH66FDR^wK_gW7I9v~lhn#>|4;l7gs7hW7)9_jAdi_0^#LkzG@G8KN^Vj|IAkg`H<^ z{OY9LmIEnJ%>wYUX+^M!7FpWWxNo4~hX0Zap9d)96E>YDCrj<oFnG$m2OT_g@w&qK zjj<mXEs=aM!cWl=ei*a1sg_-sOK%PC+hpITTS`$TaY8ST!lw8T--(our|>LzZ|{cr zWH5T061ArvDj`m5QZ4m4X!Z|z3w+9A-`G!P`u9aj)?E`TnsR6K+!zOmhI^>QCR!HO z4C}*{ib*Sc&)oo3+wrV*p)I2YRCXCf3ZaZ(TJS+pk!c0>F>qKfrUt^;QYSm`qxV?! zFUfw{mG6MLcHTgd<8&Aav(~4I;}Jo(dSxeB3ahK2Vt_AVbi_`|tR&Ea+o!EK)a{B- zX%gis)u?1XDo7=8QpZMCdS7@0TSHbF`Lok)kBcY{KKj7pOj>Y4u6MMCXi_UJ)=p4G z=hAQ8HBb0MN1f!-bvV-jHYV}kk)g9?`hMPp?}Li)m!7r+GJ32FN;NcOUlvEbw?nTj z0FzAe7S4|9Pcx6RSyOJ-`7qIxv?dNN6W;e7^wpQQ8`rK&0|`49I^8&nHqb#xo-#g) zNVP{e7t;2>-oD$}qAM84_d_`UdD*ggUGMKb1gTZnsV*}?dzM0hUHmHzIrGJXSjtV4 z2D*PmcXK-$Juo6SZWMl9ayP<>;B+D1;7Fd?xqr_LvvDcoFLCd^<wx1cgY3NFE?`{0 zhN5I)aa8Jp5?xxr+->;&ec?F*EnCSyZ?gX>y))SpOa;?EsaRM^+}Fz7seA9SFYicM zmGussTMdx7?j`O=`P@{X>??)%JeN^9+p!XJg#I%i$lLPU7}<|2FJeiPkkWA-pFSHt z?Rp$pYW6LxrHLCNt!2XqpM^9j6@}Ue$N%Qmp5o#rJryW_uc7rG=IVtc-fydCGgV2h zNlS0PcjV>l6>FC6Mp9GjE(|L*rWK}&^WdhbcOpnOTsdkY(d~WAXj9GRYgvgyRbb$I zOB(vz`NCsClmY%qbL0#MQ9V<r+)+pagI+pjoD3aHAUn4E;Eum_NJgMe1Sg95Vl7Qk z+uI2pJ>#R1OW_*B7MvUvJ$Q1ga5p{QlSi?k`DqdKW-SuLjefar6aO{H3;3Z2*c+_w zDckZRl5I_aWueY{pxSjFUn~l2paKf%JT&I>Uf#_4mQ)W-TuB05#L*{x@fErc<JK-u zXWelxA+o09fpm%x>fQ?xlxy^l(|pchH+!oyI8hRfB!wcV_f^Q7%TsNo=V2(izc<^{ zt_9VGcPHeMaY7vv!`yj)eZj}bJc}ULnLC=6qvou>F`<#*O6igc#K(GOa8S_J2J=u4 z+j{a~$HMEo0K@(;{Q!ILTKRHIy3Lwq78|BG`zt&7x@{?jpR(rp;!+pV^r=9s5^KUA zg!pYmz8AKZ8j}znMIp>Mn^9aP;VyTvhi31mKR@dG1g!Jpe~|mZ<L3q7O^MlKuVibM zJX=mA`KH1rhA2o;5yqK9kk6z}w~sMCeY(R$1^a(&KHY8MD{i^udK*k~Ro}WN&MB#? z#Bw)zZG0%Le3-?4;q#@*fYAzCy;@E7U}SDq*!Phrclv0o+~ZFvgiTP`l9XnW2t}h= zm>3mjA1iK}JB2}Qrdj3QVYf)rc}l4*lpCydJO>X?N|r3z3Rej-CCwkiH@|u@YX4IC zT+?;PHGk)wYcIf+_V!EL2=4Q1@ziI-*QncVqk;!Y;pqXjmPjG8_4prTNl*pd$1qK? z2L7&m>-Xv7ko$yJToe(QjoV<_yl)31KXknQEeOl%(I}70%rh`;uHUsb)U}gkf2E*g zI9!`g*y{46Ku1Rtwt-+?T5u~eZYLwrI7>Va@<28&+;s0HhSs&xPU&u@`&ZABsR85} zoSiwO&8m3gU9Gg}aW?r?3b`S07UE`baAnS15x6sQ)NUFV<|^UE#^WUC?a9;(6r9aQ zYSTDgu!{PMQWjQ^BvD*4A1O;ld_xW%ZRF|BO_l<%4xEh9jdY;p8XWM;90xudzW;y` zC$se+Dr^#5R|V-zDNMK*{iWj&?mG~%`H2S><lwv!6h@8lBUKbOzmk>x38N($@zClV zeC4Ur=i$)U`i2&OK|$+E+%>a9gv(;fgM{wTNF5lZRH2}Q2>EN;FXR{6RIE;AS<Dao zbjl2hwuW(~)vZL5wkmYqFEyu+Dys@`x{LeI>+4snzsh7#*6pvMO<!uA{u#BOl)V?t zZw2sVf{ys(^=ICHqAobAFKxskey|Os2$)8ao(4=)YYliz86JI~4BK`_6BX9uE8{&U zgs%PM>V*(4!uKGr2V|Qq5rHDIMLAP)&Lq<C9R?I8-`-rTvWEJ+*fuE8uBpQc)W$@0 za>5|vmufIXqUC5zfz-{Qm<Sw34I(ddo<;~99FfnAYXU3}TQ1XEPp<;jdkm*tdGNC3 z)%W6*%S)1VyjYGpM31|C(iZ2ukS+{q=&_&c=B)o7X>u=L-))R2;vC%8?!Ro=ha&3L zqC#kiAAR49eNR*DXfSid7v6yNg~BR~#lvZ2{y{s(jmyaea5aA9{<EPyUr}Eo>H;s) zkqgNP109yBcC>K|s|imp&{9!wS&><)J^a?8I<N@wI`;dak3_GmMc$4owZ-uBXzU=I z|CfMhW%T|d7Vx2KSAWnhol&zPB*dgl8qLMtj^9b;k*&F&$^GZERaT@GXU{r`jmucr zvs7%Tl~O-iy_saGIR8zcH9fLM<$L|q7`KX&jPCt`*9(3Ixz>4{&Pa9mVMM+3MtQSv z4dlZE^B>P*pUZ~d3O;S=_HlfC+*2vaHdT{6h-WAIKh_c|iH=MDDl}~k_oZBCAtwAt z|7+I0(+j)lQTp+7DWe}0y&!hok_*)a<hRt+L_hSIJz>ny$L#%Iqd;0AE?_0C4k+Vl zdf@l~GSlLS`H)(eDcBLI<t11%s`a3=6-_m_4ocaJDs|sft2>Pza^fG1e)`k#R++_J zYAG+~Yi7P>cZOrxEjI{|bKo^tyw*>q25s}3o14OeRWGSPY|43V4t92oE9`Bc>un^M zJK~0dD?m=cxcCV!Y#xH7IOOlla6ia^m_|!I5K9o@xQbg3QklW;ZJ&D)_GQI#PkdT7 zIU-dqZT99l9&^p*m<+KeJyVKXxRi;;hq&lMi`zsx|6)Rh0Sr4dZe?UVLOp$|B)N~I zm|;+Ga8*JSRZ%(z=?r$dLK$J00jDw_AlsMRI&SZWVaMiVBGg^%%gb!tlOgBUMTsHz z3RZ?oLqL55@LQ@{hSM2_Ziv8-1^IC<!6wJ?59pnqZ#PUnY(@L`07#d^?*?cnm!~_| zHNV?GJ3onxmKr}De*khnf{wa`qdcj_fDu<0psrdAczxdKrULN;H_O)M%T1Qr<3sIA zAN!|eC+(EyQRMbLYG^iYO;>q=7)GH~V@A%ascXQJhpr;sQaPti*1kuJu}F)tk9)F1 z@f>M_O)VkoOLbOSnpN2h=R7y;-eAj#fISBuM&=|Es^`J9CFMXt`RqEOsOm2f|GH^x z9W-L)hfzvV^2Iri#O~z_hxnbs_IAQ>Q#ee_C+77=a|B+;6*#^0kf#R73Z0p$9$q}D z5d4ViaN--~`I&`<FdzfcOE=Y94E+k|btEERaE?5_pd=NY3&n$MgGQg*Qx0zxQ_E#; zWdOp|OFxbdD`47<*iY>=m7-Sy?{3(GoBY6HxTz*^Lg|-$-Z~RohxlL&cJUE4SD9@w zVAl**uCPl5-6JMbQ5Tf$X3cV=0)`sV3AN%WnbFd?p;$i`6@}WWI9JkzJQDr1PR=+? z6b@b$hy-0z;#S>)&+0y#9wSMN8dYK$f}+(|Tw{`yvJ$PK0XHBXt#OjPf4Nz9H==s) za<a2sfCiOA{$V76eB@$pd?fUXE0z+H4Qs{#h~^yD<rbNil$Dj;>?$%w!=5ZZdjyO) zknqV4#uUn1>VnA8tE;O`kO+p&NcL3~Xu-gX>r77R>RC?Z;#wyAx-r|#!^iiZ^h>wN z0uiK8{Et6RvcqG)n`y(Mn~p2B{O#K}C3^SD#Gj4kBf#$p9yR#Hf!VDPL1m<ymMzh7 zHE4v9EFs|tpVnhCtb|TI(!NLy_>MKvxk}1-lBq!u72Jo#`$8MUw-X<VxiT14ly8*2 zswpoZ5wdRSF?<fF3wE<6`lFUo(|-vq{NyGY&Nto!G<maYYq8zk-5k@_dUy{H4}fV= zXuCq-OpK07^uHVb41r=N^SF(Z6Dw8d!oP8#%KTqI=~$tX@QLgN+{y38lB$DUzrXv< zXnpegE8p$U@BVA@S?S>cxhSEy&DVqM8{`bw_??gA=`7eEkYNL*C_ye*W5BCF0GI%M zR%l>SxwD`f#lZR_nDRB+rrai86m{Zmb*JoHNOX$SSV7le$*v$Xf;XL&q5(r51^@5Y zifR1B;;Cv4<-M7l1oy$(wzy0x4J*bl%E?a>k`b$hD15}uot-~*fZ`8m?-WYsGOfu8 z2;N&;(}7huQ<$ET76%XS<|ojsdI^(JUo6cXjNbbFH+%t;9Aq72m%XtVb|v{wY-eLr zL93x36X93~@(#8qxTXie3c$h5jpJp>pOjmN!3yTV>}=3NwN6QOwY>zT{JYBX{4b3E z5xt)uZ>fMhjeC*<KJ<v7o?0Fx%<6V{Fnp*tCf#+2q3uA{;iDAbDlN+ro={4rCJ4t& zeZTO@&zLkB2Bz8aa*8fNQkS0RLjO|vg`3mYs@wanf0}0lhgg3)yX+la42YGCdk5kg zsd6TZb(ty25<squ4eO|)SvD=GRS8=K$R&pYFI6I@U9{23-G4GOetv?r93;?b49m~Y zud3HZZO?IFc0c*^B|k!o5mzf9ud*MZQy0#AgemP94J0}O+9DB<RA$doqIUiz4Q%>r z6+Ft!40bipMcqYMbWgAJHFX^Vg>#VpQ8<62W%r8wmRYMw!?p(kYb6@)a$)rYdk+mv z#HSx$D<;dmi*uvKkf4=PLol6$`8F1@M96O$m2Q0Lgsj68d^n}!rxq6%KjiYenoYDJ zhrxh4S9W&xM*^9w)|4-rr2H<0W+M*L>NCH7;dp(bH>^*$7Wn*+U}beR#1MY^G8p5V zz7Nep_9Zv*<HRrh-=XX0W9-9;)}`4PV#%bP<TFZB0&z*>zD3ro%z%XgW*Z#YJ~%ji zD+E%*L}8hGu2g<{yo|v2=D1`Ug8RhuOQux_lxJNW<Oda)MOKEc*$H50sLoctVXeUV zQDzH1OHf4~J-D>oa3?_k8ub5C&Ky@QcQbyjYGC<;RUScr4X2oQHnSfolv@73=)9R3 zHH@OI4ptBcl!?)NZzv=5q+;)gq$K5Drii|@;+ss2tP)OAS+-o$`}Brya3P0EZ$AqF z4Z&)ROA8#M)oRof6f<ohWwVQdh*%ypX!0<=P%Q_&*9wVH1PU;TP}2y^^-y<Y7V<%? zvg&TgP@UmoCbdYtQo&9uVGI_B3Md45LgU}J9{0bkyEpw+`A!ebWqH4_M{nW1E8HML z9-k4xJ?UfFjmh%`j}Zne1OVd+VEx0w)~c%L>1-zPV6N!0jBSg8?Hq7d&&mE*@MM<T zthY+2tRm79DjB>6#3GRU(+lebwl*-gYxt@paL`h)Gjp`trF!s#QlO_e{<6%oxI-&m zZ;m11py6X;VA#YaPp4(eygRcxuQhTW?h(Zr@g%b!Y1}apH=Ns&!+P;Mz`Z+&pnlq| zjGLKwh6?l>%Da2eESLO#)9c)z@Dul+e!->1XtwbqefP@~P1{QnfzuZ=MEHjnWK8+I zn`;c#b|HgBjiCXFImiH2K_5Pu{qPc5)XtG#Koqs_9an?(K2cF64ks>JQIRiLnr0Uk zc=qoPl}^vj&=pQK=6WpkfH=QG_f$t6=iB%1Z=}kIikZeav7!buv1UQ8khtv@_~N)1 z0Mn8vPDR(LeWe||E#1t*ZAwtUIGvemD$DxCp7J07K7Q9f5{GZ!{wntfXZaL|l9yDt zZQ|L37}IpSRkPT-HM{-!>27lb@_D(}C>h!w@(MYMo8FE=5Q`4Vcc$pxy=-eeIQG(h zaBEv}>%Ao^OTEA<+8K+Ba<lT95~s>hj7J#pJYO)<G4npx>#R7Lb}_kOeX@A<aY-YQ zq<j|in*Umt(r81uENDD6;Zau_jSz;@*NWzkQo3U@#4zTbsJ`mzbA}4}SHkZz={S17 z|IN#$t+Z`LKyca5s_Ogbr34g+6am6TFy75aWx=oj;iVyK+JMl&n8psiXwipn{Q&EH z5J+my3nE;!vZ>Y&-jO9xrHsKn*6A{DgDnzFlwPogj%X<Zf88Onx^2Regg)c-QI_&U zIQw6uw@L-^U+EPnRR2bCC${s@fnNKNm&TgU_eD~m=2(%R(khZe`kdplg|-o)nPVKK zQ-8<HYT(Bd@6&rZ;JJz8$8ceX<Vp6*CspGoH{7z>U1TCTCK8JJhdj87TRfc#ReQOd z$Y(O`^61+rQ*v-#DX9zBs;krSg4f<f{noZNpLv1fj?E33TsKecPjxC`w0Y74R&j}X zp~y7|TOqyR`nSIbUe|xgC1x|W*C+lY*7^m0ReBU9JR>}?drOo=2vqLJg5a?*eX#~g zWw7jq&{`!_cm2N>Af&|+YzpRJTPcpHYi}1AO{?VfR8F@92VP)1!AsxwCIh=Lc$9%) zQ|1&2l-NZX(8c((dJr7p{VvZ3<`SWadBBwf>|DU(s#DO>#E&%I1k=icNd(R`Bt+m5 z4U<I2O}Hl(ZAP|}J7R5)s<%OA>slyadp#c-#`tlMK6w_|kPfDu1jHMEC-xNa#H%xS zQT9E9SO@l-w-r9KHC9~fr#@*66nx?(_vgeRVLXwpM)|FPt+XNWV<kElPVNR#t{YZv zCAKyyg=actHtXFFa*mA<WGH<id3i|{jl^V}UO^Oj6W&_)fr0b=7zrs0kXS}xDux$R zq|2P{2Z+`nDX$p3cm52}M*&yXk*jnNcL_AhxMLGimooW;^2r!La4~5W@=AAx!ZreU zy2Z2fAQoEL=iY)Qvw*qOi2jVr*%vc2r;xT;lNAb-ltEH0GaeK2ImAz_E$Y8wxA>kF zG0iW(yU1$g2IyW-ioUSDtQjadH=IN*4<dUgb5v@*5$l2gp7qrS-lxU2kiC7C(LD0O zfHOY?QCvM}E>}_C4ck$7-tFbGRjPjjvJ%RD@D%rW)OQV?SXxlYBoPTmKLSdGRpSg5 zcP2HYcsDiCk_>`tr3(8ID4^Y7{0Exr@WNq~lF)y-msM6)#!k#w11fr>&1~^U6<{(_ zb5#LvNN+pf``EW+YVmn)n`}HBs?CKkxAwKn+c{wF03L<Zc~`ku3eGfC-s^otqzUJ| z$Q9f~_0oO!#AZrq^`C!#L>vbogVn^pL7C5RqtA92o<wJdKHG;q(+4L3?S;Sy>!Z|% z0i9&32n36#vRhh*Yd78QUH9K6UPz9^Uux{X(8NFDJt+E6Nao{Sa%&<b9}DS{{|Uv8 zj#V-x4o6nqIq!RwY=t|Vy@pu&t)SoO^~7(LC>~1~8^CRN&WK%c2^X|uyIK=4d?#dI zgzn~}a_82YE?)jRv8Z4JJ`l#VDqWG({+|^TAP8P<DDj(zpoo*ee$?=wh*YH(;~@*z zIu~uqSd%F40><1jqgXZRfW^J2Awx-cS_*EkuAErfzIn@uNl*&x1qHx?=tvp|dRs+~ zw$%|2PR#Yl(<9l3fDamNw*ks|(EnnK>K(DyKr}IAv@hY~*_5KX2WjqxFT<2g06Mct zI68X7L>|A(_OaLPTs_6{`0s3g*i)e!Rmf$+_TG8(%!&slXFe)7|CV193{(nc_ED;U zs4q7YgJH{)f!E>8#`e(xn?xVe7Ota?srO~h=EK~#g<~Y9>;+och*xLYR2Xd-R)dQ- zPg^q)=OCm6)(Gaq@Zwez%@P$GVW4xL*qDzUW3+ool+t(e%_6H^+@gLV%de}S{%hJ9 zExGQFCUJy<1p2`pSK#vx{1}?@T7BdvNtRbuR^~d+GTubOJ^$-dmznf;naK?Ysw(Wb zh}2Kf4upUZt*WXzuy5TR*ck{Yga3t&hRPhu1z~<<Od^2J;!x&tQPni7s;UA}#aEzE zXG0;^XY=*8@0v6>qXVbBpanNSCxUV;l3~&%4d-c=j5F^6tMk)!t;+(d9K`j*U#wiL z4U{o1Or7i`O@o;Ve=f}vnQ3AgmDY^mh=h!mPDF!b{NBrGHR?C6-`||t-2L*XgH>7i z+Xa6Ol{J+pyyV%y+5sJ-vjH<g8vO5(J(XJPJL)Mno_ygacJ--!hbt#-A=)pZlw4r) z15G?`loW4{bU;9W-ggfFJP*M*8*Y6W3p+wKo(s6Zp&0y<`g-Sy&d2TqUFQEV0f}W_ z6f39r!eYm(K&ozGc{##=J|$*6><D9<e4umv{O|XF(TU&fmlpHr-m!}nR@q@R={x&( z>mSXykd)WVH(-2#fr-OCoDciDf>v>&q#hv7ZleL0-9oQ6jVmv$Z$R?2KJX8DDXa2@ zlGB3v`xFPYbqDTxWnEZS#oh3dhM_#Pg5B_<5|2B#L0X~yu(b9hD9n3$@_q5~8R^uV z=N>s>DX}F2RRX<8JxIK6rWa3<Rdn%xA?Dzg?dRub3D7m|HSg&By78nxcaL9!NX3B& z^qo0HHrxoKFz*XtbYSK<$aP0MZ9gCbZgUS054eRII6N}LC26n?U)+@avJT%~sG#Qh z6S%fn+@2Qr{-poM;!M$fV1tfj6MJ)%+r@q}%;4T%FLyQN!#Rn>@r9bw_C;$eVTpNg z@$(XnH)PfMT%k$nUwTXwj(L@?j$^50b0_s|eAg2-1D-MXk09!}XCf1j2*I%*Wq^J> z&DNqIYx$Q_v&LCYRH}zwdZYC;S+3{0w|lV5G`E+#)Ob_F=M#Mp0Sg<0&xY2?Wmbn* zmM_Iwy-xBRIH6YSbMX^H5o_!fJo-Ov$XkKc()8L*{Vp+2zP0I6-qD(RifbjJ<O4z8 z^y|JKJiMj}L37?_mJ<9u^NEi7t0&-g0YpXA1F!2@{aZAi^HfVhF!aHJ9FTPS{DAXK zUtd4iXY#fp?n^#P!8BE#3LAl>WUa+;i({$+4LJOJ<wy96l7~u1<53{%ux-oCFnC)5 z@@0|Q+Y5`)zY?wvz~&JrK;muo=&SY1QZJl&Tr)ZZ&9kMz*<DHi2}fUjS{O4bOSMa9 zn2PH%?`ggnD+^@*g6jb2fNRs7YC02YARSK@6n_HGZ2O#FMeNxFSdsYSVL_>cKqiq* zQshwT?Zcf+CZxmYumi{23KRqybpe*yTp~KGyB+f0O;tU$(#Hz;ugYveZyf}XS1^Cn zTTD&y25z~Z=$-ez4N2l(R}P4$SA;jf{RC;s_vT}gnF#)pc<l~|0w~Pq+R?_@xs4h! z6Yoa(u3N#KKDLMu7bG!xcs6UpJ%d26uCpYokiIlu`9s~Emw01GY6D*o=V!kiu*U(| z{8=oN??!}ew)xbzj?w>Wva6XdDlp6r@^}~+6|d~MX9&4fRpMbR4_OXqi~y!l#9Pp> zSAoev`nU77-|Lcl`RrgvpVBhhO@MBkDcdIBN<)1I$)I+FPD1k8m=U}((DAITtu>FF z@M<SZ*_(iPm%DH&&j&YR79mE!DW~J>D3eV%OlDPDIf5caaiqq*;f!iqdE}u;Gy6Mv zjl_M8)^*Gm^wpLkdZY{RFz$iAx0!`vrZ<ilZ{>2Yuml4aiM--gEqfY4Ot1UDrmpa$ z&NRxNKQj&$5gl?z9T*c-K&YV09A8Z`Y{tRO$A@5<JP^lu)UgH-=GkA*<_mTiw%wvl z%!}=lg)6wr+OJfIq$5Lvjg100g2E6^w`z5aQ<Df42IoEjcz$2YNpCQq55U08yQ}?o zZ>Pq}nwf8yIf!IBn&(ixM8sieNTh_}50WdN2PJy|yvG$g_9g?TM9i3>V3PFnMd<4| zDlF0|>Fu6_LF-P8nTB$ZWs7oMmo*-0RmG{EnALdsuGkljaV)yhi+x0kYy9A{PXe5u z8-Bli`<DBI?G}umD9P2=HZ|ue87+xjRP2KoPN{p&t@y1tUBye&_zEaxo_AKw_k@4n zgncFq51P#3D^a5d=3?;DHyg^;zJb;E$~P;LTTMOi^wi1F_k0N4Z5x=GDB@;qaAs{h zCU|Ja8`b~IKH2O?W|IO<cCh|19>;l3wzuFNKR-Dj2INj!$n4@ECi()qC5SHGOIeh* zqVJ4Nex^4JRp3G9WuZ_j*vv<KW5XNh3CUA}uDvcqKbV=o@7Hl0YPI{~F;V{Af<T5{ zEXCWpUm&l!bXuuvFtw8!jDG&ZN_zA&1W9-~h0%gYcF44*Dgx5U=3s^Xb{{g{3{Mon z>@|-v@~{k9K_&eUy30Hjyi;9A^t>>VEseMcg~KdlcO#d2lrs};{H&rFjWk4UZBtO# zW>pT&LVT;VVU>UU7?XPCqVec4F>fexIJ!D%>G*wGBhF2L9EX++Q>|LZidW=T3lUXX z5`*FGG_1G&=pnzl6H+Z|lb433k_MR<IMqljFdAjZVKKbp9)|E#GvJDB;QY4hL|^#e zh!QXb21tlN#?7OYW%Zj-G&l;E!e7c(cNy{+nC5mC_tN0l{u5!r@WZdMXr;Ps89uQb zHg_pw!iTJ>Yi|65DCXw{uiO0}N)%Y{slO&uDv2%BAu7)^?zd?X>wk!vaPceB(Ehe8 z!)*;)2@PE0AG57C`?77~>3tJKGbXLJe)DQfvdr*&Qkj$%872w3M|J8<rmn1O=J@^Q zTSH`LB6}%>tML$Yw`6ULx_IzW5xUPLmp<8KgF-J%&@VafzO>8s!@QyfVx&Ab61um9 zRi*f<-`5F$>Se~r&}%II)l+OXRp#!<lq|W>uBH*8d+fNBpMD!5dSMNs&?O}Y_&cnH zzJwd)emP}o;H(|6EIst*yqcMT`f_^$lkU|2P)A+tN_hJ+PY1cYe0lTg?ag;lrkQRa zH$>b|hCx}7tK_1wGU_R2to{~Lh86=pPj7dxR`xUv7Yg{8fV1WhTRe`NX`v1{yE30X z)=6VhQAw0^5zXKG0`NP~3EZPzX)2>BiChjcaZKXsQOjeQH4;FjPO9^qwdcd>)%}_% z{VsKnyCsla_nq5FD*RRktHSwZU%wzr0YoVM04>25M;wKL-{<3JTjQQ03AJZ!&>LSi ztoWt>V>@R#kTp?K5zU%PapNcw3g3s+Z)X_1Lbn<=qp6Gy90i=;^8YBoy-$t{Dl*k= zfmKe!<f4p}E@@yU4jITwB7xfop&qwU7%Uv+4CnO5Q9{O44#JG0NQ>>iw)n-l3d+&I za*Z2D`@c;O@butNKaBWHr#$!cK5g7u_?FBpGw@A*h0VahHapg|wV<M)P<t+t{}9#w zQ9Hwu5Lo4v<O@z`pal<Y;`jTDbQn4vI!2V&3tij?mH~4XEI&Wx8rAIJ_KDic%{n_V zHf{lE!Sq%n=7*<E+rCKsK#15Ybbi;3w62x)?7Tb7@<76NfYSrHgHW=p-L<#Zjy>N_ z_p={=$K|}&xU+%l)ZUWW-lf>!z`?VK=qDANf#*la-L%v2ZNM#a=aqutGavaN4Ke=C z=xGEbX4M~EU^(>phiAW|DDv40#Ak-#+I-`zJL1)Ib%3Bjn_2L+>uz7H6HR@oHhV_+ zemCWA!df&0oQb2~B?48N$^B0q7tl6Ya!AC~)h+Dy0C#JwD6KSeKGv)xYDD1Z`>$+` z%mNlmusNHxyn(aY#Mm8cZqAwkwNWo&V>~QwYz4tdZ1mFXNrbOuw&1t=NR(v>)-Bwn z0tzO-@`G~*&{HfX2ljfDB>&eCwP*&T`B^^K#s_gd;05pM`RUB{4EE7wsEpn%L<lnA zycV2x_DEFMV}Tp~*?B~T4%Pfw<BqMJjIYO=2910<Y-1w;rpp`OiXp_>=?5ksxd8UY z!(Na1;pyvOdG{5nN5HwJ+`v##Ir=tD!9DHEgQRlXYdHFjZ0mZAr^&CFdf!)yb@v@r zNcIrx&Dpf%kd3Zk+BC?o%P<Aag|_oy;t~3S?z5d0`}(0UeB($5UZG)v?=ugwh)O8i z#HlM9)84o>@3pm)6iS2nmB*Wc?Wn<Fhs*PBmaJw(kOO-sg__}zypQFGD{Z5fscdpz zAqMQ0ptgL;g-g@5ex{c7yeufY`=_LFj%0FS_oI5LJVhs2zZi()7=RstjNbgwy`9s< zIG_LB@Eu!K)CC=$nXpvyc2jqJ9I~%d08?)BuERzIj}VV}I^s+h@()XC9DWvUgJdwp zhtuowhjD^sRm2s;!KU;{NZajuv<}9S`_y?zF)GvMGMYy9qU6up{zJnAWhTqD%aR<I z`PcO*Q{}Mz6$oRjXD9iHD<n$Q7iP)O9ToH*5+zfn56%}`yK$F{JW0W|`s<SI?lJ{C zpSb*Mr>k=<Jrfk@vxE>$Yb}YcG3YXLLkIm${Z>g|WKmkEENYOPBY&@@{e5DUJq^j~ z`X_D&xwnl~%55KeY*T2!YRfTF-geaMbshAGYp~!;^U$j7u@IP@_MOJ)8xG@Hm^RGN znW*Mje^(f9e_A9F^GA}Zp7nivRc?DRCJpP``JEI%(&g-r%Z=zlg1rnRQ=c)b$|PYn z??ip81I-%wJ7l3oIVn5P<N~wC3+qi}K&yvR-i2L1PbGcx9-RJz4(=g_#Qtu`qIZ?I zJF_Q34UhK-kb4ucpoD;Da#yQ~h!bt+#Ge+NcfZO-!+>COtAzZS9%}R9xPIjOl5q?; z_0Q6CsFM}4!!u7jv&v(k47`oi*Q~OVLFGaQ&n{Gc(R3>h6C=|*Q9CbkU<?mpc#nde zmBPV$I<zgoKt~K{QinTzQA#4~;gw&s+OT*G+$b293w$gbR`ZiEgvFf(eHWrDPsPbJ z_BvQemLj|%==6?lFa<9&3pT-FTiwrhv#qbNo~Ok9LVPCiQ?CysPVLVyhJG(t^vmW1 zN_7%~nBp7p&!a*ym^>af(Qxv~Ne%|V__g)}t=*nNync7rk>o4!bdReLP^X)Dph|>D zB!8kVhUpHS2#SErh~wt8<|c4`fVq7={d^@J!JGy0t1t5eS@DozzHW}hPdY}Qa6xx% zsB7Xt0%sIsvjZ*7I={&}oVECW#C1S5J-8HSZnnv0pkTj55W)luM40g=m7mb>ErL>2 zRm@aA7xOZ_m1>cr$d5fAZ2~SO%+Z-;EZ!kpgzj{eVJ~{ASuj$9-*$prs0e<hH^Uj2 zNcslaYmdJujD7FRT^B1AH#2!V_Y^-G-cY~nbsO1q9Af!CHJ=UW)c25`y*QCoF0l1I ziapvILgHI@`lkI!bqu{>jc@Bz&CEUVv&{vs<gksO>k@jOr!vmj0xpf)D$~3kKLtcw zrk8Tmd@JGk1E&nXEki;|N^0ZuVP=_mYh>ez=;g5*7E(;wc4%JEN5djIVfOs4LC3_8 z=YQdi+QeyaTli2IQlZL2zdtNGj<q;KQ8ljrifRYFMcf#GOR>Yh(7YFYo#ke!xa%7~ zQ#tsptsQ1cApV=-c2sGoV{z04hLSt~03;0^b{Ow-WS<HoTM~k40a_U0MGZ@Kj9cMX zx0S-O{L_&{ni_QHM_Ro{gdRo_0Puj%LQ?#@;@OQ;KK8I=HuF1Y&RbKFcL~^g5jJ+n zFIU83LHlWm)3{q-sG?sPbbLu#yBB2ZK9-n2Ti#u;=t!hP^~y37ge-eNcSD}X3*`ds zGd{|1^p!dxW+kJl9`_Q9KJXZR`Xh%EXP-r%szfcsx1(7Q!0}H5vy8=bdH=Pb>lUr~ zxau@KpnOBnPlgB}g2oxsbJkE<+ctj_@WrzKzM6qy2+atkrZ$o5rZZXJrSW|)*Gr8N z64%FDOc3ijf@;vh%!g~xWO>by?Y4S!@Vql6sPB2K@`H;?dHL9Tf7Zt8RN%3u`9{A- z`xgFbr(Mv2Zt(T-k7A*H$lgqMi0@dKiMf?fG$kO|?~4fjvaynHcHZ#G=d0U+WBg); zG7x#3Au=5k6r20XB0qQTY9loumvqgJvZFL9MeOhIk8*vYMmS>;i=Y3tt6!|%R^N9{ zAWc*WKH-o;X`XurbCfcHmUEsxNtja9RWIA7yeu1AQbuuiUP^RH>o6;+rHS_?3Sn2J z)!j<Q%?;rdtJF|Tq5oh_gRG19L=648&hOVX!h_*W3YNpo53@RQ8q-%9_0YAzX&542 z_@|4FHYZz+e+yn$T^=@8bm}fKE+cI+T$)kv3089%j;l@G>d9Ys9JFkmHOLJZ(<Ct9 zu=V|Api!dNVj@gct}n%G{DfgmvuO>N@*0dWjTxnbD1N4c>=MIoyxW+lp8%;rVtkt3 zU<lnbpH-MB!9h;2yRV?~MtETuBLQyTes9{QEQC~*%-vWn!UQV=87Wsq&MI6%wnD~O zTN~W?L8rO$D~)`%M0ipL%J~4iEqVgZR`L5cYOE=o%GlwigPQeTySa7B3RYFb6sLEX z32${Z7qeiGw!8+tEeT|vq?hW3OO8H%ZD$6JF6-yHBafj+@@i&Rgk+&FlnG@q%nN^K z<Ptv+7j9ipbBs*1Sh^+1ZC?QKj3FT}t2I2mtR?A4rCf}Lg(G9W_dEGH2kyHkHK}YE z3C-z>B$Zg-^A|K26mFi-US>9<okC5x7i?%w+WAD+LZ#yaSQYw`{@3t&dANf?CMet~ z41~jl;y7%cC<n@WW94)&_;?sS@D9+%<eI)#*@2h3gZgZkPTPcjs5`!3Bd@*C_Np~^ z7-bQ@YeO6KS)l9qkm9Gy!GzLh@`A6GG}zf?LxRnVSU1tL6BcVgm-!b3Aqy{+x{_Ct zmvCussr(<5r`q7zkX*Tq)?lnEPoh{-;JNM<KE%2tGU0I06=RBv!#7TNM>|e6#rtm6 zMnRKy`(f7wqk!LJ@T~egl7!&FpI%g%HzB@NQc}3d(O_kq153HD>T~wf`LC^%+H$KB zWfBEvm6q-lZl0(wD$s*nX*@z)fPg<n9ZV6p!(UNdEeSGp@3)hw<pp_%({Z4oHAJ^v z+G-d*b;F~3r>UuaDh5iqh-y*0(8CJP_o5zPW|S0>Y!{Ju&SK`Xw1nINoQ%UN@L#)@ zY0Zr`=`f~kGhZrIz*X`tD+zL{FSu#SH|N+O**5CNj{mX$4DQ`A=#$(iRH8BO$ub$_ z=dL(&;cBD`c|fJ@;nf1RXUA5}7IiHX4dGV;enEUIv-Zya5%tzlQGIXwFg<{Dcb9;| zhmN78J48TITBK2iknWV0h5<oPY3XjHLrICD1%aWPcl-UVXT59j7i;F6Gw1BH_r33{ zh73|Zm2He1DU<-%nueCvmdTBbEP@%-Ab2(<UlfWAGCBGMQ)}<&W7p@{RndM#lV!n8 z_Qc)Er$;`Ur;RxlkfZ~rE8ErrHq~S$r-=kgrcY-x5>nenUtPJ69C*h@3|4268<RF^ zv6^+YzEBnLNLRQrh5-QpkQE(8l~;{H%aLwCjyo+TG3sNCpDXWl@8^y&_nes8E<4uA zcCY^#5NxS_w{wjav@i9aAjU0m{6)4ubJbszRCFq(xV2*`teVWG`4yQxBny*3I+Pzf za(6V8)t8i2iToG?K4pOa1@fdvvPHECCa5DUK)DAYWB|?DaK|in?M1Jj`a&onKhA*T z`Vyhg%eQ#m|9V%>i%0J};4?2I{;OTAm|%jNB!-B;&dS_t23i>qV3Vc>C@U(8yx_#( zFCHyty6_u77eQVB`}c3)gO)a(S*}y4(>aza3940qMO)k3HK%`6)D7$JS8Bb#-us8R zuZw|o8noSNeY@!o(~wZUdo_*}5Mn<Sow=ES_t!7$jY!2voUJj^$Zq9g-7Y6{DvtC2 zolsMx;FF%9#O%KtiH%lQU*B&}rYik-XK$~kP$BXk`aNU=(tz-KKGqjymhlD-C9}`f z*s4QsgVnxV2G`YUVqF%{1mt}<yfJEd=REqJB-t*(A3)xakbW~eJ7dGXd7Rr3+<8G( z)u|nP;TNkO<8faHIU<#Dg?hpq9b{JvHZXLA&~c`NLa_6!S!bRYHUFRt?et#rMTK9! zf6Y&dg*Fh(s5Foxn({;;21MX-fQVnU`beT6D-KHsT>0@}QWV2(G(tzkV8YomqTW3{ zOSa?*dD?o~F<E1p#rx6)R~mIG03(9PAK)8hQ#)@gZWPHM=DY~3+mr$WWkAo7BSlUi z6SN)OkG#s$1rti_IRG^dI8e<sxLV|-6`r)%d1g{`4%hJ8kJ0hItjCLwkFRoWK@?c4 z){>%6EHloc0B=4p$w9}2vC(##pLTs@Q(f0t@;HneYt+OldmSXoaP{9oz?(;PKN<VC zMR`Np_Hb_Z{t{X<)w!)j5Edan#m`+L0zd#9e_R1OZ8aip_y{CIb)TX?(^(~7>CRng zCj7E;hx*mI!H%Xk%wi$7<^Jj=>_1QD`~4!yLb+PxrFKX7ii>nm6Qw`4Xzri&`j>~D zK<P)Oq$5N+s{U*J&zEs!KY3*g%;sH0*~6v%n?H@z`Ax4F(D-t6YlPm->swDKJ@Ap? z0@J}~+S=o~w$BBdFrLJ~8?}M46ljpi>XL!3J6Jt{101fhUGrWU6E+wZRUVsapUZL0 zW+UmHq-k?aP>?t8=#;g@QeaFB@`iiCWz~Y#S$2KF&!LLkqJ?01moRH7uZnX~JetTw zX=)HzyJ@&1iQMNM^IPF`o5Z0Ik$Nd#Z6y2ppiIm&I`K(%1LA7MpHO#tWwmXO<VXSk z)7`k0t3hHzLotyrCYdv(6^5*CVYX`VS4RfhM0v4KXt>Rh6SSSRG7nD=d`lQPTY&<4 zP%^zs`cyzIoDM6F6nQQv!C$pa-g>z|j{M#0e|z?w6QvOMQy?VIcY2_lXR*+i;W(V6 zl?kIj_NQiXGR2Isjne0(IJA({Hs?jqg1)=E1B^F%<m%5%G}B!Rvsr7-gdD1Ap~AiE zx+i>Jutu=e<G12U=GA6o6e3B+w@`6ve<u~<*lo<j-Arh#Tv#7Q`3=>y0%x3RS~pew z&2R^|mb`&nnWYePqo84#(*V;tUd(aNb-fycMYWs&JG3S<*H^XKvU>Q$a>3<SbG5s+ zHWDtfE%V`#t{wD=?F*sL-qX0n^1o<j47_hA$6j)z(=|Ym4PT@0E%LtS%<~=XDa%-i za^f?GJi)b&<kT1)SV+-Udb(#h>y)eV2N#a5^Ar1bWqZiMzC?~NWbUpT{SrBzr}SS^ zFm<zA?H6Prp=q?w+v~5>=o`HgSAt#<FC}slf^!_4?6ZLQ;ydDMSAF&^P^l~L*e5R+ zdpt(loysg5V@>wn9UO6K-S9E@@7MTtQw+C{DEY{qG6Y+AMil{qH_q!yBh3Df3jkyT zLRjo(fBjThX}?EzxXfoF3Ep%YwvlIa97^PLh+!_`7tktC_|L|ABUb7$+(NLU`@b7i zi#-ZsHgKiPTRyO!j5O^2^BzsR)tAV3TEf(K(|2TuqmTw4yLG5CJim31@XuStaET+D zyxqhJe?*Jh-_26izl+!`|1W@%E`X%r{ze}gN?WlUG5w-m4xg1vje*ZuDk%NzP|jMX zQ(e-cxBV6C(-y=lURNhsmLxgP*T>gPy>}u%&*>5;NDH=Yg%MfyF=Irv0$x-c;(P|? z1Ij03Y*OqD6FiPPZ9IRAQ&A<Hl&0&D@pgv)n#Z8!-hBbAEhx2ZGvh~Nz?x%*!tEp2 z-+~&g#HMZr+i8bXe_c1>RdbAD!Lzetsmni8^}jaLgdy`@BG<RQSCcGU`;#wngI708 zt6siLkTG($VfBFNH?tzwsre4ZOrnCHm++rg=HnVkq}05fAU9x&NzK(OQ*e;N~S0 za+9~y`O}^+Of55WB2;vn+kZF3zQ<?J=k`+hVs$Ma8V9`EP3k~4qmvo#So2rn!dHl} zpY~SEJcO&&`43cyJlx4Azt-+(E98}P|8u&a6&Ju*cEsC#gX+0aHE|M~Fs6ZDr&9G4 z%=u^594Tc@-#0%C2)-VS0UG=4Bu!(m)MeF^`Ksi*p)WUVh%dDxsr}cpQKgToovQ5; z2=p=wU5j?O96qZv<4Ue=5VGpLX}vwARjF*EKEY!&SM8comx<x)n3h|)r@!3f3yc+I zY$2?)Xr}lQhtlQM&yz&haF6GIzrc2I-Q|j$;d70waP71$eH!BvHUUDa6@E^uunS@Q z&K-;ldS@wfO`=`}Uw%f#J;*DDpMP1aue*QPx0f9ln!o&jW-bAfrkMHus$QY_wQ<xu zikG-pk})n=I-iTNG$-hl{i7DX2#z1l#OWad-hH5O<gs3SH;OO*Z#DNaz5Cc1YQ1<Q zW!ZN%yQ;L(Y1RS5Te-87sc6|X<Ch|=U$<N-kwnJ-WhS^t{gB&&;WQ2<-@X5Pc_&R@ zYW^L?q(HXXV!*6nIT7`F<frQ$8kDVkf2@UgqP4nrHuA9g_+;Inses4Qw@8U4&l_#z zD*Z~&+JTeXt_k1=_pCfnx!nEYfPF$u?Uwl3e&qbIv~jNe;;l_aUP4_VT2lO9?cec` zyuFZ2t*-I6%q=_5c%6U9nh@a}u>Y$K*tq#v%RkX*P|{Oh=ZV_rwpH$fcA_KMoX+`3 zT&8kLS1G>^|3jQNf|O?ki~T3o;$-#d*I{Im;+`(9{Ks8hy^N)(@x1MRCmjQP!*YVr zCvSIrw*u%izIACj)3kOfr-H!Tm8F>ORUyIW4LY+kA#XM`n*{}ZJjmpPw^z%x1Boe} z-VT12K287Gc&*^+elLsKo-F^~lSb74dVK9!C~<AqW0&~Rc%9$o`wPF~*(pauv6u`r zzC!n2*X4eUq<p4Bh9CU~oo0`uw%%STc}5@nCK}&F-CgJJ4Bh`p3i{_T{XF;01Kwt9 zH|@N_DQv1!Li));Y0l65>Z@-b_@7~rYI-itTYO4#fnL|Dt#*&`_DNQnL`h(T7JbB@ z5p5`J|M9*=xQruf>xryB=1SH?o^#9tn|Ni>4+wb};AoVZ#f8Ua6)>R{bZY#x)+#s0 z{a4w7i%3&gZ$4-=dHKpdq8|=WC?;$~G^>G!$aC$@H1LVy=ob|<3opJ6_+uQQmt91x zk{Em;x6hNIv|80Z)RX*Q-R5N))n9iqlnC|+R#g3hE4#xdtuebi8*?h)1XCKN{71|u zldO_L?T6|j|NaFQoR=TE%K1U{S6=0wmYLLpXntz&{2RYc#a_3NCIE!N0-p)InjOPN zRUdw|2|yFs@|F11lZ!!NTEh+w$pYy2#uOUUpmY*u#3U^>{yY+=#Y@mb1d3HK@&T4# zRD|ASs^wz$zYF}|FHL6qso~{TWkm&&o=P0M`Qx&Fj2IlyPsZ7gpCFpX<%l}pni-{s zgF+T$F{YK?54tD+yVn2vqhWs>1Jq5Ev$K&~TU&D%Oxq<C<sa>oYV#bSS+>SNqXL?; zplGeD1K2zxpdhMnqyVh0!u{W~v<wT<#7LF0D_YMe{?ogu@@M`JnIf^5S)#3~A)!i^ z$~?kP=SMo5>UaJBMLmAf!^zt&1U~_=Iol5hY;(R}lQlbt?XGaeaMO4=Ks`M@1pyTo zaM=JaZMC^#X%)-?(a<ofD8K_BieuiHC{)1iA@V!lPXcm3p{EkCBPRcqf#o(oc0o2x zF2LJGv7%C&PiAw>DR!g*=segU0Z0$Q;GdN<lAD#4OU=z!lr%CUgPsaOK>?g0c``)+ zlL9y&2>PRoCd$kEJ>iedFqp>ncm751tRtPgoK3{uW6Gf@>LNOd{8IEc#RxzI9-M1J z=*bvO66=;2fnJ$GYXC4~GNyozgH-V#u=z_3ADaZpPAtbj-2k18zjvj=0z17T!Bd~C zR@wZ*y@^_s&1Tsi{#OGaw+8s(z(P!^BFK&Tr4<wC)O;DT1eBdfEhK)&UhXuz_{*$Z z0O%R7=d%ozE-}w~^fuQ2^m+^(vy&G^xpptmWEVpU|=7S$<9|OnkdsWTSqa4cl zKU5v%$K)?2Y|BLv&_>`rH8s?n4%=(~Po@kKckpFTf^HysToXQ8wCCG*Q%s`POn_9G zuKP%7kPNPySK-#u*w=3S1Z+%z7-Yor`SUd~g8%jIj-Y&74Tm>iAp94oT3^H^@h6uf zMHQH!g5fQeK>Cm;t)2qerPn>pvNu=daHKbN+4VFSR=b6h@k??376d^}?m0#Yjs70X zlYWKcBoDg*{&Y}n(G#a<x?rjg2GoyAK!ERGnQkf0JS!FiCbw2pz*F^?j8~uudfFVx z;V#M=Aoh=+aI<Li@+D(7%k0u2P^Bu@#j0;#XJIYY6Gt!u9t^K~o!#r0;tTof1gttD z3)TM5?#ap@c71kEnkxp_d;AF}DBBcJs#{|u`s@E*9$v0YEHj(Q-lV{k1wJ{_fP3Sk zl>eNJ{hoJMHd&oUn)Q!^3+Eu#hubOX()^QP5w>a5l?h4aTsgn2bI9yuuf;VBLzIA) zL>O%FO7kY{G|Y+$(E9;q7|;)P+{E8D#vK;l@piDO&m8`+P2GRmhQ2^+>OFPmFzO%j zSd*INeOG=k%-PtmwI2vwz}S#tU0@xPM9?Br-Ow48o(c4<NM^84mDXV)8lofz^I{uA zJ46wj1N3ziU=VyK&R6cHXA=d@84trp2L<C((iHBHN{rR(2$;4}D9bAA8bL*@s`So< zbss&Q_J^;>=yOd8Y<FrmDa)}@k`89Ykt&9;u>5rb09R+(y>ad42edh0>iXP0^79RN z{&DZc321o^n3jnu9SEZW$8Gg{>Dji61;rAI&Ze4`VkK3S!4;h{eap6Kr8!vji$1^7 zX$;*b8sZod`deu-JW{t;(Q<HTSYb-dBR9#sMw=0qiji&36s&$P)kem0K!+(ubb<I# zQw%A{PtrNsCu)1MP<IM%axW5|dhd{n@k$JPn=jave*wi`0cp>M{>IqwYtSWX5t~EB zUcXcE_sM?dDutK`S`iagXM>8?n7&t-GCNYl+A78#Ix6zYvK)9lxK=Dh+Wsd{KCDPn zD^gcQtMw4IAKJHhWRjv`rs6~$(fPMDZ0N<Zmy*ouV`=n5WKxpIbeQ%<k(0ZvmVZ%x z%6^RXkT~qq-gP@8NWs8G@Z3px_YMXnhpf+Tp+wnqx#wIO4>HB5C51AyYe|3l08<GH z4$#VH^?|P>#UX3-tK$-6@sK&E5OHLAInYrsV8Vx*R`oS@YFR2B6F=x}VC9DjFDTnA zsaSaiDGDeZM$+0gGyaYp#-t`9NN!?4+-}z>3yh&tFGZKUSKMQf>YGJn!iwvqT!455 zB09Lf6ni(J%U!HPw>|#&n14-i44fEu9FN*Wg;!H*zuh{F+6eun{je>Y@oOv>z2eY^ zKj=_uYUuWNasr2xtWvg&=r=R3Uzhi5!Gyl~Y^<is;$j>2^~7#P9Xx4j)gvD&))RPk z9k1zzsAk)W^>@sWQrgGzH~OZOK~zFh4?g?}=d|9pO?PX4$)_SRQ7`d=jxH!L<P@30 z_E=2N#o1cP%;PpZmb(5zyi=bobzPvp&y(z`d*_l8(L;Ya0_BpwSeFPpac5hSJMKfb zVG{+<HJGBAa|qvpc7UEGXzOD2FdX8l>gt)vz;mz)VNK?pz9~3!*U`LyJCPDTyB+u| zk-_KjON>vPF%rBAq0me98bPvyRRTyGWySc_UDO4eYw?5FL4i|rW9W(}*OHtQn-7^g zWMB$f#e!uH=PGxjh`u0$u78Yy4gV#wDE+M7c+b8sE0RX1;*t?L(!V1C)+S);{mup@ zh^mZ2lrbNDlwA5QpV1dg$8@>tSeX?HvA=}y!8@3b-$Mi%iQQZuPUQJwE7U`t`ktIp zFQDvtHFxt*NpN{|vOepDROrAW!thwX<;I1SI95+?W#@*4$%4>Cq%d~s)G3x;G8+*Y z5}_*;1B}lZ$MvGM2=3@Fe)y23hJ}kjah~`bK)bbs6HWtsIO3JxsC@R>2v)w?u}Cfj zF7nD0S4tZwab$Rk1K4w*LCRD-+EW_{MX1fPtoN}Jvwf+93^p-cu`wK<J@<pKO`j5g z1tQ#9p|x;_J6PL%c_^O`8x7DyVe6bJL%7tR&OQ{b3yfT8IhCxW)NCh+BZF-Wd1ctC zi%^0q_WqOIAP(@QV3;Y`VM=V*JB_q49Z5i1;v!QomAi0!w{6%SqYriwB)UzVf%lU4 z!avtWOxyuJo;0>j&Gp}Fjd@|30{P}hi0;lpz4HqjbeKr2B>OGXe`7q8Yir|!XJX${ z&YuRqWN=#(9%bV^{hBIXa5HU!^I?LaNJ=dz=3K&?NwuL^ugqvAiu(Nl)5J2O70i35 zBFOlSBzVawFWb7Q=!ZCf>7|p)@cq@E%Bah~x?dCM6m$UH<d2FS>$-2Is4?KG<5QAs z#%#H=351aM#Vw%0sA#8&;cAMtJFjZtdB-c^OV$O}Yh~LRSZ|uFaKrGaRule~Z`Sfl z;iWEm?SmY5sb_xfyp5sK%8j9W22WcyqK@9MqKYjj(}84KFywQkamhR~D<ULevO$%( zi;wc$S?@Z}*aqlh;JpH)?vOyp#?f>hhjelZGa{kzS^>=HsePYrK%?&vl>r-c9^I>A z_mmI#kG)57ji+9iMt%rjU0M^<!ra*|$d*=@$XX{zR&}Y|i9ONxQh^<P-2V{O=E!%< z1RXF0(|>ay*d$_89I0U@$o1hp9v{^E8Puo@BML6h>n%sg6Gq6ezWjILm<tNuQ#1QA zsh`Fzy<FGjCZGWF*&hv!RTIM-47s2O>t)FM-@2nKv1zj9LOs1CQ}Jg9g%5CM#a=l= zMbtqi$E*l2080s*n2?{*of&+w^muPK-9Bj%;A@7g$7I0OmgLqMByjLV2~3g44#dGs z)n38c(c(a+_!o#=E><oFWs+BpZ{$XgNz(1@WW$N4?f+cPa9SRTYC{xYZV|oWU|6 z+hl4OrUtqN4dSCE#<-2=r!pnJnYt-(I-277Phgl{B)JyQE-kWu$ri*YKZj*yvLtNm z1L@ctF%zp+(h~#@wMDXz9#)B?p%}+2gRD-RafajMC+3D-7o@g_J5oCHSS!Q+56RUV zHAb2xyJja2EK;2Lue);%77kCfz<4O}!N{wOmR3HNo#c4B?PYN-$&I=m6r7<kd0*6~ zaTs~Z<h_9N*{xH~mY`0ATe%pU1ELO{=p1(5b$v1%Gb{`eFR3-2K6<5EX+`xP$`-q) z%|6VS<XhV1Kqxu}tWkRMUve+%kWG#J%Jb<PHc#k{meZPTAXI*=i);vm+NS*iMv=ae ze#kskS;tv66Psaw6h}B7<vx&C17Q>07&+eI8xjsQ97FeAp~E27R;*GRAM9d6Wp0+< zwLud)^{IFPb7X?Rp(oG3(WM4Xo~d%^ml-I&jdb7~((+VJgmkI6>}JA5IKf@s5wBj( zv#%;MP2B(Rk$r<YFhO$XBK3}ANv>w>;_(1Iv`Wo4U6K`)^!3gI1o(WOTk{IwBQ&oJ z@-p5{c`nwQ1!t?&t9qZ{k<U}zo3b3NW;(`vJb9RICsI#nS|7jQ<lEk843+%2RLHMc z+g-N(7qeo|5W~nvB&sI&ryHb!aOr7mFg9)h>B?vSyvj&>l`FQVF57+SsOInbzR;^I z!^8zwI9s2kRR9hK&w{)dIDt$vmeiv)0+-mRi{eLpB(}ch-M3zR+!yON$@Xhap(E(O zHe`;@i1~2CyFUsFRtqZhrb#7!^~<AF4uh$pRBCSINe649{cPQj3QM2eo9f?;(bG+x z6Wkan6nKP2&xZXfCi_?abj5A>2L!YAXe}|FY?1)nfg@10wKznQV}p#yfs;v|HZd<7 z1zS6NDgq%ts_)+Gv{2WI7pkleizdZMv7)L*BJKq1v|LPKnYes`Ye`nV8ND**_ww?Z zw85p}yFS=LNN*LTG+NfY`wd-bJ##2IZwNKR+2;HcmrkFVbjjhmcY0JCDj+5@2Hj4P zGlLfIKOV(`L|SbEs>gmktW>6%CvT_{XO4o<4$BIp2IwCNh+%X)93HFi@s%-OZTN2y zV0v#1t*sKjG4KDu`T{DU>L(X>PI3q{W(wx_<+K^Z{*1h~s@_k_$e3Co?huEST&T*? zwVNXZW%6Uuee*mx*Nu27*4yM!QZgKMWJAs$6TUh+Ci-{hZR;L;XgQIxRxVv3*abF( zbQno8q$&tiGLG~#lbH#mefmpHGD+^9SfHaqDoSxsbbE96B=Y9hn^WVULqe#m?oZ%? zUFyPIZVG<=LZeic9y;TKrKSmu&IK3!^nM2@DgH5cBtX@X{uYe}dc&Fi;PLWDsOCo1 z(O1-!m10Qa==vUKr~K`9XIzehuU6jU?JfZZ=&II}`F964$8D-wgnwxdEaSr@#XfJf ziJB4~7l0BN)<GgAxJF<e&=cxT=RNV=$Mq4!vlTB_((3kvO&!Fa(*6(}fX4QReu577 zx<kfCqJq)>3+nyLx%+~FXqDQJ!Dw@H(}uEqji5cU5f7wozm!F_I&gd5Lk}hDRbSur z>1EK)lVhbO8m@?{gu*)AA@gj_G6VEWs_b_IpbCM~2_~UyH-<tC#W{-oqB8{-1ZVVn zFCNcMvm7uj3X&YGHXHAAZjU|29NxJ*d6N_+31~*Tm);s<c#qkR4;*_Yhc!#5k+JZo z@Eze;{3bRg41bmRs7<CNvB|9>O4X#mWwB=?g`?e==_0r|l9iDgAw7p(fy#VZ7-+50 z8eYETkJT%%o06I3Rte}T8B2su;)iCt@d>Cg2?|tEk88-54|}HTTMZ3)?bj0UAUgh` zo^o5?S6dU(Bn4i{pblYLNGdAA*dkNW6F;6bKX<`{Nu*yY$HcOTv_e0GKDj?=wC)}@ zP+^{s_{{N<g@UdQdC^z&$HoC>n3Cb|W~*_S!lQEU4Xx_DU=8GZWuft1kFVMyw6sdx zq7izsLy<Oy#G?olEyi|y@GxGD55_q6vB3A9*%b#uM-Fv!i_zNAR}b+<5wf=kc0DLp z=fx9<KJ-K9UXYJCRwB&3NX@_a4aGRGp%cnxf<zk6hkMrclaUzgr&n!`u15m=(i@@n zV_ZMRh9h7lA2M!{dO5EZbQ`6&Y;$gXd@#}vR69Rpa3c4gZcBQLT((_h^>NtgmiR=I z{La4LoEM47ioIAPwz#Ivd%N~7Cgbx_0H%istWBD4ljuU&)oV)*!@NU#H4);_D@UL6 z@QRP#^#=$2s56BW>tE{%#`5_W9!shXo=b8!j!>`w+Y!Kql4x+fkCIgxKCc_e?&q#H zhAu*gUq%T?(JXa^va%cy-DLIYIT3pwtx`db=)8|Ko(|B{<&Yi}>>2dX7t4qrFwt@S z>3*Gn$G5xbp?00HSGMK`ag8oGO9+#UVr27Na$mo;z~fDF*$g(BI(b!}x}ik(r<0z{ zTtIVN!S=8fH&n9J^x+8AY(oXPhSPc)d$?A;N-!1*jxwv@-x&J2=;X@(?--u5go_Xi zot#>Ofq4x#T3OKNS%^8=e?jH~iRYdrF>UCr35m)&eHwU=74x2x6jkP+LdpB(B*x!; zU|!ucHQ?^o&%V8YI`!cbRi2UEyym*&6B$1~Wzha~((wtu-;bwP17&5Sj(S({loyJS z_b>Hk50T4j=UC@r@a>)c;y;!ASr+CMpONOiK1lm;b+i3m)zsbHa!_5nx5U_G#)mCW z+mm$fa})D6I|tlqv+d>2td1rPPladWqwx)5nQCvaioYM5*xxT>3wh{tb>WGln_@Mt zv9J%wp_^rklAc7!dkDeUvNF()@8tFh&pZc0GSZ_v6SWcRtI66`Ynpwngpr2;(M0v; zzB&~=&_H_V5@__25H3e)P&1(6F6ojwU5j6?Zzi@*ezc#z<i}hd7`&ksn_C?nH`PAk zB^n<)*+&hegf8&jC!jxL__^Mu4A=0SM?6P^r^r8S>sRhv(Ant!Qkk*xN5L3JoRC<# zxb{vxm%fcSw3eO-R~BnJQ5<L2%3t4PLELO*>Q=B`_9~m}4e)U9P^&Qb=zI`0n%?&5 zKp&SlN)|J}R{LZPHR@wsf?f`Ca!kF)K8<FN1>FGu&ml&S`RNWmzhlE(No*C32o+zx z={!rL5+ZVkFy;tSEOiZ^Ufyg4WmSeA;#40-Ww^!?5NG%$NcQ&oEz2+?2=3p2A&4h5 z)UN`jFCuL1m_`NOJJ5cZ=XclX1YLj^gwZ`d06e$#1Z61048ku}G9Atv)fhU=YcZ{2 zlyxEEkqJINPM3h`9Tkdu*}hFs4tf%<o=b)0um5Idl4?V%Swg#W(MW(2%RSXfjg92L zxs7FBpc!;De8p<^U5|tTlboFY;<T5z&p(F+(zG;ztYgcM=__@L(t;=+?o#jiT%~d_ z3~e!GN}4SxuotpzYLAAnP$6RSX=O}8=k$BCiHFcBOQ(+n=oU6!>9dY=A4L(kzFse| z_!_#I$(^UWezpt69O@!miAwzgHUXgb<$juLU(dx-Sk4W|7m8KUGqa*SFv4<fG-A z%RA~++eg8kvC=;_Q-4q3FMu<|25Da!jK&YRb;TC*3|BK|tDu7AiZOCAm)u>6xk&fL zzFz2a_->SJ{EaN4w5!QlQwpsv@bjrUo#c<JPM=Ox?!)S$n-9>FeJlti-O{lKZabmk zgvxlg-~^QYsn#!&?6E#o7<8R2{aw=6X%+Q99mE4KV{}Dg+L8D8(zeNx0boB0FU$Vb zyEo<&&43J6Ql0ku)P;RIg5lrie(>swFA;tmhXWyM^-o7rTN*^>q5n}Y|E1h{Ms5~~ z!Vlr{=O&(=HcfBjO<q@PC8sS>WFXoh&A#nhBlpKf{cDx%NI>DZ;@<g#w$Vohl~0pc zFtXQMS~UrsEpKgO(zzNZD?}R_Iz-Qd(3H-vM6rUt8ov-=BpjBDkCNP(S4niMdWr9S zBp`A?rOO|+PSDQR6v}fR55|bB5air6uPJZq?0zYDTfa%EoBo#iD(d&-DnT_}&IR}6 zN_3;bNW$@IikOM<KINAP$xE(R_W>}+axn%oI;x&fyt>3oCI(_}H~U!a<n>^!JjKd% zISx}<sjo|qw^A%sBffw^>98(G%56+uDohY5iH)v{BdAHbu0RC4+Hq?Pg~^Z|Fq!L9 zL|c>PNwN48t5Ji4(TxjkfubOr&rta%Vr0jZ`Z$U%zqnH_t;7+qM1X-%B?<-frn613 z`l`v0L|?b)?xxz*uW==IT#$j}Q1q95dH;IhrS#N^2ARc|JOASR_{|H2Z?%R#w1095 z23}r2w7<Vm+MqrhlAsWfF!7<^yQz2{q3m}DJW(__1UH2HS;pZSiQW%CYxp9YwZ4Ck z-#Q%nJjI`ww7lykAVufOsrOXr3lFE-Jr0-7yxq5P{$+bcRgTv`C%=DnhVO5v_%nVR z!DA2oZtBN-?g~Gpo7Jxc%W1cFv?K?Ew?_KkJe6FrtnFDLd?3Af`}QreF!NOe%rw$2 zhS;;ZH44Q9uz=uP@_v4PP^EuJW7^E(Vk|!%FnHn3{130~sQZyoo9}m<UjDlGH}8&^ zpCp$<2+t2!5*1@9RP9u<+!ktVWB-9gnjb30K*HbdZt%7bNRcWZESUYHzq3S3#;J)^ zXa#2gfqp>d2<&j4CxU*6sx8T|8ymeQVyG{<`~>?mFHf?U5c08+9>5r+0Dv;XW;Q!H zGZS`w?F*uVNMqmyAZroMTS*b~jkWTGoxlHv0UQ&EKEqjA|9=Ps9Jh%1&)Q4im(twa zjF9G9Zji9!jBYP%0?I?x_{3+C1oYjlJ|`P5KLBV>NcZg+_y$c|a4MT){f~8+^H{ZM zWnE%&kO!?g$Ua<3(eBB7T_!(qrMTP4h>XL|n&S_=zm2I51>Z_Wabm&C+L%6qk|>X= z)A)9%N~=mN`~HCq7Q&R4jP|FIbAtXXImPqpUL|x_jNgA)?~fcAUkgbmPe}>!<R^{- z)aBn{z@I^MQG#*@8za8-0*)2bVRS%B+pa1&(Q$i4JuCNFWWf{)3eAOStzgf1CewDf zUEx^D|8W7@OMM;?Mwb6~AhzAXFk}-AVxDs#WG9FCI-pUH-oxgz@|uyP#chzK$rr$~ z<Vzw=8L|N~`N@?PixxozV`>T6g#26e6?J7La51EEdKoIoH8OtZA=n1?G;W{1V$p|C zD-wf9HGt$GrZTNJnPz5Zi@tqx9;^{G;h}F<c{o2krTfVvH9z)3AoJPFm$bmDq}V>3 zP4llT2(kmRHRQY?0N&V4TYsf!@ozD-V=x2e)@Y|{@>qQ8Cu{WdQi1$l4+f+Y#{v2> zrJSweG#Hop2x&5^b?QvOAKU-kLJ1_H3B%`!;r<|hsm<>K-qJ$rG+Xg4E0<Y0q8(Ts z)w}$TY4Y5LfB$~=@gTgtT^f3^<Z0C4LZ6kLZL59G``x*@qK7}uefKa%K=4N=0Prr` z2|;TfqWpi)poJ7LI-!;W7k8k-v`hX5h+t{5(H0vU8rxCOzy@71U_*caB={ck7pCqb zV-bkVLf|{o3f>Pud}5?{YHB1*I%w;@J(ep5Bq!kY@z+>J|Hk?M@V0N?@cG(KNyfyt z>8K)@$@_VW0R#7hSC#YE{)kTbWDPGcy873y=YWofI%XBQaM5xv2rM0Py!OO<`**1I z!p7yitlhkVt?#>`;15=*#LLXgV`%_83$@@2qbhUnMgI>ltohn_ZN>3N(D&W=3Gg2@ z?bf;s3HdCzc?Ar^fdiM@R;E3}bPR=uP1FG3ch9xImjnr$P#YNyGDYx|0RQcO@2!iL z2tdhZ-vW#Xg(+p|pFkR<p9;XFAE{0Y0Xgcl5HW_FW;4^ff8=6TMYf5&?dNf7w5o$1 zS5N@dkwgUR5H0DIVf?Q9P>+W}%JrrFu*j$;NySKoN&<~br~FnrSF2k`2t&5-FqA21 z@2ZLyJqyl479c}mOM-z4m67chDEI|?0yIV3^ZdM|kB6U$b=@pn+__gKVS!}6Sbki~ z9f_KGyi_jvsN=70i|(t<(q!x*<y`z;KvanmWB3z^6N1v0EVWbkrAh<6#0o{t)@B&Q z{XJ4NDv55^K$H9Y>%5yylUms*d1Ln3kzF}5O1T4s5fWkWYm$OVvcz#L##>!0#?}}} zgRw(U>YaOllq<IH@{Od&PQr7JqV)HoQ+{xV<IYZ5(+c7A@x)n2HgO&@T<}?-9%4Np z$2E*47fX4PvM~a_21`!c_94H>==w3Q0B+UbYNM~6124^|z@`Fy37A-<k}laPqc3U4 z<r%9OGArBNMEU*g30KT&D%R14nKxSLQjofqG0JlyqyHA9m)`ekP6oPh2AuD$tQB7@ zh3GHraZ58sFz+k8L>A@CL_U(f*UkAj$wT*K_H3dh5c2Nth1;>uUea@giEqkTe0&vs zXVBAw`53cYZY`Myp<*IS-or2g{68|SgxV{9j0=2iINKEt;d<-C-|7R#PbONtCEqdN zxi4ImvVIGr+WS<*6|y%scd@|nX5o}%`OgUR?>aJ3e*^`u&<}Ppmuf;jnKP7t2gK9U zG=HigrJU1qZ$x>mc91leg(>m&F{W5}DD0{la@0F~QwTy&x}7Qp7GDUlhS7BFnMz0A zEsCy9DhEW~BJeMV3BM}rK=eIAe@H`yICm#Tw2a{>@rO5nRR&sy*`xBaXU3xBsWM;6 z%K_*M(zxoKtt~B?T<$-S6qVt<iu~b*x6OZ)oH^usI8zI3{6N;N=`8(uyTacT>&Xs9 zt@dpnaHuQ)_CKqrWruc&0so_y0!NK7E3x*GxNRSBRIpTTtVVfuMUqxccu%}PBJyzY zAr(&$G$Q=cE%cTvYBhZGbAZrCwd41U0B??ot5ImKc#+zG6q3@>QlGS!Uy-{g3>Aaw zJS(i&hfzo9iqMtg4$lyUG0Wrq+7e)2ZzRAvZx8c32zYeH`K`M=73;YuVpM4w@TsG6 zC9dheh3jo5?7<&Kw~y8>PK(Y`pBuSw>p<cu1Km%>d-w~u)ZUzWnL!GeaQ#o;G6YTL zD-?bR2|4bPKZOs)e%ii(5?WCi-saO9m~_CoHig^I&<+;nqPJ3BtYfIl@n1H~u=X7m zKHB3{Gm^NzaOwYYqfqy<4d&@eNw*o*rA7m$e6)oZxuIuIaOf7QaT0GYMEO75I{Dk& zK`(hXH+&fAZumu3JZS@}YYAQ~UAn+3p;40e;~feQKQi0`vaw|1eh|0$^O*-Cao+s) zK~YI7ke9=dEtdj|l_op7rZKjnE?9-unF@<*?n=rOfv*91*GQ&;hxgYS`VA%`E%>@n zRR14Y?RwU(0i%|Rmq}@5wr$BJqPmXMRu?8*@9aLyM9^h$#Q@Unt4~nwE<F@QR5-tE zwGNOb#0KX*4SP%Ppn}Gk6UZ*`ZFF!OYogYk)3lbjIlpHum}Khg$wxtN0-c@SygM`O zGmI@h^N6b__)&18@K?lrri=vM^zs&C5q2gHE*4?u>CFNk<547M<8xoG^ajzx9kn3o ze3^+{*g8`tZdbyGy{)N+Noj!7<nlPOqM`?zl~&SX0Zk@F>E!^6kqNe6!K2(<DXu2e z<hP?nHNbx(nFie3V|23}>6!4>zY3yHgoGMcbFnAqrxUrj5oeSZvX3*nLpFIPa;mw_ zO<WJHHd+Xn7v0eoX!PC8D5WCLSq`a;8e!&Fhj46{3W#LGJC^M*2M5Q2<4=!*I+eAz zQ8zpYD83pcq!xD7tBbWhXr{)!<30G?vli;-R@D;qt6r#?(5sukpl-w>PVuj%8!r0J z{sFz|I>lTW#vhY~g6;F3VczcJzHiu2#`o`kQ|;`_^>n8>I9GAEVuCb^Y{wk$J4*M3 z=TFa<9<(nPSkq#rzh)=$tUP4S84rCk!!5dGy!=b*hwKuREC`eHR~^65T{<CQ@cR}t z+;K_RXjd2!EbP3qauaxz(qhrwlrK)2XZEbnNIu}OcJ9|=*w0vnH&Px7vfR@D1`8^J zUB-$EURWq6A)ufmlKtcb>*>Wn0v_hFU5ub$`kO*A4a>Sn%j5CM)EX0dc=cD|D0#A2 zc0dp|;KsKm^B9}`kxOH2DB>6WA|U>JVwO3V8d#KO*(q)X)vyVfxOrs@$d~EJR;*eb zdUkY=i=H9scwBm~uZRP@2O5a-E+QLkoLS#3JxD?4+K4!Lo#c16s$DPScxBc#sIJV( zT2bCZE|@aRBgX^&NC>?~J-*AGyPvs(S$c|^NNzEGN}XV&@78QEMMKd^BdNbTXqZb= zVdgqt{ieWfdekM;P0mBJ>gC+y-Eo3larI*b@l}ZwHI{(-byRzvIffig<oRDY9FF7H zQWW-*$hq-=_`l(JTi-d{U@I^AGt9y+R$w>=ErgN`%@D!^yedm8TCz&)Mc3}|*__1X z9`q=AO2|cPxM`~Ft1&pPJx2`7r8%+oZ>00;6yNF{C7&V@#?Im$+C2~nT~2pgGZ883 zkV7Q%e5oMW*#&;$t=}tYzf@fEyNFpcsF}664G=O6oCP8=b7s<?QC-d5^eXv#Ux;7! zub4-5-@iCYk!0w~A)U3<ddZq|@Out+Sk#Che8ApIk@h9LV8(N%TezUWO^Q~G_Qkje zr1V~xUHcOF{;B})bgl3(5b}2RR@kMvfL@oW<SQ%81#r+YW-F8J64CI;j;qWl+ntIg z+GrsybiC4~nA~tN+F~wTv=xQ%U@fw^=VJDGF`XA{d!u5Gj-(=ON4)2e_AJjm3g#q{ zgOwuIL(dt*ksHo)F%EbhK5s;~s^dIH>#$3T3sHlL%lOm*Cv0@|?Ci{4$!uzZApTzr zXe^Q+1x4Q_`So`xv4t*`BA<lD+aGTyfBwe*M-bxJ8p{l|;g<Ru%Cc<T=+T%oCQkEY zyoakhm{VkZ)mx;y!OY9_J?g?rAf^yk(bj;@Sl*0x?Lc&4;FDpR7nKH}>Qkli83b{D zKyE?uDJhI62CGQVoWYOrhWr4g)rFsbjrYr&ZSt+9s8CNxg;Nl`QwZ<#lfRAoQilq) zdc9w?m!l;EuAvo|`=#!`V<=AlP41WX+Q^Z6b!0-5gs*o;SR{i?kh=7RcuvP>RP6U+ zTG&5zCNMFx@)g{7F)w?DXS<(xt?%ahQ+C{sikQ|M({aUM30leHpr^i}U0xN;D!~z) z4*BV1xVo0H(#<~W+Nsy4_##lW{&yR3$DwJA_QO^D$D->U@k`u;yGp;K9h}nDV_P%W z^+ik7YC7L~=w3|}3Pu2i#dH$Xota@lBxu-WDJVP%vUmbQNKjT)t~J0sLSbMQPcN(Z z)6y8rKvAxkYoZ&9wV*v<FVafytJ9mH92l}Fa!<E6`<_JgdAMWdgaM{(7<SO>k19qB zmTbzA)J+az+rQ`BUejXvUcix(7JYmHClX^<JJCihuOBl6e1DYDZjVmUqo7^ExcK%F zj=tnEOJQdf?~a<W2y`GE4YRqBFdr)}!Bk$9^-atA%SJyZLKd0s9Q~(#jOL9fR!lRS zN~kgQ_<Z7o)a>$PO0vZ)zdtH%oFObbA{DI&DsT5)TAOa|{H>g&7;eol95jwfxIQN1 z8cPTyi`EV&6@JCj<ViVn+xVv-McBDX*Z4GJP)GO;6z$4ACcJ-)ILmE0x-6kYZr!`2 z(h){fSamJg<#gP$<pdl{7)AGfFphh@O%ZQv5%=Aq{~aCP(iygZ%u1L>vHYGFk=eVa z@Lv&D&K}<d(`^jx-a&S`(06YFn(%F*=qO~0(d0OqCWVhFUrDV`h#3Z#`_7&3J#<(4 zZmkws+@p=TOs|Roz(Dt{*N8=M__xO}bZMHbMO_)r-ap}<Np%KuZ{r=x(Fx9*I!(!c zN1nqc+_A<?XV4TN-8za3I;+i3gRtAD;yksDV>G&-jg7;LzN1cVDR9Xu`sAkyqP&-i zoSe1@bJ-cR%TB7$E;42G#-LQz;>=rFPK=n=Qf!-!lpavF8S5+mgjL`1opvj8xav(p zH0NO(X$PHA;#(dHc-wc(W|B1ZJS;v63{+h7ww(j%I3nOBg!d;qOZn7*6-CY{vi8># z<@ZxT+a(j#9+)%?3sIB=&9LlpyxnJ9C`92$-+jdFpVJCG3rgy0Ey2i9fLQT3ag#?D zT=w!ntfIO*t-Kf{;#71$XxUFnct7PeqhAw8QBb%1-QuFOw|FwwaA&-9vFGPLdrXRq zZr~%fDcnz;bc(|Ad9h{dGbcMf+|f1uj<0**;k9^c@cW}8Y~9uFcz-Tpq}jhMWkSAH zNk9*vs_Kuj$D>8zoewrw&=R75JYZ@t!Ft8TovwCy$mrbbnzw{EPFUF6Z`Acm^c>N( z(h)ZOLMl43<IsfHbi&;rMJO%uXVxSUx|@O-D^1;Z-1!}Nyohixo>17+0u1JEot(## zHPh@DL;LK16o4efJ-LvBUVcUAJp5t==nNic(f?Y7Y3ZV9o_+AtWTSbRRCTio!B>_P zK!K|Sm;XVwkpcc=+HY&O9wrdLgzZoHS}!z&$O`6F$Ex?%p-z`5t=gHY$~+M}D@nHM z;qmQdp0kbyrfwY-<Lxk^y#7a-0<MX*p74m^7lF}-e}5s6gXPN!&p9~?%bgp~Px6)b z?g*`iA0@74-uNaN2Rs#d)5y|Jf#Q%A{HBh!;Wr2(xFc%M?v`}9LeU!JCdc2CBTBC& z_V4*3f%kpn(d-EkH;sm{?9hwwt20?DgG`l@U0H*BA2NIo!LM|^(7~-Ad%;;JKd2cs zMU(LB5x*E^!jf?t-(k((4{=tvv*XA}EEL9cuEd6TEu!V{LmcvF32GmR+ApRD+<L-? zCwCy5)e|vjW}-=|p9(U3Kb)X{#9q63x_^&W&;akF>r5GcqwIk!gY6APf;iaT;G9^M z`GnFuEkxMc(!!rHB^n`0N|}J0p9^fzVR6TAFon`>L6^WV?or-Qvk)HI#<36H#v_N< zZ-VTMj&897h?ugqn3JkjeWX3ESm0cpq%X~T4ni9co(-mng4$-0Ze;TX(KW_10dAK+ zbB_p53)V)2Cu$z=lt&yplwvPf8e38+?gTn9l8MT`8-h|bL$URz29HbkHp}yMFLnqw zM|52A^22NaqxAEn1N>2xJcgCj(^hx%DqB{UyXy;Nuyz2--hyCvf0S7y>#QO*cE+J@ z6SbybaLJZ9cK&>VsNYy$avXsS#?&sxFmF^+IO}Sw=?@HttPr2Qih&0cV+IBM=MWY` z2swEaT4O@|1O~}l&uV`90>9<H%Ob-3gh6-Wh@iA8OKMQxqCWHG8Ef-E*Wx3eXmceE zxQzEZIvS!x<ThhH3mwfj!D!nx@JDFRvdH_CXP3}Y?Z{yKMp5gd0}gCz?6iG)0Mo8| z!y6N1iL!X%g$N<ntWswellr~GXY0Pa#8&4*`r3ijf*Wpdv^M8MHztW)#A+IqfN;Hf zC@+!Iea>{eCLw|*6;epcpNtjKZoXkkX*H>|L#On@T&{?u+d+~t|IVVcZ`_jOhlgGb zy;wpl69$|s%&8?xkJw*Ew$MglTKKar#`wirqt7!dY%ZE^e)*>sK~~0tMl{f#?wqT? zDlLR-yQ0@e3F0)XXO;sM3?F$adJz$L*JA;+U(v<s4rqh+wshV6pQ#Z*BwDJOcu$~N z@J&1Y|NaR5Ea{^g{;n~gDqa)e|N2KVm09sn>c-%pw}|h3W(jr1?&P!SvSmTRoRQ}| zr7RwFv@OeX@sRw5FipO;h)Vx8{mTjb7jQm{?wntCIW@1v1<Kgo4D`|Z5v*<#N+<lj zAwcMiqqN_L#$W1*ggzh6V4>RYqtT3>S22bcRuC%^7jVPY3rlq`5e<cm`=K`p(>f1- z`DBGpS;vgY<YtBU15T+o?vD+hu|x0~TS(OJFFBs=UxvN*FH5IR_On0Vaq_U+iTY@w zvQ5cmtD!$)I{QuMN6&0HT7-+NBK8w0N_&e7$DQjyM7`@uwD#Q)WCBh*A;c7hHZ4&2 zMY)Ewyu7Qpoo?%sqlphR%jKg{`vKlp-{Zy0#D_-o7pDF+3#X|2OZYi{KNl@&u!Q<i zG=Ey|ycS<9D(A<iFE^>^dM<=+2=_o2sT1j$%IhpjbPfIvr^f&Gx6!6Y@@VNrU|3*- zFS1_v@5B-+-NFrp9#2I#^@;hww+7d)kdznJa{9QRL>mw~slB_gS(65Df*G9qixN99 zoE_1#w(D7~*|EsqWonlhpi_LyjFrsy!7Z(LBWGp>$@96TK3%8d;^KKbY;bh#DuQ_W z*W;^`*U^3`VVBgdZ_fNHrm1b~fR{KI_vb!!7Ct1`7K>rq<}0xUis9v4o7>^I+zY_? ztHk7Kpr8T1rt=g2G<)REI-k77udx1lA0w|{5*RD~xP&s^++*1<x;-zJW6j#5Ny#yj z;9Ye7SSUJh?22vpO=tF;-x2?HOH7nM;bMLuh1M`Mr^+9+5;|gT4g;~~6~VUgCx4YU zZJxhBrB?IRdk2E|r(4Ut^bY~F`?2joGLkKrPk6Kkn$!a#Z`$vqxDF*AU1w_}CZ*oa z9hFU6p^06!4!a*)8kT*K30pbe?`K{&ZQcHD&w7j=W+h}R`UlxO;AYQ?6bN6Zzk?bo z#pd7eFZmcMAgx7gmXvtZ5sg=6OzH!qC`cSlAlOY(87z7D?^t`f?vl+f%R~4l!Q@wV z2gMp<46s}8Z3j+2tLq&DJ>%^$dF^z!Or7eB-fLOvD-q*?`yd_<|C)&p#qxLbuv?dL z>8eGCA7@^m53PjXwc9oyV|RW)9r><7d3lkZlYZdOaUR^|xn}zF{9DOCEglY&DcAw` zfD-it)qsTnGpU@3|Lxqv8BcM;UxhY1xtm4CwfL)VM%Q`6M2*Y3HwF?<l2r(}qJYTY zbqy=Gs1_N1VHvgQs!}^FEF!{JNMxpK=K04Vi5&0I0rycH@!JdMMCQ+~&pZ|AlW|Dj z&huu`{Q01ku6&<W5**R*J7YgJ0m)6!;D`qRM)9bJpe5W<T>7|ad^I;#4fbX|(fvl7 zu}h9U^s6mhQ>9@*4q(goM_|p&ezMw;p!u_>yP^Xr`XTr^CZze(He!osw&-Myam{Jv zRyq%MM)b$fERpYF6f&`JLMO89BYDt%;SJ;Y82TxeR(H0Q>dO`uY;)4jeZX0!x6=H% z``PwA!J$bpOYJTF<pg6+SVMp(ZTs~Z<LbQVH6nmup|->ku@URiwMid|41IXWKgyT! zBj+^rm(t3zmJ`JT?SAIPMylBrFPss2!qrIcmBjX@!(NM}V-Yr#k8e-hfBU(1C-)?- zuH0W)91YKUnfjmaI+SU5O=t?u%oY|hKYCyFo)ZYS3kw<E&XWnDyybb?`6SQ{_gv~o z;dW8<9?}um_9)&-WVQCtIFvH*`1$R$s0a&myQk6D7)>I!)vZg=3;&bCOZOEiTI8G) zb4_|EXJ7!N-E;iWkr4W~zmKXKL4#W}5pll)4cfj4Yg{D_j2<^{q|(KhvDL5Q#g8dR zFGu_Ry61WRHE)F^H4IVey*?>QI(PJm4*?hFZe<FAe|Fb*0Lo^4Yt}ykWyj)zwPZq3 zNl&EHQ~sRqE^+CRo$>`^N+)=7(2$SOdf31)+GrA^yieH^)N{*f$ZELw0t0l@ckJQ3 z#DVsLV$9N75F+WHQ355Vd3N0=6B&CFjoTR={TUB`JC1rRWTGp2?n1jv(6u{`1iIx~ z)PUEWvgl8HWK(vfqV@YLoukpkcdrhEE0_i8z8`eGp5<v2!MZ>28>HJApnDQ+u&j7z zYcJ<K#&VoMS6vVm^atVqbrxP=A=NAom*|tdv$#X~eM5+bCS%hPSNz(8li^b0&)s<_ z<1JJ3^`9>Q<_2wg)7f~Z*&TRR$y(YA^R6smr-;K$U12J)I5UG5e3(Z%3JRJ`P>B-? z3oMWDH-7=jkrbg7ncPpjovaZ4BjPaPn>X0wkBAl5lJ*2~{TZ24yKb<KZjZNK;FC7X zcf7FL;U>ax`;s7PP>|hEJWjw2<qLxUnGm)baarvlB&UiH({8)XJSO9N_XN?Wo1{su zM6S$?hlZhxp-_o<hJoszB~!V}Usr@*a(EL(h96-l?LSRRSN1iNqweF%=j+z2u0Rgy z7hYuJLOnr-eFNWMoQP|vYgMsMxT8bb?28#AbEW16D}o>6mSnEw)YYa>A+v7*oG9cN z6s`8MJlOfV4dzDkknwt|FZ53WIS~MfvqfF|o8RuemY}p^L#+C9Nk{h^Y!Gkbzt@J~ zFvju%4G3@&g-|>(5qf+WK1|YvUY+?d#MnBC{l3=P77y5H#fCqkWDs?G7D;}7c2)?S zT8C`(;Hm$$_lPdT&_OOqMFjz1fo`Fna+qj4&(~l&{rXz=+Q}hNC;DE2P%6y3<L0+A z<}>JQpF+n<Tx9-2oO8>&o|A;s86n}BwU>bpKE=t=%(F>q9BzAmFIFKPzIgAdqs9Zh z(C=5_o`^Q5MG-74tO+3g0@{6a2*GOG;d|G8D);SRG*W<Ny3s+tyr`_e)|yx;2SKBR zP=d4cK)Kj2OiqzHW9H$#<M#xSKT&c6&+$jDh6Gh)<?1|8Ph0M>x^6l4A1-BHt>upQ z2pT-gOYF{Yk-f`s!FnT#_4Uf1;h)6&@K70myIK;vY`mt8RV+blj$6|J8;MKXfmXb~ zIR{BI@t4N`&k*3vQX?^WR3?iXfaB`_!kV#VFazfFYC9uIFUcdu-4o)7Pjgv2JR!<* z(<_+mv7G}S^5fy35!Y}5;zQa-f`rZ@6fJ(!Z~hprZc^kZoX{E$;!CjvnGGM7=ap|$ z(eSwQ4tKVxuf0)-t{9dqKd(UCFwCzLLWAx)7HAaK?0dd3My<9G+*+~dAtcK-0*$&9 zXeKqFWmpB5ZDzlQh3Vr?pM{RUHYOLS108(}4F0}5^+5HA(EIex>uS1qiOC3cFOx?1 zjn$l!=#7-&99Sc*_nU+?1;NZsDmb2d6WnjIiSegR^f2oX$^RGa4-)Wq04YOptjFvg zubvrEUL@77+ooc+xR#z7{y9z8@y@rMg?F5L2LAOsKg2^%Z-%C7aD5NOl8s$^_T!|L zOOGm<CVl04K2Be~96x*H83dk-mv-#J6&Id;)V)Ttp5gWhe@@$Tpgy@3mKP!g6UbUH z{{9wtDGOn40KVs;+#H~y+&mj1v>mj3`D4hv@D(IpKLAD7U_SgZ@E6syGSvc0(wUiE z`=0E_Xb*|4Mirx(`6PiTisDhtwr!936x*TxKiY$x#_~6#HDa~?zLxvd%B#tIp7HRu zRxmNv_dObAI~_ObL>N)g*z?jJUDsh*Rz=`pEZ65zL;~&<C7BE`I??Zz>nAEB6P-Oi zF=eb-4!VX|&p#B%pQ<F5l8FutP#%+8?pYkWQ6b)Q*{tR;&Ll@hg0RVR7^cH`=HYCd zC>KE(qEsxPx3?Ez6rrUdi}h<);@(G|!t<}}z?v0Hj=F~L`*``)t!Qd&L`zE(5?Z+* zwzq%aDElznAb_#TF;E^E9lf>>X=u>H2+^8F2v^KQ;QKI41IgBUAc%m#gOW)=sY^js z6lnDs^q#d0*7ki+bq)GJ38)fO8tp-zl4ds1Xm%bDtI3&Bl=68kRBA?}CFx(wvgEi~ zNs^AEapyJE9C(_h8IM)3l?de1^dPzykCaShP{Ey;YR(=xFyx%o$|IV%Bs!J6v}!8r z$)Ox#$}(|TsufId$Az3fk}00mlJ-Q>RC7otbI*yu-F7^LL5QSf;d39n0XJQJDY_2# z4S68u=B+#N;8QQ)g7s_RdTy-yC)$w_KkxZIl-?Z4v_KXB01a(PL_t(cDCOfL+8PjA z2Es6eq3US=;)mepBB=ZOp#48LBg`br(_a<9Y0JXbRhR%2RgEXhPSkoO%^adW%<<S! zorKu3tavOM85?q9eBYPcmL%yo8A0w`P!F4Fn$UGUE(@C|BF9E7)8d(oi2$M#1!lz( zDV|v}3?p`8CYnc@ra{xRqnw(ln57X*$#_Oa(=-@{5oh!!5?IhX7)q9AszW0kwej<f zmnP372d#YMg@O7^3Yw;2|DkRaOE%h?8qn6<fFL-!JW<m$oU(c)?t9{S+;#sGu&nZg z*=#zALZN_6CS7s%-b6Z+s;WXyCCk%Ml?Y+J1h^hx>4T$LEm+_BW2lOX!1ob2Wk)Lt zBRKte_(1?u(=oWfQ9G^EaeTg{@!4_T_mN7aY90Vk(KC}sB;xW6-}jNpWQJ5Sk|aqQ zokLQqF`*4k02IJcrDT&?n@^yVz%P%uPbA2wg-;wDh>f=7#L#*tlSky(R2wRAym=(b zl2}HVNF?HH)nrFU$?4`LdK1Z`ir&iOc+QMi+9>Vi*!eeAOZG<UnHlMKN6I)2ENpMZ z6EE(7?YMaM#aD6hx$EH$jxMgoo7ScVG&j`2cFKQaC@P+PaT~h3dvN~xb$G{lXAC>w zWVC!0`!B781#d|^lt;D!ngVRw1HZEuO4>RCMDxWX=S~dj8Yf?X|H5l@Is{;7h{6bA zR6ZbF3_=aZFG;h5R8@_$GvgY~OcN#y!+>R3$Ye6`JTLx|j*KKp$If6<+Lb`4s;Wq* z)8j5FtA(fud?Lqbj_32Dvqw{SC?I25)-fNAE0$MHl)fA<pZMe=a%6N}M>?GzSJ~Zo z96xbn?L_XK<GF7o7#qLdn~uE`we+r@vUVjJ>as{!2L9)#58%N5gG1`|D2mY1)PQ-d zO>8d#`C<v1x9vi%<RUdmlk*a$g<$;(M5+oX3e1Cj*!#6R0OhDf#%onI4R8MJAtZkP zIt)!mRIs64cru`?{A}|nyO$*$`~9OR3X;hrOw+6x-&CA46Gagm$ARm*C=?3teLpTa zk-{ZO(y=k<yn&sj3#L-3<63gT`$D+BI9@bVrr~&waur8hA5R`}r<j+OnWlN%M+S?L zH)&fW&1C1S+Ie6rmM+HXCG!9%=<Mmi*MImkytQX9JkK564-o?2M?ROsz(5YkWCF_< zwj)9W&-al^TDanZv+(0@d<8dOa~T}h9apfaTIME-B1EnS{lb&sFP{S?2;o^e7Txg- z-u$QkK`EDqj|d@v5P%!_C>Dx%?e6=b{=@Ca8WuD^05VCa@4E=09}L+;Bz3^-ChFU# z(&t*JVwzbxordE$&@>IM>%y|isl-}GrAd+`Y4paV8b~)y6Q*fSnRQlkXpZFw=W0Bn z!6j3r&YJV%cr?6=j*M8MI8}I5ZM6M(2U$p(c_3#dJOiJo2mqF8;)W|O!nQZ|qiEaM zvTY~+`8z+td8e+%;*L2;m<IAi8?V0hCc69c_~Q@Xh|^D6h5Mh}f-_D&5tp5J29__H zk01<TJMM%z1mbnVFhp}>6ZU`kMwlD^H;m9kXc?II_4}~zx!0gvu^#%e`GBs$+t-ES z!_Pze&1N*%A?noxlu{1*KmH-26Bi&X6i4l7$)1_n>-^VReWLS=6^q4q!)3GCxSo-F zN>aciNvh2-jP$ouHbvi0CGa_!MrSO1;tlNN$WYK_D)MPG=W|VlEQuMJWHLG7!y+bH zhQ=dHlU2G_>;0vjoETs;9eQT?O7;Lp{&RrHk<QfASH0?kit|s;Jm|=rHd3?GvyJ zeefX6u$*yG6x{XeM{(1;FTp>2{-bDVsE4Mia9p=SFN%{2hg#!E&%t|U0Km5$w4HYv zysv%&`1F53Pg<~49rK>th2H0OqL|PSAVTE%$P_))D+cPc1oT`9+Q;4v<x^L|DHM-7 z#CWLlgybHYoqOK0thlA6mOj^t!gAmD<NA044KCX-Qn(~Znw*WyL3$7b@wBq3OydEc zwUj~diDkS;W~z@vK9=hfc@&0W?8r=Y9!+QaBG1V<Hhi6qYaQz6VH9D>g1Pwq|NatA zSkeL4_u&O03bu<}p@gFCzz-vMeu%xDJqRM8rJ)`G5FG16S)&O0^%p?-+9wej8kE3C zQq|Dz>FCHsm_HC<fvsYJl0=iQLU%)GAHE#g|Mw9%N;GD0D)-Oq+T(^{!1sMvmK9G5 z9V=C2W(Yiy1H(@Qmn2Ej<ZNUyQbp6aro-CB!2pv95-4*;XE7Y_-jA^m1&EG?Eb)xY z@fe0Mm1SwRIK5-N-bCJCo+C80ju-jj`ym?ZviO(3{4_Sd`Z}I??j`K+?1ATbuuK#4 z=d|GbGuC0<%B2W`a7Z08QB(AW`@Etkh(2^FaLO`7-~0uX$6kigGk}C2LIn`13Xrv+ zoVgV0hc8ET!+9v#4*bFM3ai~iW?&@InU<=m!uS1(p<^{UGt`tB1VMcE009Tj^Ww%F zDR`13jl4O>Vmx>>oz9S%F2qMRbH`&c?!(V>nd%vtYR=eXg7u-C;;Ek98x90dcUv>u z`iD9-o)3>0&;5qG=5S5oW4(X1(k1a4W4%_bx^z0oK(%Kq2OkuivT7MlK5-em!A5yS z0ZiTazwMpRPUBV-#=jf?K?ni^EV_Uax~V!81|by$&%lP)=<D<uShC>-Sj_BE7f485 zR7}U^-vY%DVmo$l7xcI{j$=EJ5K_M1W;9I34%f%`p6{M>&w;8agke-@PlFH$dA1S9 zG0^m()@s0SzoPQ{pD_OT8x^mWlwZcmcZh%a5#ho#!iOeeEwwD~yQc5QGc)fG%d+6Q z?z1xq%>Q->B2+4sB*ddPIFp~9o}O~V2`RuZ4Ag41QVxwSWMn6O+$M1mVd?$`{Ww8+ z|1aIKUYhxi(>O^<<bEA>Jq4>DThbd=j+>ZyN%PK8?(}9=Y09$){h8^Xm4Z8Zx$h#| z%DR@`z*R3Bp5Dbze^xJ{omVbcj{v^pT1AfeTM;B>&dlhMlYZtn{hW%zQ|V;@2&1s{ zcTAr{DYDC6=V%JQYtX`@0@TI|@M#4d^_E32-!%&DHGQs6|89@3okmAS{(d!^%@-B& zNmf^J5cGq!a(+gPZgq8)YMGD%lu~$jcqqL<>M23vJRwOc)u4Na=wtNUeA>5Q6H-iN z7-OV62>`|_x|d}~{ffSELe^N{_u>0~QuIT9cf&9+H8lm(G?O*Bmk^L^wOTEBo|iP) z6=5imUU3q_FofrMT|z{}hGkhvzlUD;7Qq~bA)3u*$35kDkb6%~P9}NqMa}Sf^_dx` z=uEEy0D4q;81|%BF6?K1$tzfp|DpnMR@0agJ$Ksec1PbU`jkZGJ(;6kRLv}kA}FO` znr27ph&0k9g!J!_W$moW0xgHw<-D4_XXBPyp{G&loxF=27kwft+VRvkT_kcmuH&RP zj_k*ddfAdVH1c=bwv(vLIFC`<*)BUyqjHY)=tH_MQ`Yl3J3GV4$w^mgonaW*+uK96 zT20P8r6U`<(-}n(uCA`|`SWK4LD2EJ$Hzykt*v2ma}#kK!*LuOA0PKjKb)ADz|PJN z78e&`+jiHz<(WiL1jljk<;$1Ecj$61OcT4iyQtM_9oH#ilX^sHls2r}Ufwg+?Nt9$ zL|?1b8cMW5>`BC|=XnT%0AUy=>x*nM>F-85S_dEz89@*rilU*7XS>~o@B8pP55DiC z)oLX+q(66_y?P(WGnZ;+W!J~FA7RSHZf|dsRI_xbRCa7GFE2Urg!HjnrdI>ZTLeeF zXb);qN>4C($gc6l#YJHyAQ`7|jLKw<Q`s?+`S|AMrf^b!&$gtLLKH<KU8BTN0|3`` z(P%VspVh*`0=BlcGNTcm=OvN6GU;A%9AkZbJ@en^=jTzc*8x05?6$YJdtOf*N!N7~ z0i7kHB+9U{v5|W%+qO}!*E0oK79z45jRri=dlPnS7zRw!#MRYRsdG?EOH26n?OR8r zWS9{MeQundp2p<lWU~G^j+0ydSdJ1nj?+<1v!8eGxdKd@9Dn%mArUx^<FF{eJ3}JV zvJoTaJ?G};O0AEHKtDJ*i1+vRaeaM_AP6|Jgb+dqA%u`uC5~gv&CQigySHr{M@L66 z^VCupMgXXg2_b|KLI@$xMZvPnp;Xz-yyD&cJ<iX+qVBp3_Ypz}A%qY@o-bvT!tCrU zepsntrdl1Yn2DkY=U@MVdw>7G$WJGP5JCtcgp8K^e}g5fAAcHXgr?FhX4+`nH&9^} z2|@@Vgb+f=08mPy(P#|3VqTY+F-;RQGgUk?y^Ih-2qA<JG63Q@Ms=n-@N+X}x0o?d zTmByH^EO=fj%Q{FA%qY@2qDi#DTUdY8Pt}Shc9LTpjxfs=Z_x|MiGmd5kd$dgb+er zpk@Hee8p;Jz*D-}Fm6Z)A%qY@2q6O%GnQp>GzcMt5JCtcuTC7ts8lNbiy5U9EX%_D z{5(gI5JCtcgb*?^K~omnwxN`Q83X|i4-a|JpAbR_A%qYz7AU0<1Ofg5hf=$3<6K|$ P00000NkvXXu0mjf{F7R- diff --git a/plugins/kimchi/docs/kimchi-login.png b/plugins/kimchi/docs/kimchi-login.png deleted file mode 100644 index 66387fd70adebc3b20b9520974a127ea7faa52ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 318041 zcmYhi1y~ee+cvy}bPCcbNGKA5OLs|&2}mO)i{#SXjdU!Hgi3>y^b*n_%I?yzgt&C~ z{=@UW&-;G|HOw(Pb061z)p=g$L_gP6CnsSd0f9i|8qZW-fIxVnAQ0|1A_Cw{-{zD6 z@Q1)sOI-zoz5Oa^FG~T=5Ia9JbOV7%X>NaTK-oDAz)3=P4INd&d16{>;Rli}0?fcE zMt4;McV#C>N9&L7AZ1r;3wP`H9G>>>b{y&&I?vw*Q_zDz93Tx9#aCW4TkW3BChE{r zZ0@{nyXxE4f63Mw>5p4ZBbXn6`}>jR3m_azn!C?JKOKZBJUh@*BKrJdYC(ZS<L{q& z0!Yg+!LVvNj9aVDr)4eG#CAb`EUQw|%~N*6cvCa)SVo2t@vdxZJWICTX4<n-mCbic zWW808X_Tj*f~_}}uwU3nprF8Ef++Zj^-wDR%Tn#E+XGhq;?$x^h~;Tjy9B0U%EFND zVH%0RaL6PCybOH0Dl!RGzmIJ{u8hh2e?MpQ*&hvC46DKrg@9Jm-#J;onsVL@r?)gW z2X*X*ij?yG-vfXHNPm{&Z1d%g?{fjVLY=tyZhYWi**kCMC*OaU@t>=VY7JCcjC*=} zCE^@Y$gftU7lPG_aZC{RSb>GMOT~S9W6Dun;4cH`%qHkzu<Px9{_A^Iu!=G%@g4Lc z{lOwx+>@h2iq-MW0}}-?TwIW7X6=90j7c<s{&{^CtLM+uKj%svCt{afTJ!`kg0#oU z!)%Hvu|g5{MhqT@ur^I=DbDY{4o4vi_@NNoIDl=;&<JPSTV1*9N<`*xZ(KyA4tFD` z89!Z6Vy4^zJ~L3$Sw~e?Z5sVGt+R_{lH4EyCn)%ipmF|p?2qt}FF59VEcA*yEjbEP z#*lz37l@mffQg%6`uM?K4_D&yJ)_=(r?!@Z1+g3KMv=KQAYEfOCbi-7j!uhv7N5p+ zsETny3W9Yo0TGT>3Dyo{{mGo<^8%`4ND7GGM^PRV_P#>2^9ADo{PQbWqT4<7h-0!M zi=}@YW?_dPC-OZ>zf>C~Vtt%DzEZ_LAIzE-yWioN6HijPoW#Bm!P~eM@_oxSN51Y( zlOLLpaSa<MB5RBA*;QVw~gty}y-<@L^t)$dtE&AzzaAvekI^_D*l;^#t2!wGzyN zW3o=S8BZL&K%R40d?xLIp2LL%hjA9AE_ZFYOGm%WJXTQU(l5^r^0JYKtFd5e1%wHt z8AI5NE{GN%lV$$4-i$n(nysDA4R@f=jkbn^^IA6E$Up=Xp_}{+k1>o0a@=|6njHsh zoI1q^VX+P(>XCN=Y*j5j5As?LFPq(pq8!%qqf3-$Qp-s=pDiqTrFd-(EOxPCP73PG zInyf{dcN2;n0|f(zV&u#4{^~_`z{W<H0hTx##^`7qLYAbp>Cd-vdNL-K=()57yBGf zW$&Cei?2{tNz#ONe>wZDiU_?!VJ!Z4pn{|yG%s9$x%w1kM!IArw{R+s#SH=FvAc_G zJn=df*_!Jhr+K9wFB>FVW*V#S&w}|Fh(CMs!F-H^Dd3YCK|cdaS(v#0mS}UjFn$N+ zxb1{HUTaloP>6_vs8L|kPMS?(fpE;ljw7=5T`1#68?jG?Dds=!86WPCuZ)Iq?#Z47 zv*;A=8FwuS#a&d+6Hq`Fqx&ng_6gZLDC(mq5r+jUx9<GXV~fdAeUUs|2?*_h3ToVV zN#wzv=icbMyom4X<Y)6R(@4eYU>(ZEi0XiAkJPGbZaJ4V78&Se)86-Y>`Lct-)fyP z?FOBlafj9I)V#Bl%P`N1NYMror-0obE|V)yaBW%i<elkvj4wsED)ckg`kMFg#Fs}b zrZ2Q@DR(aO$CrbTs|#xO-nSj+imx1<qtAwR1DW(5w=r~{FEm*U22Ec(8a~k83S<+4 zI9U>%qHpGzVqW9vMB<Qv+-jlM?ajw0mo?UNcSJUpMuw|<UT5S*_ncIt_2f^93?}gl zarn40>kpK!{t*V?P-6eEqjyAToSM(Anmy9m(kxkxq4WLM*c0!$6HD?q@4e@JUk^<q z#m&5N)(s|M{EG~I(B1Q=#*IE4bLIF8rhZr<`B-0`STFP_d*2`4-+QC-*IE@&!Wy5o z7h7KcT>fTU$;r8F3qTBfc|V@-TOl#R27gqWS9P4a@0C$3<p~AQIq-fh|3|qr9*8v+ zkl64)i*Fj~M>k=qJmrtXD7>V;y1iM6aj5QdctgHCIExj!xlCY{z+SU=ze`U*2j1*! zdHs?n?cA5{j6!RvIELJ2Wr5H;ib3OnH;2s!Lyu~0MziN4-K#Jw!GvsGb=Jc*e&?=Y zFr5mMA9UZ|RQ3R8o^<BpC=8C=ZvF_P6(|bF?MlQCqpm}icj41^xLw`H0bRzMAfqX9 zWwh49D<Nw&RPZi{S&tR6nk=afKRm-T2*d<hPSug_wIa;opp-IUvpaK9Zh>p=ZC7XW zXWg=iO7FbyEO?LIJtOQFF}7Rtp(?UC=*xKi<LGI#%?;5`$ED%i=@Cx_V{WWvNt|mf zDBgT1M@tNk2Vu?`6-D=5{NeA=?^kzoYPKn4uvg>D9|H+YT|~yDM!Q4hKZXPs)Lw3! z?KJK7uKpr*M#J7%thD&L46rVS%lT3))cvz;+gSfIAsj*Yv6Eg%Z^oeJ;60gL(CdeV ztC=-3Ne`A&q@kv9!36k+dj5}Z#{25^!{Xmg&qvH6=EE=5GFDni=|hOlA6}I(<@Ua$ zTnM>lCIyL&m;?xpNuxr5yKK>0Y=W%u!(R};5mlJ~wnFX{NU!NeP-_J@^4my<X8LZD zH}9t!dhIX2a~Tlt3^gQm>Nj+1#gYDaPMvr91|89q7u{0K<#n>~&KVOrZn?T8jvjqP zG(CU$a_(Xg8`={oABJe#@o8&2{^qrnzN;u*6&yeMp!sIq!Nrf*WR>~0Orj<&A}oTa z?$(+<IqS$j_ZQP~P~9f(-a^&uKTIpY`0SkS`?GiKq6;J0l<HBv3+=wOw&QF9Mh$#d zrh^!n|4C@=ObH20&SH3Y!Fa;BLw2*WyoKM!41BAXd>LB)G8y|DQZFvv&^GSmb)gWZ z@xvqWUYl9@7TE4<yJoN{s+RGoCq-4~4!!dY3k^;Q5g(NpPCstu@L2Ebj81}kzTmvJ zQ;j%1<Q}E{nA8J1P?Sy4{x8q{@x@s(`1?Ig+ZF%aA1t8)R7Ln#S}&*^aK_r*`8!-M zS-m9f%%}UrS9(`Go#pWqh<Ho`aI2BZ&0AN8&L^7#g(Biz5&2m9JpYgM3w|?M5^G2L zkharHq_kwh!QgK1tZ5SoU2fEQz!nwPzLZFzuk?PGBW1zP9ikj5viJgTb0L{VDw_eD zsPE#U<ZVa4Ly>=9D%967@h-QeY`EY2I2nHC&0uTnb5BsF5cl7#*TGnPCO1Ki#p90C z5P~vEib~0Z0kcMzu|ZzTkDG+Zg7LoSvYZf3Poa;fbCMi$Ho?w|7df&^xYCX0mmTB= z*bzD7tJXfRsizrBebo!0`A%ZB>qSjV6@9PIzM2OCy+*=v{77-4Tnru|g?0=0$&(Pb zaar*xwJ@rX$L|`=G1HYCVdi5wlE^l1(MG353b?TIq$<7j!bGa(17nxIdtQ6pg!?_D zLJA0|alrYSL9;Vw2#3i{C0O*fhLy%Y0SPDwV~lgm0+<qIu)-ZKvqTHm{q_1!QJg4R z<ww}!?Hc+>l08|HcstM#gTNCn3e|7-8G)!Lqm5&jFa(X`8GXll_BW3H;hi7?BD+WG zVIuC_--lt0{S0<X=9ZR4-?J<#^UNB!f^&n}4vs}U&-)CD0`Cc-VqLBu98$?VgA<Wh z(Z*5zjq5)3JENTt!&PJCI|icVx_PZi{kho{kKdMwZBLynzK!i_2|C3d^CN7-yBFlU zM&Y+cnAnpYC<B-j$}o4q<+t5|w{4s~_B4EB@2ub07(3h<^GKKN!?l_zO_e<7m0hHS zeMExNV9-X3c`8l;QF-tK-rTs7*Q8`*ze$B97DF(96el0nZ~Mw!ao7b0vidB+4?~<U zH4VSvH<(m+;{+3s3{-WK^N|%zE8f=oVu$-B6HwL&k*9E#sRrZo!<9~E28K-6$GexQ z!`47fwKLMnrNUQykI(NST726Z59EDkF*k$7ev{jK$9Fv|k1nJ1XUD3FU9B*Whp>t3 z{hD?#R99J<=+%z9zdkO{_S%Xyz;6J~&}L42RV$L3ksB2ruFTB6s?kkp{7TnHNbWjI z*{n!TA5SN9<PjIC^F_FA*XIpOXwu5JjR`7EdO+%*6p3On!IW*T~w9X$#oPZhPKQ z!dWbBz**&N4cs^ZBV-mME7V3*DG?S<N_w|FY*!CdEkc}OpDA8P#w)<qTbln=apuqL zD&h%Fl}UbAFSk8bojm=)&7+8)^moa*V&7O$ofg}V!vDRb!!c!@&7X}iROXS=Y7+UR zbdOYxzNo;dx7{IM$@)QG%Dcwmu?UyJf7JMdW<8HRugDU<GuY-mAFxW44;s)jPSAQg z_Tta@ZQaq%-o0#I3L)(w4{e+L^5;Vqm@4%}g>lPWhv^C&(A6rhe0TO!2VtiL8BkYm zuS)6Z@}fOFf;=-Pr*|mrk$yE|f2)2R7epsu@JYxv;sw(i{O15Tsk7=X--UntJt+*U zY3DTFKk?)`y9iv#yX=S#WS<Q^OvKAk!!!C(XR!3c4*ajipG1w{ctEXqxrdUE@7Q9N zTnv{Ihpa*ZO=2v$yuwR~B{I8V4A##~Y`UIt6{x|Lh?inYhz)x3eEQ<YrcVLU5}3(u zh5}bp(SGB--nL8J?8}5)ifwkWpbNn*HM}aCASOJCjpN;(JH6`lsIZNvljXj9xa=j8 zw&+%eQ*`<d#L6Q0igqH>d1%e4C(VJb=maUgci2vwb})Rl{Pu>CtP&R_K7VE8<v|l) ziX(29JK;S_!1NJ^t;D>*8AdJ!WzO5^Ht^v$?euxH<8z>Ug}KS7b>&v5H;qI$7Hj(H zaN;u+?`;t<ku&ElR)zE%!E^{_E^>H6XA^u{fIBJHAGb8T{_4Fm6zej|{Gs`90o%Vg zXWNahXg&6!?YN;{Q3KRus1Dy(;8!lV=Q4DsTDfw4rR?;EQ0~-<Ce2XGW$+lW++zrp zIS6I9oTsDAz|PD%k0!eytNo~({0`MKFJZe~8n4NNXC?vEw#CpeI5^mgF%+j9wV?sN z<3wIPyw_Y6yT89bx2w#rT5HgIyXk>9ei8|I#U@WhwLV8xi>^ADT{8W+xxg&9R$Zi} z-FB=DoRtJw<^_sc9wqy_hvpnAgba5WR23MbN)@?2KhP=O4%7lM;rBR{bs!2go`RGw zMH!V9HVb#V_;4e}cBlS4wx1BY8?ce!kWCREXa>qIEk1OvIBv1SN_*oJrz%Yy)3GxJ zJ?Xs~orxt2E=@^4t75%(-%jJCi0KoXkC0SJqW0Xz3nrGCacW#02Y=H6+3-cxGyk(r zUL#(-=^@AaOu=f;E`Q**F3j#0-KK@=H$dJ9a%`e#X%&GB_Y{zD;zw9;5QS(f(hb+` z&F==#6CfJD<opL@yzFOa^T6e__cS4!NeCFen$X|@W$tnjVQu!V#}F3>zR?L_?Cw&& zhLNrq=IRIf(jBTLXXK>F(Rt@k7Qe@rFnCe2x@ngtn4Zy_Bdlv9R{wJGp!3|<<7Sk~ zD-z$j5_|W0-iRF&4kJ5vJ=kEmki~nLf3`nvxhEU_*ouhim>K7{Eo+5Lb<?8iE!sD& z1k1@SOwI9s3}LWp33=p)Eg}Kk?&j;7YKv$XTl!wp)lBp0zpGvC4}6kOmpccfV;l_z zSA@9LSQ)HjMa&sH-p!o;9FmGw{^js%!K^a$7IjQ-JUtQitC|`4f6@F_`J9S9N%;TE z86>Fr{z<i2C$4IAghS`GN4<cWmaaV|mRTBYS<B#oLlFY1!t}W0yphwOq&CWHwl$<9 z30Hc5u6~Q){zDXe&)T%)qQS@U*j<RfzC5)uH|MCc{{*D!y7Pc<VNPFO^%SYbnllje z_xIO0&Ne!SP7M=q6XD`3f(Be_+&5p4QBr;j`|#h}&5RtuDOe<efGd};4#x+Umdt-_ zeRXX}ZTE?L5o1#yt<L6+-&$pLvW4>6@1qw1e0d~Kmbta+)EeI4xog_C*F!3SjuSO! z{TEgKKWqxHOt9!YgB6*y$5z+Z*WZLCB+9eH9{T<PsEuBJptn$G_opqj4|x%zS%N#; zczMEzhlhu3_Z80`E&c!PXY<b{LP6YJcu{@Y5ohw~jayw;q#mW&u~<I?Q#^s1nwpfW zwahrY%0ya3Oe}10P{S)P@(wB8(o%P5IRazQ;dck@v=G<gwoznM`E{~rtGtPWNZ4Uo z;5P;;#uP8il#>3a*r76jEtRv5({jL#?PO<<*7<*}g3?BgP-T|fjcFx_ctihTW-f;P zY9QCZ6)x@aVo?2JA<SYi_7v^gB!i1?^ITbvUFRgC7>|e$As9dG5iABh=cC=Lbn?eb zf8E7sn-jb}+f?}Gn}wYn!)%k&K$Xdl8VG9N>)#jNNxR?s(@hJRoZ}H)04a1y0qMN_ zNjXVIOG>~po8J6^FFm%v1FwoifFJXVBplaoF>?1Z3;YDMx93J!6EMXvCTBr6W+az0 z^FY?&)bzhQT4%p7LS>L1KP!JMay2{N1SjUZDvc1o+Gj_L!4;+}X#VLe<vC$NC2k9$ z!@5kmvh(q-T{7bs=TBttpsG!0W8UNAybb8l)FhPE0kIG%<iDA}<js~YC`%DW^<2|s zOmZV4EpOqZk$FFB+>fbamsIi&ez+!MZxx&ZRP>IIUg!BP$Ie;g_)3=BV(g-vFRiKg zByUk+$079<91H214M4XWnBy-83NifHYk^^LNpDuQnk{~ZYQ1*iu%36?;V)ShO=>9Q z1l`zf>&~6cJUtsS(L-<DQ;sI2&My5j8u!2P1Sy5sfRy<9o7&^f+0W?xHtR_KvEkt; zJ0G}Akg?}sg6;9eh!n(FOAFzrGWe;%b_CilBX_k|x+LJ)uOA5qPT&^f7>^TL;kR1! zOc3KP;!Tk;FyR!-`DvOnNXa0&={v6^uX>oPdWY_PQy{{zB0IfW{U~#}C3-gD<d2__ z(pI=^ZQC;S=G&h=&%o1`-^Mtzjr)a^*SdetaF|HK@y;S0OcUGLJ8ANz2D<VFZWx`e z|0eFAbYj(wUH9)XWWS8i<8S@yI?RCE8Qktm*;U;0MY4GBiexNs7+Rh#>owoe`2^@i z$vSo;*M{m1rb?WzK$pDp+Jp>|dG!Cc+gxo~%cbw`(30H2X978K-TXBP42kVLs79V{ zuy@PCAJzW;Ub~X);Bx+V_-y6vZnxYl;bVb*Y56NT+79fUx$`X^nTxD(%N5T+JT10s zUcYnRYEW2F!<DArQB!p<soCWtzu^}A{G0EHrTyybI|09&8Q8IDh~m%81|D-y=KRM^ z%;U`a4(@raPDa*Pz^5d(e@}@X$0hmN0kv?>ead$)t@?_WDc)xb1NiXGfe;p#{c6dn zz(C+&o7Ej2_T>)pYASF*9Sg-<I9#h<VdbTQ_*)PutKxNtM(7A_hp~&*UKYgO`KAk3 za-`3jYi7OJqH&()k2Tj<;DSPYE*K#wM3_i3s4U+H7o<?E)7G}^0?9778moH=cmmv9 zdtk4vh41f&rH7bNzeU0l_aPp6KT|$<x-5CzA0rq&Zj8w#&$2WH8>*QyKtbe*LD&A_ zw~5bRgW70Y|C_l{?yvwjx%kzf25)Zak{=aAL?XH8d<=W_VvsG{IseB%JHj`4Qk2ZQ z-Yi;G9ZWmQO%_vMJ<(2qSXK$AWrmxJ#Lk4L?B`@R2Z+UR(#nB7dU?yUF7*YHOVoz* zHt!9^TYLE)b?k|%-yW%1*KXUk-`3@#Je+d$+dj-m_TIaWL-w=D*zx7fjc;C9r*<0B z7_u-sgEl+jlkM41Td++0HQ@>Rd_#Pt;pKRjDt!mfF}?&5?tgOgelLyk7lsnrSbCxU zzklskFpO3VtgL-oD7TsDQJ`vD&5L)2^ZL_c*cT(4usgfx?6o^yzxxwA&zhPmeFy{v z9lHkPju1$B2a&kz#FcMm?Swxd%mswbh|X)?ld1qNK?Aai%b~J;RQ?t`hm+OU^H0rQ z7+T+>aar2z2VQ))e&+Z1voY*KEQ-E^f|qQke`5hlh{RraE^h^cf~C&hOpg*rSS(Gd zv-h=mADYjCf!tmygLlcxdUZ`HZiV3P*81TnkoB@}_y@0ulyPswHaP@2-8GMCT&bH{ z?|vffJ4K~b<A4wx$(5!DDhWyR|L$4^7RF#Q0D#Yor%&KrxG^pC?Toup^-%=Oy>^2X z)pyF5Qm5#G#T=1@jTR1W%+pvbdlw~67b>>0?_qx~4K+S()kfj|(72295pIrH&&2z~ zy=+ojv^vJKr+t}a?rPzw7qG+3Z~g!Mknqmzwx?J5`s!ixzajBu-$g9A5rT@N(K8M` z9RDHgR?Uzn%4IZ75FDm*C4F~kL%x}H_hPTiW$@tPTo90a+=oL-s6kQ@iDseVCV^bK ztWrV!aPi`RU+Vh_h_OD&`0r=G6V18_6Bpx!7Nw%iZVq^z`=SUCq@Ym+f0l9qqiFGY zXD(ef58;~Q(6e(<LYF>2a+_MB6wn9u;tG1Sq^RXWoLv=jfyE_KezNy{@iEl}j%uxW zkC^-4*5K{S4|~_3IL4P0pwyB7)^HCAf%=g+{g~jsZ#6bhMsmH-V4V<Uor3S;;LpNA zA2!MS_IBl?V<X7%#e#MToq0SPG$me=_&bZl(7bc*dcaTzfh>weFIy`M!(e;ofqpDy zo#*%4&N|Kdw95Rcw8+>iwmI&R+-W<Gz=mG#V2K4gS6w;KYHB0oOBCtWhG(aNSdxyt zaG~N!JMNu}kDb?VfMjwBlvX2VX*C?1B`EvVJ;=?;h6`ptzw6Jpji6v03#F&ezmOGK z;-u0F%NT^oeZ!@rN+l3D`@xF;y<OtDQH*t{6t2A8JY}FGlqd}sr$kEgHBHBMXyal& zNq(WWp?H6ZdB?6^k~wadf(G10nQR<_!ck(-Onahh=7!7W<t5wDrMUDG;7)1pq-aO~ zi;<N4Z&PM1YAK4A1{-(!$B+^P^|-M-2X$b2itQw4;AQAi#5F$lNZhRFuuL$_La)cr zi+I7Kkzx@_g)ew?4}pF>jAg){m0){O%F-?akIGg`&GJL@1CHyxZ2IEQeo&f(<Ol3f z?(Z&oQL&%*9X|g>A*s<?wM=gs_<Dzpt`5F-DJR&n`ob$O|4d4gUsrnj=;zK~H{G_o zyJkKh_M0QK!u_Pg<#~FtAwl$S`N2Z@hNLxv<tr+A|BtwxuImsniiGYa&6j3XeoEH< z;5<>9re!{Qa=)t#-Ows~4t%de-hepoVr2=5g|1MuX1YARWkRw>v^vFj1Bw0r86eVL z6u#t5XL^WX9~dMhb@n3=jsYF+oh)8b+1zulxL7-d8@>t}U??wJZfLre3UGo?Asfml z;zr;hY4rs#sRj3`YIEnPp0auu`0fqo8@Y2_3ZH>xu6!9*Uh?N{&L_|_Wb$ia8S-jx zM5Ksk8R_F5_J5^}X1_Px+D)BaYiW5&D?R)1BAX%7vc@5$yrnBSb}@SVACuh8277<- z;te;QHw7d=ScE-3g1jT#74uYLyGQ?bW%2aU(rev;$biece(SO9eZH9#ZYP^(xr@G( z>yy(C_89mQ3X0q&arLMq$l!F-fLISD=S4RE8i~UppQX&l!8M=W0}&DN{1a>olhgG6 z`uTsFbf7#RTdsEAU^<adgb5)6nuvnAo6wtKFA)1$okv<V0;Hhl57YJr<u4=xj^D~h zos+JIiqM^;Pl}O;+3opL=4~vSVb}7V4=)$kJLt^!SP4f2iqbB%mn8)=KPuYFm4EEv zrma%9FybK!>VkH~;gXS?2jgXA^JN;H8FiZU&(vw#5lNY0Bnz_dyd;zvxKm3a{QIMt zVa6K)y8SPD{v;dufpQdVGEq+*ra!Cc-&_PD&;yB`A&<t*LK54q#qh;i#z(9YWh3gx zq)4?g1YdUnK=nW4Qh#v(;$80s%A47*7yl{JjbR<=))DWd#9jnqiK_#zh0L!ncx#*% zP1`Q#cl-QL=VNX2=Y!-gisifWuTl9+GY$)6Q(}Fx9C1qe?u+ITf$!{yf4Lh>bJ}Nr zyhqV)Bt*29_OAM=bVu%yQ9bA;!;r6h@>@j{P25ST>=#fFB=Ahjb|t0L5A2uUvmf$% z<MG40U;mr5rk#BMKx|fX7&ZCn9vj8UUr)(LZg_i*Itb!$GC_VspLU$`013~hJ>qt2 zLNTo-8ndbVurK}MqK4uu3G|;oTCUpa-lD|+fGtOxi`8aTN3{?RqDNWL2*+6pY+$?T z+hP@z$hmeD+E0pt>UV_N|6UHBFJ;AuKO^ey4kgs*qkVFkreC^c0M_JB7cdNAmG&@q zc6K(BvvPK>F&Q%c?;{`=BTE!m02B1^-Qnck@^%$~*qrRl$BK^20EEKJ>y;tX<2Tg^ z7nF6z@-6jU_`GXp{zqB*+w^?@+On6w+c=DQw?{{MdwUzy0{<5vT36pC^%ZIK`{ddZ zhfa{*nXu^>CX=~2L*Fv4Aag%I7Q&NVN>*AE1YGVBekI#I9KCW|vIzSKeaa9IPnVrN zVS=eTBj(R1>pjr<2~Nwn?z_6q-u&<HUg%WXWNEhwO1)u4Olt1X=YF%SCEEM^zTqp3 z8Ykfa_o-<Al8>oZt{sy$`V*5-0d4T&L&M=22w5RvJUf2D_7w|3S94&~>VLHWVsXmU zoJs(;$eie!N=8ahL!OPayMgaZONZo2P)Q+i`NHna7_A?5MZ6%9CuD{T7x31IJSJtr zvRd_zQd{8>{n@^cr23^Vc0XQ+3g5yMv26ZQAPs=N0VikZm(_TW!P}>>gAtrc+c(JH z?yr=&@$U?OSX*t#*GE9%wl5s&EvO+N1%%k&Z5P!UG|z~)6<LIZ0?j&C^}Hx=j*~V` z*tohQSlj$%O~u|1Dy1c<vBGp+YBUeRFU2*tVSt=wK`5HMn07(GCqg8mNapRV$0G96 ziC=0Ou$sNgUV`nGi)XcpzH<N4<4f&@U2BpMXB1#+hpWl4ezCY3@|+Ph@i-N%dhKSh zlNUD%<P1Ey-#}d|MB=TUg(z#lq5cq$Yy56HxfKHoOYhGu6e!4gINhQz=3XRNRK}+k zig{y~9kG$;OCi*@r}RTbM6u-+iBrf6AHJSRwvoP-!XZ-tIy^VLRBRG>WK3&}*mm}d z>9hPxdsk@!0*3D_$BCqBmMDws5N+Aiqf3X=h6-Uk_{To&Ye&?$YWxq=GzW11xa8JO zLzf9F5SYijmDh_yYp!0oB6MoiXO|D^CZV)iB`RP)g}Y;=vK(jTYZM}!_>GS2u2KBt ztiL{)6i>QBh;SSifBY=fuWq8-1;bQ4>>)E-Kdg&4r8F5)1+tmv%^KEl24GcBV6NvA zEAw2;xCQB51aXB6c(AThiwz4aL*a1ShiN+XsF{MM-S$_4o-%InYQ^7);~C%DL;fB6 zV9v*dtDaqE4Uee(ydLc7ud7HnUyrKe#6LEAEXoWjCxS4P*bz<I=u9P}7zjvujC1?@ zYquwAC3%pvvCGh`c+N_zFAx@9<2EbQ9z5C<^*l!N`wR{2GgO=F^V5&_kt$XDc?c=@ zSj#E7qfPUdd|g!Q|Lko=;~o4SGTXCiS&3S+I)IfUn}r}0Wmp<~yLAhz>}5p{9&j?& z?N#k&kCWh0Pw6Wu_nMU8_$}<ntIn(!F)6xI#E;%ofH?7ihIM(vojb`cn_#w4y5oJx z3&{qBpD6{a2G2F6-#=)rg0Jv4Y|{kW)DtsJ>=BBRam_U&8|P<&zhh++jrKa3;|XM3 zin%~&d4mCbvr3OEj;HoG<s>N_px+<9Qw+xWnFtbm>W#2t(p+;Dfbqwc?M9N~%OBJ0 zov;pUB2h8Sj0LY7IP56Fa+$p>g=)o<Gbj>B0}G_bcLNfp_?sN&NLmC!qTHsjocf zXX$gk&-K(r_w6C?ZT*ItH7s6Yl5|9a0e^pqA{z7K0dH$iC=B3I*HQD-exQeBcG)P{ zaLKx*efW-c=Sz!Us`=NNH&iMd54lf2&H!E(%?Q<bZ7FIUDo|q)r(@0K=>7}oC0k<; zhKVM|?~M#XG`&$oWuKlf54cEuwWSNklguK|r@V_II%VrC&49*Hh17|$M?>yYQsRRn zEZo`H&H@H3N~{f+)oi4YuZsHPmtGwYl_rPk{FX}Zw;5tubOMVw_*FyhBWl|q+}MH9 zP3)?LDB2HB3+^*T5gjIts2!2R<8>(^rDqXSf5l@RWH>*g-Nan>(Pr5%NOY#2SH6Kq zk(AIL`>=lYS2mihT|$I%WV*J$dI*KQ2WY9xfu;C6<|+6*wNko0ECa;yW(erth{>5V ze4Olf9^-L58jsQ|!sV1W35|5k5@fCg(W_?9{U3)K+HI#smFZq49iIEGBN0M*SFO93 z%RI^XcX@IJVWlXM%woE?`-+sTiE)tkWl@y<Tz#b|h(`@S9pJ)pA6K85voH_Wxz<yE zbM338&Mk!xmQLD@7=Yu6BA@ImO!dE}W!_(an(TUEH*L72txH~fv6A~|J-3>hSQiK5 z2Kxp7jUbnIPe!>5RQ0XIS<`$^cu<?9_naJ_*`t>5_a`%}H=gX;gvQ_K^l+UfjDb9I z)o{SannubRm)S)wIkz;RZV-b#YVAKAQp@{xIa*4;ShIMeM+erx7<{gu4|U4yUw6KU z(1)z*m{$iJE}xK}-vqs28dGO|A_}BpoC13$AO)N`M-{%-wD)?U%74cmbIv+IT+DYR z6}c**>wseisv(XTHRQ9uhyNXvxmLI-w$!Y9X4q#*U0RA4&vO*i;~*Bq5mbmFawiX8 z=KR~rhPxt9g!St<Tzy`|=6-{>7f(fVfY;lnHOCkO6Qgea86mCX0`Wp-nR%Ktp?wOU z|83rp(0w#e=HG50&?7dwCzWWkk16r!ReO)V3>Y{T1N-gqf%hTJXwLeif!B24qN&sq zZ5?{%fNSTvWyHB(N`}syA9sDNz&G@TdrdSfu?QKpbx=oLtp5a7{t0lpRhK{H%;#Cd zLp+XEa??n$nHL6Q#q?l(H|Skh!_xqsIOct+#h<;k%VQVI=4fxzzs_T{;OnEnRcHlZ zPBTcW37Rs}2`K~?oy2Bo1k__%S(!zZW!5Ie9?!kDCC}~G2=Y?l!I#r0kmj*@=O+Aq zB&1)!D<LuTyX;;AowGdA^M@H0U={{la#cHXa%LNaLgi3OdY=}2+oE8b@AxksMo25) zE&H)vhyVkrW5%T}&E2v)@cI5?+2Fr}q2e=hTIeUg8W+~j&CPw1I&rlLgs<C9xw<2U z2`;-M^7)QZ$mMai({&g;5-hmXA0#99?%a>o`Auxg!d$hnaoT@;C7Kj3p>YyQF8^g^ zF+(q8YLsUuOUn{&mLI9}atMza1tdIVZ|=${E%=~085Oma00tlUxi_P@H7NSX-FduU zB|?6!|J!^&H7b>!LGIaFgxuq^X>w>AvEixQpTCHR(RsqW#@v4y;a3b#!zmgWp;{(X z4ALyQ`%$G=`1#z97TMw7)`hR1IEL;S6B;RpuF(pAh__6CO41{CW(U0|{tWX-7^FI^ zWYLyTv};ADoyy7{-W5cQORi8T5fx-t(+(mWVD>^Cf=n=HiV^}*(F00R+E?#9T6_06 zIt4c<RR>vn*##akcZiZJzmK4%nC6T815_iE`pmt)5|)EOuemCp(%MNeo!U(<W^b3Z z6k}SLQlao#*h>m&JznO0A9<v+#(i5ZA*%b#Q)1FcmGD(x3ogyaMM#xeOnSVZ?8BJ{ zb<5{*bq!n2b=1}D4v<xvF|IzfjyJtr(9r3%K}`oOpp?T}v)C{*?EghA3@aT{eC2 zit*?J1s6!sv`CiDFDVahlslUF1c=oh9!FN`WQdAAYI!g4piVORCUL{t4h)+Rt1QNa z3;<nYT*5s4qG61Y>`h_VC;k?)QhSdpa~V|rbKGzGT~{l(BacV$j&Ue)WDu&)p<NH< zCO{;m(Ms_CAdFS8p-P|aL^Qz^H-{-`_+gKjkvv~`gwlM3Ed%n+q++*}hlgJ>t+KgB znU}s#fJ<_+^85RHZIIO(_utUT&6OXnD1J0AlO^s~35}T0*S{;&YpGGJj*w(sVl*=9 zNroxvr*6s>$4QS`ha4+pwJ$CI<a4ctG^0Eda!=z01u9k}-4KOrlnp13)?i7<POQ6) zQBiM!8fv}GRtv6i_3QUsX1i(e6&t&0Iy1&|q_8%(?;|{$?ve@d5^rZ4b2AB(BX!cD zThHpL5oZlhZ5uf2bOkS3G*?IHHnG`vSg?VoHnA-BV9`-=2pA?z#x(+?mS3cz8B>wX z@hjrMy{BjOzARck>gqVV((0p&;5z-fGO4@7Z}sOViW?Gpu~4xsBdy^LpK>X-^-&lh zjEdzq1JR`U1<pEL#l8+ljD>1GY}T%)h)s<|8Cgg}JG(5+<{BsEJuaGQou&1v<)sTk z08h`AFNH_MaO0=)iOYo{n`vCK^qwz&(>JogLe!=?7v(zeYr(e((mUZ$4OwBChL7@S z{^N`+>BC%`r!-Dx2?8M|mV%7py#9##`Go%b=&kNEz3gwcQZTW|r#iT_uScus!S=4B zS^Yd?`%x(hp2Iw`4FW>2&n;5X<bnQ8n9LD1kJewv&!d0Tvq#-4_NV$vfy_?}gRfzK zc37B#2kL;7)oC~-cGkhJHo#?VBcl<im)usARcg=5d`~X3FDk)n=KeniMr(%YNMUt$ z)nM8s0-P&JL7s@y;&tsFxAr$t+K9qkR%MHBTu20EJ^=`a?^wSo-6e=BZY(<#Z6*l{ z9A|qj+$H90UJz5Ksuaz_iJy{^l5}B6@j!Q6C<2+Rn_)e`^-zXkKy9ZM{wVz?@jJhs z$8@n4e+WbrQ_VI~7&_U~Cuok&WP-mgLe9)H^cL!Y-qwGpISHEV0yzuKiPXtO=qFlm z)oWSadX0|yZpd3nW~FBjVSHIyw9JM>E@CxFu{b{=E6HxY)?9B|mrwiY)o%>_@O&kZ z+?#c(Eh?QT?$JNhbl^H0*<q>a$IJ_d_bFkfh}v?${?AY460uWGU_-=NK<#ZE9a1wM zC_;|B!frU%OV0SiO|NWPmh`^7QmQqG%gEYira5+Xjc#vvsf5}WCa1xJ5UIWiS!Z@8 z#2}>`XmrY=yC{1E3mWX<EUevfce~u$rxU3rYU)Du_!}?TP7=~Zn%byJ(Uy?+AR0SI zOTLn2&y4SWMSb?yd?kA_lt6R+hqz^4py9=rFn_1Bu~bSb5P&~M{6dC&>A5%0(aEi< z18^6X)Zw+~^=zIO?*ucH1@&3y)_T$0tnX9DM05zVc&`|~JJ1vQrmDTN;lkL~rys>l zMU~c4vtOB_xCiZiAypo1oTS7XtBF&>_#9oBm|NVf*ueTTR((9oFbUaCKGxVR43%39 z;t{iceO`u6w%B7*W=TqJ9bE1VvE6W;JZQxtq)r7l1*tM<oIrbP$F`fq5uOk6<HKr# zvyZFyHLhiB?!p9a^s;3hR?!CJVBG|2H4ey&4<c<I!UQ@je&;E@hY#F2ohpOa_${he zz9D57gbPc#CmXsWEWMSc#PsWiYGi2W1SIm}+qr(|H(?5J$i<)FluT&TJXKq6bb3e> z^894I3HE-bG2Uen9xxwNidQ-xw2;6ZJ;}ZBjMt$G&-2K3G&_89Qh#ga`=hIF*>Pnm ze1LinFSTc2W`-k?3}o=Gn0t?E0<kxHi$_I2bbl$vv_d-eeFgx{_b5ypy;+t|@$Kkm zHuR<g4u`XHD##i9I=V6h-#6YsI(~dDk5UOYMIT+cD)}|FP*|E8z8Nqttx2->b%9)z z7`}xhID!q`SP%Z4A4<$lb@TA6^XQQLdJL;*$(tH2&6xWt06AFwc?1KRV~^&8v5Rh= z#|TlalFoq2{q{NySYlnx;J=ZL(a_wF;Ooq9=+Cy6B0-x!spal=aPAfsW28QOH`?I& z6sRE**5?`F+U^h#YI$xghxCeyL%_j0H0A)7?m=yI<vCd;>vHV9W4_m6&ly&*j9m8J zmlM6R@&23U2`dd|&YSk?puC@J5H(+l_A&i=T*u4H>(YIP-W*WT17TbU89g+Tlqt*g zVB+E70ca(;zpV)=dUA~4-d6VmD!~1vP)d)V2JgXscWF>jh+?I0mR|Z~?5??7R%D73 zF_3Ub*xr3gdEBm+jl5W3oDIcH7n)W_h8q6X=zsld@E4^@`XiM;i}EaxRo{%K1@?$F z7n(k`Dy7u#8+||<M<N~jbUg)WmrciS`<EA1E+^_r?sMbG#Oy5>V@dPcOg=&9SMx8i z$B5>C;y`mJJ&pXSKM_z9o%~3pHVGlpA;A_4N&d`Yh*YWEAGixEzv4{NdDWSiHN;aX zWm_%V*$WjA0`8Sf3`xEyT-$U=TgR?ii_YJc7?%LIPJj4ERG4psTCs9EAt<}~-A21j zuMg5C8~RZOzu)QkZ#L2R!e#K%9l2~cR6>V$&TyZ-aMG^p^g2Cf<W%{bHq!XpA0uqK zewV$aLb33+#@`d}qb@~9*Sm^TVfjMowh7tz=v4~i<UZy1fbvF|tirIK01(<n^X7p{ zX#ae;cX_f6@9@8@@xMGtxa)OAi01LI)%ohqmB**@hlHLmMW&lq_GjLP#c=v#BoOg3 z<I3NSwkHt%_9^JqxAv?HYhl&p-7>5Yuex`0p-g?HZ@xi|$9vRd9?({^6N6o=Lgx^i z(K<8DN!6!AJYO?3=lCsYnOg|jf2!?x33!wxO824B55LNFdPz)Bf-SFa1R%Y(g7G@9 zDD&Pvf;A|SxU_C<TBd;CZdh=cjrZ_;8P}!*A22PF!piYltkTHGp+8#_)~vZUe*VN5 zyy*NS2DZl-FfpUV<BSFptik%kyOG1#Xv}$9hEC4noYP{>JMh&4>p-vt1MA`-mAt}K zL(MoD*2$9pJ6|O`C5?-H7Jo#SF=5Jk+<FmaolZv0;bwPjvLtGyo~U>MRtM_I=d5gs ziiBU8RFhDd6^Y%y_?SjiXzrvArBM)nB1_#!`e`Ir)rmGz5M-6!$Z=C3>b~{lj}0Ll zfF=xoy2^xf{7|ZhBi%Y&9=H0hO*W614(TJIs5ZYvO634cSHX=TWjo^o-VgZaRk@M* z=ezxjiInTd7z7-^D+?=kWBV3OY`Dxaw6<L0?dFcl6NWUd73xj|KMm)uZ<<gcC_ldi z>!Tk=>%3B5;|A+zL%r{&9)E8?fksI$%lv};`gb@CY27rLcmykV`6C2&ZQ9K0RZHdS zT`PeOtK|(J)+`_D18LgZzWu08A{)hh?~0mcK^0uLrMsh-8mTj9%nIFA4*_~i9_d5< zgD+xW*I&>)s6f2V43kh@^gHxD7#AA5x_O?4z;34L$one;*zbdl-}n=2Q8=qj$M9CU zW_nTR=hU7C?Y}nEjRWTY@PE54wX!`^4VB#~c%N!sB-+N8@i!L3#B#%t9l>L5{^m}) zjd|7@+?Mv~fbvT#q#m*HkV24g3q=u6?(nd#?D4C(xH$9w(b<tH8~f4Jy&t>_2(&8S zHT4LSkx@`sZvHB{rA7Hl4BEUz+)V}^Rkz^|xB!5ZfPmmutp}(|Zn;}OKN+%iqx5?p zh;*iUfiY#z{F8C@mC!ipijG~Yo2zq!8gm?$f$p(fX=;2NV+6TpXIXxLlrf_3=K4|^ z96i4t{PSE<|G^1GMx#Wfj76%AEWeB7W5lwZEzO^&5{Wh@sS(H02#Z$K`$4?uM;S9h z;PzE1mV}(PfVwO}S?uIbwJnDdBtxwmlnEx#lIKlwFv1NsoUZ*i++J3@31!6q_MAS; z8nWRzlh;snyvXA6lR)kv2o;4(no2l7OrK#lq?IW+tJXz36^H8-;&A(ANmZK65ss;1 zln-=5H(JVB<%9KYX?;gz6((lRqnW0fsTe!I0N{y^XF`mekTPMJ17}1M&mc%7E@32O z+q)dhgj^xB^n<j)C!di#8rIMQ#Mx))#DSH**joE3o~^kS(cfMNCZeDm_g@+e?Cb*x ztkUM$Jiv=px-$DJKsWeN@avz4x{_<OGDj222CeS=>4GLP(b2?YWMt-p$q&44&Nl#w zcb>43^(+`*u_Y=DYH`!83sI0F0|7wOV|jgXT;s?LFfkpwaA7iIzx_T2Ha3cqVBQ>O zTtJY&L&3UsoAZIKwuC?g;u`wG36orC_&x?%dmKb7<#kZ#`@jEn0sb5hYo4%wg>1=( z6s_vJKvq-svwrgMSB&WS{z`65StV(&iPj9!wxoFwN{vz(WK7_OC6FZXL+XGScmX-X zto?gkbo`Jt<<a%pHsKQhi`ecs*Cds&T-(q<g<ZK(t4Rr}l~w@!y2>v%<+qPi^G5cL z{&9i4Z?Rzmdn3*^ZKk%R($jQaSyyjbPJP3=NuZ8qv63u6m6a5I@PzB8z>?8SvVlo5 zQwNWx0n{!N(#03bB*>FXFmz#>s?ADsArTXPpCmXu^m}OZgOfVDYX++VoW58z9i0G6 z#FuknO&)>D=+G0zI0qgggYwQa`1HzB)vJdV_EK^RZz>FeYimVhPUqap-+W_*h1%3J z?x>xQy_zFt_ndR_0xH36$-SMdZ{&Ki2?9JbLqzbce#`e{OA#1GgwvZw{rUE`7$~WC zXn~PS*zG?k$VxXMJDF#b@rQntaDR>0z9pdJC#00w0|9Z?;`(5HJU@{}R{}>*_L!E4 zll50!xzX|y=Gs?~oH<37EBmy^zchV@vY{^K2hVc74(3OjqkTUerm}BE=qwzB+OO$e z4yw76mBQk$Msx^ae6oRenQK`-7~!=7Np1YqD_zqjNKuiAJ!Carmkq43mT}q5^F<8$ zyLo816p_4sA68yB4{YktAr)dSpnlV{#WPDMH7}5-E;?nBTlG`QkjFq;&u&C~CLs(6 zEOA(y!<BpergeP2J*2lqYRE|!DEy7Sttb}3MPaR$Q-O}cvui+#wEC5;&c=l7-62bs zQXz=xj6;pOL4s6Jn<`#Ol!Wgen}AKIh<Rc=bJcc_n{>)r-QT*t?w(xl8&*##)zoOx z(TSx?w)9kEmLv7an)aU^WGn5e_UCUZjqda_L_|i`+D#S-yWTC)pob=35uzF$nNM~X z7xjm{-Q8*BFHz$)ZX3G5Gyu@SwH^J^YF<s&0>+C<rCR9%!5iKNO&?i_I4yb!?2b*A zU_2chkeLR4<D5Ld1C87K*d21mYdy;rcpp)k;8}K~ghs~We=PitX@BU<gf?{d@A|nQ ztjiw#Q{mDWA7?-M9KdOKe5Kz)0r0-RMS0(tYYss_p;Xegchcj}=BLCkfZ;I%xUdSJ z8z7K0GIDtlh53+Q?g&HV-pih5sJ4vBSkcCKkzwN0;lQZ)RG*q@*+E?rB_%Cv2c>fS z0*Erniu(Yln$fy>4j^refe@r9`!~;8x6L35;ERe$46pLDx_Cyho9Q~~#^YS0JcHt^ zlD=1fCa-dzc}a)M`{lDKF&d0DJxTbOaMCV(pE$}U=t+cYOGxks;?(cVy5Q^@R_V6x z8b7zo!?hT`m8x94jo0Hn!ZbK1Px+bTl#5XyJVlgw=1T(2HD&3k@`nm5?a^Hh-;J6X zCDu}30+yBX`Kw|Nyp>7L{6SY+Tj5r}$+&(;G9k3x_cTI2&)TrCSWHX|f3^{r1m3C+ zA@i+IuM*lcVFnQik?bvayO(kRT@1`$87P7z-PYaza`Z*%(q+X;AdBzTC4Y!kw@>Wj z9#Sg&RGyML@H#a@Ow(5&fjJ=Nr*gf9&rMqkg@%4O0PQ<E3<ORps<+d0ays5rttW@; z7{z<<w^|!ULjYp8I9TV^%D%Q$iic)qndeI;W|92bci@%g;T|4`aZ>$yw(kkYLp)k+ z&zNAJ&-qB1lN^~~&3W`L4t`9qHpwUUJ~yUFm2-J-l*-z~ss-0+)}}4nPxrdPAN{r# zDYV-_1KiX<{FpWw`Q8wnD8}qkr8}Io$z$upQ?ne6bv140yeZEvRh(+z=Y6f=0}fyU z1bk|s9tO?6yV{RI<hUU2k;5e&_8*huLnX}cDH5Tsn|&smw@|8h5L5RYC+VdLtGS|J zCA$?FOxy{WOmvm%z?^%Cd6#a>Oe+-AqiN~4@pDm2Mt?~@v-~j~JhJVL1Qu&~uGqo6 z(HUy|C}&s2`{t9ucP>rdL2O28sP@!htklnDV?slK79d1RAv}r=cb@{Vl0cNzo5KaN zqI3Xolm-WFW<CK)<QXm8wVMwRg^TCPQ-eIZ<MJjD0DZOBC9RQpBY&R90sN&?l`;#g z87go~h2$AWw%vB84=FvQ4iyg8f38|g#pjv5r+NBTeU0c5c=E~O<_Ml-GNg4s&<6LG zA32KENp)h#;2J5G2O4O;EXGBFDDpBdX!Yk`aej9jNaR?Co<F2jAPU{k|63ZY)=p8~ zo<yzp6@U{O4^E^Sd_ezb(0hc840uEg1YbjI{HJd^K6A12XkvH~1sgwRZ1er;4%bKF zIg)O|wqrTZrFb%I+*x?9U|933_F^%Naa})QC<_}cGifwTLJlc24(n0ds^!Xi2C#;@ zlZr9BfW=aws5*)l(*TI6i({7L7RoqEg(iCsQS!vY0_;?LtyA6vJg1OWA1uD;Q;P$u z)<#>>m&xi{ahWALG(O0aD+^yOgT;GY8(5{hYP@u=OR84aP)$avs6KAx_smYyNw1st zM*a^;sZsL98r+^<Dwhl?Vmga)gT7*WHX}7XUN`>))&Lctgb82_*ueJIKk93e-0Us} z*Pm7IN2ZKU-r^-VLZr4NwhF^KsiiaLy}x(gv(%dZ*{d&45m20>ZcFe`I>o%O;tX@V zKNNS|6CRNYw7!xunXfFX4fsO7(_HeG*nyci9=CFAvq{F?;ZPwBjx~~(j8yym>0fJt zX34Llt-wY9Q^hGU03O+BM#a@H?+Q8K6ic-ovI~4DhVObVw0SRk(!hdU%i^$ImPkp> z_4^pxshm;)h>Bqz;D<sSh6C{oa<t;XEBu9j4L(1(yUy>)^jh7Yr#^`*Sf9M4u1+JR zMFpTZt*yDtHX!eTF==woFLh>S?~q+y7@vlf5Tsdju~O!rbHaZ{2sT4f(>GOy$e-b~ z2dUEWAB1_O2t;$^kqjbL!A^AEuYM1D$)i?tzx_xeR(~BvlST|6`VS{r8S#H>*c>3g zrq3$SrSHJ)75m<()qU9Eh5WURs7VKB^?RNKVjcHJv~Fba5v0-4Gp_=Je^^0$2E0OG zL@s*z^r@YV<W@-!T;*WwWrZSpiQxt!dfIjU%VtmGJ8J5DhKUN?ujvGjoeM<RX@K_w zHl`}naVilQWU~v``dBXWiNi7^`CmmW1Rx3O*NpZA)dc^m1&}u+-1KGxYFZ*7*<R_T z(F=2&E&uZYct3_L@TmM{51+r|Z}W6m(k<hADwbPZ@i=|g#3tiSzWmp>n#NViLQntR zx}$nKJLJ7=AQP+t%|ps;xSsrZBk_Z_ml(jSji}cygMt3+oJWYcg*~c#c&vvfQ8b@B z@n3|_FXNo>crRd#x3+_!8i?rZcsJTQqBdPoR;z&_bmd0w8Amp^HONpnFah(fe`)bK z!=D=ZZ4CjI?(^E#acn%x^0s<nZU8XtF*HQ2x~vx?qwfA~yU}BUNp!Zn0~=niS3p)S zwpfW5g&pM%WQ52PUOh}pkd5UOynmpkwj~M|zwi3%={VjbIi9;KeS|GJI!yyt2@hXb ze=0)wg=60bpnP6kt9qvzn`Y^EO&QzW3;N^!yx+N|nW&xwUsbjX$EaINh#jASJoof7 zMVUr6REfxAdnR11ICyP1!)jwJ7un)wYal53H7w6qErAkTOTwsUzH%C{)P?h0v(^Qz z2Cyosv2@G-zE$_%>Q@BlM5Lr*0BC77o+q2s>geJ;RM(<e5&{qb;eaClQ~zs5O%lo& zE43Yh#~5yOf4sq};u!l%Cmte7ZE&ZkpIm76v4cvn=F4FOU<=OEa+-KCu>O+_KJWqY z#$=CLMMFw2&rsGbFS99&N=_mLJ&fC=k&if25Ufv~@e#FmXXRO4bh3J1Z4wma;u_A? z$Mb<T)+!@h=a%=bN=N-{p_&?0%S(I@uFLCu3)Hlj7i>qc_~r!F+W(KH^A2b0f8V&G zsG6l#%$lWDGd67%wX3MwBevMoUZvCswMMeT^a6){8Y#NK;vYW&XUdtJYOTm;E= zPR@Cr`?>Ge`<-54y>7tk3!;YKA|sE2EWuip4dP&*YnH&apuGRJswC&{or-F-l%o(y zOKbmyW3r<qa;}KB&TR{#7+<m|2uM(k>*Z&hza(`N0BQQ{rEnX?Y}H$7*KZ+x>Bmzm z93mEN3}@yvz@S26R<gFRIeRa##jxXw)~mylJlQ37<f@kqY&^LrP6otiNq?W?{HMtN zTay4NUx48++h#N3?*`UDLZKzg<_n=A+>6n(KP4Pomt7AQUd?#T2mB|-073&{)(%iz zq~?GLW8NjwA@Htza?!^`X$fJMj%oCAzPJpd7)Td=SZ(lp07*%R#6)mK!s>bx36cIe z@thK3%4<&?q7x-26-BiYMRRhjHhqBP(n`n;(_jkqpVxziDGR&+336mjOumv`+)0Mj z1p}59Hgcb(`sIohRkCFo$GrqU+LJ$A_GN>@PB|Ek=b6g7UzgIyP>9HW8|g=Y%A2i- zU*D1jlBEkExyhsjrWxQCn3sD2FI?jAS=CZbz6F{cHGI=Naq><Xl30aOx<mtiBn>?( zfhbLh4Lk{<!G4vkwPgyhUg<NjV1BEkOOALFm2c-_ObZNl@{d8|ON`zVMBfE*rnwG& zhD@Bj$_-W|`g#)TYGXQx7f%~VK(Iw9&`*Mwi|4|HM}aGz`Oq(ier@z1g0pC@+TS_F zYVr2pe#CY|c7`fRb~CV=98+oa5D4bsdH{0;Hd+8C{{I$a09?(%sgd9He|5(yrHgRZ z(|88p_7+>$xf#;)&4D&*j{g>L6$fi)KY;*e;Lirxi!qn|=JVH+r|&wHiQ0E-=gHJZ zC6D}o$tCLaJof})VM-|2)YD2%ZpaM-A^yJ7nKbix6ti{9E4$&JNXPBIc%Duz`52T9 z_~0e?lCcLow$$*#D4ymDWnRNH4yJ8dAh93C^epr8f$9@}_HY#`8v=Rys>U&3E)oHq zb~FzN@JbC#bP{Vgz^?AqbqC!D%Khh#vXWDn15dRKAo7au9!InRrg$8L{k&d^0n=Fu z0V4R85Bk`i=J(c;puKOOIuuhJtgYC~50#?SY3{l!OUiDto<SQ<gM0xOvL*YwX(t{o z6P%uTZL#@%PH?n=j0B<LGr2-LhAkKu?+Q*|-h=s3!JnJoUAQO&SXl96aJ$|MRvH!g zKjMn0e!xcbHRAoR;2iTmzwevBf8@2(1ylR@?4{e<ss@&^5C9yWnozp{OJ*33{72TH z-tQCW48}d1*-v=47%#o3<j-DF{Cxl0qXJk>sck8AJs-twp7ZP*@@qn7m$HO7yl}7@ zcnp1M2~HY$O65OQM_Jur@ln#==uPrzN_n(fc%k-dedfpO6(|^}-o3QxGR~r-)o^6V ztM0#HCDuNMCk`$ScDw%z_)<Tb`vvyhYl07Sn8*7Np4YW+3!zH&Oa21$j{-D4VD|Dw z0D5K2^YBd~3$K+G6=%rcf2e~EknPtu0M0>C!m4><O)QhsfAh*CxX6E0S0-BRAjsF8 z>U6-ff6e70Tw0**#sD$AmDEEr=~1A2PemnjmFXqu)PN2*+6`q@%0ehDAb`VV7uNxc z%Fh<J{Uf0Eks&0XQY}XFllZws#93hx%TbxJEN4<sMWKqA)~d!T6`?*My&j*m%FsNl z=HuXtrNyqiM}ENj`@mHH7eslPi+5PlnzoCJSB^)uoLb`9^AEe<um_Q>k+6&deyQUp zAQN;M{M&WBS)#~)cep4OY-*#)04Tp4kuamzb%sxsXu$rmTZAB4Qve82^<6XXu;K@1 zXNMNr+E^xa=!yl74<83-DFo0FyNJXOnfjT<qnJ(w+}std%ysprGCzQGq6}EFSt!M_ zobNTLRs*c%VbGF)htqY||J+z+aJK1>HfyfSaMv#RPMnbM`NQ$TR3Gr)_IiF}BEJN- z_h2LXTmiLgqbqa@w!2EApwqNpk~8@A{vIcO$?o3>5PjcEk<WiB$dGT%J~I5gcj}u9 z;ZE04<o|7CpTPK9_Q7_Fx<Q$I62FuN;nQtK_T%WhtAEPB=yUsM*UZ_sFOe0>BUa}L zK-ULy^v-b8{S<YbHwC7?w}pYM%FvaB%;pNpavLjlepW#5tEB#jP*32ODr#wI!pTF# zujlfBm)ccY-I)?Zwt+E8#$7lWwv(iQP);w7^8~y4ROkco-zBnAx$pQJmZKD+4`kQy zIwH3b$%z+WyLz%w^#6DnF3pEu3hS?2kXkK^1OL%CcIgv`^Q4q7fy^)a9TBZGf{~Y; zs&@ogSW!*)$Bk}*fu_*urxEYxVVp5{9MoTG8oid|ha#k8Y;<OAmQwcZEF#FFP-+=! zLe*eJ^U2w#-1<32(Rja-6t_+<2NNQCa@^=IPI;c20>N+*3!v~x>bpf1q7s#Q8?E(C zr4q3{R(t?@kTR@Zv?fG_?U~F~5supFtndI%qdIO9N^$20NB9q*v9G>s1e|v{pchC} zq`@*wlei{hKzgnX+qqxV6N~_NlYMa9wVrGikhgAmXr;=e+<9n@r0aP!5UrQcf+HNt z2LC9UbW_7Uz|9wON_YUjaTZ6K3XgP;XA7^pSjyk_ReB#!w-)dD?Ye;{Ye`BeOR(+> zv8^Y?c>O~hb@@^g`Co#uYqv6H_r56N^aZ<B6Q@#$yb>_@ZDz4Pc((5Fvw_?Z$BdKZ z7nWwAlAzlWcaXJ>jMRE~GohIK%@3U}QDRlq&oL?uDIq}h?1;D~EdEd&DMTmH^xZ?H zhp^GxB7Urqb&pyziBF9dRCX8x8CCx%34;M0Rwq=J93*kh>u>}esf!#PLc#b36`xK2 z0GBOc-aKA-Tl|fq-zWj|wM(8%4E}7$NJpVA&oyx@l)EflRmbaU(;BD?t4w0e74iQD z)WiT;xs-mq>7So~=@~LgY58FH_=%Kn^REhJc=55Uww5FA(tp1gtBcPy_L&g$fyFt< z&b$DR)}y)=JQ}RnhsN!ex%L^dI=T88vaEh=P24H-3dOI1&bICj<a3>X3>ga~P)gCx zblu^Ea-UhhKSGamf<`@MjEq)dyM0!Plit4^4erAsh%>zp*~7I(uD#4^#PK86RZEI6 zPwlg1poz)W|30P;1QK}eYi)BuI3zfNq9QSpCs-W%93Hf=7Ng)_k8ReF`>n&jLu0mm z;&n!ZodmcyFGm|**;ue|Fpi#FFL7{BFr-=uXmMU7sI=!Nvn2hfeD>(4G_(_@LJfbG zehSzPtA9O!2-gs+T876Wwj@0H5LB-yg99inOJ*@UXr=hE5U5@R2#Wz*4_QG^NB7l= zO02AbNz9I{cxRv=np4$XnZ!;G+WWXNTymbM&TP{HciUG6$cD5&DJNemb~$%f8Sk96 zttyyC`hb{bnLG_x|K!?r$Y{<r(Tb_RaTrJ@UO4!txF%NpmmHNt?3NWXfSQ(f8E)s` zFE*r8>)>xPFW^M=eO!$C_+`T(DRRY^3(<>24T;PPL;@t_e@5yJvy`Q^(O?%{=(70Y z-MZYzu?Kv2?=9XaUcZ+NZjZ;Bjo*7YdJkpx?_SS>z<0ZL2k<)~B1Xk~@=Em|U)tTt zj@cG(r8$UKSQ`pNcv2IpeZNmyGaal!_qXtmLltk(p)7CCL>xD9?})G#0ekr0oU;Cc z{-a1m6R=in#P@P)-QnjNYft*OI@@`+%DQYHPfA!@QRz(?q)2uC7~n=Ms!y!|*%{kq zAd<4Y00D$=f4GXib}m}82cGA~!{`iXG(RF$Bt}r`I&yI$;2f@IL$HOYbQ<iVGPjeg z3PhWS+BczIjT?k0@k*&Tu<oGM>{>ghh-Zr9NONWeTbLMp0Q>x>3B8%WinH`Wm#(ww zL~lP@jFti*AXiyW$KpxQ2<Bu|Y~atD?J4PTB_PvRUO%{&?IMk1+k3s*XRLgsU*GAH zH&OoXWp8GfYQUH$p6E0IDXu^cUe}{2yinG#R}gBXXWI<&A#92x_yY@r!(UwbUjpGI z6igMnTp|}dgzglKJZ%F07cJzdj}a!OWn~oOqn{lvJ1Nq<jVFSm4CI)fY)8U8Wb7-V z<aGWs8y?sgc><Z05ut=Jv~r~fxF;_=vrPePj}xgpLgUrJ)wihvVW0dNC*`ONq0$YK zd%EM#f#LXZc9IDDh~|F?uevPM1M9ElmOxkV$4Z1!AwZWk6=8yQ+UjH^LAXjFl@K;0 z<$7-6?Hhe;o-QXm654tB)*85XpTJ8V{nP^xhees+>w4*TRJv%5%W$Ov=bqfWCI3;a z^t9HmUf<UntWAj3CyFCa%T{FtDl^!=)5$M>Ijsn{?kFV5ExYH`_O3L^JUCm0N70{! zum<{hx8djR=ns{8+=7i9t&&``jY3fdfi?lchi#v9Up0RSqBjv$*LeBZ3vHoGb{l%= zJGnIYEyyeIJtsHkq2K-&*vE$%rg6ljQH{0|(mh`J*P@k4@<xogE5vqC@7F1e1~OCs zDFwd&Aecv>z@=}UihF2}I!w<bfM{`-05<S9|FNf;j0yWGu#f2o5ZJBvI5!Q3skN8H zbSAUXlyl3tR~iA{@Wm29H697mb}RbdcpxGZ>c2u)>Lp>Mscwv=08-O{tN<9S!2e32 z0$}hPG5lu;MXD!tOg)Deini#1?T)p|p(EEUX=snDaKOn(4Cr8A6pPkP<>unb2cuW+ zK8}h|y#6DgDdt-Pc#$|<=lg^bE;tIKZSSmby0XnFXe(@S3beX24_zzHybc27NL+Py zd7l})EDgl5df)z4hI~(h_y;}_uG~zInwpx&?D6Y8<F=rRyaO}l(k%Za3f*+Uasm-e zmbARN`#{t`{&T30OXY*u51=iQr@@Re1xm|9jk4r`;F{D|zfaH@nzJXPoCwH`)*zsg zahtm~!{312_VY`8SONQBcv}-74H7S#pp|QqZxE5Zc9{{d89q)s*(l!BDL#-sb8-ZX zQS>dJx(qNN#J7onkBok#Z2x@-4=jV&L66R^qY~;@tP%_IE<GwYJz;TM5h-hTJ(Ue6 z{vEmKyWVZknz?(`zwnzAIPyyFTENx9;>op%HduHmHiBEUS68m{1t&kN+lI~<?$M8I zU>K8OX>jO}tsoD(mOGo<F|1sc+`nEL;1+h)%_hcar)2HAmu{<7sb1{ZUz5`4crIV7 zSN<zCaHBSGbbh(D&DnR$M5fGX+MtHRu=we8j+$1+%Xl231fHMaaGy1*VRA~>!B}zE ze8#=z`xPcVf9iesj#DWSUT^&WO~2&Ak80X*`gkImFcAv&A>A*R*(o!5{lp^aA59B) zd5idZVNu`3>#CaXee{LhO%qqcd?JQ>0^Dp2?$PuR;nOeJ$xt1X&?nATu8ZOI+IDN@ z_tu8O8ofqq7)%#b75nb)MioJy*qaeen(X#>Gzo&iL}Mhdn4zI|YZ$(5EL!KdSsVCq zveMNqx&X7WAjx&_N*v+JX;ss8kTGEO6wVoW&uX-$R7>9d0T}ZB8w69gqNQrZ-)iRW zg=J)CljIU(gb1hJJ(Cfs#5R4cUo-%}FmSR(>cj6g&XpknW~M$7=0q-J2LwKW-?(XF zLL8p6;CZu$DrT<Q8eSR^g{U`#kl!1gFf;2J+l%t4d|+KUd(Sa6Ke>R_Cna~)v36P| z0l!I$pB<N{_>sw4`@g^PloM}9@I`576}kG6W!d>G7hgNxwulMnz@FcWqWBVcKG$FL zTK5AEUR`G4tGgy1l`+rpfHMwdiYt>l>@lvocK^B&>uiZxuIIPsgx{}AHo3lV8xV=M zA)kdV;F=vNC7=lwNW*d$`XS5-;$gPq$tL~rv{N=rG@zeO4Ad#o_6h191Yl<NA@?dv zBXuO@TQN|mdZyJv6e&(#B9tycd>88y`$P=OL1{Ib!=v0$An>LH8=PHY480mMN#fkH zzYjmzLr~h^Uf%wO=GcJ|UHLqJ#~d(u2W$=NN$Truc^HA}IhVm7P*!{)zTi#>6z3u{ zE^P2=t`;3dSV((*5noc6I<>-ALg?1sr9S4{sjVnHsq$6rL@e?tD>c*nu_PGh??9!N z!>I-MkOXd-fEI|gvQ@%Tps!wom8X!D8SLE9CJAszs5<B57AJH`Tu}t2NR-#R3H5jR znvxX)Gl+||lDBAzhDp=u4{|9#3M<AGUS$h{>zS4xfTl@sNP4X$;5Cl%RA3>LX2k<^ zb=|Y%H?|^oT92|HfQ#Ka^ubRtwzm)jC9V(HGB>L>@p6a=lzul*nbse4w0yiaUY~6V z>GbXk_j$Wy>+1B8QV$>q7w;ci+uS1ObG1gmh8oz@v}{u0W~D5J%T2o1RR>kF;Mun0 zX8s3#Wb|PRM-sG{-K%2VI6=lULL#DM_Xl~v8dy3833tRiOB-`~y64S(0iNfqkiY+~ zTxu1b_G}(4{^h)q)#j$zI&E4lJZ8*fATidW!lzpqtbE$P=R>FP^@$H?^%ehTM`N#{ z<-FD>$8FzeCA=HI!6-0}5m200nfnc93nAt~n9x@@-1oRasD@Ot+TAR9oXbVl`9_8T zFkA&W+<3&HJ4BzJuc-YF+}xE(7+%Rc{2@%8k)6m7te_QKi*^IUpMS57g<aouBZr43 z5%<#b6||{k-~w-`ySHxos3L2MoFYhvhwQ=Avl<U%CXwbb=8f1hsJK!xB{)+Otu-`_ ztPD{@J%s~TYd_WqUAbxHg9o0dONX%6y-c=BgxW`|Gj>xbRfOOqRHbVA@Zu27#Udpb zaS$;uincv!@ViIZ>{xvBua=+Hsn0(knCYS_ah!?Z93d<hHwHh3kd#zV0{7UrGAR`j z8OiFw92&l0&o4C`&>W)d$KBrAS#7A8L%l}f%6l%D7dFd2KxEPSq1G{4@<oQ=oO|bm zHWnJ$Rl#>xZwKbIa<{l$wiq3(SiG*9ad{StMw*L%TgL;x{wY1f2nP+3a$_(%;m}~W z|7r-HfJkW5<)8ZOXj0k((-y*Pd)tkyJ?nf&LtSq?qkUoNS(}6JgfI8XDvQ2Qls2r< zH#G0Kmr6XguXvdJRuEbXGO}^2C17(Ax11fa57;>_*~#1|CtS73&)Pq@X3cuY?;^g_ zKIV5UUGCS+pOJ9yjqG^<iycMo`_@)RgB70%8S>9Ke+X4hZ_^tTwNhqVSrjPWJZCL3 zFqTR!DpZz@gTU3<yizp4FEefA!9L?RE%GU^SRCpxZ?TzOTvD;H^?w-X(%z}#^phbd z7@DL`r$7M<E_86?G^GS1+Vh`9znYH-5FE5d3SxT_OGKep>#vEbiTZ|6YZz}?@N_2W zep%^L5cw}(Su?6|ik9Ga(nSpkwT}QXJNvl>o0kjyDf{mf0sS7a>l6hO>qU{{<`KXN z6!c>%e>)hz#UR`9;g*!}215t|6l~}q!(fBQrW5>e&|0bsRf`cJjWU{yd<J3XC1b0D zt0!2Pf_=%S?@z8m!Q2(*n7s|(suWn<Sb>9QsDB#)k0R!cD~Xo-*FNix2608~ch{Xq zP_kLSRzWb92+kvf)%n$w>}`&L7GUwg@QjjiFq}bGH?|T1@lW6oPkJtpat8&|fC4(C zQtk#STvz2DV&3{ZR!U*|Q1O5StnTH2_^dA4&NVx*9)3xRSY*U5z6JB5$gyfG;p;tc zJ11|oIe!(Wx7dsf(3B4{?T*@t&H0thku^VlkwJ}Rdy*)U0=LOgE9K^iox!hD135$F z++D81IWl;9Pe)aSe%sMa^sn^LqNjnJsSNF!yKbU<wLh@oi-FuthW#b55lmI!mBjdv zZ|0=kjWiH~9nZ|>M?llHzy?Edy^6C&^_cGyF<$ZNqP?hzS5s3EIBcEt^m?G(x^Vq` zc3Fkgf4=n@=%3H;6<uf;({79uI-HdFK{rO=lqJ?Ykt0&NSMD?H#{U5vDD>j7l$m{s zFoZi2u|8t~o}<TxMUiSllZ0aoQ+F*o6zwhZu^vPF&)|VFBhU+CFn{!7i=s70tk2E| zOr4}FIVPr45RHmG6l+(Ul+5^J-D_a1yUGLqO(%y!u~bkNAm}3xr#`MGKvDLVDHX2k z;d6a62SU)n$IDpddUL6GPzuX_Q@wtQm@pazv0q-VOB*(jmU(cW76bKr;j-nW-ux%^ z)BT$0^a+}uQxh>`<kO#?>5m-$8JF)qLw>s4)_!pSw-)~JR=gWE{@0BZG-)PH2uh7> zC_XOTr9q-X151kcyOUwXdc@V%RgG6==EAxg>lTn92{;VB$Auj@P4gMXsCm``i(4hv z*D!Tgl1)9(wJR!hL|Qb&9lExJK|oPU-yL%uqy*4ii26)Z78|h09X$joa)-dqe7c1o zCA^&K!qG~CV$w=;{%W`GqX22aPVVY`ciVs`wq=m-<$ATHvmc8J9u4wnod*qhHU5bI zSl85<YJi>!#HbP?Z{^`3?+ZZoi4KOo_Dp%Ve{6FFZoWLTf}Ag;L4<8~Z5{5fW9kwv z1;GtoA-B1+Mum>6>XpD%^m3PQs0)=`!Q79kVQJ!nLg6OUl#koRPy<*k90-3=jk& zwk|~r`gi&L$JSHmj>*$?%Vm2b;AEK;J14?s`BtgHC)E3N;4*P=m-XP8UrB0Tf@NSy z`D5c^Kv=o%BtY|*zSl$<ccAus1ZkJ$?4cXSPr<53S>mxnDR(iVD#nQ*eyii0)o?Jp zTJV;C742TX$Own`kghsbl{L<ToP3yX7G8gCS#Zel3JG|x5K{k0Wh(+r2RivzA+uI+ z6=GXDpM)+eUhl%Z$x{7zY8U4~Y1C)Ui>;x;GvL`c!p*YqA_F@lR7!x|KNWbvNUH-q zM9-zX{`l%)Fab=yH#=4sOl0>Xuyz2G?SknaYo}%jLQrFQ2OYdVZ|8f<2UYAw-c~*) z=Cn!t3#oB&>Ir`ZR*iG|lZ9EgV54&fbt42b;OH^IRq{dzl$yK)D9;Dm3}Efcq2JJn zHMueCbKvA$+r*-cOp8UK{Ar*vD<p@Q(dhAZZl>70krU51rh!`pytK5P5qf!)hW<{G z;~MJZTH6#evfa*!KChbCr_MV0ok_#b;_0ZlF>zI2UYdHw|2;7l_G9U}UAQL|bZ4C( zoHWY-b{|1#W8eMmuJ@ywQ2>`|OtEl+wQsLk#K0b<nGocg4_<oM660cHS7<EyyR`jI zxR*L3d}~^udu_%QN(z_Q#7JOfe$lmtp><-iAjePE<@mu><>N0fYLo3IMeC`>cBe|5 zV$`^mU;d0wU>ND)^n((g8kunC3Eu?^I{&m8)!VvKSMSX=O85Mi<kD-FDRtBQv~>Rc z%}zZ=&6u1&xxNmwVHi4Hf(Klc1^RNyu;=b+7RV1nL5WbKh8@*PiRy_(e#G$d)<^JF z-j)$`?c`b&i*Yzrub`LeYUBg%BMhRNOdB}Nlk2OA1@QLEHO#=~<xqS09D^D{AGGY8 zfUZBz5*+WWKgx1P)Wc>DMxYvK(jl}p%wwm<z2kTtP53hGK)QU}ee@Ka`%oNb3|6Jt zU)f>lx|@_T^s6!7jo=@#qjD+U&Fj=L$pPhHR8^pA9;0eiV5+6?Fa0dYXw7c#5f7Yn zmaY70nQ<Sg3{N5josc(REnog&vNEmVQy?X_4lJpi?%9XpbeH&o*7*^kY6$(WI2wQp z`i!7phZW-5-ZjQ*GO=FkK@N)t@ZZ(G8iCaxkby<geb(~pGxgZIt(Q&-z_kWEVbr0R zpi}+?pkddx%yz}CCw-?bha|8@LU;Q8Yy2zWFI49IBWGNq(1MrbtPNT94GluFjY@KL z`~QfpUve_DPfGKn8$>Y#ks+m&x(2e@qIoHS9~|y|DLoxESp+bXuoL3_lj@jkJ44GY z;=z`{B)I6vqDMO|jRK{=)YD}?%*T+RSoGpYa9c3U24VLcd`nuf33YqXjv5IbL~NS0 zroa-0-+@EW;T*^9Ak>@xX8~SwTWPnCXKnzC@ZEdQV3paiE^jQ}VCmp56Ox`=K$Ima zr3qPvOQxY7aX;J<i%J!nW!H|E$)W1a34pkhPwS@xy*w+GOd%b%dWbV{tmwcLX1x6q z!&p-7n}F_ARC);(17pM=k;7pK=2;;Sd#rJ=y0;=2%LqF4Pa?JQQU=<sW~IK_%<E-L zFpM3g4Te*KKlWJrX@DK0XV_ZZ96e~dyy5Cv&xV2+p=Tc$r^^ONCoAi1ooo?LO@7X} z#G;MSq+b~HloRMaOok7r?H4xuVdCO8NzXr^8SB}ojo0^NjhqsFxE-dAr)i|1v~|9j z7ipN1X-1OqamO`cBJLsf&GXotJ&ExnS2j3<f;mQ}z(7_uH*^f@j}8}H(GO2KF6(GG z={S=F`)GMYcGH0bbM?Itf((++t#UoS<wBFlju@esUl<HG83dY6@QXpu>kDafI{IXM z2N(PU|82krIH_R=D&5^Ho-}};2B=C1t!3b@DLlJ)1k?m=Xx-Hg0m!dZBOw>N0ZP?{ z=A+bgv!4tRLf<;)Ct}}8bfjVaihGj4e@j^X*Un_hL_mQY@Dn=lgu!!0F<w>7M%dBd ze*=w<W3rQ{Hwj4Zw&NZ?`(<39^WqmQhuzfaiDWV?z|02ex*EPoS<ja19xE*;1;6h) zfOPA4HK(>VlhAbeedeIB>5^<c9H)b8HrNN)AKe*Pu9K=~l;OoB@1?huZu4eHvApfd zft5}V>ag`P#r7tj<K>vUWYm*4v}0GWO;&7Y^~rm1vFJ7#E$gK6_<Q3srASg|!}|Do zHn6+zEil|q4uaume2`vN+R|qzzcFEDIyxpZ=s8?<LeeM!7I;Gkhlp%zfLD?<keeEZ z8h?+o8Ur`Dura+xDfSbZrJi-F(3A$&IZ5~zpqM1!l$t}<<!%$MxuYx<PALD=8gad( zala{LdBvK3Nq&<6i>2KStfF5SIn`-#GT~BG#8B+yun!%#eNT!l9qyhA9iKp=H(7`D z2`vaIWWIL;H3Z66utT^my#lxp*qyoj%)1PzQS-a}ldFOWNwv*OM{u|8MCwGy%zd!- z)N;K+gzCm+w>=Y1t>|*}0IH_c$YIk*13Wo78IAn`hcOvBf>lqh3o7(M-5Tb|nu$d^ znY$5#2)H#eZ^E1xH4Tj&K5l&r-7{d?`B>U9a=or#A)E~2NB9NByLE7)o<pE}Z=8Bo zxCo%OvKBJ~J$$c1I5ZY~V2AlB2EJSOGxpvTT$j{muZE5s{R&^TaoS`ofId&f48X8G z!+C10azDId^o8I1t=1bKKZTmvjSO|<E9%okKf4(0LRDF3)UaegAk$Q3kkOw!N4cez zla-On_?hbt<Ll4h5)P<m{V!0cz`z*vo+KDy4jkCDN^{%10{HA{wxu>H=2`7-W|nqA zh28YTUt`nH=<hPZ>U}Ad*=K!#$f*7B!U|8o<@O=C-{N``x@OVT8=hU%rwq2zFSGd1 zq_Kg-fmn&ImBH%+K`E7XhGZ~E<gd$LZXIw-$h?XzxO-iW#O}&s9W4e2#m-s?xs+kO zozl`MaMef68iDy+!ZM3K{8@jy&%?GrZ8xElP<;>6@7IL*VK_$_nM;Bk%2PKbGQ**5 z@(G<3pYeW5zV&G1d`E_o*3peDDk@cYwv(A^6;d>!S3EOv6k>aW!*)?+VoC%B*UY>^ z#*3xjYzkR*^qOfXVNV{0pcT2Ewy=m}sHvc~Bb}7pS4eHJ=lK-}qWqWpnCGZWD%774 z^bv}K+OQ)-X7EA54cy@}PDgt-XodGYV1@JZ7GP8DmVA1RF*bN5gi1j$=dGNL<qQVE zIym7IN6H0IArbX$vu;9n6=W{da%mWtQ)xiWJ;Ptxx~%IWx3L1zq{a)o68F0^EFNMH zVgu5h6fqkT$z(L`5@6rKwCJC#(4^#C8?aU`6emQ0grZydd~QIZpj%x;s9+@{cSs$~ zs9gDqj#=1g=TwoKM&W$MC>r=?JAn=*V5UudlYtDiG4&vgh8d}DrxVD*VHzYx%@24$ z4Ic_n8OTYv$hccXCQPFtTtnh)vy#5xDldi#e3P*y_BToW^~rS-tR@Q9TZf<u{Z=Bz z+*kS9I2AZkrUYm%I{j#4SGA$~r{J7_O(Gg;fK<&<ruV8uXa=3uZAO<FyGK>VFZY?m zEr|<Zu!8=XXlqNEgds6_>FSK901B3Nhk;5vP`$-&oQ78-x`EdAJLcL(0wmRn=q6=3 zp<uKbE!UF)3A%`aY}kML(WE~pj$M=i3CH%XbHNcae``#cA<G8EyEA`f)(6B_B{0yE zYa7YfG#{ijUNkI2cnua+fg!>VDaT+w?Q27M9~D@HnM*TtbHEYIKqg3USiD+y7%&tM zitQ5g(=@N_t;CxuelAVE2T!YUblsnm`E{IlSNQvMc_m6UW}~up*4;<Or=ltl^oX@C zdBCumtVuzCginCQmC>`j+~FVbvmF}2df~k2nWPDFc7xVXfL}V7Tz?$M3p)1wCIyx} zQ~}pGTK$#DvPq<e=AC)RzzhkoygxXsyJ469J&F`yi&v$1&61CWp&pgYMd*7yb|hm@ zY$ro7%HzJ^{`Ikg%f$*7^IY1`&~SCxKE+R`yVx-EpO}qNQ@FbS6F4c|acqXRJJc)& zL<>r<Q1Q`m!l&?A<^PIbSg}G3EIxc{k_9cdLe2yQ1vbYI?MhVtFk4nxQ?LKr8?GV| z7OMWGp{!xul~KK7F>fM7YBKlGAOeEjQNq-nT(ds-?NT8)X|FArzpi5mgF`T1zd+CU zusd8BlJ&87LvmdxZ76Cj2_4=idSBvZm;6UMDi*SC>E7%;(=%BBY&S&yEBzHyiF3v8 zZB!H_yDOgqdO-qe5x?7<H1I2xr3Ix*N1<23GaoN^W9p7rWE1ZWKs}_|kQ@5)c%b>M zC<507FZsG~JsWU+O>TK!4y8Bg-wrIg;P_o~a<Yj!BV%NRV+4H`o(6ZA7qZDH7)lqM zPCG@Cy~k<dM?~Z8SeV}KTl+A5RqM+?y*9)BUBYfqdg{LE@S@+^!S>DMcnChmQ4G^{ zuWSh?@&$!pY_WJ7|Jk>UkAy-{Tc6<IxYnEE^2Pp0yJ^RuGuDH{zMEnsLZVs`CF*4P zo&b_7jIuVsU8xkAXCu3D$~YFn!)ucc7dddL26l|+DaL5qGfiw<8dsCKr=PNcoDVZ9 zAI42?RK}Sj6^G`<NyIg*{!`$};FI%mtK}k_Cd<-L)zlj;3uOL8`}p6Z1gPzjYnmix z(;%W={1Y*}o=#48yMiMYjnLO7+%EF`*l+Dv+QE6u0!OFQ1*tiC6T@lw#7;D=k@<=j zj8MA7EbRkxJX3jVlmubeORc_zEkEe5OvkjqPdfdCKOZsAc~dWFYsKWO5`Csnezbg; z=-_{67n)O|^?}o0^E`lvg0D1-;-%Jy!v04GGTyJV*4`A3>AD$D7WNZ6`(ILdA9tJ| z2FZ~x{N}6tP}rGcw|Ges<8Pk&_qg1`J#SAkifU%M>*81HlQAopar)~OPT6Poaak_T z{2r5$5+2h{88nbQ7(Q<brv3Rin0(<Itu34(b3f!a4(^ar|NSrvyutRdpy*NRl7#(V z!;e_l7JNu3NPyQJz1UiOaGRRtimQmzao6qU{*LKDFFn7jKg$&G6;r8~?vAvKuo; zzQ)#fl?<13D@Uc8*2k60oW$!gMl|6x)^>^AT}imy5#Mc$(*<383O5kAP+M^6VKwDn zxX)Y@rQSbY?Vb{Psn$U0D?7rW&~e{CE?XB`htno;4H&7a+lrdl6&n3}-bW^qu^Kk= z)!hzQ47^R$_m=ZiK6S#_Gy(nF_qMUqx@f}uDQL=JA;b5!UVNfvR~f4DJ3h^wegv8? zvYl!TIS;A-eZ@AJk^3IQ=^N;mi{!Y|*Ov3xOm70lv6hL&<@Pm&KGFirKo^1&${#QG zkbj}LMK{BJ*^5Br0kG8k-?qcD{lwhOfcnXAF{><bjCyomLsxOR;{l&}_}zH~A+<>` zj|N2q=M&AJJcdn&Y0sO^dHtnmzm727-onWbLRqBS|NZH1HvZarilr7554_kDZZak$ z%Aw1;?0h`uPm$dxe7#b@vS5fMaPA~2_rD#z*f$7gx!Iu)j3S-$$AMP7(xtu_WigiL zaDvxok9By2NpU@eL*zkU?9%!Z{#X#jc54bX9gmW0O){DW99!wg`Fv*iK>1mq>qYA! zk+ac#@3Z!Z3l#a;#XE2BU2VOKC(>W_m={LPL-$*57@b8)?hf3^+oPHwNZ?&d{dCWp zk+slmWs))I@EG@3!f@5xz0Y_rn%!7T=c?XfXf(6-4q;g<Z&_qI*S*+k8Y3<W&JC{@ zcC(fY{T76?d>^!43H;$FKG>}-KU_}eIQI8nq!N^EtjG0^W@!zAdG+;(Ykllko1y7Y z-F>k6yzl_hbQwvf8FWH-w^lG|M)LMG`Sat$@gdni9i$y{YPI4!S<9wD`%g`LE{R)j zRX%^K_1?D&WnngGJ3j2snhlYghWx94PPQ-8zWgulz_8qyje>E%<&JUw+9x*WSuiWg z*?*6?+&SQSC#`Mm7lrf90sS1>LE8V@!hXP_?B^O(-296Jjoo=(IHIggb!|-Ny>*rj z8V0g&_18n8pF;B=#Yuoe3EcUx8Pkeh1DV(^)H`Oz_=;GGngAm#23+qx0R%r8(-z*p zOT}P|5W(A#%Q&>PUCiBmIBgc%aV0#}UQUp<TcZyy6RtBmwi)DJk+xapD$OO6@kO9a zBlX1dFO$lq=%awdu^;W8Ia*`S12>sFfDdY`3y&)nCy02dU)z&TV5JMGZ6;sq*O+>h zvCs~Fi64$`#t+&yiIlr+7tQ=97<k@aj=OKP9BLaa=7oE=HZ+eq{;=@s&$~VMYqh4B zRA#xZyW{U24=t|Gw%g)b&*|o$<L_}Y|3TA`ru^F<LJZI9$5}!4r*_-b$_aO4yFHDw z9T~jUXx2HEKmQ~>TuU`Yai41*wBBJwKfRdm*!RCAzUwwMS)RM`yXaGGYyDT;?d{<A zrS<stbCb)3r?(qYe*Sx>gcnL#rw8TCwFmwz<v~L2EJ4eT*M;~kM_9s(<bR|sdd>?z zMfx<y-}bW>;rpu>6{H7ZEk_i0&teaPZmK%t%0SSgf(z523u<O*|E*J{i)q)`pgWDw zPmLXNx4-=AZqKwuA|oQyLxPTfkR0GOxdq`>oY{gMelbpwC2Oo86rlXBf0uI{4W-NI z=IZtrVb3~;$VH=yx}3beoXhqc{*GFXn@1m>Tr!`t7%y(eNniJ#Gl$Cf(+BOJGDWcj zem&<67g@4R#|^r=S*IB2US}4#?)75HCARRtQ6)b>MQ9$H3bC}_uE{rDT|c-zu%VPa zN3maTJ?<voqR}H4yC~liyXe@LQEaaNBX`-y$J2U_FXxQEWoUu4)DT3u1O&)P6m0lf zHj>n9{8_{8e7YQN(mRTSNJ3A^3h_6N3W5zD33OTStju!86>a<eCG{Ps`Nv<8J-eA& z0n|82T99GiVGhC-bwLky*quAgF#Kc9|J$HLaa~Cpy0do%)Xd&%3G6`WIExkFkxhVp zXk#+cL7C}dqty*!*ZL_SjV?rE8)^^^fF%C{=9Sc)avRd=r%0k-O$j^OQRd;0<pn3T zXRl7fBk_#!t6M(MgyAtC$GnJfkKJ*>k!E3|;*sd!Qg83TZ#_=dI~WRFeSCeRc||nN z#di?U83~Q*#2Isp)?1>HyQ{z_$7`bg=RNquKX6-FYPhDW*pU217fD3Zt1<m{6|pZ* zh7L+>4-Z~_*4)GGd==Kh(kQ>}H3~g3qp9Jvec|<Y->Syz74;KhyszS2@M(hi8~s?0 zM}=8db+Ow1x4eoJ1m0J3!q;^x7njTH;#H4tw`NIvrk6swI?s5+$}^tIdY|K6=Rxny zEph)Nc5eE_V&eQW>{%l!vEcp|Yg@<11!el>+fbr-oH`1O>Ha+d7r8b#x%Bl8#h*C5 zH=bXz*gFd@?pbwEa@>=3mqR&_*Yrf45rHi-)y=p{Jax&r8=SdHnv6}hUskuuIvm38 zuGz06xN-k`p*wVW0PbB!d22Wy7pEVE+mnYw9mUfW`z=}7Dm6VwMmbrWEDe97eRA7k z0y&=#A))3-<-<kKFX9hex_JHfXB}qdzr4&?P_>KRmpLBJ={lcByVyz`Rd&+uU3&k! z!ENV4b%?k9D~)^MB%^cc!SwY<61r0PnM_bhTxGndUrJ_>)Yvx2-Cjzz0Duq%fAa^6 zqez{VgDJKhERCSA8z-`}r<NaAlUW!H?Ux;Yx0avGg<$9!cC3v}i^ZcT2{;aURHD(B z_Dm>yvlJxdD756%HUakW?=fEt0W_ToW4Ugz90ef*Yr77dU%SfO;etQCUsGA*c3^rB zR|lK0vzHhUsC6C)S0c#CQ5X?VWIDP*5(BbCvfiaxE^AKqU?Sd!N@6fYp~h|2Rb(qP zZt|(rpIn{9I}|5`HP+=4p*u~N6`8PsOZu&R#msdSqnM>NPTPH@^gOc?0uLsY#R_Yk zeJz(*BSYW!Kl@TrYo8zGd^5!3Um%oCcq6<2FQCxa%Xqo%iT~p2^EuyE1rFltVrSXV z)V%|#tOJ}uN=3>9@epyMw&Qn`kE5D8Q;gY^UpHm;4c4J$yQjaj-S$RYcoDK>HD)aw zljAl~yIf<Xszm~*)ILQxJNPe`5@ZEXEW<Qq{}dat1YJ%J9hh*wqml3)eLYR>nUYyl z!I5Rb?(KYk+oHqJ4neqPISNF1O&e98%?mX+#JMGVD*c!hwtVB=b3%0{qm2v>IJIJ; z9(uRL<wGlA^s;GO?_<wi!J1hXW$~v{vUycpE`q;m;k{j=3)#2RGotnhnQ&&Sn|a3J zN<2?%W}o=ohF;v?{}e`8r#ET)neN#so8{wFk9UvWd5Xx^^wPA`TqK!MG<EsO1+om; zFLZRc`>XC8e9>cG;wAfQNeCPop+wnW4_8#qUj5kDiP>#+KkL$U=Z47wyQrU|UsY&x z0%v-tNaK8r^_HZELTb9C<N~6+0{g!0>@DsGo>E;*#|d3){U*LllF8op`<h7lMnAM& zezu0^m_*H|%uj79+xOMi@_;?!Q`rurJWS-2E%Ra6tFOCUuSWaellet1KdQHGaL)Jl z4=!18sc=`18TVygyrbc~PQ;9j{Em5;*Qu<89Ii<T{sv--hAm{g?H+Nux3iY?Nx(ca zLwFXqd_8HZ%~$r3=sF!8gJVP#oL<b8kzHtoY(*uDZx`{29#`IJOp>U6SP(-k0}|k{ zE0X1lSMqebPi~j+DQI8g@b6H)h<d~6TP^~hZZ0C+JZ0%YE)q)aWoQnMBBM6=&0brz zF)x!CKUin4A_HbrEav9;!!k4(`WGSCt<KWDQkPH-eD=tbM0zXj1lQz@cv9q}51bN4 z?fKs=A%nk1F}BUOm^wD-#Ua$6GjtPMMF#F9&Z=Y+G-+flOVh6H=VG>D$4?M>wGdw| zITZ2XB1~N?202`BK7<+w;sK@IG4>NYoPhsweMX01P05-y(_UF9g`>ONI~vjkgNle1 z^kLnI%Gdfo`0lhmT;^WJC5uT}_z#6k)=&cA$c_K>nV67A?&k21ZxpzVyBajMxwXID z_tmU&l2@@|6Xm;Nk~q@y?ilhjlO-+IgXV7B7p=EMrhe2vOI4_KVT98-vcVk06|{oP zd(tAXml;AF>i2(k4Us)&HtxFUC6u^bo*p`w7$x49mcn6{e@}bS-+GHPKS$_&n#}ab zWz1~h3E>M~mltjQ=F#0l4%gjY!aFxO<m{SP`n9DylDu`p<Y9v01J+0c#uEExQHXwk zLIa>Ka1>1=Ft!O3ev$60ul9MZw|5DxT&T^M<<C|GTfA&3YdKp^&*f440&^e~WV zUKSqbr)2$j2yMuuo#ML=&bRy4Qq{HnK<T^F;Z-j6(3z<CPfS%X%ksl>x;ekrHnF*0 z7qgL%Z2e?~1|j0+FWD(BWdn7Hq=`WO>pu!E?pn^>uQz<Ya3{BobA?Y<U1$c~u-zV| zwS~gsY6g_B-(|P^G4Dw2GS@%cv1!YvTcxe$wjf0E&g!rv*O#Dn;Pw*p=CsB*z3+7W zT8zVEA9BMMN{f@Tdc<KAb}>`@^nE+qXPokj`*Zyufvs0B@c;0%2gEOf=5L<1Tqfc= zZYVcuyEM(dxfs{Owe*4MF%w{Xf^8k7o&1}c9v)0+W-iG!`@veTu<lJ>Jjt}d#c^tg zZ=~C6F)Solx|-CMMz4^TiHYs_=D8DhjTfJ1w%C{1*l0RRM{EB1FQdA`36y&Cxw2+= z+7nmlrzV*7z#zBP)?w(%dVGLoAv^}nwfzxu^V+CpR{7C3#-U>PQ-PNBVE+E40#=6x z{&$N|sGZBOTXC>Ha3&*;R1(}gYp1^SU4wB)@|)W|xJjbyPO=*@JhY38Q!p?bW-Zp6 zPZt9h1iO`HT2P^5;Kvn|(U=NK@L8RKSi#KY&?a=nSEQSZ&IYMlO%bL(ji6tX`{V>{ zu~_UT-$6Wou3^Sb;I3jo@*?h#A3Vq$T45ngvlhOY=H77+#3v>)VWGrWJd}2qCw!?X zIh<vSne6KgKLxFHux&dHZf2SNELNOHc)XY6!#{%<$R!^#7|5xbO07ZTfwAeXbZXHd zD=_%(Z2UQ{i*%q{TUM(fj$IfF0I2(~@s%%R$?+U4XYIPqhMT=!=uKn{LipWp{Rets zzWhM?^5E(1%`uHaRr~z)ANHnC$vDruYXcANWeSC71>LP*47`x}b9dnx+v>e8u@|tU z>%aL5pM`P1^^PRy=+@nqDZK)^lrd#-g9QK$G{K)=iPX3Q34G$G*9etoVK4iAybRb^ zwL033wu^O9B($t-!A(4D>5qbLe{^4fvVy+eZSqN7-~?V>NZg(n^ieW6wihIDq5Af8 z7JY->NqH||BRFMm)?O^`?@LSH97x>WL_97#zb_uQ5|>Ko?{G&Hv@TY5P@VIqk-mHM zy}?fN-Kb1v&?e>W`uyyopR*iFEbxHtVn+31)-;v^N$4FI&=%xfj2iEMv0N*cXtDip zC4w>Nq%@0N56&A3lOLLY+~G=AsPK29WYi#{^4Tz$)T8@%dva4TSy;@WKKkmkTC#M( z_L}H!p;i_~m@Pf)f6mRaVA^`aC{1#ROf~%@cLzUj+akVOKQBKt{X=*Gd^7|7%24JK z;l6CwwEn}j%eSMXnF}}q;TFKKhvm2^Z@p4Z(*4pML1Uiq#O(g<u~+88wy8IL>-hnL z+_hb#1M?Fi|Lf};yxS+<!9hpxEQP;g7r@3`hXu~}($I=T!2jl#HIAml!qWFoPV|WC z@0sMS>$(55kv~CNE?aEad}(u1Ol`(O8}@<ShkS6DA#W4&Kw{zihV@+-5L4swVK6Mk zjVPqEl5P(Lqo5$^cVH3$HP4Ap<o@@RiPdCVjZ;pwGN4j@y>c-R?Cap-CF7$0PnBBb zaYjO^X|AIQrzrjHzcsUdOj+6!by}_S6UOA2opZBHo61c~0slh%$#f4-A@N?oh~8Q! zmAS*zWs@l<!8om~cn_qoF);XU4WtXF`0iUM`n1|o9&(MT)7p0~nP@)`fRyGd%tCx` zon{KdJV$EaZ~G;|+P=3pEz!S2>6{I_Bq!h|xK%DQG2@a%o_wz`whz8pgTk|$7IpW3 zRZc8vO*@^=Wk69V^oRjrK;@=|FxY8q9f2ir>v*=kmS-~=B94N!-0VU8h4qJQD_naz zlpxpCAhvKQqr1I;6Ut4#FT4{GOFDBIC+PI~r$e5k0lTnp!A3^^(F~m!(z7D;6qTWE zC>2|eA~lYy#B0*?Q__?yz_ebc-o3w`+rMGH?P|TCz1Z_=jjpjf*gel&j%z)ps-{nv zH57waHEIa|6Y5!?-p%iqB6-fTGF~k4(eTu0Z$cVXq1E8@8|;u2uG=h2VihW*%bxi7 z@m3{{H2DIq76Utsy{fcIkH46>si+;7T+PM%RoKht2`%f{TCl!4U}>-YI@T?%T+iwr z!BbTP-q%fOHo|?bS-SQy>*XWmebBpm)4R!uu&RZ`2gNmIPE#~Kb8@MZ(VK4<D?i<A z(0(>DmipHhK6xB~uSLRU>0VTm@}AP0L>2;ww~Wh!00MGc0FZSO_s?3KQ`Ng@EPr!R z>ugiFvRim<g0D19EHK|a4!*yR3rk3R>_b3AFmGeF@HOFi9ghEeD7Sdox!=n|;|7+6 zxpA7$wYK7as~9~qLoQ{dxstd7GGKP5MA{=n`hLlIowxOSRzgQ%x>;x68Ab*J1!5OL z(RmuuYba95dOSjHpVTCgt^F@}Uz63iP5|;TIo)e~7)-KKR|MjB28-(z#B2q#A0Vdl z7I2BA3HZgyhRWH*<qtL}Z~uwm-(Hjw5ZbC9GpMtzQy&M5lSuU+n=c6tp_pE#J8ATX zfj2%{(tElCSm_sc6(S#l(Q+|nAgXpmG|vsdKscVGZzaMKcJVvUM$n2<BAa<7t(AoM zOFXYB6xpFG$xZ8*D=1DqrYTLE4jibL-ZHeupgEm1ta60KhKk^xMWsm^bPa{}1^cAL zFH2-!nVcH;AmyFU=O)|4C+w>~e1d+5(lms__Wj<D?ux?&7#LNCNvq15AF)FRLTN*! z3qBRTo`|H|*2<SH_M7Q(tqw*H)VX$D%&AO(KK3$qD~gScZO4Nb-fgRAe5;<aWbam= zKevAlTC=08PwM-B7NGbVLFYVCdRU_XrYs-<e-koC7B;5(4I(MO{&_o_(*Wd(@J(^9 zL`Nwx=@Te$9F4hd@{<|%27WW&t|NM3WLE4}0h=3j!_6zUj1K9(;pii}@`n>j$JUkc z`a|I>audGzZyzovb+#|o3A%T**SU6jAHU-TTX@IQZgIuE-5xjC1;jJJnJMC2peI?D zin9W~iYp)ddJ*uT_3mG5oZLmI+=jC?K%#FmXwf~<%lz9S`)gD|{x!)-wLu?S9iv*4 zsAs~D#?KQ+qN05{Neu7XSD(;ur|dQCG(ePGW5lCKpPNqW%pQAFu@kdz%I*3U>XOEk z`#N#heHLKVvu(%~qLbESRTl%83{o;5nT<$U91kJd-Bd@1n}n)H7(E0J5u;v9ISj>B zO*G-NqfgqCj8y|CC-@ewyXIhfWQ8gZ>h|o}P?(EMk&w3*Zq0=vo0WIpQtF`;ghKiR z+EW%?TnEj2eX|e}HvFTU;Bp3}Zw#Aqty@RW7_RBc?C-pNRZ<>tLI|_;aIoH&1R@vw zTNUuCG`yj#aea22ZxX6gYxj+TzP|-XUH5Rz>}P_1<Lbn<)4m^wx4G{x8vDJwVzj}r zEB~20ClgyNrxELc6$`zLleDJCvLa2Q5cW`PcEM}T|1l|TU9IZD+%n!-5xKg4>Vo=x zxp(foPp+`{p;0+6W%~2ABJiTry@bjKZ~!1zONchxivLaOu3bQBx^@OgR48-5Khb^g z-UO|&aB>*Ny+}2EEF;>(;^ky+5sO}U4F<yV(9<f20F28B*ZJW=3BJY$e`yc5jdM<h zG3Z^cV(HxOk2ISg+k;`(vyRiBc088M>__%#K)KeMrCo}ydtAC2zYLI>y+bNa@G8Y0 z54#jk9{m&qAAM+N8T+AL`IH;;j(z|@$kY4OnX@dYVk(uZ2CVMEWl_1)E2RJBv};FM zNTilvCi!vJVx4)1t1$eo&Q1Ogm%3&jDWuPuA7$un4@Q-nvHyZ3p+C<E%${ryf1G=! zVNOMUw5ILW(FN5pZqC$hI4f!$ro7>De&TGcw1PIG59W;ANmO!%;re=R{F5cazLFs5 zp_<<PG)nrR(17q;KgNWem$mNQ6ojHtTa{2b!|Ao$OGbqsT-9X`I#*F@+m*`0@nf$h zj1P8iDprrB`}3GttV=%!@@tm)oEw>zZmmaj1R8BER>V&`c~L<tqG0^t+bwkSsZ4Rd zla^zkBRX~wnr4YI)64U+w6;>TY_81U0n3gT1Nl832iu<5_jr<jtdaMR!=ad-I*A?f zAO6~tzfPf;HY?jiCq-<}XMl7cLjLBh$ZyYDRl%j!;b9;fa<7P_!e=v2+*W|ngZu{5 zpyK8oN@c&$eE&KEGf3-_oavh%eyGfL;@6@(Q<yZ{n)taj*Lbqt`T)G-0shm)r9YtP zFyU9wx=;c=k`GU*73;Q!pb&Oo-20o`3x4mJtN)LtGmnSz{r-RZPJ3u9MJap8ZHZJu z$?`^s#yX7co+*u8sFW6lWQ(zckloBM*@f)J*k{I2Nel*M8M6PbKEKEJuO5$yhq<r& zI_JF3b<TNS&w2L1&nuMf)uF{BT4`5H&E?+K3AXAyjK;^6C*ck3iMKte!{rX^uCR+B zILt9Gme2>Smy?D~{k5QHrCA<uhG^JI4zJr@cvo>k3y(l3Y(5tHhG!PWmT}(Ag|R~o z+>7@=rj9F=kBG;5<@+c+Fn2oczo|+<PraVa5jnDhVU6LD`Tk!3Y^6MCRol1p;q%nB zpO@t^zu?3E@k{qO=Q8$PEq^4}PAXd1cI3kT_iQiPg1WBz3C<nY_h;0!8wN~VH+HQ| z>jZXVl^f8X-%#tOtlu(D1;j0>kPgOMkmlBVnI%cl_zn+v8$VY&T>c}A;AHw4-`JFj z9_7L$>7AOcL&zcrGI81@oAI#o_2_<G=IWpHZC(ulGsH&meKHVe$iJO<8aI0v@)k)r zOW1IL!imOEr$=w!#ZR(V-W<sl)oY-bw4eOR02TYj8B)T8d+BonG*|Z0xtFI1XAbc| zW}s{6ofaP<^s_FRNEf5~E1K<9pn(q1c(N<2$>Dgub8jcnvc^0$nR-)@%=At1Q6t!$ zM{K5(T%DO+rD`U}*z!>JxaI<!g=?6Zt%9>2HB6a5(i%cy-?QYef}X3E^~xw^Rw>(h z<Lx7L_ZY6Hvh3pF$)DDBACdOtNf{0NjoPP;DVf~SD*CD8D>0k8yV=#eJ;m$O(XxKr zsj?d!SVqh%{p^f>rPSs0kiMmmyPW1*+jDgbW5enxi~5x`wUUCnvj^CA8Tk$tWPy9F zr`j3&&b-NHe)Xt&gO3rDc5F~j;6DPwWS+mTg!8?ICSi*_hKueAp=&W8J!BBrlkC&* z8&@z9X)A?z5kxVYe!>&}`mrlOg!~YIt~>io*+u6&M$0*hy-Kkqy529mJn4+q8pz0% zHn@Ms`ib5l6@6&)BH`Ta3R=312AC`xR-tErLdX3)KH{7VWWXw?^TWuvl(yDL($h3{ zDq4|ZE@v-RkY{9fTsw~uqpfN;YQRVq$H6@Z$*S^AMGhI^_nRE5>h|Qv6T^$sQmr3O zc9g!y|89T2xQB76<+ObWb#VQq-Ul;5f)noMrkKjht+1g#<BuA0%?q8`tvt~xmI;XQ z3*(`Q2B}*m1?w=fzd&`ZV?s!dE%Q!gJ8GqCK_D<2Uh(<)5{&Pu;Xl2dJ!rzQ@I2+8 zJYY0Yr&6+bsJ}n2Ml^bNIt8DUpLy{Oa>aVtVrk=KVhMkohD_fAwW;qqT9t@?Zl7`R zQiBw-eaiD`%;JaaxD+YIlQdVZU5wZ99tXLzu>M-z#eo-%&kX`~pvfjuX%gD>gsSR! z<QMTw_-?SMcxq~gc#n3(=SFcMk^oWUgjGDx6fJd0flpTY4z9oQ1FF{({$XcI@1qb- zeZ*xeWiWdkTC#dS`oNDG61%}2BS$2lpx>vIzP$=}8AztY?npX#KC*`s6=pD5Tp)-# zF8Mh=6MTuWbGKigaD2n_+mpT#TZ10;K}5UWF&gHNy25NRNDtw0v3>c|7c$FvmxUwV zHYg7%yn_0w{fgva<?nwSezzYIj;cGvY^fg^gOMKjskm&CF{k?g^m^7^sWDW>vB3=A zq0P8-!s)5MXcJpIBFm;NR1P(2K%N|ZUwSIQTTl`8*p99FHPLF{(@O`OWEyTj&aJ`H zP!_&WBOA(qL*;Gs?~RDmp|4~4tuHAH{yPwB^^NT0sXqQl>jHw6sCIgs%AFabW{-uw z<4FoQkaIEW<&TcClLtP<6%@J;Rr>7Svdk!Xqoq-6d8m2ss#WgMF-(}kXHTZFO4oH0 zsz3j(+*d<At2yX<Pk;Mdp&{2k=CNIK6YX=@O#AQd8@@$jy|lw?8?S=mqzb;5rg1Z9 zX+gC)Md#r&S<F8JU35LD`yAmDYG;ho`M|z@yEoCmoBXmY(x|bAtaMeI_8e)EnejMw zp`Ce|M^Y<ZNc2DeG%S&lDC}`!SO!{?fcT5kvS|>4<}lhLtZUz;kqxh!R*f<zf`lOi z+C8j)VS{@a@fmG>L}N<@arW;uvSDc>78-GdAJ>atdBVZBi9%pBVpb5Iu$n<fCwJ`8 zCAE45pAEtL*h3TFYL7OTc(m^#oU>`jiW5idAv`%D&YpkX`wHdGK+=kt2<{tGc$XvL zi7_;Fs^2c!fJj_iKSdz&e<w=_!t0H2IJcz^9aKPBT)*6Oh4~&QDN;<F7pauRoJCxO zxVssz#F*2Db`6XjQ1=+)BY{dC3+06fN`7R;EmegFr+U1m3x8?i{1lV?a1P;w^ow7r zc+}-d33KX)muH7}n$F(7@#?8~prKgBFcz>`)_R4t#H{WOj;biYzdUsv{WSQ!dD2$h z$J$7*7k)g=i~jx2liM$JYdcx~@P$=6&o=p-qe>~qss0Z%%fj(02?im#l82zEMjd7Q z40v%(PA#CWy*Qy~A(A{2S~|*)n7k2_P<`-Nw1MR@$lCbxJE?nMLQa8sBAb||v#-;G zTssR3f$2#Uv2`!}(-^vLk#t96f=--799Lt&CYLCo)G~D7e#GjKsrURHW(nI)%dKdf z(be=^xl^b06(5KS(ae$<0|%14QSgI!JS9;Gl|fibfah;Rmm^x!v8Lv_;6{+g#|Sf6 z|AHC?|JMD}%X@XhHQ(XcXG=j(s(661b_Se&>wNwha3ls&UL+i@_O?_$s8$xtOys|w zg9uqRZ?}d{LUv>&1s2A?X6WHjgj<ndd)(fG|7L1tjamqeV+-RsLtSW`^89#^M%&@N z+YseU2Xt`LwuvjBrk+Z~G&~t-=8;)?Wdk@X0ycm-S=6PzqJC(HrCpm@?ctt-+7JD> zk~90q7TSuvV-y5jwJxN_JN4iHld~+m>+HSzBM%;r3t#oEY5tsI(KebmJ?KRgbY0H~ zkrKN)nLI$FWSJw5=EzVOZ<8~+54A5};pjBoEzpWP%<THM%deZr6H+Yo*Wu8oHY+RT zT(<EinZMG|8%)w-^?v>*=@&D-GO#ywnEO6l3`@apD;F+dJbCIjb%KU&5QJmKvZ<jF zVTHUm1B<G4VisRZgw6UD9X&sqb+MB6jdffSGJBDmueMa3VjDE{Y)OyEoG|z>E7s6g zcGf^}p=!b~!gFVNCo-2abp^tfY}kG8tzV>n1{0%v<vFUEZ!QY#Lqrz8mVshbvFVql znyj03hJC!?zAq&3&U(0*CvPc3H<AS>Yk2+t8;ncoSSSWQ@EG(ughxpE7ug5bCI$%O z;fTl%iP#u<YdfnYp}{L0H}2z0*q<Y1t}IHg_yyPRUpker#|C*Sq6O34pHB!X!z$Q{ z9mb?@i(bM5Wlu}LdEyFx8~m^e+Y3A3hGLu~&fjz!I-lchX96Cw!jM&s9+t;mMpS(J zRG}DRpz!Ve+X#ZJ{6nh5>1HInSe6?gwo4Uz_knm@XlIV0c)pv^9@x`5(b3cdx<Q<) z+T7KfX!@FhqqjX7Qo>%7rcPSTNKq?Jj*bW`Ye9jUkr6!BVHq{qFXXcqtpv5Lahe)f zNve+0@k|YGHOTtAWY6FKT2gHNhZdCrI`VfKYvvgUFN$1!HCN-hgLrOB!sXCshboQi zX%EzxrpJla^w}tt0is6)qB|1tZp#yXPMQ(^rRgT|+fAs?N<%R_!XaA4p^6$hu9+FT z^_6I>+1Dsf;CVul+zUU(?D^1ySKKnjwY3C)>WKg9>%6HLhp3nrfufXqhaO69b-Q~x zf{6+AIpq?j3QC<yXnv%nH4et2)Rs=@U>SIVdF=T`caLjsQ+t#YZ|p0v%1zt(>a4{P zN#9e}FUPL=aLqKoFY86UXiwhwaA4ew$vQl>qx(|$8DEy)i^K4*`r?4V6h2Z{<e=4_ z?e|Q7e6IZ~DU3x`J&OGxE%|t>;Q(vKyrR+5<VeqOtQ0|&7H#3EXRbSZq6ZHnKb_b2 zLr<+#ir(p$sFd2*o9rIjdGy|w(0kL9&lL}>vG*Vh85g~^ZQgPkQt&^jc}cbYGo_6v z7-AJ5cU5w9E2Q{tjfycZ0yc2-aQ~;eJ-pCK`wYZ!;r6UjhHr|ikxH}9A*LWHUoP~% zDi(Q_<Jznv`>4d{`X{5gJsNUdyPv%3NGMFpT%BG@IxV6+^A`WGST(#Dtfk#fChNBN zfhzJ5$j!0EU#vht2<~%7$kL@Wu+Pq1OMk<)U#$8MG|hH%3~rx$Eu))X+L&k{U!R4s zph`dr*%uMk2jwBG=Y<D4O$PGvSgW?sD~v9Wo!#FZD7?^69olW^lKW5zggDF`u_H0V zBMA|B<vMZ0U&ex|b{S0u-<?C7h*2J+c3K$EN)?>}DS|<|5@>qq)ibEjY(@7fH4EkI zR-DaxXYo}2S5s@HgVuPAaZ(=k?q!Q_ZQl$OLd@WB)$>k1i3a?kZD&xSc$+XUd!kL` zWkQsPqFuDp4@$u@KSI{A0Tb!fvocf>d#l$#Gkcpv9s<>ny^vaQ7T#q~_8dC#oO)(! z?ya+*T)_jgu-!7tizg7x{?BvPU*e08_EhI0lnYA-6HUW#TGt)aQ(Jg4cFWtaLwC3G z2(1{!RWduqL#>mp@bkz!2{w?{bw%`;<!NZs$l}R)wAW~QQ%Ti`b;=e$JSg_4p+O!# z^-D9CcOX{Tr`(=JK8jrKzVjcQ`xmXlQuI-S(SwKGj9eOYBHEA@0IsjVmn*~Du+5%- z+mBFWTCZ^P(Pv+Nm-uQ&Wtf>0Z!A{8MwkD0j#DRoqrf|^mODnP59VC(Rd&`9YBsjg z<Zfo=3uGGhklrYryEgMfFX&6?z|-fT6K*@9GqJmFPqM||lygbdDO;dD5w+8mDNQiA zv8hoLVek+Qy}UzahI|kxRz1XckCn&46Q$%?&W9pzItidr0wAk^su=vCh<4_oe8dHY z%k3w1O>yU}dWaH`mvx3XCn~0V5njc1iNW&(C-N0B1hyUdc*_L}McT^~H~^`!P@E7$ zlC=XP#J8*y!wia_;j7JA)d}Ow_q3wILUAU1fl=n59=qbr4R>eswKH#NY>hFdy)A~b zc((DbEs$=%+BI<z(%Fpm>LFc?Aa<)j)01AXAi^GZygW@sMj5Gwl}$mQkC)q5o>9(! zlQBPT*yeu+j%efQeLd9WtY>~<m^Ja6>vBy+koO4kqQ+^2OJt>-{yyKhQ(axx)e0F_ zUignjg<daBH*}{~Chd5SY8x*v7ZzzPzi0&aOQ-z!TWSRVNr?X)#rv_xXia3j$>LAB zwQYuj%gst`*ZfA8jfDPW;Uu4DvFBS;7|5Z!oX?2{NBH5X+|$MTZ#mzMe{reWo5F;} z8DHv}242ld<6UTb454Jh`9tsyf`N4rD*F9DozNhBrE+GVZV#XRXjP&{lmY*)Jp>BT zUFag=@t06p*^o^wUTE=*)0KwM&T>;`$yCf+Qnv}~>fEPOWMZaZ$=bR$vuq$k6&mpW zIL6ydirW3jzScaNXTFj7qaIeLIc8vQbJtT*$3xH7U%LF0A&8igEu9>i{vj=$1z)lY znNtCW3k%|-_h>rO4!wePq27Nxb*+!AsZip0lnmda#iSw5f=CGdHvvvW$AM9;XcdTY z;vnO_l7cuPB%126LK|-3nc=T}Mh#0sSiupkpobDRCkc#)R+4{d9?B~4@lnjkya;Bg z_wC5U>7Oa<`{DyVa#I$6nl*gV+(N8(#d@z^JN=j@Jhi(J9&ai2%&r_SApOWNIg*)b zR%G;!|2qFOrSn0Yg~&gX@xR5ytZrZwEe3dMHl<ScZjCR`B?s=#a&xJW)1N`^tv+bd zOU)#UOpE_igObHJU^x9Ygw`FqVfjbii<_I|*;o1~`>0v^)5`{C1$_sg`jVM}+O-#s z$KS&rHAWPm<P_U|jad^x6lbjmQwJo%CQs!M9JSmXJvEQCWfkq5EG&p^ECwG4#h^jK z{gY}BSzvWxp>wjy6Yfp)>UJM!P2#*cbA4ku(kWwod9;`DyyUn~O%lGOph}wX)vi~? z|M-6pxA;NBMM4}y@w2mCLtm0rowyRSg;w*-;L%R_?|!&%e=fSgk986XE@6J%10-~e zhN75PG0H=~U+q(w*j<^gkDzZVh`OVH<I#$#Tj5ReXVDH-1nQUBjqnwk0XuY5KIklg zPfhvIZ(pqMX~1?EksrAIdooMugZ6{L0l5g25)q8(s795SdA>C{$WVH}bJFi<XsFWY zHI8mRVnJPtwP<zKmB<cJI=|T&Z_{vx#jh&iKQ+C-U)Hx)^9TLg-(9&C_4kb=r}tR6 z#07biC%5?kkg~?sBdC~jO^xb5R_JxFL)^#ZW=>~!LFKIU5@~1mM_e=4fu=KYyzeM9 z5q|7c1R-wlu%5=2D)U6egPl&O3Dn^qGwO)(u2YrFkE8H48LHV&`MRu9=0%BSZRV~x zZ{H88rP8nBNk?}Oh6n5vt7a0>(c&mdtariAaJ3_4jF_=vUdP5V54yPo1c)2AF>@*i z$)acPxOfr~BgIFm1H?*a)7Z?6lsSEvu@6B(#>E?uw$HD339wsA{kJ0=mTh`ePKCZQ zays5oJcnlZesy5jHSm$n;%0Y2c&hlm0b+NcL-=aiC=;gK_wAD$Xbr`aZY#eo7akjx zPeD+Ir@AKd;ZI7XVol#w2n%e@jPkQi8R5M3N-L3#XqQ?r8!1h5W(=XRzDrfi&S2~% zWyd^RgHFGq8si$}ZB(G!dk@59x9x=Ayp`ptPX`uG-;V3Di^i(G&iPMhh$}iNpTp%8 z{xVDZ5G1@>Gyh>P5uM-n`*^O%tu76@H#;!Hp4r2Le)T(>=~tJJ3C|pRxx`SM3Vu$? zU0p4DENtuNl_#z0Pf(dD>ECVCeaB^)zE&uue5Qk=yH9ZG+_io6Kz6JiG?l*Zm53@n zOAir3m{lQMp=6HEQ*&F915eMHTg(d%?<goT=YbT8>g<d5<ZVt9Fu}vwmp?4N3Djj? zBaUbghACUq!)244x(*Mmz2t4`O>cEPmKQJvdlmbg+Ea^SrCx4+P6t(;#ZjF$<P;X^ z1;0{nvx{DW?a19%ITJIxme;C1M~=ksaGI$>-yb+Wf6S{;s0Q7*a~o>vhrL@W*uq}D z$K!V0>JnCej!!Xti<R3Rr5l_3<*uek1j6gI*kwfj<H+S>XTCkcb#{5+3K$a}WY%ry zYlSg61mHg?d&01W`yUm^_&XO(zfF+6`Kv8inN*&->Gxd>J`=r?d$IDmfcDuN3fXPx zB~1qEZ_7&zSk>`&$;P#sl~>;nqBOG0P(v3nMD*TmYwQjGUxLbOA!j{?Od!vpFOSad z_=3O^=Q>m~4}7~0sfBumPp!ndC;VO+=I}r_79SaW<4msf`QtE?q|eXs+X^LsGIVhr z43gWD;V#^tM?SQ_^_Jf=RbYi&HFlBoZMbb&{al<NS-O3et<|OzUfhk-yS4v67BuYa z)A|^%n(5>-WEHkM!SoCVRC-mjOP;sf%WEx51C4p1@?m(Xi1Qm(!*@N04viU`S*GW> z9UG19c(FWx@jmT)B{NN~O&nHtnDH;B{~QJmj~ydyfsl%raTOGsm*W0*a@24Lw~u}c z#yV|wd|XI<Uz|1?s@LqfX=?5gzJ5Wt$=6CuD|vIGEKOc`BT0?H;jzrCTz^^2!Y-yA z7f`0G>utr}Upd^d-psH3>{sZyCdB;3@4uVz*PQosQFB_tQ9Wl#lZ?#UJHDf}nyBK# zo*wz_!Ou@NTyZvG-gru48R8LX(r+XX$3_KWo$+H-$DtB~5QX2U#}jL>TKr9!^55Em z-wd@8_O3*R@KAXU?|n6po7O$52g>X-ln2mR7)lobf0+6(9FdF=ZYi6)SDSt0TAo8y z%HE7U+guZOgxiness!&8q+I<m$#t8z%EjDwv<$@z@_AyQ*Pa61^f0f8ypPMqM!jVL zHgu&o728Z{PA_{uL`&T@d(l?3E!AZ}>+p>d-x-@{blZUES_7Q1>23BLQplzH-;ZYu z)+bYg5%kz;->Tax5*6RJz1^Y=$h&=R+9cC7Z0oXA@dlF?b~Uo+!jEXb<9UzV2VEZy ztb9c0^=iDp*LoSt<Gi274(x4G*F9}SY$e`qyi6$fi2e_nd^q$`3{E_)ZTiDTt*%K5 z5aS(pGR=IC4}{9HK)V#vH(iQCX14SuZj#$odwnReS0|;IAF<Ht3Zo1RoZBcgh<g+p zUvO&hXwZkc4-vjrd873=v6FgnN1;Oms&`$|{kp8qVou6lz(A=hQ)o7ji_D!m-~^@( zYXfYoKu=B|S)%<Ip^P{lbE)tb-XnwgN$T+mvvJYC#DD0r7(B#@5>~#>f95PaRiRUN zz<ns+@pvNq*w(WruG<603nhtN5v<^XQKntW%o+4ghK2&$(N?NHD*<gPXMcR@GmGRG zctryn6M+o!CMrZI4KFl|bm0-S<>K2fN8LV)HeGOaY;)wtqmKT3Uz{V^cfHhQ=$g{0 zq&KK{JjzT#RqP&EefV=*qG@Y6<M|#!&bsp@?5VGRBY18v(IW|)EB19()mP3d!{|q# zfI2rcI?fOIMHqBgL=a2|rX2k?$xjRf?%KV<dw$J?bD8TGgueP>fAvr1z!Bkd2E9N2 zb7p8S*Qtj-Nx<v_<52#nKM58#^&yup7nz%BJXv}lpWUE;`#HEwkjt4cTJik7eWvKJ z*3?;zj9Bk`emaWdY0_afoC_-N&Y4+huB=MaD)5I2qPlxX>NFn3ZPnd5Q+t9J=(RWA zjIE~dg-<WKWGEC#J&JK&kcqd_INRBf)l18znVV%+dHt7KP5($EM$w#-b$d59@7hl0 z1=l+Fa?S+KoG*Of8DR%zWyA>|*Q~W5Ju!cGxUYYDKde5UvvXftXwLB$HSe(kgr2v< z24v$^%eJiCmL$_vCbp9acc_A@h7FB&CV=l&dG@-xUtEYg6yBP`KbVoyZX+=YTaD^% zdO}P7o~lszc1!et8Vo~C{$ImI^$Rp+0RZQnXQ)9^%eU>h540>#eQwc7m6dahZc~dw zF(%ZGP<2kx62T$d<bYe-o*PT(DP|XI4#m8+|0u%)?(lfg`J#mi3NCcwoSD$8XgtLh zVz@XL&hdX=Uc1+>)BGoE4XeidHj%_i`V#u}?{0Wn#oH1}`lUSK6p-hzE)Rdbv}Io% zb-mWyh^#8EoaA77YIm-`y0W^=mSufbnPR#9u?zb$#{3p$#zSSH=CROl`M*JSL)#F_ ziYe?g*VEtzEzU*_>k#-?CA{lXEvMIcqj@>-@AW5Ew+|s_4|FUTE2C)#-Fyy=g96uM z&0=)S=1c+e^L3eLR^#a_Ikdh1*9)MmfHm;{o%LsZrAw!9Y{xZ@ch7B;%Q7=xux=ZM zPNOTm@OwI0;!Oj%g254|QOr1gZF#6M^q>UILqqcg59*M|F)!LMTz?-$X2NH_7@~V~ zO<zB4d`Qy1vzQdhX|`nS8V<;Q_jT5;-p*8o;T!MVz%pJN!x80?&-!i;s3U^q5dj(% z?H~n+h6nv1%EG{T#{24oQ>3Fe+^UTn!A$4IndyNkz9=5P^nh9PC@69jzit?1Ot3zg zI;@LAW#<TgVYoASOWIyhWONwrjNS?-mwST#J2<I)gt$UmVIm>r=bx`W2<paZZG8Kw z0!=yXQ6OJBG`Bd}JFC5VE<ET}rzCZxtIy=hU2c|VGb&eOcJ=D>w854A*-9wEW^4K2 zY|GDB<R@&WETczFd*l1KzZJt~q|bpC6oi1`uxcfE!megN)MxWB0^g1IKZ^)F?sJH6 z)2mQ}55dyiI03D?`S2iSK5BU}QJ^hXfpN=vY1j@`8?>L$IbZ^2Sw2|9&(2(8-2Hfe zksra5^yUF;@`x(YFtBzL()m0o0Om#i?ncD=4v7-VRhH6;Y3^Ppv~@sf&qce1D8E@q zl+SmFJ-NwGIKM)ZfI9_7*#H&56~{GH*8gKt0KyUXJJ<QQLCI2+^YDy!)9RSp@b%Qn zd65cYI=qOdzFU78wAF;pDs-P-4%l`5Np7ybku%y~?cmv%I60v}*_r*(v#JKtt5PLp z0ft3<Tv3+`PSqHvtrx~XE#}F^itQWy`avopQ=2|;vxHCnz+x7&>>1k%LJ2S4VRX^3 z7e?ho5fw)(3?M5pP@VCgOb|ep3QZk@)Fd)inRkkb$6w-#iK)F`f11GIhD=^SPdN_= zfpXL=>2@>N<@<9KBm8_4AQBC<BsHP)2XOld<<I8}$q80@?A7B`YK|%6R`uq1I&9b) z3`4jT+K^Rs3{_q}D1us!YapN((%GS)`(VqEKeS0^A0C&;6Nvp@25uOhEx)5$3|i!9 zTAEi-hm22*WX9XvU{U@A2FLKQAOERhb-1`x+`6!D2WmUW5BO!&tl}<rODSv&^<8(X z<@l5K=meiFWG|gO?WJ`8UGZQ@!k#0R96Oujp5#$0sPMJF1+(M4Q#L8>0`DCLW3&y8 zB3}u`U!ChJ(&R$~990jc_9dw)Bm5Ib9Y)oxZK6Ajh+tqEP)6=YUe$yBF>}rFJjuAF z*1xLE_x_us15--yIAEE0Olv!7-IoSkIxGhq;1fv#($N6PGP;9vKSUlf1sj4a&>lPh zdm>?*Uqi*Nr-5L&V3hKsly0L~Ly&Gi^wN58>E`!K?!rq+J=2T0!D-V6j)_^54v68e zljv`Y)s>KkXEb`KV*($}_Is87srPF|%_aIt{@C2z*SmPm#1GJxHwtI9cha}wQeGu3 z2Mw(Hc=QmiX(~%UkBy6L`-N1ywK`NIN-h%FYo+<9K)tysGvrW1@tS(*hC=zfS}Axs zj}G`$rOh~SID8tV#bm;ZHw95(qOYdrsuZH4rF=)rF^JMJb`MIJXV=O=6!Zok90A1N zP!8<*urGDkChzw#MDjH2!tZ9lWI=(72VIQsUt~08mbnQ9)uEH9fU+<IcM5?a;t6)A z)ytFeK?c|fhXvzK9%~pYrYzllOyu#O?KOWJ<=Re*H~jz?rL0xY`6(ebESJ{;AE0>o zw`?P&Hop7Q6>-Nu1!sQ)cgNSM>YACgEL5>>fupsnPd@W(Q(tvbXbOMkN57d}DM!B< zIa)*0@4Xx%_q=BNeOl4pg`WE%9d0$wJG~~ICq+&pX8?h1l$(eT+)(iuRBUV#?(pQB z&fTec0TJKnAyIj!IPC(cuN7zv1eYM~c>wh&gc?e!yo^{~<Mwk*APg&|qiJkWxe1*S zVDlKzTdEJD84QJZ9Eq4pBMKZml3kqUUK+OzPfUp3W}OHKA_K)lqf~3{Vb22Z^QXK8 z2`Ci(FcUU>jmjoj9v{U(vWib4r4Uz|Y!j(DD>N&}-C<qzkyhnw$LxxiDFEaB`&5vi z1U#u9`KsXBVz%Zm#&L1a{pIAv|CP!VHw{zQY96S6wgtCu6&4nTv$c&qg8|pBa=37< zGVUA4AYMwjPseH1d5^MUg+2NoH1<&8;nD%4tsQi3`ZsIig4CM09{SDIa?WbE%PhOh z0e9Z%?gdxd!&5wo1x1+_**ErO$AkcKUhsT*O<c`61YP{k3CQzIIOZ}EhP_3UApf)c zs0_Ze$b$$WaEWi%{SYuA7BpMYlYPPI4kLV$^dOA-zOTV1k49}O-Cr_x2uzuo7dL|? zvwg;+@zlB<-3nUhh^l^lm|}tG{c`v@Q`n{6pBM5TW*QW$o(B;beS1^!g3uN5t@4BA zX;gIAkndSAq`p2>K4MKJOs-|nl;Y*fvoMZdRCRkF`q`PE*jK+TJYlcfpo}VQVU}Dz z^>T4UyZ3Ukv{9`sRi~)dp8vECk9Dd*^+N9#m!2#m6#QYeonB|8nSG7RO$+2sz4I?C z30j=$&kPa#pTm8<$IIv8Ny`IglUl20)JGgpoHLqlU?gxWOom0Chz}&oE>MCOb;ck@ zm%F?Fn4wX<%`RvuwmPVqI@<#yU%$Ll_`^ZVXbuUx{JCG>lmhDEX%{|alLT<98Su1$ zuv13Js2pP`5L#LQCrSSXs=$CT%Pu1|lBlY*CD6_jX|LtvBMYgOYbZr@^UR+Iu_aMC z+jX%2kY5Tt5TcLN@gs(}##c6*eM!MPXbVRhm*;x=or$H`yW`;T#S07FwfxcKw7m|C z=-y&<mZ1jf^~*pF7u%;YQI8m#>;CMCDKV{sl&1AUj7;jCy*a5Yb0TH8h*#l5=0t^e zmdHs6xAdH%G<q5;OrOP(JWjqfBofySCxhOiUHZfXDc@|^^ZL*`DZjPL;}C;EiOnwV z{%lVfo@{<WO^WUmB$S%)YOn#Zjw`DYhd;8z!ongNh7r~Q|4>}!J3QloA-%_u)7-f^ z@O1BYq6!2U1}ac<)5+27p`3BXgw;!cPt$f(WS>(3SQ97I9n1J%nrz1fj}9Kpnv=}V z`wcpuYV1U=u8F6NZW~bWozYVF=f>A{@$)ohGrAf=&g=`Pq3Of!?rv+5#)?`>>82Ls zJMKc`?-b~Kl&pcLQ}@}POe^-Sy%{qZSk3H^1l-j>2Ws!Y$V6@_4C5!t8R4qw(gjhL z_2VX`yv@aFG$TL?AO}ra?Y)nf?%|bl8lC?xLOwG98+I>LI{L&rD4OrYSuh!|UrO0q z=do=Y(A1<yL?S)IlmViWJG1OE#~l=JLCHN_C_kxw{GC^^x6sSHPLyl7W-N7(e@m1I zT1({v##wE_ovq^;NeEdg!8#DMWm<0>3G7t;4QQ9p6|O&*$@SL>u$ZE|D=Xdi`=A*a z##0)fmCEXUVApZ@{?<cldPbsmHMuWaW7W;vHf{1X%yGxO+)=UC^P;`5N%O9jo|E+H zw|N6kPiYu`@Gmxw1m$&!|5zbF*8t~5FYX4AYU3$Y2BVq>6t(N7=h@ltv~?x5>1uZ| zbK+}5BN#%hWRyW$rvHnuWF}*DO7I^V4?JQ?a|}Mu*E<}~yX|vh)9jxhL#U8DE=wYg z@y6f_+HLCpbxjo$x$B>)p@q6QxI}D-pOB+6{*O5Xh6LT2`oJ^%gXuMc5or;W7CR{n zU==hQ$B)TxYC8Z-9vJob3)naF<4PM{=m15(s}RCWWY-6;X^C<FKa9AE)$cy78WIRC z^Z*63EFSn>`AN9z07etOugRIGYwC#U6}7<lPn-kPLa$<@`mChVtimq<4-rpF=)L~! z6he(bv*tWBg|kW;?=Z^}OAPv-cCB0nz=t><%%#tFH94g9DjqPuND0Lo<{~xZg6eem zt($(IM$i`|G-|7b3!G3z{n;ddK6K}<y8pwLO|!)B)3%J!D7u<7Am25yN>gy~tjQ)h z4s<91EFL%>Pa#ml-YT<5HAI#1+@o196KdFEx6MQZT0(!QPL5>I5muUx^y!tF?{i%* zHv3wxk-H<@40`#M2>{C#e0K3oXN^^VWk#lzW_%2)!{I^B0Bt}xQsZ;cG-iJkXEn;E zj;h465*;h%uFG0P;D{cRBmh0ENkO`6mfa)=VIcs<P=zjE8v+DEaBzyNDfQpPkrGG+ z$evgIfa{iQWRJ3KO>Jw6y@yQXF<1g(R|n-;VB^LL%ufjpPev=2g6Afix5+o7b7H*0 zsYDN024P`BX-f1r9G^EvE7C9bP%di%p2k1C+g;OU6lfixegQ7x{|CFYJ39gi<s;=x z{W0pDM-4cVKp1MZwp;khjeSU4Tc6LCtIM3NA}62F4&OTih`J~z)#v^iGj$mRhtr6& z{UOe-*jtF?9<SC6+c?VW-Xqou3G%up{0Fu6E(|{R0;{of-DkI^|JZDgDu6?Nn*l_v z=BbxRdKj+Ko6e_GluS#r1jeerQ;(_N|1_NF(JGXcF9b;0==<!h{M3LU0Ht#0uA3hF zKoC}5<bvb%_zt-!U7`D$o_vflY-Q82!^0mjJpVX$t{Yv9q${!bJO17l063YY^pE~1 zWk_w5ulxb>l0wJLBp?RnmdY%Tjb_iMmcrA|y$lK(-dzRvYfj;QX}aSYO7~XFJ;Ij# z(rJ!W76FK+et#2a)fqWG?Ewl7NTtgV;)@I`qesDtrqVyeD7`*V8yO+dkZ8&2R;S^n zaxvA37^7Q7Q6+JagB{&@mTqDebS3Y~;U91COI{BxCz!2OoCD!DQRVppTy~~fld8MU zj87mhDBqzfhj|MZB`Pl)=rYR+_gc5E^CPO=MaTu7t^-E)TFqv?mv8lY+8NzqGDp!o zh_$JHbc3o$(ye^rqWTL17UfmCOIPo+PSt>+aH0SKX9@#_n`kDah(*Fk4c{gPV<4== zxpAmWHI_Q$uXRN-m4FY@1Y_vJS0IFiTudhT`8qT?K~UM$oofQ29_<dOPT<tx0G^F2 ze*0b6KfeHSitGmWkAgAOqz-zc&erq^!ky;7S+2#y*knNdkPp%u|M_kkQ$B@6jGig? zz`f?L{hG1@IwCmi{G9kEq7sah-+Zs?1!H~P!Zlw|&kqok<iC}E(+3bDv70Dg%K;a+ zi1e22+xK0BJi<xXZFLoZY}43Mg!{W)>s@He()lk>vanqxJU>;Q91*lv5mb(;{<hAc zWoT9g86;*2fi`O$dh5h)^PTic5un;LopDU_2-l58-0<1HfmOWaA1d?k;Dt{(ddO1j zdeW{}r-XpRP;MBU@s5U@Jl{4mj#n@kg~I=y&q)SRIdWVmTo%HOjsy3~MvdwiErLMo z8aWdhAMb$k@+xf`m`{RXpB(vw_HqV;(>=%?Pl5r7O4$%87OCbm1TwDHQvdvc5kc=y zt0x|GFx$<Z_#Z;7J&!JI%>D{snG9TK1PV9*2@pv?q83-~X7m9`y!S%$*S``F3SiPW z)GgXKf=sKI4ZT8<)s{t4yL|5YvuZ~S>zzz;V9EEJawC7D8IfsMG``lTHy>?g#mPYF z*PiWSe9-k`vaLACyZEp18Jp9&+ppbz_22U+j!sUU+%2*YO8=!UmGH;Le3LBQL>u)( z#$g^y688z0O78MEWBG>LDl1og!U$SX46*Nz{kYc*aaIZOLZkN!20E4#e6mT>k>7q` z9|!+kYsq-zkJamjDWZl&L%oRQPpnO1$}biC28<icY`IP0jSXJzvMpZRJF6UH$fb z?b1{!^Y`pC^-?R0zxk;~qT(g8It_s96w5d#(18M;uvva8?{Qtn2vytA?Oew|>xd3f z<dQ;RgC9(mJnR@t#I-?Te^%pN3GF}B%HS~t^(`k>Xpy^TMedAjG^h9gdYIS@{?|!8 zvYkQ|RS(unTurA~?rkF$Vg|Un5@ij3<-8V8**+}kceYm}F#{tlND5~Bx~h5OLXnt3 zGKs4Flc9|vUrew?6TmmJW>w|$*LFahc{^L3P4dJL(rc5<OJ7i@Sc<<0?x&RR3tpvZ zDC<`jZk4Mq%+1;Vk`Gr8HIC8gb}`EiroFlD8DP!GI)O*~t*)wYbUz1Q+IWzGe4~@0 z8W_BS*sw0y5oq)MWcF{_yZwhc^bfNglP-&NzI}Ft7}7S2)9dN|>}yhBXJgVdcjmRG zY;=1=mRsa8{~V&CZT!#IH3%muYaOgL>+fF=GuDy9w+GH}7@?z;+LYU^hizgpCg5UP z*#N#dFEY>AehZ?(0dYm6M1SGuE(sW9qJIizyzZo|1EN0LhJrbvPABq=9AFc9X#Hkj zJ#9-dC$6~=oF2Z=rp*1WiNH+c*}lLab?AXyCkEO^FhB@ae4ytq%#se9vv4Aq{k#WW z%a5cYGR9<cLJ~ukR@OIoYnwgvN0j0>{HVbUqvd6=QtKD+$E{!QM1!ba>??EfQNI-J z7#l_wGWY#Z0F>OaxE69T_D&R^Utey&%Z-$To_@FdSK~h~In2Lo8++tv3H9dZO&yHT z$q=AA*V~QbTgL5I?rO-4`u*W*=L#?Il7Cm-+q<I#zM@eZ(Doq=78CrX&XTTwRp^Fz z*)45#vGmrRAq=_Ad)0|zdD*HOW_^sQlx>G3E;c(2ijV!U&B9bI1PM^)WNqA{m)eV| zlAA5|3Slt$m1B7!<`hPt_7Ll@VOSo8ntr~N#1qK1#VCG<!m{>o2Aejz+l%p9*9V9^ z(S=U(S9eERIU@L4eETV?Mw?`S)0NoBgvok>cdj4P*zyCL#s%veOYuuy7`G_`)M&Pi z1e6R-RT3>$R3IyY@f#HhM{&zTr0acC(fkp$kyWR<87?<Zlundf4Syf*@SZ1w>0kFW z=RseF)eNw;3GSLH%gORoznhnvX`r{J#p>)EF}TcZ<v&Z+1K!YsX=KjbEX{^Y{JHB> zUTwcjep?k~pIf}AO&e`FBK5xhdS~yk3*+j$arU}rGYh|DYA@)_hrwE`a*QWGo7sfX z-PfhSDsUk9CHw7uYX(R60KJR3`RuV7WsbODi@^o4I#_-l!mNkJ?{B>WmglwJt-$(p zM9*tK4TX5=?shKNl9F)2HAtWa7~<_Z<fa>8g>pMh+$Izwd!>m+=BcEGIXrgTxt2?@ zcYd6L*-TnUjlqnMX$HGeJbeF3mXC1I2n&tgz(=gRc>!}vot4IFGBIz|BW-H=X3UQ^ zj9iLX*x<)F9yPw1)Az=3lx;jEqV4gfFOT{sOt1U57ww^A+t~bK3U_T|lI`*IQ1#UW zee{7+1(A}tt|Oe!hiJ608p)LJ`z<55gqJAw!$Hvb{S~~tkCKOXxBuE(^o;W`mNK%I z{rp(rAjD}i-@FG$i+-@l!koITXwwI6t}3vQF=Ax>S?l6TuRrVUFwRm?pjFOR{IFvJ zJXZ0Z8}{egkOi=(fx3lMXP;i%HyGIvPH_Y#uJJGMP-^l)2^jI{))ziO)&P8kCTKry zYHtaSW1^Xza!vA|soJ;(3k<<)*~<E|a#e1XDtDMxQzPJKb2DX3Ucl(*pFbDp^Ixe; ziN1L?-X{_(+HSPe@yk-!FHToN&p5ANtbM+PbX>BXgdP`VO>~+`#tINRPADP}2t{92 zhYfQ9>bt%fgdsahn*Ow0S}d>pYw^Rk`YK$eY32UE{%*=o&*(&i#9&kgyaj)0W5gcM z_<;>z92`qY*n6`46=vY+w#<E#a_!JpdP*~t_qM{K|KINTbiKBXS19=kb5;^=xN?E@ zHlXz4oUbKiq}-|>3Mw2ZHE6R)r9<s@vh6p8ZAvi{kv11te{Eg@+migZODvTn?p%Lj z;sKvzT}<<2b%|J)V$3Bx&8fkiD1!FC6_XWfl56L2B7}{H#$yQaQCnpgoA{xJ%;ZNb zeeviV%*`*U&II+dm>JKwg<sU@R>wAh^rD2>1pBd;uXaKL<qHmB@t8~2nO*i~RfpmY z)~B8RT(j|E<%h7hh^%pS^|xko>wIHRKmOHfKNkx2aXeN%5@WL6QGh-|QdQt1Qq|!( zNlG^--W9ROw%Msj%C)8glEC&m4K`i)%3+{|Q-aM{`So5ud~8E4!HS$($?(FE576yX zFmWqW;5jR52Aw>sE30Jbiv0q>LdrqCB$hHKq|O;c$MSEfv6^rV+EpdBzlQ!}qrc5& z`L$ow&9IO8`4!3-xulngKGEp*=i%%X&hnb#4#es-Df@#{tloK&beMUb($2NKo~Ssz z%!~2u@`AjyUG$g(Z)^HQ^F@w_m=S|GKUXBgvX7oV9IVHD7R%P2TL(ddF=_^ns&O>M zS$%G$iU)2_C*?J)s152woGHclf74#3QX)Xe{CMJy4Ij(p%7zmo)a?@Ip^yp1INL1& zV?Lsm)C~3f)-1w|%eYqRvpPoAst&PK=yjOUgNpQ0o{es8j8@00q{lSL?+ozFpISs& zzU;s#Om6>F_&>`4!R1tPUOUA=GGgN%CWB5VQY+-IHtw`+go3F&wpgq$aLgKtSGzrg zr-%486Ov>*)G_FRT%s|)<x<pb1A<9gdRy?_k_n$)(8+aS-6)|ke4olU`||@2)P;*Q zgpo~N_fB%+>*pmVe{$6Gui7A?p4xqf9Z#~5C+Q<*EOfuNqeZLNpRkHUB9$!=w$co4 z`1(`Sck@KdXfCXHSTi7jGWU@qN;$gSOK5@tREHYH(mNZNslW+GA(l$Y7VvE&Bzh_S zdwDyFs(!vMjDbE1K1J?jd*r(#YJ!Ye`C;r@x55Smmajq$R`C8VgFCOcBfmm&K()-4 zTPio%_Wj?pGAWif@0^*Q4abnw{Wp4N-XAs2xtqas(W&`x&6}lyG^GHArN5cM-x;8! zm=JY+Z%EyVNbiLC=XrwTPJcdWXY}5^QLdlpVT~+xe=0|!N}7-s96c@S7UU4gHF_-R zXl&K1UGgDPu`)vtJGQ{l;Vp^k^e`JphR&ThdlV|_GB>gx3VX<G|6!arDDK4ut}pMe z+h?kRZFMfj#9Dn2eKOe7n72c%W>o=0b`xBaXEpg`0wE>1W3i&?FK}SM%hy&7{Q)wm zw98Ui`R;ZpmG?I62%(i#zqOa48Q1%A{TxT7r%LtU%WhG8+A()BCw7jV&vcwEO~;hz z8X4?_4nKBi_^xT%(e>0qGL}EGxwmaj)P%UXDypJ&fYVGQM}7ewILlGW^jJX6p|JI{ z4l5@2YTHYw3ZM33MvJo5PRsQ|YT<GXkc3}7P(&l{64du3gQ@hIUP}(*%DdQ^|O7 zS<OAH4&1viHM0`@sQZ>10sn$As(FF+@iABZ^$76K3buj$Ku#s6(4jEku3)Vmt{HPY zU4AncZkYXDr9vshnD|5#fp)2J(n2cu1+(!`ITmCQrCgMV$US=@Aj?}>W{~!2J=-Lw z5xqbsey%)<M=Od-8ozE$(2x%+OCcE;pO6=h%s|TO7SRbrp|e2uc=;D*;m;bP%j{#s zip_rQH7$crKR%k~F8nR^VW^i5xxEiD0Nxw7`6wf=m^wZ_euGuE>$@4NDN_JEb^EI) zz{U<uI)NZU>NbPPg&&=B5jab*W3i`(%Rvm+8@DK>x?D~qQgeIy@&=oZ_kbAV^k0M~ zAM4{8oxCIQ!2bL`2o~jGhC~Wb1hZe?<Qxc29&i-Kkp)8hU4_~Rj4#{diX6zMam*E( z8l}8#=;2AHB5fe|a1BnB+hdx)ju%8D02@0Gt4*#!j8zGYRS7o)$%RVkCE{rMDePXw zO8tp5v;~1wrG|u760B2gFOY&ULoTVS*SderKDN_=YjW@E$QiC0@kx7eki`D05m<JP za!14J>nHvK@3|sjn0@kAXoA<=x-b%aUxmlh6_gPgh_rF%^V@-J;}r7-Pna>qm1eAB zeDmE2evHut23mmPYt1UVD;>hA0LIKE!O??kVg%-|e;X8Y#b8A&{$h<j>*KqXFh)}= zne%tbiH$a6eY`as4^(bBxE}H;2z%zQQNYJrrj1f8Pc;t^soJP@GX~mtQ}IFh948S0 zWC33*4-G}|L(<wycvStK$4T(I&7XC#1aBIM4;zc4@12-^vXU|L>Zz8H)rm&W!A$!3 z6Pe5Gk~{J?6c1h=8tss?4(iN##MgOaJ((BW(FreM^sug7j$_JbomrZoTDXGm0Zz6k z{@#^9+KISGm0NWJCSn`y#XPz$!JU-3?rET=;=wH?S{F(>AiayWAR8FUr8A-R*?QsH zPD+CEJKKIpqUWEQKMBiYK6hByW?~o{u^7R^+boaeZ5TzGNc92Wq^%$2wEw(!V4QSo zwlA>sx04-dqk<WFDZ#=XY=~(y#<=K8q}B)e>$xHV#wL5{q4mF%0BpiGo}xAgWO-Tt z2}CwK+xY;=(M!{^Ef~?Qwn?q&+~K2;pznTQCe%Ld25*O>Lc$xL;_?rouPHfnPVdh! z{L5UQm+fPZV%o<(Hmyrukr8aqrdtRw7b1P)`S6DE*Po1g1<Sb?HME!DZBm^PLQCx= zJa1n6;mz|P`0kp>1v2G5nA8b9a>me?MwW6)*bF+b2S{-fF|iNBivQOOu(mMRw0{mP z*zG#IQ*~1&SA5Nhc%NWeC4HodV#)0+Kq171^R7KHH+z-D*E~=P+`)z#6CJCvgaV1; zLMpHY3xQGFP|T^ZP&V`Aa>cmj*dtZS=g-;R;HeeaBw*B~R>_8MO^(}~6usJb&Qrh0 zr*c@4(oNfcs`<8UUVq|^)_pQk@$J1DiZM;HS8UPNg1;nDY%k*DoMgVRhi^F!10X=W zeO8Xl#C$qm^JYfYjo|fB04%^jEc$UjWlm<CbIUXp<mcB^hakgU$Yn$8EMNgnc?`4= zQ_pr!;=3$w*5C4qSC~^Hq^%)%bafN>C(ak7c~pRHGb9mQ(pi4{_K~6nuX`_PWe0Y( zfZR8tTA!8ll2a^8U!b)@VUM~0KmRtw-YRV1#36uk9~i5v!LAq;n1{{z3i_oqkBp2g zUWsTP1=p6EYWDnI9{uy@p<1`;(=>WO^|uoKqtEq0ceKli=H}*Z4j28VQM%nhUAWm% z;dMqv20vcMbb^UTD36QoEOFL}&O6tUZ<6!X?$Y~}OEp8Gu@ZA|nBy;%9f(7FoX;(R zr1jU=PtQjl?g_S5X^sgOl%JINr0Z5SaU2o<V<Gc4htZ@vTNI6ntILbS7noA)m2b7K zOHw=@&j8W#Cnp|*P_6TVM@@)W#LGuzn8yMGei+k#36drak{t$VnenzXOdS3fAG4`; zEwUA=`8XqqY4~bq&AK>J1+zK`?-V2me9c2pPE)(+MP0X*Z~tOW%TJCQAx0Cdvh1-@ zVEK4Fz7z&0E5Ow3MJwE}6O{5>*s>02z8@_9!lQ<;UsO3M<r5Z8!NI{<Dxbif|2=xJ zuGG<d`KyoVfsstQE28@IY+~LeAmbRr!}yt*nfLnQy=)!U1QLk&1P5Z9q*(y^#1R5@ z92x$JV}B)R;N-q>YtQd~@<w-t^2VJ4g!YX+>{wMVt9P0yDFa{p&iED*9xbYT^ui~; zTo;{yF}W0fmoJj9Uum3=DZcxte?P@iH+9Qwa9nhCjZLIVRvsLmF#!qNP@NnJ$Qoeq zCx+}#vN{&}*+hJUlI`CAMalEYwS#CP=Dnv3nMz8w#Uj4Dmv%tyKmP?L(mL44RI^{2 z7OsfYPwPs`NEzjr+MK(Ry`r}^-%z4dp1~P(C&d0kA7RtH{w&cO69439!tZY`m$P1k z|4MMJv?_oU1ropQ5BwBVs~LE<omBpEuIgT`Hh*_})54uQkF9-A<c-I_4nd*`?Ozva zVUUaMePql+LMh)d4a5Z}oRDlU#IDP?{R)A!HonoT>>}l_*AF#hEau;Vj~l`1J=d$8 zmtBhYQ3;*~Dq#g219Z0UESF{>cOQOENz>Hx5R$FmSq=>1!WMA-ryBp}{d$_;)*4_9 z60^D}Kg;qoaiP`6i7l^w(RL)T^>*`O8m<7vl2z0$LS){Pjn6JRSSZ0D*m+5??n=h0 zsHv${UN(Ioo9vu(9C?afcX(7%r6nf+yvN(CK_5E=&o7<A1RF$EoTrxUQ}aG5eCvR1 z0LTk~AjZEV0ZnOrn+80cO|3K#<B7l_RrqeUml$OC`sGmOUU#b3uT_1V1_@M2fZfTC zRc&~5)5SQx3llBME_DAFDM3UxIjB_B1LdfA+pv&2f|YJ8>4t@^dvL~cFCkW!MYf$6 zxYodFaC~B7B6ASLwCHEU*67UzR40$=Gfho2>yKA5;^f}MH=q9G-jy`XL@}E#JhhB7 z2-J6brk<dm<)xiFSN|;FBy(0TQvpR2=nOC8{YmZM9Gln5{<D7f@-2=3un!IGdnB|c zj|DtVR=MRGNOvop<Vb`ZJovu;$pD87vX)-D>EWAOSARd1CiC#^mPpG~KU><$y$05x z=0O{T*BKq69OZq-u5TU?eGFVx@#w=S9JvLOyc@^V(TqMlDW|6VbH{{+>2QijG-gjo zUElusp^i$Nn$f~65(tmq@rm9tWS$M<HfZ7BVZ~n#pQ>^_KM=|l>`;pFlY3}{*HMtv zhOHa_i&e5nh{of=0+M2S=;L}f$Xo<bBstrvixH((1+g@$I%{I>SacAOSIrhhZlI}E zT)f@ku^uHL7DtwjDDcl7PbPRRh#2aF!zT7zf8JmyThC{f)QNu#4pyY!pd{-DsKJFj zP~NZ5_D(ztZTxLr0ca>c9Ecq5h)0fq{Ynd)%NhDl)i{N%SgJkwxpo6HNBF)jzBy*Q zdA??SzMa8fyc&6^Qr(q9ES0^W>*AN9TR9xzR;m`bFIS!Wy~C99V_zp<to*i#Ym>{a zuuOfNnz&^gHGJCXp@4z^pucs-C45VaUCWap*ED){L(b9raZVuRKwnBH@#Hy13@xaq zRwkQil5e>u@pnHeSKq+CEAI9EFW4emFEw`9{^z;#As3RpY%VvCx;qxJvr-Lab{aQd z4|Z;@x22J!)sj0Cy7N8T`@7F17_!CNNv;lQ%LC=z!M{y+d!z0SNqr%<XDb>cd+Q~( zryVHF!D&5~R+`|h&dtp&vi+PFEro3Ju;Fk97XMvhW4LjLN?a!i&b?UwBX7%`()}B^ zo)3v~yhNn3iyPJcA5GW&NcH#sO9_#^iOg$7BI}CCCF|ORi|k0a*0q(9J@1uyscT## zgtEumUb(VD#x*Y29v9hs@8^f_AMm>OyzV{cxgO)N)F7>=_Ds=3SFw3Hdv`_~e<KTa zl9H3r%Az0y;##TMClI{t87G$&{&~PJGEit~;uJz{ef?@=^5C4>ImHJ4-oLV;`&US* z{hzDGq5O?DT!50v<M9&{qqq*EJw2glx2`Fs%cEvS&Zv8@Qk{?I967GsRpouaM{~zb zdBBjySyO0aT7H5(rZw$7IaBI$7HAbhZoM|8r5uZ%TGeylh?CP#iH3pmA5V7pgcWwb zkZdw6)v=kn7{?OB1HW3oZBUbUWXJaxtMcRcL(cHJ(V)?(rY3~<!wLBe2@@(VVkdM` zP&J8MZlmp$JhyOv<$V3J^mTsQ#a7#_=2<LOb3u4bBe!Aw$_H?!aFs|8-c=p-W~GiM zYKUM(r^qF7#03AyVTS8Zb`1>;sWZyGA8pO~mNN!z2)t^c$GmNR!#-pkywNE6zd&td zvklX#Gm)|xiK}|&Qh-VC8WK$(l>RhSrzqQG)FhS03SLznwDrNij#+OdPyPHp6L{YE zdqfH>d9&2%9{ssG_VIw@s>XTS0*=`XejNuh#9Co(+UBkv9NMjZ0~vHzg&vom;=``- zr}KNECw3zVp&P_v(A0J;b<K;zc8i*Z2AvU6C>YXDEEGyt`iXP*x;hO1im}fd9#o_` z%cCLU-JGMhiBUD1>pL;xz$Z3dl#M?UTl81VOGUk_pC#7YDC?^HfG;hN?%!%sjOci? zw%5|HC1zYP*dglwR#9k{5hVHZ!SRpdfTO1H#x&o**0Islr^Lst7l=u`6#lEmEwI#q z!<YXk_h(DVr0cL4D2<Oeb}?e2xJNFZz2wO{?Bt#8Um9b-%+rU<Bp8-T6XAeAS#q4* z+#_;MGoPZZ@Sn>b;Xb9743D7WzvYiQK{Dw0?;%(X=8=J|T*TNJ!NFv}m;!(gObiU% z=H}-9U&**2rDTQ_6^=y^^Z(pjuJGph)%7ouZxt04S-`KrExc*|-s0jL*D2$VxsF7o zP64l(GbAcudx=s)qhRz1ybn$Vp!U}IUkNblFyg9w){>KwoW6wa_yyf-4h{}h9RIcM zqcC2Wbgflq@U`G%-LKhbR&vA6uB%puR7l===Ck(nkwSj?f`)U$)Ru1FrIzB61#wlO zGJ=PJ$b74+z3pus29a~V=iFy@S9*2h=5UYS@{>qJg|B;5;~(eG?W3@%MpRRBwy79> zmRiyMH@?hleWwuC%a#VSTm#R~IJ8?45M9fY8Hdp%cD)D3;a=-7&W8_m+ne3Wy$eoG zrds8{1eJW^<cSpt#c8hwF`^xe1QP<?=iOmV+MTfjBA&+=j1jBlM@^Uqwqi}P(b3UH zVP8pdDc%u3&hMLWLAjzD;d|T?@r{cO_-($uu8?{Z)?NF}S;(><yDq;G;-G!bcc#Vk zme`^Q_72t6aIB<YCNUTcRW7k4yZO~<8<Bh+`9S`Reg-_ES~of~c}TcazffZh3TQLI z8GKA`%(oLd%vUdvd=4X!B}ln(;R3jbi|Zw${fw3?lryX_MPqgGd3z(Qk1u|6ANbD8 z{~buzTwOWJ3b=<bqjy)IEqP_+MZ9+^kBAx_OmGWhzJHl)Tt==n{%<oM++O$&Z?{b? z<+OmM5q)ja&(I6X0?c2+a)?#n66p$K`j{c<Q;si$RpM;Z0%!1CpSZ-0<3OqVK7$YN zUQRfE`A&ljeVf<aoNTW(Q^n)I`yZx-m?UlgD1Bw?D1siz&scj_F3&`nbPQ);AS0IT zx*Bh`cWXpgD)p2{x{(i!*>WR=<VpO*)}Rj^xb5UZL^=xN9zt#c{2ZcmogB9t-pwTD zKqu3kopX)Id<Sqk={`@)&Cv1G))bl4&1oF+bgeASkI#X?F9;{ZV<F}Ky-H{F<7x%V zg=+oVzfSao^L{JUJb;V)WgMSLZybU%I4RM&oB#R)$}PJFxc4G=6X>6Zzy$t@sUfC? zc?6X*=4}NWx4&)S9f5we#~1R$W8ThQrMFVk%!+pm{X>zWekfyp0z}^?pQ1?NZxY*y zqty|>XU&zWKYzV>V`l$k2qpyG->p^x!UICoMP7->?L*||Uc9z_E{hZujMP~R8S8av z#I!IN`-(eQBA@+LZ~F|gM~`P^{VhA-yBR=5W9RRb-iKVb?B*)vuuBB)9%+Pkeg9ZY z0(bs9P@6>c<~uG@_GfK41<#pEWZ)B-_2w<?1jIWmjo9hu3u&VJBh$ovk-qNc<eR=s zDRJI4(d-iEvIlaAyTZ^#?^T51wQ8M`oLr`SU)-od(9us3<D-R@1AmK1ufc(h2DiS~ z-6UB^?}7a^z5<FLmqnLMIi`^s8?D0fL$Q=0!tdeu05=bhk?uE4{pU(zUmikvXQg&U zFx9MYo{q3q;ouaaz?D+cw!Ay*kP9^s=*v*Y1%L9m$Gki^GhI&@BMD;^(^Gm8g$T9Y zldvSrt^2xH0gScJ9^^1&A8nj9J&CuAD+ZnK5@fUW`*+>wDP_>!+RfuwPc0E(?dueY zd18!Oka+g;Oe4|yc~wM2#KuEYBi+58-sH<qL&{R^F4FAdK;azy^$*WpZbF3biL&6b zoDW~@X}iOT=^AMCYyG>CdJ;vcHQ+KXdt^v`*Nc%_;|)G{lk!{B@z-a(_NbNgBCZCJ zm-jRtpBR`7R!dh0pI>_IM<$KZH3UEUYANC{-6}8<A)?F)lsb6h46%9@GD2(~YR5a5 z?pK1qoCWl%8EFD%+R^D&FVg0XZMSNDn&-1pTbqKL<`h`Y>k(9y<)QvOD*ktXx#zn+ zi`)FkeJgAY5xJQd-TQo-^Y#iVY5YvVZ2uWQ5<M+^Bd)+FqJM0iO|{WXx7l&)5xQ$N z$m=vx!vH<sEU6W@&hHC=j2T5GwE@w(IEC*q+E5<p^c16vI9|9_bn%9~YjzP{j0{NQ zzLEP}_pLd9F{1ux=5EiIaYq(CJO%(2b7*M(pl>{*9z}j9vaPBsI7@E5xjN;bl{(V7 zTDu}ln{IjLqmf<5q9E|h{q|q=5iOW{BL8{0@xcgCc(z=-YOw_PHPZOs@5Yr81`__+ zjf<^XIuX^9vc30Ts(c*9qi^X7!n4*QhWxy%!m+~jj{)pj+a|b!X1X;LP&+fhI)mGJ zT(fS}+v%fd*w>rSkb4Vk%wRFhs`iXqVbv;_>fF_@%ZT=EYsMb;SR<6@ZZFT8#E*wN zE4qL+<zIBH_{^KrLfw;u{P`YbMe1rwaHho4O0L}?_h5dZpOmEf2z;if9r~JU$w+5y zhRTsn2w3>VHv3bxWY?TtqTO>!JQ8Zx6`Aqlj!cKo+9ao^zq}2g+x%6LajFJ?O4|i7 zJ%4;x)32>UjkE-*QBXRpO%hlRv+sy=p)~n&XcQvCCsS)iU4Irs|C1NXrezr08Jns} z6#PhSJ~6U!mEKo$X;l`BJU7x^Dvq7B$HySO^A(7Y<$EE=$zPFhMOwcma*ao@@PUS0 zAs$tqeWm5GEor&tuI_tV%^N5Y9s!xxD=)7&D9j@#q5Sz4#XXUx8Pg0jcF9bf1LOK1 z-k^nj4b1z00o|JVYmnl+EMmgdZ^mk0<=Y?&13XEW-_4|cfjfo|+Wi+VClIA0W_$~+ zuu>y&=hj0Cw1L)XrhbigC2#y~wUH3(k3);uj^_V6*>|OMRnF#*4~fI!zwbv!4i5ti zd);Z_Az;$!+m5$*WTxexFw)p|mM&`a=NA_$u!xlzB1=GXLgySF)N%klSkiSYTn21D z<8Ql<yVwG!Dt8wq`Uhu(3sfZzG?7FOt#4xF-I9z*&MBX<95v&H9=Z=W*eF*uKeEx8 z-ICved>`$S(#x`%*XWEz7$1N)eVI=PR^fW1W+Jgf@AEVq@NxeD!`v7;SLcsWENOF( zTW-n4uhQEb?hD`TQvo)+x_nv#B1`sNiT<I4-f20_XDkT0@3SIdU%S<bR>h&<ssT%H zM~R-tx`d;P*I#PR7B6{1VfX<rt+Kt(;mXww_(Cu?QTJi5FtbALH_4?5*ot$;`^&k_ zu(l$|^=}rI8Ut;~TdF4b0Y8RwOk_G~4SNOdRuIq1^@j(~+A2o|G4gc6dEXe6FpyMQ zN3WO-iL7^qs;@^DGE^083`USdZucZkDv*<JPlr@2UOE&;NM=Mc7Gz;dQndxdlMitH zr!W|~6k2nRM$_h(Tp@27?9=ca-YmJE$wo#Eb*0YtD{ZD&<Q#O3<5xUI>K`O(nccnt z^UVAFDTDg*4<t^AH9kD69n(d0rOYiz69fk{o)WvNd#qeS)^0X&g+tv$cltq{LI3IL z#L+wamzorSa`!|Qwij|%C<bG?zCj}zor2J$sPyk?tgmvP#(roK<2NsR#c!jsx7v}_ z0Ux+*ai<zU^Z$^topc;qhrf1^XM6rmz%384kxPsDlB%Fw-hJyej?PP{rEMYNqs{y~ z;tCdzLO4nI=ahL~D54{8r5=98_wq-N3n4kc%dh+WPcry|lF~JccYGA2KzZ2=oZ90u zb0xnVtm|;z$C2qqr1@SVFV?+<I!vJh|K%x+XEP5JyXB_btORj8$m-Uf&O-|Fx}60C zsq~4(*|@V+`J~gEC&ut4b(hf4dyjneDU80Rgs1s-6yH5`?9|x(04T&@<&~6_Ud8}2 zJ{Cfm6||m`n=PtJUnN|oUfv5Zu1UlsDtysV749gFG=b@Nz^&wDOoixGgviiSm+qKj zpHVizNEuIY?Xn$74N|FUIaAN=^{ragH{%-rY^nZ5n&>~sr>$*#)Lu!Fjf9>{W!N$0 zE$kuknpuc9)I>`S-}b8Q_I*Tnk@AwBKq30MDx;O?aKZ_{ao_=QO(?$R3Sr<;C1&Jo z+Vk#D5VA9|&gSC~(kr{%<!;mO3WSGj5fq64>HOh4G7`ZGddoj{8Lx8aO?xR@SyD;G zJ{$*7WE7G|y+p`&6vssBJtW6Fywt;*QAm6}j*|~>s_CEm`!_p}V!>P{a0d4W&*z*D zOB&~odsuY&03CU`s}P@)lQZt!<=wG%`_N%Q{@m`l+1k9CR_e$r8@=h=N565yPd)xL zE-@k?{AV0UZm$*ueCTALQusEdS057IH&S^CYR^BhYRqq|C;pSP#sU2?kNxB#V7ITd zB?DkW<kel_N!7ERg9Zaiz%63|zNwEi-5Rx8zs!B%YQlVF_8pjD*DT`wnt~&d)hYVm zr<_3ic8bV;t<W}ccXXs0k)~Z)+3D@=X{R3@Cf!t+mOCrh3d`MXPT~JCK2W+pKAi<t z?+D))^7A;h3J~{qH;ldAH@K<D@KOuKgJ!({NT=y&t|#it-*js;UQI$3fQ#QZK35B{ zj<o{ok9?ZvwDPfwFI_}f+*Oyn<$Eyg>tOfatpZ*Q%QRiH*z8v8g!z>Bn-lY-smapy zC!~E22jEVH$z?TZoVTF0^>s`X4f0F*jHY6@27&sak*sBhK`iA6QXw~YI>iQe5zT4c z;}8#$09xg)e?L%_yF2nx+t16Psu(U?!K(OtiHQQPC9hO%J2iR+Qh=p_1Q4H}*a`er zdJa&^OKUjNNO(zj-Zs^NE<6wDeJ1c@?$a<y#+=ysojA4culR%^-44v{N>+FhIs9Gv zaD=NC#hSMNJ$pI$J!TR&nLsK*e3WxGUNEZc5gOcP97UT$*5Vx*&5*ZB%inn((>GNp zA@F_4Q<s^9y35yqJw*1twZ3AsuIN=Lh1(N005)a>X+$~Vu~u3)W(NFamY<K;g8mvw z6ooZzW)aAq@%A$;sj1<?1K*b&?+=!#b_Z0RhbXYPn#RF3#_F%zvrUOhYaDAdt<4xF z{Th;a=M;fRG+PiB@usU*-IX=qP`jWl#Rb_Rw&>U%%?@$zV<c(tK6$x{tA4ocQVQ^m zCLIO7*gLz3b$Fv`G1E=Q6SXo}kXtFGY<Imlq#96c_1L30GqsD)1$g{|`~bS4E+D9b zv9eBK>EX^KxdmKldi%dKCAZ!hn=g>@@%0P(UjNKkO*5VsZ`u16s6vf-R+e8XXcCfr zTo4nU_ftE$80-ffklm{Y25&JQM=yK`tWRZZK=>eK$AN=;SVZ5Oy{ODQ>BC*4jJ&nC zh(ay=%_)hZU05TPHrA}pw?)Y|;IgHA%23=G)@ch94p0T$Hx!7`OijK#gE(?%xzqn! z8;cXRtNFsYZC!h@GK-S0^Rv#;mN;)5SNo(Dh!N#e>o0n9tdP&aU@B-5X;W>qnwFny z_w?%o%w9IT&h|FZIAYm`I?qaxKL2=z;`mVl5rR^E?vL*uCJ2|%lf{MYgA19f2W9Th z5h~8z6^xAA4OR0k{=OP})@UN)5bSYBnWMSS_-<OVgQ{*6KOQMhrk?33$W{3n(9ipo zJ$L%tP=h%(SH^%hbKD2a)Gt9;{3Qnxzhi$pq~c{Cr`Ica6EBD9|4_=m8||h31D0Sk za6kGoR56x=B~oSH9kKUET6PinlvgcXyX)m4c+#Z}MBHj293O6{!N_vJL`9wN^^v+) zvQv^`%gC^QqyECquip1_qf)2*leWExA>xF77>~h@co#`kouDJXQ`YZ8HgC4(=qd-W zdp+%8Ff)uHUlxc9An0bA_EJYqFy~2&ky{$j78xJ`kjc9^W4|TRMl_}*{1Q(e0j690 z8&I!dX<)qk`X0wn0#>X#HRDlj`^xUFrmJ5Fx{iyh`}N-HPY%Rj<oPiq08P#fBY!5$ z#26}9;8Z;LTjJ@G5oa|WFT!!g`2HW00rKYsMh=E*X##g10nIBV^-P|2_HtVO3gOZb zGh`=3hMrAlAO*N%y`4$r<+}ZA^bIsVLhkz+H!?&ZMYPNgQHQ+eet}jF4_~Ft2h&h7 zfaM_>+Ya@hpf{Ni%BSn#Unl>0W`jsrCCY}7hCd^I%LqaPWyC%D7qvmM_w;lhG*op} zcj@fo?uM{v#Rc_*JgThPo456<m9v9AQ>4iY|7<Wn2tQ*S7=zAKI=rmBgC>cTqNUkW zq?^LxrM0MGT%0^T3}2-SFoPW(9SQF#9*-lJ9u`xH10DJChCLeBk*<D-i-{XElpgpY zjNyqeVYdp9uvu2hAP}|$S3DD)hjtnxGCj4*7NztWqDItXqgKxF@6l+(uV3uj#Eh*J z1%~pB1L$NqsnJRp7}7KP0f^UsH}m_LU*x`i<-B}QZs;K-b?ZN15%ATdB;iG-Phqg6 z<j&=lcmT!)vFE$bD!$<|6U*>s-i5#xusi*OHz5j|0*h;2lcUh-crB-EXSn7NER*Oj zz80JO9r#VI5NJ-Eg3vl)N%5R)e$htbB?zGh25fHAqwS@&U^(G1?tCESLp)N_wlL*3 z2RFv?QK_YKHi+wNTv$2@W1<xj2i3<WBVnV=!DAXXD{V?Yn>7cT;-v5QJo!ZbzCf^k z7agiJ$+@^7jCx;Esfqi*Vkle*_<ESI<R<8PUnFcNiux=?TuC)dtwxDdnzL+>R|ktU zQUVu{mmglm6IQ9Y@ofKEO^(bGUW%9N3Vrh)LI>0*fAk+E2fR6{Hx}tR7`4^uUFok; z)LQj&^Odnz%v0MqB5b~FY^kBDBrC&Z+uh!dtiGd7FMzcfh@eg|yFwsw*LMWpBZwZ_ znXtC3lylURR`76u%dah-0Zox=W*;3E6PjPp`ADf0%ddA-in#JmQ(ms5khu1Ge?{by zzaL6%4KHU1lTS1Gx>5rV+|?24F?o}UpSDwwAIxgnaRHKg`Q`h9jUCQAbqFtfpwfO$ zeIGTm;$B?Ia?Rbl3dNZ-uN-JP7mU7DFJ(+cs>V}OQ`;$86+er$uyU0QAij;9VpQYz z-%EZj0)kC_bMh}|w3+P`VGFkf+<vd7H%=JfRUfka{nQa{73?}+o6>*C(4bp8sT6Rd z7>|mPB3=({EfN>g)m1?39ko$X!iTM9UTH+g8`aO3<6uzk@rz%ilR0CkC<YbdT5%oz zQZ7raN;yU>N3EMu)$^7&rZ54U<Au&u*iUGFq24?nM`Bb`P_PnXC>+O|?B-<$yl2+& zda%gw=sdzj6*&7kw!cQxVJ1E*D?lbz(=TooQ`3LAeKhk7^I`;IkaVfV{Is$Ty|_6x zfom~%5y3zwsEZ>*2CfMa6sc*FQ+_2Ej84Z0r8}Q0<5C+DS4&Ira<Wln;9f~~U6c@k zIA`kyz-|7Y3y{<jBlW}{yk$sH-Ilyd+T1)huV!vxhILqZ*`5<i#&Bn++}5B-^~1b< z8TKJ3=daU+35<lG?ZUo&E+^GJDVU)VDM}{zfG3AWoJTB)Y{@{8!x)dt<J%Rnz4O0P z4qoWbt0+6;z)9q8Qa0-xT?aBpsN5Vu@(B8I4D04}MQnMMFS%w4?Q)NWi}ktryWx}_ znU8F?NuTlzxBX6wy5C5Rv03AK4o;r_&BvYkTXIc9Yc2NA*Y^W6EBq;AD+(;xe?4iq zY%ywwo{6{QVF`RKBbAi{oG(UV85{uJ7cdytyGBS}uP}=Q&t(oQ+z5<sbs7HPT@G>3 zj^c`cp>grbH=Qtqv!bZ(<Q<(#YFMN>w9qJA2iJHKSZy2uMl}D48hMe%p<=AVXjivg zF7Y>q0S-Wq?wjLs8}-nAm&;l1po3BDwf*)VwO$DnM5M>5`5}m|_NhCaL8URu&`D#N z|53hAO<ez>IYrxq`<*IG17lo)RfjqeqVs`$q~<{K14|ZGjQ|PYM58;ZUDG?ZA5tQw z@Yvbe96^O#)6{j1r)@*)3Jdu)+2WEqCeo@ZkmYHLofb|-mbp>BZ_3T`kOeivx~&zs z@vwWXTe<j$^1IN+FWwH9s9N$#nDYk|bxWM&QkyWTHlV0m)gQL(EUz%xxXG;;=dm{* zuh9pec9SirJG8xAZq>ZJXb)k#GE~#KN0<2SU`fM6<KJm$@Kif<`}HxIfr3Bn&ECz4 zi_i6LSTA<lUCp}t2m*D!XA&FCKZ0cD{gPJS>#Z%IVi#|<6E)9%k5+(5EEj^ANcSUh zG=<Xbf-kLtug|*PhMdNq_B1y`iSWk?mixzYMwmBHrfjkVtg#6~3>B>_-SAxdx3h4E zo;povgBU@=e=AH8qLV@(BE`24TF)`*DnL*~LBxBAqw9@_vHkJ9pIWVr%hO{F<u?x$ zulHwYMjNh@4`B5<X#A#})~Xf`q$Uu=o_{%YQhl~Nvh2KP6R)!OWcT`78Fjv(+--d= z*LLwwg-R=tc!>T6)i3{<l|{+0fxg^YlTIM55&Wj}x|H6>uG!Q$F5+|~>_RMX)m5kW zij{@qpm%n!x7kD5?xv&uz+`p)^h{&c;Bjk8tC$8eP5U)J7bAB!W|u#k<G7#V!BF(U z6>?<R{Mzpl+rE&L*uS#4%e~wl?a?ja;n7V4yJ1vT<W?)6jA@yOt5-gM;_mjRfF>zH zBE<M4J6KKp1ETx8Hj056?Y(mGf^$=A-CRvAHF-H_<VNcH)RQmtsy&oG(XiXJHbz3} zLRzp{Ik7z`OzNJ|wShnx(~j#X{j8WES~th`L~}0aNo@O7j~>bpV}H{zbubwUP-<)A zzQHSVb#o|Rfr5`rMgLX|_aBOhpxaC#6f^ek-o3l0S0$&$`eZLME^+j&v`M7>)Iwvf zxbEZGQ#(~&hV`LitO(}GsHeO!^HY9iAelP;{O`|q&W~cxcd0vyOCFes>1QDz`qB0^ zDLhoYCm(75_KxfhLUJ)9wD3cf;FCUV--?RV!gcfw)6L4cI@Kp4MW)w4yj|bCIiP^S zCX^6hT-nZD?@_nBzA=A#bf{5%LHs9MbB5pQo~aaN>VWU#EOvSt-#*Kc9H=SD4b?z$ z?EYLXd{O-Yq91D0(Py$q-?T>GJ+}dxxWl79r~$E1;I#`13cBZBN|N)$8Y!Re=VB}9 zP3=`rZqA>dy6-Js<TK;mS*zH~K(f;|J@xswU*vNriH;l~tbT9Kt5Y$+8E0A@vr?EM z%KZcTD(e2()c*+PjRn@|_mgw_A64JB73W5Bo>Ozhy)F84E5)qJyN4t_=tQo9H#_=O zWtQD1B)=6^8MjW~7)Xr^jcI4?ffrc+5LqoT6_MoR>>ZC*?p`TSQEO!OXge{On=Vmv z*_XRM+A%=H8*rYek2VH~ZqAd9O6>LK)MI0if%05oL9)Bg|0a+1`n3>AT+{E3QTM+g zw+ev+Y3%#_<&7PUQz{~=W3^6(YkWZftbz(c|AEavO%S75-Xi^v2@s$1E3zE=Krfx{ zZ$M}!t06$M>=up$m_*|%?ms$7ic6CfDfayKEwxSi?zrYTXzg`Qp*xGn8;wYy|C&ob zaA5Q#;B?J`<s+?HpQE4rKR?pKjyJ3`>rdL+Z*ce=hHZosCadYES`=W9*dG;W1l# zA*>#C%?BHRla<rc#J5vh1`o~nMhL7&WCmr30*g}hM&qP&^$@`?o_}$kzl>AYv>zTH zii`#0No}7}n|bDu**@787kyKm0)@anua3U`ff{vF+asRCql(u4PX$6CDUnI71e&&F zvgoc%<80{8pPdHNt-g7Qwgmh<?{30LLC6krI=)M;?K%`9s+?5CO=bVi19(q)F8*pd zk;cQL_h1|i-CN*ytw1&e9I7Mk5f57xH|WoF!lna#y*msA5!U$04!y*MUT*BxPKVrF zHOz>hAQhm3g>1n;5gkuzu2<v+>zA(*trbrRwntm_%K+|nI*tP81DpI{w)|th(1Qba z#uZKJ*&V4TtX{h@&4MFcJn^aND2sAXqu=w;a|6+&_I3tX`<Y1HztDiR-x~6~TRkkq zhsh$K#xixw|AIWaiF#z$D=p)}mD7Lmz-pV#ZcEuZy8???US-W!G|fdqAYopP?pDBx z|5lgjQQktLN50N-LH><B<lSexn`q#{Wd1H_b;WYDGTqs4-}8Vc<Y!l~03H*<@0#l= zFUcWVTB>$m&`2a5rOc{ktu`UDDio(E!(JiO!%zHu86}gNZ?5uFJ=&Q(wtt{57Qvjd z3kkCx?R00OT@5!~wbOfgb|=HIWhZ+^n)WmCdmyRZ%Y)jtHet$sLq)8~pA1CIP=*z1 zt=94CR4ZE&ZL#jAv1|Vlr{9~PyaLg=!P-i^9DK$x6TB)a^dTAd(bU<Qw0}Wzfck0% zuYM;1xcIr3AagFJc4d!*b&hN~MeW%Hx#MBcB(AY6#kO;xm}Pa5smmy+v>*PaHtoJ9 zCW2`j1Nayyv(jNer46he7hgU*89}vsuiRxC#U^{Shq1Ooh27guLXWt@IFkR-@CMp+ z7XXMkJ`oNnHLX%BkWRR;nNQwrVB|oyHvDl>bGa02YY1XQ`tcEjP}PUvxwe@YJT{EM z=4PLtP}04&Fzk;{Y|U~Kpmf0Bil<b_0$<m<sAe0=<Kpg`IqC|>(+7?`{LnNKX{pes zu9S2J7ae=5Ok~4)13eO+oba{8sgk-*7#@6vCNy%dJhA~i{s2ugB8^@!IvaAKWOQ0$ zzs166*fun$+xReEN8}26eDCYGBiTq+?~cmg$0rt&%DmF~2<j`vvxG?da|8lq?wXJ? zG@w2t-3Q*`T6~oYPI>BS{uvbHEvm2s-d6T!Hb<alxAJt1U5BTep?vOE@48_&3-P;h z$^A_SJM&d5F7@195zf#X3?7P@L^a>Mp9_&rT0z5>+uK9AfU@rD$NQndSCcS<2^ptX zd8Io?oHR9Y0-y6|H+<P<cm5?P@@Q(#IjWM=1aJl;A*8#8JmP6%@x&3o`lqBqkEuO0 zyhyREiFh?;3?Y1>bnL|Y>z$cTAkG~$i5V@q*0!X-!bqgOqm|o^A+)94yOxvwg;0#B zG#z-!K{id=F=)At=@#xwW20%6k=<)>5`BAjNO}LbqoQypq5s~z+$PP+-wWkL%c;78 znYo14c|R((yJBX%f(38g+|`R9v6%|tM#t#PNi6<HtV5W*3e!@zIKwz*SN5Q#R5f}) zracFPNDG=59`vexW!$+j(A1>7<0nc~_~9nOb8b!tXXq1qLq>p6>h9I)d9!n>$3hHJ zOS$cA8?3mVY;Rw{US!Bu=jXTbC$WMxk$R;gR6>x9W~JPtEq<lo%K!4ng;V1>VYlma zGdfgyHgWxW-#7Ri?ZGSI2;ILlR}3TYvje9JEac~BJx_&{&bp8>^EuV^260}Fet*+- z1yfhesq&SRzJ>7B4Z&G8<k_bdVp@kyjV+OH(|LQzM(kd<eBhQh?u?=rBI&p_y5WPN zg%>~){hR>{ExynFW{=mokL~5S)WdRnx+KE5vD~`Le-pPxMOLdvT{RjFV`B^y&&L4= zJrUM!?>*E7z`Mgv7e6Gu@0$Sw{|N=I4o}Yu_3f`ek*REFYbJiD^lbIdT9y^(WE3z@ zE%dLVrw$Mxg0qIc1QHttYE@DJ0V@QfbG@nN<V-QK9TGy#FC+{KM|#S!cEcmw8GCGl zZ@zKBzi~v5kVy)&8$5iTFmmlLkq2h4w&d<<9chcfSJTNZG%&9kK3A{=j=CV0_ZI_> z&I^PHMoZ~`<#sPOhWrhE?5d37_mnR7{Qae4NH&e;?(V+3%i0p)+_0af&E_jU5#VI2 zV!n+CCJ+g|zZ&g$3hh43l}&gl?}^u{;0FsZWS%w3A&sIrhQj*4MFh6uQWLyIq%(~- z=1RSF8N2@c`J)5KK1*EYL~G-`z%`nP=)P3n%AOtBI^HIl<=LxHMBl|h4-0Jh!WrJ+ zN6aH}yzDs@CF;U8E$l(FJ0%D~N!A3E^}zD3nN82h1xR``VD9FK=3qxfIqn+^nO<J+ z7vtpf^(UbXCyt79*yO6VCXRr2vhLe%>ID`_3T}E}Zq4~$9zF|4kP;oOFrr+yUxuK8 zND^#v{$JVlw^x(f*4NFILIL#g!F`pKs(!gw>1uJW)^*Bx(B54|No~jl6H8$g9U<ZO z_(6*V@1x_kFoQkKYg%+k;Ae4iHS3&g8nH3*EMs_1@N>L%wTfQovqPuVy1}4h*e<{@ z7xmtV^G#fTipEej-%on=vj>OnO7%|}D7A_Xo@l6X61&E`*a|QpP6!lqV&S%yyfW^Q z4=OSyHoyHrdMg_R8V5TC5t#{Ol9>)rpNYhhpDV+&+<nc!^yzI#JS>c0yZvlSQf{}m z-~tPhQA)ai?e&JX(e0SZ-<zS#q#WqzPVo}Mgs_F{ZSXcLN_~A(dcd3Enzr4$E2WYD zjov8gzD5Q6#pacq68~+JJqfPZ+|)?sqdbIVQ4>N?kSd9DW9x}0_8zbhVe{vP74lkW zA9a?*;q{f@QrNBK{=+M(*pZq<`rD+B>~O-v>t#*~viu2jVMEnY2eotALqHX|2yqb* zzuW_0^M(Ry-W~Mf@aA+~h`5)H6IPaF^Lxx_?iqOOc5~GG6>!qcufV75MIO)REh%{Z z6_|yN0fb_dBGQxy%dcN-%?vZ#dGocvJ^9)a$yRom^6C}!gLHQvcjx|dgXBN%qINf1 z{u9YU8GI<^1Y7IwrLK#EtLrECt^iQEZyG_hOa?B!7u=zYK}hu<IY?G6&K}rFzD7YU zT`M}dAP3ZPwQGHp|2+A8SaxNn9vjbrG~o12wtJ%B@(I#>b$Gf@3?x6HgkbKFLlABX z8-L>A-u7Ria{yz2nxDdBQG$VD*hKQY<rM1KYGbZfd2d0C+|@2Q^>*+OS&HSV=RH;3 zW4EMaJ&G;#Z-i5M$o<jBsQ&nMu4B}nw;;*w-iT;D`<1`LB^iYNc*E||tJ9-q>z2dX z_Skn7n~aCz;8!>R%+*sd#-f?-m@v>NN>Gfu^a1pJVWBG$#wIaXgGm}YkikmWv(<g! zvL`joqG6q&GBF3n%W0MO^|A%VaitZ+TU^vi8FMVB>}tXo(_1)3;sduKv#|r$hyGsv ztgXa4^BV4MEYj64f}Ean)hKPDYbIu^=X-regSqFMnpGTE2mHMk*gj{QU<PyfWOq{q zzPV*iR#F&PQ|?$FmNjobXk@f&g+)F9mKojO>=2|ygBGm*EQs2Cz+b2Mhk=79tct@9 z9_%CjI^!3J;s6cfWK?I`GV3aw;?Pkl1=`6Zwp!57$FpI<*;)a9oTs$iqh7?G{zv^N zDZd+zj$l1WDv)LE*&*sJl>G6gEg>PYM5$HJ{;Aw1vDRpujngXS+!^*uXr5pHcdz>R zIvN@h1pKD}_xDmvaxJ1Cu4rxe*Sq6?kvPnnd;$Iaut&XsSwoMjr*>D)0$Cwc;O|)p zKtnfMjLawF!=i5u^wrXd61mO!_l4AJADM=tuz&z3{G8+oKb2V{fFq7kZ>e!n6)c1E z!Luj!Qt_$}>mY%vA(0x@OBy|O2wKLyyS4$0PZts4XEdNkM{IZd_<4I>NF#ZgE%J(U z6S^wh275*#!x$<{V`JdQtL4I;OJ}L<UlQyGbA0jr9!?87p{2zo=OJl9dSzMF90)@u zc!wpi(~lcZdjIobbA@5>g|EaQ$8dkp$nv5;<M2rs+nxz`A0YpEf^`+ku$M53(V*P4 zVBB2;YMkUHV5gX+=J7PaqMXaXqgO*YMA<JVomE$Bv^0YcD4-2Y_~c+sxc!RpC{;1N zbxq(RvZG%!g`uDeGb(<3G4Slo<a3YwXll{-Tdex7-3;8?{zh8%c|jbU_*cANB^Vr8 zk|+QHk6P9v<4*lYPgI4zkng6X4XpYFZf+emA2u6gTVS$Jtui`%H4UsBGA?~c1+}ES z#(G>b?f;-jH!+FRq34QiK?EzsX>ri|vBVV>0Y3{mgR-7x<+Eo0i*wTn4h{nez2!I3 z39Ki}GaUxTLB!i8{R*r^LDr0^Grjg{m8*rpQxq8!USvtznh#+!pRKe-P_*3Tw-)KU zw(I0VKc}cNE0}-Q$YUAZgB7%#skGD|3bpyqCGWugR*#B-7$c?w@Mvg-Ow3A``wt>^ z1rr_pTcTElP1f?}vlw<t*jq^CCRof}zL9M@*;Q{15cQMcz4z0VDmi&&U|caND8N{B zvSg}^$S^4|P7=z{l4M6ptFt4Ktj}+F^0s$+u`RVs@Bx<-5#@l8a!69}zF6LB&_Vr_ zWvZU~=uAoP33fh_yKJi9Zy4uA7u0PbR7&REq?A6b?<36@CY`+-a(7NB8`gz|gA`*% zzi^CjDJDTnnUP38&iNe>o%w`<M^7L3F381;^JFiSz3cBy0<ym#W757}K7s6{J$^oU zA!&Zt$Yn!L-fZ4lc5rnID#zaQ=il)3rd!{^8(<j?^>PQ?84BU*IV4Nwd*=aiF5s&0 zJ52Z?y~jC{m=8RNp1ysIQG^LVv1DIaBW+q~-Q|(AG=R}9KYIjAYO-F2lDdFJjwRHa zIIalU(==w6wJ&Fr^jAtUq^myur?+y|s>Qg%%RX$#SYU{Q8xRwpn)3>yAEZ>R{3jg< z%DHOsm@q&DhxU50VbcjqP>Idi#J6`2!3%8ZjpPD6$&vH+svt&6A8~26)g#48#otK8 zmE3cHnaV$JRtc7MF9zAKwqn5+6@RGI(%L3qrJngQZ=RlC5susH2Qw^yGx?h)I;W5| z8`M)Z$0w!BV;jP5l{0bc3-Ns`UK8pX2R&x3(<Ptn_K#E&U<#u%ZW=dd<LiIeB{5nC z0~ZG3>AV~d>=3Kfv+f!OoNA4x@w^ht8#Kz@$F02Q5sDTb6ZQq8F}$AubLDRISJo1! zv4k9t`J^39F8B%niqF|w#w%aQZA!l5=yB;$(d!+c`&`4)4qRFl`I1%jB+P*N(X`cl zrqLZg=LVuPkEhvvlM$a{-!*w#6hSyYF-{I!)EWEW{mZ}MT_Z?f5oc85?+N3GeJ`+N zV|?QB%Ur`IH`yH3wmZ=&nsG(H>*xa>MQ2D7p$G+*LAnygeqoWN72#`Xd1*q=xvUqV zg}lI%(py93s6Xd~Vt1}6Yda<Fd(VMA(KzBDHg4nqD&gLG?6e(vA(y99^LBeK#`WeA zSLg+3ZoZ^@6e>}fu9fNt7b5Vw9tS$iIIvF#&aY$|*S^L2ODxDWvC!<!Cu*!}{eWTP zdYynz6DnGbin?E@`~8wXs5bP-?)&(a3TdxK;rzudH<`w$z$j^MvUF^9(bkW`He-6l zF~!c*b%v?$Dp#G(Qs*(0l-8ZiO!gD|A-~&M|MQ<0AG9%wAM}~w(dqX!IkkbK$wNxW z*T1TtA~`ck=+-*%;?bhN6e7y^l=dHNdeNS{x8;;Vs`@HUlw+0`WDm~vZl1^SqS{Vu z-Ja<oYF#-h-pXtmFa~gP{#*H5VOfp6db%5WuK8mYIo*0?yKQV=+<)j;s1rkxdUT~i zrQhZe0pf&-O0vObtJ#*dol3vsrtNpN<O6ODj{@gesnt^*R~!EAHbYx4bg62@%9{6j z$Yl4rxs`8}4_+2=uKx844&G7U-r4Et>N{D+IOq5NOum*}5OXvTxi>1>$~Gk{%Zn}P z{_>LrY4NOV3Y#>@ea)D!JX{dt)N(OiZ;yVSR3*3~v<ltizesfq_~Ew@3lqWiwO-it zm?fIF)LX`nzGa=+S4$NiA_x()rPra~kD&my_o538$EKViP{8%kKtzmC&oL~NnY%UY zF-lH2mpYl++0T#`n9J)3%)9CK3z!fs%1r2^>p~y&;79mebD$RmC-!KC1m^++hgCzJ zB<|jVK68W}{p#9r!-9Cv^+~j3<y-=dQX7{|=s9REXgb!foGo!&wG#V0NwbavKKi70 zh1U<5L)<fOcjuC3Wr^i}zEZ3rA;uM;biEN&J?{Q1molRhtvuGKPrsb$&64^XLwU~( z%iTSH7hySEBPN4DQ04a`N2m*k!S9{N`#y)X9{%L@?fC?xhTifPK%@HbAcro(9Z|oK zM1$q*mc@p0**x??8O|oroVcr%FT@bm^`Q81boE8Y$cnlEaek!HJ;3h@nMvRXvV{8F z44vX!o^2ivpPruQIRE>2+D5I{yD`*yxUEP%80yV(|Ldc<)n!-`gdD|AzWS)IkLORE zX6}zvzL$=Vd*zu$axb?|0&W960H5+X@X(a<6j$mLJdu&KCuKigVk`oxos82eiitkq z>Mb0Lv#iG^4;wNUXykW?&4qDwo%bDF16LZn_u@~h$R<nN=M(aYnIdR*^>poE>R{Lu zAmgFKo1?>9^}cs_%M!Xjj6CgH@sd{9>&9aL#s_=S&hW=~c(P7fOVlVPyG<lt;geB0 zCI$U*({0rZAejUM8F}~}{V@ns=Mq0L@i7tN#YWD9V!Z_j*d1vh$BEOXU1f0x)IOcm z!QFjb{Rbc-lFga;^6hgLqF@(C)9A`}HX?o^K09Pq>kmt+0c`2?K2*ZIev*tIRIYTD z(ZLOuJ`ZpUP9W+$Ctd$1<V0wPaA#}h)k0Auf8_((YKNk}d_F+W*X4HW9{$2!|Euru z2tCX>oeH~}YVgKmsHy`*HYi$V<81;-U_$9b2AO{vlnQ&}BO7r6P~Q5$^RIf!>c%3g zZ|f~n@uUv8bK=l@F^e`|bh|o15cMTjMk2!dA;L{6;E$R*OCpmpkD@q_4jD!yC&*QC z2B4_*kZ~~m{EpF6Wj!>Ka`W{sPoqlCRKfd1G&Jz65kVxm5C69uT>bS?v;v@MJ$G)S zdE><Uq8vjiFU{XYr&P43!Sra*wdqfTcoXwi$tAx=Bk;M8`}BJQ)PI-;8wb_r(^h^U zh8e+;+I2r0PXUw<s-*{|7krC!k0{T~+L$K7_P>sXimH&oIe$C4yn8T>^kl8-LgepX zx;S@2Afw$3WU6m6_YHSe@6sB_q2!`gZ+mq;UIukjO#Bq$9TGGUH!B`XJP#Rml3GT1 z8!<|Rm+$7D-di!+m>(d*hJMRAWs?@tL?CB*qObM)d$kJY>YL;F^|oW#g9E?E_qq%m zX7~v${sy-^+|(%i@FenHq~xPKx6>(>sS2xw!0@s`9o2J^HJ0k1lUZ4uhHsY~(xzf! z2o!g<VU<ECNNKObz8IJC!yZfSVA=}TU(zhau*yk=$D1`-NY*3S?Onsh`0Eed4l=&e ztfNRTn<0{>Tfs(FH$rjbe3@$jT*!(FxHmNLFJrVIT=Rb(PSQDmTPkPeU0p&h0nnf9 zJ5Ex9=3JAm^1R?Yt48CvfzptkpZZThOzJAkjv4}1+YqTF&yGsbwvE;(UVXepyCubA z$*ndOE2z%R8qn|Pn&4s_z3ipjtLfz+4Gp+`@lG%OoAl_YGd?nFu<RVj^ZPK;oE05h z&7(OpN7{Ex7dcwZgJ<9<`;@L#)L*-8oOh<?xg5nGc&3ISn)RS!jC@bl{{<R|#Fc8z zZ2u5LVfT<)#rc9492}`UGc0<U*!h!vsI9F0lekd=odPWUi|`5js(}_V&~gn<dhqoG z7qI?oi;B`(AjpGA&=vb>N{zzLyUCyj>iB4gQu2QMQR%1qo=Et_QBKg?=@k2?n9FES z;b-9k1&(c<&u+VdPa{7|TA$JE&9#KMM!p-ADSSY_IRq3?OT@rWK@f7xLttB2%#$#$ zAs1i>^V+ZoNmle0*gJ~EfKwsk{IJ~SO5}PY|5`Zoq#29Uaheuz=qw@Yk31yZIR7#3 z!=7@~M2*ZPR}!3gTK_R|%}PX0hGs@v36@X5*;d`tiO5<Qh=KA@Z)2u=>Zwuc;-4 zXCmIDB3y!n^z296?<ZgZ|7l@7QD|B>#Sq#vm_Beu912lUSPcZb-p(s#hB)+63*Ncg zNUc-0J`tE=SHx=>w_WUzMN|hJHcP%q3B&CRXIK~R7!6t?Sd42>i+GWjRCx+U=lSL2 zbQbEWiog=DMcfI|^@|NX;0@YkY<@mh^hH$=w3hMSsxAkgrp*&lb*G5qYR2V9d2DhQ z-K&4-v_}AFAkyBE`TOPeHW&QEpp_v1gjxAdHW$~n%38r)ruvxLAZd1_-)%I0H!6JG zymZFU%}sh`_~wAdK$uCAHOVP0K>XzJ!A=q$T?hzZY_WH3`JF+(xfE0#?pFBh|G5A} z1;3NR24ta+<R>J_9D^-|9RK?{TMerX9(%6T3a{BYnnRtw@qTeTt*TU#Pk4rHQc^k* zS9OW0CO_QW7t8pXX|?&bIX!X;PZ$-?R-JTxmYvp_93wWRlmc%zTK^LF@CA`H;q}5~ z(haV+h%}D&6`2bC3weZ1tt&_&0q#|{fSSEKw_~ICB$gS&y>_(zG*V6Q{Eno!$R^ok zG(rJvw2yT|V5%inNF&%MMH88)zB2uw<;JBSgYbY=(a0skS1M;T2j@p*grc1Bq8W)$ zWyfyE=0OC&OL3h4kcmoSLf(0GZXh*Pna2)PH;P19kslMS=zD~9A2R}2yG-tSX>Ceo z?+bf9WOOFq0ups8A3Z2laf)V4qasgzohjzgHNrV_7@$3`p19DcB2Mb5#6L~scK<Qm zx!a&ezr+~!XMNm2BZjGdwl>A!D=ywteweV@<7O&E#$y*%<|JZ#c~YLT)M&f%fq{($ z`UnEo^;ioHuk*Gj%6{prJvJ5@5ooPwmOUf?6tdlQH;umU+a`tZBQ7kG^A45CKn&B- zPDP;qH;9!}k|&v<_?#~4fLG%+zl7+m@09EN!hZT8P#PNG&+e?u-v+;9p?XvST*P~w z8Et*LKNL^A32s?Oif~agebjlqihF&x`1=4+(4DIJ_`(5}jYSUpkf7o3oj5q18+tKG ztvXIVR6wmz#NoT!kP^qh(fQBEeNBMcCmgb?F(*6l9x(}a`F&Wsb!BvFu9pqT9+iD> zl$|<)6j8wiqzLs>3-0AgKqp@VL72%OI$-d~r+qWRALH(gcJv@m1PkRq_j+K&SC%|% zMxo?J+Iu0gy|F1!9%#y#c3y^%KDYIP3B(+b{nXGYV_!H=R8{53n%|!=_vEAFNA0ke zjuk}S&4}J<LN}uJg`h`b&JXi9=mu(qDM;qGk<GNPVkFLuCKCKH6ji)lA8@7%&PX0? z`Jz{;Ta2)+11t+?Ayb4a_eE3WdkK-B$o%FW%^0d{`wzoX(R5zqL10e!6h+GdsX2wo z!?6E>h059OAd5MFqkA9h5Xjo>`{bX_y<FjCU`+kOp0^vB7xD622n?Rr3|o-jN&7;> zQek-85Y{>M$a91ew*5QfT)cr1r(Xy~auAFIDiPm+VKMTzyk+sG0elF!%sdaXLgb%u zKR3H^?hW4s+g?xXc%KVHPCCZhkzsaq(P}ciEm!|FzHzg*d68z|UtT`#pS2iT?6~Ue z24rJSNFvi<<cD{cT(Lh-*otfWubuUBL%evD1L5{Zz1seW^qqCl)>l3UH1p;XyE9)- z1ghI;6&sy<S1IuaYPi=k$1I%TlN=K4=>VM2G~FUWNkJ0(crhL(r!;Z&Ns*R5LmrvA zvuo<yi`nKX4+{14^mMvtVR<TE_ySVMK!;QtNNoXt_-hU9<OC#Mg$vV^laTj?Ax0ff zBBH=WhFPiHIy;MW2)?4tjsv^6SDBp#O%tLL^anrB*;HMFyPDjH?q{IF_rzMmS9@b` zTt-}Xxch^`rWWJcWBTz%`!NuGG37(gY;_k`Ek1fvbm1V(qVVXL;&DNjx+O@2*! zQxwVPCyZbwP7<|#UXxGc5j<kO6nWHB{M{N+^dSCR+^g5f!}wQ&|3Gi}RmRK=5g#*s z1+8$~qud8q0ph}FEg><00@bayjaiDaQUUjELSwtZZLMd(fyEl~ajBzL6EVV3DE|k; z8l(KE7MWfine^9p2lIc|wH?Nfi;?Q7J~PBYn6-{>yNREwYGdbdhBYllIH|PP+bOD@ z&wMM7JP>8D(|TFc%c~GT)@7<}dc*W@N(UC2QKW%N6~1y;f<awI31XM2D_}FHW56DU z#DnA9=6){k3(qU>R(s0{z*WHlq^WC_jH<a=+dv+xL?#cd(uS`Reo$H_c5&T`%(X(- zbBo>eC6f1fqC^h8;+t_xc@hqZwx#FkvjHD>#=XH1xvOK6tP)E6oB@RYXGUCrhe$nc z3pe0(LN74R79I147>>H~@t<@71ay{B124xRhfD{On}2rHteBlU!MlkeGO0)~AQEOY zJmx}*++dV)YB2h>74l&*=xvPgtFkPLrXmqPBF<1e__^a)z4LJELHhS%C244;7L|0h z?T6nZ4EPdkUu62e(4h6;Vq44Jw&2d1jz${GXmxP#qoi3UyDl=VhC8xThP=}z@}~hM zZeOX($n^I9ODq3xa1w2x^xn=S&v55a0*EM42J}TIJ^tg2zWmZ)WQ^fy`wUm4zsmhE zNRa}QJ0pr>Gh_liedLY6FJAWxxf}}ATy9UKoD{}iM6WRg5ciknL-{A1!}Mw0q~4{a zBxr;Cv{e5NnVmKvbek#-Bwrl^!?3*IlIWNBeZ|*tNl8h?bxeIxAU^20IH@Jk)8f0L zo}9VPK6ndHVZxIep2+5B<H&K(jPT-B+2;^ONP2%jDj-Hr>nfHyujdwra19ZUZTG$m z5krvk81lSSLMi-rG>Q9fUkTbY9F<KZA6_f{gop3n@q5MOOirhusF<s{OOY=UXLsLw z$yzjz5+5K`N)Y(j{mn?hbokCQlLqA&(jU8gl*WXy;4TG<ougw$q^%)QKVJ;}1%Dr6 z4P~0M*)UJ7dX-1Mly}q<9`0}0SE%D02O%4r33@rgB70FO3*J;rIumDl&Z5Wai+}Y7 z_O|uqm*-@^8+i#T*rBB@B002ijNj}mnIL(lbmnqy=d~=y^e6*PDK_(iZW|N8jtO%j zV4@ZYvcbr@$%}EDYKq;uB0{Nz#jzC>H()qwGGcWtByjrD#At!7Goxg4ld|g=8~<{f zzU#cUy<J&K-Y2j8E!mt@7Ye>F0#-Rb%$_sU`M~gyxuMD1E%!G|v-C5L%LQWsX-oJ4 zVQ=tEcy?!42Ruc32i!yAp|AngJ#?BHavD<$7Xco23)gUT*@(2{w2?E=C_V9mA7wMZ zea$Bw7j27cSnk})P%ZXMS>W*{r)?iHC%AdvGu7CxcI(4x*gX}9DQ)OnR*g2H5U}<2 zL2a+m!mWu)9ra1DKfe1@96;o0EDv5<Ga6|k<LFO8xBPnM{{RO;_`a)lc6W4GsYT8X z2st`0)bwITUQo}DusRar30q@gqNxNEG6qk|FSBEzVuIaWI&e-cIB`)Yj82M0BY9_j zk(D@*lcPe0vXw5En(F2d6VD`+(=Ot!HPZKqk8fP|u`_K$s0W)13?SZJX4g*yP@M(& z6LMsDZU`+SCY=OOcIN!flHBW3v?-+>LWBqbVu0WzjfH{35!eZ%zy+tIY<!T^t>>;g zrSHb#fKyJ{j>}64=Vb76^(u!?QM`l`AKzWzlS0CYNB||@(HHm<2BY8OusQD%IxmdK z0T$3aS1NS$d6jf=X9k}oxft{}EMnOWcdn+o&*adsgUY0fusu#hSm3%sWU6@}f51XV zcz*KASZK_%En&d=?k)nsE#<DVs54Kv=nIjK><r|PlHU%WVu9?<OcKVq--ldF=0lvW zD~39UhB2H{_blSbwMb37bS~uUxgvsaFRGR)nRgy6C%i7OF;7KNMId9gzB`*j@}=bD zoe|&w*MUXh*4EY;aS~3eI-Sl;Y?(<|ZK6ZMJE5$U5a!}%!l%^eB%(y;#%<#}vzT9S zYC5lYXEN^JjmdqAc0i>tr)22;_55TzJsURc1eNtQ0c^5!`cCO-SIlMJ%;`9rmz2_H z5vOxSPM&f*-f>O}8KWr@F?Y`ll`DL_$SR(WfJ8(UA}NVseE<bN$1$cjGSzBzh6AIq zw7P_jgY?75(W@@H!=rqB$PpJi3WVXXBjKuJDKZ+nzp{<X3(|@DRD#niF2i~ulu$h* zXPP3cyVkhx1EEx`l5tJ}RF#v%!%ny_BlUeE9Nqe!7m~i2kWQsmPd|H#2jUPRCQU4& zd@QYt?C;OuO9&5bqX5BVmrjy*M#TW9S%m12%un8#&V&jzmrv%MViD;Y@Z8Jba;Q94 zsl5$!f=nzNd+b|(Q(ZzfP8{k%I3_z~44$;Df;#UMZOek3*k(d}$eofsXj=v_+K$1M zjT5RzrKDih;iQm(lPFmTIai@%%3SibOgNbok+4oK1Pf4yxv)d4={XBr=g6?}q5_yu z5Ecu1ok}@uI?cmv^K}>4V6fv9(Itc(9;HHt&=TKHPc8%($T6vMyuEBgZWPs}xc7m{ zJf{x67t6VxRIehek0KNF2VCAqkqJ)f+~2Txcm9z##K@5$-k-%ir&%r@qKOI#?VO%- ze-VFP{!@jF7dp=6)VbhPVctSb-Z^hdrE&n}Ixae+h8)#G=h@ErMdB;E<hhDCk3))M zi<Ul;SLW(bzJh_x19tU2*{5%(FP5MVi#RTYB>bDAHTpizf1VXDDbMWx;j(mZRuVeT zbKy#VIyah(`IJ-s#wR+=ugIyBujRr{azRsfhN2YQA?RovUy;B#!iJk{t?%xFJ#1F8 zvBHUsY{w}i`O)OfJ95CKqjeU%naL?A_dD|a^@nkc6R;{TB|G0bP#hc65s(DQ%9CA0 zCxoe6BL^ubH!ry9BGMqfN5*y1T?bu7k-B&sy$V0e4Wk@83#O7Hbg^^p-5#pd@bBU} z5NFBGduqcv$+rq_uI9ptj1!N&5YgZ1;HkPnxB)S!J3Bkm;#S>ZT|~k9_{ZT-gkKTL zp}$j2CM6=l4x|zzeHUWV$sb||Q;8}`kUln^r*l3lNggxFILWp8E}TN@{k_x0q|2qP zN$Tdr#|i7H#6kryiy*-fJYh^F4osSakL8`>BrLV3#^DZZ9{An{es}T#C?%be{pOAx zAGvd5vc8|Iy)gK(aWMp$pW-4eckT+1<Y_o>Oz-8kVM0k2L&wC^UwKl-4y1Gbe9}f3 z@jSIXo*SJj`T#0($ydu>Iyc;{MBAqJI`Fx=IEmsA1H1gBiUm$k9H!!gbz;`pd1nWc z6BzOl*|ef<83ze(^4&~SP;y_)bK#;g^cN{9dxxG8%1Yl!?v?vu-%}$#0AY9JYAP1Z z+asf?0U<yX7jaIXb6|8QHDOR3B6N#tl=|+3hOv1_8Gnc6)oQia-``I{2HoHIUM${e zP8D3))E6TvPHC#Z;$BTDCDWAUcCtQq$;~V?$M52~(w-S|nKa=|#UZYj@aeSv5UoR5 zZ<6_asUsW5UIcRWhENx3G^K3gf<8p<u!xhtAXJN-JozKHjqf_)xpgQkCv7h1L+Cym zevF%Jr24{eof|g631JrW&Kn<W%y`p>uPe@xW5b3Vr_(OaOgaf0y}Uz2+svaau*u{o zE-wOIia$A-(TAdP1ywwJOvDF9a;`&!7`%NeunrqL7GBj;p^BX{1yVh1mpk<UL77P% zRyh}!t@LD^hrL>@#{T~P3<lLPq{KNAmn~aRhEDG<2dAWq2`k5!+@$Th2V@(nImrPM zuAo4tZjR#^x$RlcRY|Fwpqz3F2kG0OQ}3_m=hD*(zT}~hgf5v~cAq(RW;cilEl2Xi zm$GxtX_b?6oqMIgPws>|pt8T8D|Wt#5oM9dWSx*i!Jk;rQ#FknlL<+rG&PHV-6{RN z0)U9RDuh%NbDHD{qc1uo!BqZ(&(&3gxVy>y5tDh@U5Sg2rS;hz)1D%2vxDmVAQpix zgrMNTBGGZ#E+OnBOfJxsbhIxnbh5w8c5~`^cz8HdAnRP}bwXJQM_~7vv490GVKnSQ za!ShJ$Idt>DpUb-;S`^!D8Z9$<*U4*M)EA-nuILMU+CxkyF0;D!IjMm{yuFfcNHNe z4h-JvF1r*gJM+GKiT*+jG1-6xw5vY}_C{U?cfIMmF?pA-mcQZhKkXD_H<~ctEX$@4 zY6|{P#&uTGygZ|<<wam>hmI=+vbo6S0rL+wUYJkFAL(@#GCCJb=4Cs+Kbr%D!Eh2t zseBfdo12@{?@LZ0zdPfUFNGA;mPKM}`7!rWIicM}B*-61@t+BuXL0Yl;A9*52#F=> z9JuYh$Q0C-YJ7wY3XS6nda1(bDu^t?i0V)wLmsS(E*0l&9_X{nf3parzaamJaZ!{D z!iafp#34@YZki{S#N3Wz11xZ5J4Ys@COQ;Da&D6gs}POD39f9zKir|?1#r1sj!vgD zb0?HndtU6mmXwXDXaob06HI-#K`H?G2#h0rs!KVhodJxvZQo5W9*@ru+FeVWl_@un zvKzz%Qci%<jZE+y9>osnJW>*IlvF%PCF_)(ESJkuAq9uY5R=ZaGbMx_dn_o3;~agn ztiFq@ThYO?NObrUlWle&2!mlVo?7@M2hR%I&lO>F44%4(lqaNvr(y~hopGe!Xf$S= zqzWAdPfoK4TceYa(@nvvyi=th?l2YxXBU~EzCOE8gz)Ix=ygIKl^DAGAu;Xjpt4Bh z#D~oVU;4;NnJfK~Lqlw?t3%Q0F(Kp*9>SMcP%9y27cV8ROu2Z+9=nPVc^>2=sE}d8 z%8kmL;F1qOsEEUKSwy&8sqadmFZST5B8|-qCRHq?{JHA6t4QOd&ll9Ot4V+4lRk%@ zQA|MojLm@5w2UNbz0Sbyift|`!z7LcFqiYCxK(_eus$VFvMrkn>K^MeyM%E{3O2Rx zgHRCtKK{HCJ{EDlSBg*!U!lOHEd{%C)P*=a6s1v-sAeRmr1EF7jT4W(`>UU4jMkl1 zGVlA)JdTmn?FBSZ8-C{~D#KlFES%gnEP$2lbE@jQTBdtu!0qzAS(GfNKhfFXol~5X zZFFaK=6zDA27>O4CLElida_KVLQaS{p=BY%hFS_9<$Oc89ieAzJUf4yzu%W$vtdW| zPI9-XzR5`;$^KO8^Bp@b4nl6Y{267tDVmkyV)9Osc0j^A&z<~<kWM}&B~619V#4a^ zkH~c->VvR6LZ}JR_T5dK$aFfLGl&*W!wD($0-0P-<xE`EDrxE@%#59QCmz!YIfsV9 zQ^Cvk)KDUi!Hrx8eJKW4R@Ef9>gSy(NYXVEQg-HD3f7@#?2M;4Hhh1_NjkaK^|Za4 zM9e#rD%!>+J4u436LYAC3mvFXA;~g@4W{x<N}bB3X8HLXlTJkys<rTS{yrxARI-s` z2bZRD$Bq}kDY6<d?J9)$*$F-KBF&Y%G?tzxvrA~1E~Y0%E;7N3%qgZEmrp6#+1H)n zZUM)f6FMet6}vHxpXHq+L6rN2bcWgKqC7LFQS={<za@u-gm|7CcBTkpA<RWh3w3bS z`E|0s5(5?*@-6Ll`^=6VHYZ&2lbky$EcteO$NQ7lmfCJlJU`EgHxHO_QU!>KjeL8m zGtTek9Zq&Y$!C<UIc@SgN6sC;JD2t{ad1wZ@5Q1j8Wozj6O2;&JU7nCONoP|wuqBh z%mUisnwoCQpKwVmrKNf9h*_6EVF#57=XgAxfzhzx=EP;53!OWk>=RZ;E`u*+q-{9C z^)&)6lgs8r3XiWlDIeurP4YP8uYA!ei*-W3crN4*z4OgQt>jYB-#BDZw)Ol&=bFCS z`9&<0$P-Z$*7GCZ=i&R%2*c&1PyUL0M<>KP$HpPnY{)qmLir7gFp2^2x%-YCB1*WF zk?<z+G+3ylB+Hfi`M$FhkCn-|^VUd+_w^FWt@K%#JI>qr#XQ=5wKrM`pW?!9HZRy{ zrNBmNF*6~Ho;MRhtuxO8SwF8cC|Pbo7M*)e)Rn`}*~q1Qb4pE^vfs?le8&!-1qCva zoEcS)?2yjW3g>u}1rZ;J6F|lFU{XhQC>?e>Xjf10jsvy4eMH9YEum%lH;&|;TuWI? zISOuI_gySHjIJe41toPziMwV8G_~=VooyF7APJI^o+)_LJQAc6y2!C{`DGR!3J_G@ z;=xk4CPl)e{Gk_dI?O)NA=k)Bls;9UgLi#>-!nt_6QLA(FXFOw?g^{&(W*LGghz3t z&e5y>8(nmY4RDG<2oSr3PKM(GIXyQPI!b2QtzqK8q>Cg>FY*XmJUl#{NerlhsHs6} zk=VS~$=yon|4W*h39)SJ_*!;@ytzObU0;&MC1%dqW1+%?l*PNNASwV*ez{hw&2(>F z64bd8vMmDy$^QCzPiUR+E<5Pl$cJ!?I43p?zDzhBuE4}W6Ic&^^nJQBde*+1$w}8N zaJ~3fF+eCSw}=zsqkB&oUY;v;9yyI-Ql_&<`DL9eUrtP4O@SScV@$@mUx>Sz)Ew}g zU&OS#{BkNWU<cHHzblWXB#f#2#m+e)*PI$qdCQkRst9C*Oa6$91$`fgLxjj>;Ai(; zDU9**oen8vj3!*uxt`n+q`&J<G48Q>pw|g?B{$1OBoxDm%Fy{FkCY0JuAZqFz#V|x zKF`=ne?wVrLf81m&lPRQon9_I?a918V+xK**ctC{rBXSw=+uieuI})iT$D#9e2TUs z{F1q0mSwTEwKc<6q(5UblSn6*!e=g;QoGYRm%kx$fcX){j$A~`VZQREg!!|nl-eVs zW~E*yWYG5qIa0~R0AzcfEB(A;uM3b7Nu?r|FyX0PowV&_f7c3U$CXK)oFuspo;dJ< zQyD}5=EP=>M%g{4JhB{_4!gq<lz5SdM;Hs8oQ&lXz{2x8q1~k)eeZ)RN8c0Ug%-QZ z#1`u^4Tr-SNPxp=R0Qg?u=`6V>05U>%_5o1t8NmmxI;&0gTa;fSiQ%=!NJs#c!8|Z zDK9Q1LAmQi7r=w76Hu8{63_2b1r?e6>`quGDciftMNv$##q2IK@$gBZ5>lN5ojW;R zj{JpLC;3*R+Z04eL4Z6FCQaT+<DxHe9Vo*~$c)~bvX>;Y`b5QdRwyyy&I;oF9bZe5 zCLO%q@9^+&=Gk$(Jf&p$^Qizsf8$e7c0lQ`)CJ_EkQ_Lj8_F;HB#sLNS;*+Sb9%M4 zwKW4fkuT+)B&3KCBTB(4sgf@z|B2nx)W&5J@VUs9P*t7_E>>pT@aed|8yEO;dc=fL zT|y=fj6<A)rly!|?2w$xZnIuzQ;K{6cAp7Z)c**hQTJHSj&V#yEzb?lykLLiAGwMT z?+o`k5YJCv$)t)L8BM=kn1y#{JRVP{ZJrn@sgkG;r(HaE<ZG(CtaGLAFq376Jo=JZ zq9WM2_M|O!r<kz%?j^#*neb9tnnDeZs?h6%<q>(nbLA5qpQunNP<B;wL1#l#Qu%6% z5lI|`oorW0l&{wBlYBB8!8})-b`b)^MXu!3$+r3ol#}Pa5Q>lJxlm!!3psCsv*D)u zIGIeQ|DV2&a7s>?$tzRC&I$31`D|9|Tya9f9D#REah@Dwo;yy<*eKQ%)OQT(TyP@9 zrj)PVkS|yKR)I-Qp6A`%A;|R<^cU`rSafiIqjE=b^0ePbe^+j)d&vAs=jzO!897O+ zOR?Kb<q6_rT|eJ<T5!ZhyuV`&QyboS8Hj@<{ECN}8tj6cC^2!3dI}ZDiKqkOQm?+X zmmLKiRw{{+Kg4c~l40WUiD}ni^o5vI^$^U3Nmt4?`mBU%FtMQ04Ix6j$gUj0&bRL# zNG<aucZwYem)PUhU+1u}z}3(5A``ks$RkyRIGQEYgRfJjm%CJmucwo&)oN!n-n|gw z!c2#`xQ@C*jN~Xd1=U4&jd}e%$IjfT!HEmGRgNw8kv(B3I#+Bw=v?{oJ34qd9^&=& z^LmE5b6%jjiV!(@OzNDor(~Ro1v{in*0~d79*@N3o7q{X8jKU(c^_ScNQIE@v@dN; zZG&dQ>s!QW8&`u#?QYWlXO~YZK}@P-8|T1K)r?7(^Mic4PMC^!;e4-yFYsmH7f*wd zpOiZ#L6lQapBm5~5p$l}kwd(_%QN%Y&AU_NJ5qXDe<<9Nl2j*5M)y6{8K*=rJNM)Z z(wFKSy3{@K`n*%V|A;Ucy;o`hFDJzGS2`CYb<1{yvFN>IJNjBCT~xPnWC6KPoMQU! zC69A_uAaa6o;&W?Ay+dMhxFYk%;IoO6)G+Zt~=l`VTZ=EQOd>8YNRMp_hzH3p1C>| z_my!9N-n9dk8u9<Xf%p$w>!<}QoJ(v)q0&fbO>D|e4IR3ojFc)1oKTTO6787UrOzw zHspGGUhDf6$?0>YKlfK$QcJXuV7@*<PASIe{b@U%JEAr?#pD###fEq%NhhH%<sLh4 zj4;NNuQ(o$r?J)-=sJX&le#3#j0vj_f#YYHm^kU0hna*hI!Oi)aurfs203uS(Hyhx z^2{#Ztc%Ft$}ur_7o;ATtD<@ElB3Xn<5LG;21=fX6I2DeBUgcmgG+i6W9lP$;`O=p zH>G&u62d7i1E*EKON9>JwZa|lz=W09VkS)~GCqU1a~)U!bENKMek~KN)oN$pRV1qs z&Y<t7*9qldhmxHt?vZg>OJA}^9rzRx(C-}gDll<TVnW=tPx43vOeO1jjwv}*-6`U# z9Y4z=&389(V&l@&N=Ws0PI#3xDGBlAe5oBgoK`t;+4s13f$Nxb?iZp`jy{XaC(Cx^ zrO`Hg|M7S{vrU?vE<)2%opo|}6bOBBBH@^99&p;kB24EZ#s6`h2q$^EC)_*bMV{_d zY6-3EMLBtO=?I(Q#DyJJD&25`!YL#%=c%R?p<}uSzSqi&e=m?-dfL1GBp$OV#dD$G zMPE*tU2$jxpYpv`j1|sh@JSnCH6Fv6m=MP6iwnIwtm2$fv%Wuw%}Bo!ByDq2=gM4! zkNfo8A&G>0a=OkOgxzA2qRCI<4jw`zUBH79!roYMGCuPUD*3VT!E?ubX57H;d__WZ zm~ZfPLCg4ulIUKX%NOhC*-Z3gopDTda?u)crzG^miIUC@n?B6#9Q8n7>P4XMnep99 zl=XJrn#UoY8}evV-<{0~SG;8-n2izN>A7V-*Z=?^07*naR7Kty(Kds@V44^Eej%<{ zAZkJaIofwdK_7B-7{l3&q%W2~BhQtbKrix$Byd$UPBHz?$QKjk#oRL~0Kn>rdfW^U zO4?M-vm+sFF#`k-6BlNBfY4Ne$+kLGa(tB7bAA5QVWiwCNAld2!li1y55%#4#7PoD z!~jBEret*We!is5aga<bWIsAdK2R#@P<4z|FCjv5Lh4*`YTz9S;%}MEGvOrWT;H7m zhtsCXWO7EHFtwwH0guT()uq@ab&{l>B_VaLMpv)bXH<gN{bf?c<$Q9IBw;csbNsD3 z<IWeLbRz=_VRiF%HxZJ^se~`rQ#VEDj$6d#fcf3&ptYn{PEg4*i+h(_X8|khFq;R2 zs_J!i!d&ume}8}aEUD(g#D&4t<=}ZP=!A(Mc2zP?dz4V>bxy0fY}6A@3LOxxKxjv* z6Gdnl<(GA?7(87n*5RP!LJ+g=+n~Akf&SA~$=Jc<)PQ@fJmGXzuz5>ld8eFL#yjaU zw>k@6<fWuyDU9&{v-j??+OGLs*YAD~>wKC$oujjvGJ``1t)eYhN=hKmq}H|sC84y@ zXiTu0SV=U3nn;>p48#}+|CkyGB!rZzAlg7uv04)>q$!rb)D&z|Ct7x=hyAX#-gm9_ zoc&|1&%HkPcU|k9J<};8`@QdEl6m*Dp2L0J*Wq{g9@6(A{m>F_O7+?mO0N?FQu{ij z$Bj88E&m}qVVkdLC~2!W;KE8u;e%;6q&Yc*3H7j_2v8EsMY}R?Y<qT?Ee_$ri(z%_ z)ehzpLSxx)C%{fnQ#gen*4?P>c3W3hSN*wX-dY;;dM|d@k~K#V?ft0b-IRoN))eng zR7NVg85NP<OPM6P7|C;W_sB&d1bbZNPp;?b>1qEu@kR1HEK%$Zt_!(7<9#-Gzf0q2 zCwXa3>@KE*{Z^sY3AE#@goZhorl`a-F+bYKhTN~<?Nn8rpPxTLT^KHPette!Q$EL9 zv;%h;EouV_$@e~+%?2F`)|_Fo7LhP&g4oY-G4sZ-J>QGZDceg>RK_O2LQyFO;3Bni zibN(DQt0A<f8Ud2h7a{0IgxSO+CiJEN5=Z4(hiACy2HAy<xMB0WG$1MrjacIs)O;A z2Xt1ST?ym$4R1=A%jM<epwa~f)NluH9DF|SPn;xUW0;H;PpBRP1)*Z$_MxS%ZK{+G z?5{J_%xaCX#RO)q@=d4HelqiWO$cKnG1nmt?u`59^Id^S*-UQ~Y$&Pvk$xaPyiB4@ z--lL((@-+z4P&1McFb8SSE-igVBKS5;<PcX%qtRDE2a>zCbTReNG4Ibt!%Fppb+l# zC4Yy2FUhZL!r<jIL1rx3<Q#B1@JQ)tKlj{3(`}mXcjY_}ZLu`R**3WJsZa1HxT{ z?C@r=P6gD7kOPP0IuKA=gu?qt9w1H@T2lB{m}Jd(ja$x?{U&9-?S*203#$O7q8kT) zLJG}&V&1s=>v`Zr#e2C0G>p%8(B#9F=jy^s&YKjqvABu(jx8k}W76GSH{l)59_x{! zodqbI04EH_{2e;5hUJ;(nw>zn4$SF<5nJ-y1;6wc@?MLDLh?WiUE}Y~A7V|j_i^ur zM;Tt_PM@J?37<-bcE=aYX+DEBmq{F56qBkQbh-PTa8Gw7Qkj%QhQ!El((IPC3cXgJ z@_u4ON&3jRtKc)!iB1OdaAaD=M&<<^8vFFM1T@S6W<POk$h~pS8G`NNt3A0aHjt{W zMjqrD??k8tWo-$!q#qjh){-FRJ6JOwTc5#}u6EJL4T3aUH3ZUew-Hl@Od73YgJJd? z&`qteGjbqBBGSy$B3tg{W!&uqHa!HBhia6G6=^M5-tw+A-1CXgj1MnYOj3Ti1&=a0 z_c>B_3kOMyjKkHNU`s;J*kzk-<pXI!$FlXx;p8e@1_o|xyJBHtv6XC$UC!4t*tWE_ z?~RRsih&aqx(bG8F*YXpWo5m!kj(>m&WJ2s#0fks-|Pd&usf14lj+Pe@nlbzakrHd z;**=0IWUIh@oZa_GIOUqFPRsvd?$~@N;;_?)q+R)a5TZ510XBs>HFZZ%Zi1$RmRum zyt2ZQ;h4z}viFj^JDyi=Tc<Rm)nJmV!2dTyC&$hr6vjfkN@tazl$B(^NTCCFkR5PZ zDbQ6u8v&-$PQoRgD-Kxx*#WI#Fs=@#OSySznf&`%q+(l|54$s9b3V(V^0yAET;WUu zx`Z>N^mHn|`CxXCV+c@I-d(tGVBwC6;hbp_YfrDN9_N1H4zSIK-Bn1>3KS?)Dxcsu z=ap5<(y80ZUMbt{Gt`hodpCJMN*<~S=MJLmPh`BliyP)?Sc2F*5MC#kw?n&;2RZMU zS00;mw@+oSge-c^r-Bpvhu2iXc<DlB0-n`jLt#0?3251GOx91&E_a(+g;*zD6c@ZE zQkcamVUCYdyd;$X85;{?cx(tr-Q}?Cw$(FRCbH(OG0)R0&PK1Vn-}H?`-~<=;2iS% znHPpjdaq9b3kxk7k@7leY8zUnw^M807?SAN&IzvX&AwC_JGv;9zEqZHHvfqKZ+=lr zO5ZSJ#;(OLO3897pV~OpT+SAsF=f3|tjOowbG)->rJ21@TLe-jfG2YjwhSFhi9N#+ z98eOho3L&eix+Ad|5%zaO&hJO<@dL|4;)k_oWV+5&&i#-lI3K;o)>l@XQ6ZN?zkAo znC|q3Go(bZan;7h64+l}UJklj4h(?Zr4Nj=^p-kR68*f1nMlaINV0z7BuyqW48{ip z2Y=#U?N5~C+SEaR&I={Sp5JPWX&yihs@%Fw13OojU9m6*G^;suDZQpzYc9JE=4Pcs zI}jpQI2}|O+snQCFv1gq@u1_vSWvC8T1!??Jx>e~0`A~0XwDl47OWXIHLnQ^XqY5v zIEVKGcLl7Z=RGn555FJDP6yw1+BTHcT}*dufX#6~*)?d*8xE`7GjhK%*CFMVlgH6Y z5)CbL;NUfpa_^SVqyotvXMRvZ7A+!?>YDa_Z~@Lnt=ToOfvz#>>38M?HvQ22eitsx z$+Nt&tHX)sw_Iw=@65rv<xqk60fVs=t!2DjK{Zsv#AToR7J)Ea)5V9DOl}%8yIARf z(+G?_M+`Lu8DLJ{$;rte0rr})w6qIuX=>f#Ugg;5yfG@o5FS3C$~OtDxt>nq46AeT zAkP{2iuPhbV%UBk&)EpD-&jp96Cutq&V}>y^C!px!+MQ8Fo)Pmg%18HI=P_6csNO8 z9`Eh#4S1|BXqz9D=ERO)h@TQ3<?gllMTWW>>Xik#l<iJ6yi9-%IW*@k{e@gKvP`&D z$CB{w4zN7{*^4s?WZtCYIb-j03}gW32nl-53$HoWOmb{oSh0yM`=$3AtFBti$U;!8 z85jJR*UlrJaArtkOw>u$vJB=Om}GUCh0Xw*LqmnrxNFM`o0OClP#zNPzvL=df-fOL z4w4KF14GItl2We5khZFXJ|L|2VmU%@6y_J14ClkMrO)5uN+glc9yqR+xN=1&jlTh| z;D9kXH0d+bf+LvAkkuGhP~DO@|Hnj0zu$+ean)=D-lW_$V9up+VJaB81HvZCXA*21 zZ_lP+DcF>5Z1IoWR&K#HJ+BP!@;W^{JnSnlCJH)W%}N)~y5%CCo)_GkiF|BK-o#il z?nbo&O2Zk<RY3CG)gO3imLN7nh(wD6--LDUkNt<PgdvNDa=7C{N5fDqD>&MR#v%}| z40%6Ecly?TlZ6+HNF?0TL76e{4q%h7XmzVJsrCI?C?U;@U7a=T&fTW$ej8TjM8zFh z!<$$$1T_imvKRor_44v^04ZYL7$$5;qC0&FIn1#!vVee<dCOi-V8NI;Sogtg7|V0U z&2V5)r!tqpWPi?$%gf6FRLyG!IHzGVPBJrSTd&tWXODo>-6rt*KIfd|QIO-iTI!t% zEwdt=d8R&Rp7ViW?9ybGe<OpN>)lY*<OsXl)q-<6DQxi>J$9Vo=CZob<8urS4EIm+ z?{mfwK%**>S7tFHcU)K>sIGcVCSNf<dXgWM#Rq?Xj;*`b6l@7dSF6<k=8FJ;tuk`n z7&_*AGY{2kDrK*U&C;{WWAAxqz9RD~Z3MjLtlVXj*@TBXST{VJ1fP4(;sE1g+lO3J zJ|~Q}$wb2)UeG+A7v`aQP0~@ixVRX2?07Hs8SX^I=Ul1*yThBlR&@W<7~1F9lVrw+ zpE)pTY-l`x%Fy}nZ@It1CrD{Vs?P~6vniyFw3f@|K+z<F`E;+(z<>wpEF5exf1e6U z4%V44t|GXj<H~!!&b_C!BYc5W8FI_si44I$<7WwDV~aVwTrINigOj}UxJmOp;}nzJ z>kK(DqAj=SRIjp{R!V}Vp;Q`XI%u?ERGLPnTAoc4O`3LML16M+r7FFd7@KsjH!<4t zlueB1L(r8NQLjnXmmxr{ZkXX!3HMA6jXf_C(wMT9&sDNKFOUfKJmUb$PF@R-kH?Pp zql9zPX|%+!6;Dzc(wn6B8+#kLqvHhFgm^0;Ww8I83XlWRR3&pz$AQ!G3vnkP<(X;8 zw{Y1B17_?KD&qY$l>|9t3Fg_4lDG_fDq%7fjp6Wg;KIS`!!Lzf_&4*yo*3rb`11`} zOn)QuP%KAk+_vW(=TLGzJ?~7;wcM#Yfv!;6P?KQYuN#(UZk3BtzL2@K8lOAHsR-u; z+vkjnRtX0+soP0l!a=P<WayYXKHfW92E9q@Hd3I)ne$$0n62TQPQY8T-|4-?IdgS& zHGoh8ugXHOyZ;H#vV5~uS%LVpIw}@!aj~!Epl)PAavl8KZ30VW-SHBH^%UT666&H+ za;s3+v_OaX(>8@<-Z{p|u7nE}6yz)-;k}wf!XA8S=<Qf9Efkz+_?)vjG5bMFAS30K zTWcocYIki7N%VeX>k&(18wPA|MURbRL-vRDdOh%kN;qah=P8^R-f53P_DUnCC=Rd( zW)kNZ!bm8qcP7`<U0u^zX3qXv_*u8WOoB9lG^@kLU7PD*kB)>#S?<&=w)8?_le2^| z0cpx&Cd9~@s|lkm@~kJ5-)~<A!}3hl2V)9s&bVt6(t*ji66W@#14_fIjN5irZt2EU z%3*SuJlisLOhQ<itl2$2v+CAHkc4(aNz7rftT$tqox-eSnR{iKUE}$^kdw>cpv|gh zc|hdh=S|j|nCA@#dwO1&P@b(*Z{Q?a`P?(;GH%)}dGi5$0NC3gRfbFywyb0xo=MI% zlq7j$<`>zdt91Z)9=np&k{C{JB_9weOX-%r_oJ3KlUwp8v?pHQNfiO76I2IL_Q1(X znX$tTIJ2wJg1&j)_yBRD;tntK(%p6AvRPA}w}!2mSLW_H2bf_lo>%s5F)Yt2JuM-H zRMN2@n#sE@se40=e2yWU(&7YqP1zXH3QF!4Q(aDokvqIjfUTnF!VB+b-f~Wwf0Q0Q zCVgk&gz=!lYIl0`8S{)!3x(`rI+(Wal!I+UT|r%N@8&x?Sf@Ii92oCM2?w<zTq?e~ z`pa0ld(M92zxTYuW5<b#rKx?6xto<TyU(quJf{-QN#P`Ut|^6|owDR+`QDNX>W+=Q zRt(`u(soO>+xv+X-3%?W&rI?_e1<bGIHzpAVc0+CAcYef_|nmFY-nZD>>#rynI}$k zTJ{ny=-Ic*h1M1)uhpeZ-k5!*%;j|QZ(2ig?mRCNve;5lwCZchekVLU<0C6n`W$l+ z+y!`dR9XUH&`~^(&5g?aB<J0rGvkUyssJ%rTB;mwD?ewFW+z!6ZagqoTaxr`oMX!D z+6|h8ZRnYO8;rAbOUtTd$Q!!bWSLzSOLknmIMUe13yrMW2LLJ)BzrtCOEcOD+nXd~ zlaiin;t6BHDcd;7gu!G-$1>UQ0jv_#N)la>aJw+gM4ce}fU%EEcAHFAOLDFgjr6qe z!A?-+mOc<4lORp}174M?9Z85cp}tim^a16Co|Uxp;7O&M)|&HkGe^dqIMzf~LsC}K zl_hg%z^r@yCoj#?i^lUC^WKtI_ShQY;x+G0j^cs2OB_PXQ`U@&HV#sZIrqG1`OKI= zYB~2TocK8#u0RE|)$;e6@;rNvlV|L38fH3?;c%p@Ku`uQ+HlS+D%tbGd#!~I3}bV* z$<Q)$uhO^5a7*t;7LnlDI*Bu;-9<H@V_6)?>Mwf+?{!d@#)kI2GTGjV2wf}oI{O#V zaWSXP!91Nf4s;49K+l{&)9G`9n{x8*5N9XQ;vg0a@Hyq`Fz1+gp6oX*saVz=>&!t< z@<7-xoXD6<*>zptiOaF~*m>TWTb0SXi%yngH=of#m*bxlcJaJPvrZR79nfZcW4U*8 z=2|uY$%D1Mg!ghM&?daQBV&k=;Z$kdZ1qmYKFx>ydyKkZ&A6LowMxq`x4M{%#iH+8 zxESe9n&IV+Kg@?Tl+`gpu1WTr7O#voXZR>dRw4tknAzfqB>$&X<aWo!hL-N0=Q-sf zvtj&>U+h8XHRE~Xb0#Spv)QbNbGCf+97ANcD<RlUkkc&P=a}OkkBwvbiL3732;d>` zqw;|<!N{(%MP@hxuVs7C`uqeYE$ngPBpuLN3fcpj!MFnpUbiO(ue*InYm^C_UMp-Q z4#ry!ryNp-1XzC1YA+@VCMKPYfa<NQyFPqqAG$hh$e=NzEhq=DH*W+^ggBfHn{z;H z{4SF@392kMDq(3j<*Yt=9vq$ow*)54L(5hg_iXqS_wL^gKHl&rZ-UH4Lx30?SGqhe z=oEU>^t>=UtHn=pW#6r1!=GAXlaiJm*IYBq&lWd|gFk;8_wQhx=kDO%YtH;5W7dJ^ zSVGvrK7n}h)(j_gSHiwFY?36;CViWHYf^U0@t7*1H)Q)VaPX7F0@X+#nddycd^of2 z&d$yTIPI)1JJ^1%3u-R}2m6-E&2E)DefB4^#}yqF#;?WMbBDzH5rKoDtqHqpd4Boe z;&5ygz08F$f2ie|;f{`B8cu+jpI%cA##1?qv9akizl;5Vy&*+w7#oY`*tdcGi2V;Q z6?e1P&-k}(0t}Vq_Zq4J1Sk_Bo^=x1y>{70+)bkL&YaFJW(xk8E5N+*8aq2X8}O72 z%S-r^*PJa9{PzUB+^fgVd`Cl!-0dRC<Xmid#aQvp9bWI%_O)si>|9WD;iJXX%tVCo z<8{W4bF4*}cVWeel-C&hA^(m2$OSjX0r<EDI1=J))zd@{xD)6^!aNJ+1;qt-n|y}1 ziqtMjxgck;02cr+FE9K12FB}o=7JrCq34iJtT}#9nj0r-!-bVxbB33@o0URNF63H# zg#E~d;Wp@X?C1A;|KWA7c{dEqmo(BT_hK9TI)?FH{G>BuuN40%vf@-&Vn9>6(bb;B z_of<*4^Ox3t-+qEWqx45TrBzNj*M~F$+NI}l*x3d5@eo+;RKe!H9po^wO!852S|tz zz6~bCgP&y+vgbvr$xsPP2vWMwd$L+h#-@(mfD<0&P0lbDYsj+@-JVSOK}&|ZO6bLt z@`NS|GPcI<qKINxpWF3Ti^)XC)nkI;mi%BE)R{Y#9U+h1#l^*d%-d4!@IrS>A4NCw zJUn*kGeZ^9iX<jck`!1-fjLaaBfAF7f4-XzqN_12hjyDnwu}d@Ld3K8CYbw);ZrFl zV10cPsne&%ZR_O7m|MlzxJzodrvujHRx#duw=1wth+W-n>E|CD91Pm<nZ$YQ4NWuG z!cYri=7G`p@XN!M{cb*=54xnRce_!$I_<#1FkX99War<UI+J%3s!9dh`%(HjWXH!& z+lE*9-tB9Zxa{X-xs$JGckLFO)1>bdO0Z}|@<0g6_<NtxbP8Pngo}`C(%da~>ROd` z!#OQ&Z8>;Dai5c-O#@$wl`eR>3z`BOmTPx)*XM+TYgg{`-p%o4?%Jp|rS5s%XRx2m zYPITxTP$5|{t;^iiD4I=3}JHdfahii5DBoAO<VHL38%EusFSpoX|)p-!-P{J*!xxb z59RCb!T{TIhdSk%4a;-a!90&tHM11Hd9p2qNEiGPK9z}x|82u>#>O3Q7iR3q#hkal zk*z%pyECWHQv4n}+YA_)kYWL#eSmKzbl&0}6!enYog5m+hPme4T_;iDxtk}O+;hi< z=GY`0lXJ!%Jee~LU}ou{o;Ph}trQEeZ-fb;Y+|XrWkadFsU)DbWGhWfCZKfX$<DWi zATfa~TbVBC9KKYC=?tU<v85s%klM5;tHZ|6GC9(_fGSqD)Soki;{BE@B?wuqRs*vw zb7b6pv@v2z@NxKBUNASoREP2==k}pDAvVbjc&WgrX9a<QgDxj=%-fVOCLqmfPkIvo zSMb90yfVzia0mxkE#k4EYgUxYO(><QTkt63W3Bd*0c$G0CC7#NVaan6T$5j0lAkUv zq>_!-oE1l?l(|sCchiY5gem=t^4|IFPGHlU!1re5tvs9wXgT1#-&it~0)Zig9L|RL zq~xceX)df7&X7=9=5(qAnfv7~3D4FClnWy+ZkV)f=$Y39dj|)5%SbhaRa}%JV0CdI zP1>vg>BGuvCY1mkcsN-wkvWYEefYMxo=$KRLY<g(_9L%%7u-?=!d*^xB^-1y?<_6N z{_Z5uoIQWO&5;cOGQ`?zj^u(f*wD58{rv%k-+_bg&9d7*L(SbvcY5;yvXkb*hM^?P zyX4%Z#e*S2-V<`a;l8Z0=tRczIDKL~FL-X;Px_saAiE&uz246yc_QhRLIUdo7;7>O zGh4i~ly6Q|RZHD_UO3(|4}>$;ohb9xTzqgxhI!$l6G>bvc1*)>l6Mz+nO80<+lwyG zDMO@98z3>@-Wi*G?nXuUjOSi0ubigT-fP{JuynQg)t2o}{!rQ!aKFqOVkURj?G=|C z7(>^b$Yfk>k3qiM=EbdUQWor7;J3wslQd#CL!jM_vPHtPYG$q;8-CSV=q<v!gDy7c zB)fT``+#W4%-QW3>?MjK*?Mg$b7gzb8;J>|c>uY}=WY^R2P)qLRT=DCLNp0ouJSQ9 zEF^cUc-=CQ{%y3C4J)x!>}s{@IW*=Mx$AIoaWT-8w>%+or#2gPHO6D>B+x-u@{1gh zTFuUzP{QiCUmMsZNz%R!e3yxOY=TbWQU=#uMssY^!^hkzcO_rEcrhUQB_E(=rj_K{ zRF`UL%sYWKtj+<cja1WY)PaeiTb4BEx$v8=uCAU09{#-!3|y&VlLlX#N`HJuLIU>p z_Xo*^KcBTvpo4%0K_Yt<8?*gF2#PQe^Vm3fw`jzR7cU0tD^$MiZD13})6>&_Tn&Xy z*-3t%yIG8_$J)U>&@y{?nAFXjut}xYB$aXA<0Q}lpCNyS*znw$OV`)egTs@9lfyTK z66gx>`x35@ueU1eyvBa#!<cTClT>#K*|$@GgWv8>iG8s+r}#|s6?yI?VeC<v+*3Jc z-Pj|C-)_DalI4c|xzJ;18U;0<Eu0nJ&p2CvTYBEmfkQpha81^fJwmLOM^S}9&B6F{ z62S?9_B=EU*fs)&6nae_9UTplPGof1kAX;Aq{3%3P*r;~wM-)^ptSrzQg|hO^3r(F zLIL)HVcvMn@!R+I_6E|^Dd(O(cb3Ubl|?7_Ev}}O{>*`4Y}kiWmDOYCLa&QP=7waF zXN5__?p+j0L`fDtvIuUtraSdEWn^ABadNQEe%I=9GF~q5TanEiVh8KoyZJ?)SH#84 zNq1Z!>yy}}&{K=+=`{mo!fL*TzVmwe6B$<L*wHzIVaARfEiLUNi#20jmB-FSbVJLZ zm1gFPleBHAG%%ukP%CqFR_%_B+tzN8k$n*$01>i#JU7i`;Q^)&yEm!iaai_}AP`AU z4rd1z#@D(9M-b>18Vf8{&D?@(buCc+u&E{!B+WwE2$CRb7z~r0acyCTEf(PJR`NiA zM-iB?iJC0u#pSL-$`kr^Hf1(x?%Ap#31>)0V=G(O@t7)`m9?^~VB&DXT#Tzu3@G!) zFceD&8wYL~Tn_KV=O%}y1)p-o!}BTyI9LzvR=Jwv3TGd%J_LP>#ofb3QdPC9gZ+cr ztXH*KE^9h{Nb+`7+ug(AdU#ap)iMs}T~$5KtD9FZ9|{EbpTF5`s;jQL$^GHHxVx*# z<Ppj-nM|u{*H<AIcenlTd3pV^rnBjz0@Q3)i@V$Es;kv{U5mwCb={;^%lklV)m1$p z_-nhpFT8a1(4pPmd$_knAJn@Gy0^Di>(#P0>u%tsQq@)0-5)Tk<)XHmZB3?=y1INZ z=n5Pi9o2HNsO@$$z!q0^wcBm$^z^LmZf>f&dg7>jUsyS+)pDVEbN#USKNb%bcef9F z&bDrEZ~D*gx~jeT>|yM71JAGRc2~36w5F3u|N8v_xv0sctFD{eKaWXQyX_`8dsUOk zec;1$bI?=O)oQt@{r!X5Z8x=Ct*Sb@P51YGAIu-s;*P|stDBowPY9;V#a$Fe?%&^a zUG2?hb$5F+IH&ISs;aKLPmphKUdeFt)%|bX?rJu_Uo$taUOp6#Hg$LR`2N{!T3yZR z?)J8JyRGgI)v;M^)~njA@7K{?-?g}ZHuL%X{`J+WHrve;^W&qV`{%ma-LI0nhxvWK z$5b629NxcvKjrJ@_U3+m7u~4CTHM_gG3?FF{p-~|DBA7q*WK+Sd}DF9s9o&_$-v{h z+0@O=ZT}oSw$tgf?rv`%&iMPWna^icyKUXPx`$ldyn0ou)p8(CvYm8wyINJ(mEcp4 zoWAX5Q_JnPYPYMq#a(UIo9ZT$+HUVV%*(}{c(nKH=l<F6>hSQO7Pq&xtKA?Nf9w?A zuQ~Rg+q=7m{bU%lxhS}0Hvj-207*naRBK^Aq~)3U?M|@I&(8;B{Pbo@WiP{@9IPkI z*M^%;Bw8}L#7hL67Gg-aWh!U6^Op7$$S*T5C={CyNfHUyAyvtI#+w_K-c1%CA&zk| z)7>r?SDb*S@)m*da6cF-k1`%ka4kmU4z92CdNa>sI-L##gBW}BFD<m-Zk3Bt7OY80 zbH>K}RznigY~3-u6(|$3n4&ZwjZ&D!MQJB_hVfe1#T^>^%%pddg=08pn78goxgp{B zhGfS@tU)r<a>^zdNV!z=4-&7R)#1dX^L{5QOekZETLyJ$-uF8FellC%EY)8RsFOCs zud-$Ds+2M1Ez(jtlx9W45FsXG`hi$p8A7@pm#HqBWNGMG2J?mty4u6Wl&WNwo@OJk z;*#HQjHfH_Ho!Bi&-do)vdMQ;$K8HRiDF~kUBzc1o49LdYqy1&cRsuf8EhqKNespx zC{1RKO*RDbIZV3o{3%^+5~bl+mbUiT5JcSE+zenP^ZC4Xn{{n!Qt!^*su$gU-OjgF zdyiZW)?5!`I@k;#1O2A9tJ-WgwV7-Ng!{>4Qr+x+(_7W5c89w`waJ_2V!NpBtQ%B7 z-$}F3)2dw!E5v=JuNKwKyMffL)%uo;Wp&5H&v#(6+FuRGzWlykyrH}A6xOb4GMx-6 z<-6UkRtFCR)!jqDF`Wz!iS5aDfDeAB>#CbSl85W)5n8r4-y{C(5BEB)C&XxTgu2si zz)kbmE|<&N9q$JBe*gaah<UkO*5q_DC=fU>S=YL1uLcK*=k@wvJvf}1<K6t>_2c!R zBgDMn-nU2F`}nh~K>*d?`|)F-FrUq<x*Bw8yOVAp6YM}{xm;Fv_V}D!7^$jSZCBMD zcTYMG?x1%^T|e(!JYZ}mXAk$@O=>ou4LE`8Ze86$Hz+`OO|1{sPr7CGkjShz>)IYa zj?H{FuWmAwQ?26~1U5M@>Zk@C9q;YS<+8TN+rjI6cXjt`l6xC`{_Nqb*)FQv>-xX< zn(56_j~)Y|z4=~0j=SBiR=ZVA4j$)?&-m?jTkCFJlkVa5>14pMS+Cc%IodoSjqi55 z>Z)qDx~rqvbsgWnQ`6ej@#)#Xqr_*d;g*IW8^UAgm^m)y(0EQ*8vAt)@2s~}s5FN- z)%1K0xocrqUaJ#m)mBSc+w{>~OJWvx@_0Y{tNDy6`|a2;z2JyntafLABTJea&S_eK zePXiXV>9$jbXp#Q_FGG+YZ|R4v@8w5z0b3kn$O4?Z$2ZjpLw*NSLWb&J<=frVPHt4 zq4$h!8iqTuNRL5tgr6()W`n@0WG>_;-;pA=lTs((wlzs^me+)#^8<km!_3GONi_VS zCe*v@V7Nk(+1RjB3Kn9sb<TMpR3MGdP2(Q(K#ad7kg@WXy--rZ&lQ)H$xVa0lvhsv zj~6o4Z)=5Tz-b|Z491NWw3(KZft36-89(v*>Asp=2v<lg9cjXP9sq8wre_8BZcMtn z2A+)8pwEtr$IfJYDqHsRa5cuC&n5_e$Xq5=J9rk%o0P$A$s?vvf?a`Ktx4`w9-h`& z=XD!mnyZi|YMH>gYGz-D<#KtyUN`G{w>zo-^Y}N_=Xa-dwb`rP-sC<i=_qdQY7kXh zG^BrBFTU>egHRmV#s7Ko`fm8|FZuO{|9)6s;_J`dTa3@qYwmsjbz>8+<*?SS>aaC- zeE05|d+%N|w(%v0-Fv_HC!hbiv3U>kV*gh%Z@R{Fd#__tPoLY9d9l0yeXkpvFM8g5 zIbMG+b9(oM*UbK}#+vIMf9w}}c1OR0vDts!*zBr1+}3HgsJAxn)~9~yZ&&y7-8wuz z>EU@4JSa+8KHkuI7p*8p`gOyA=}1tNvS)_li<H?lgxtY8P*#HZ^sOSkatFrel(`NT ztx3{%8Y3EZmtq3uLRhuTFkSPD9G_&D(makN`x`=J4h?^6S#QJUtgdSbV#d~m3ZrT8 zVzKX4DvR0=&2g{glZ`krC(uQ1OW_*^Yi_xDs>u;fbxnISF;_tIF!tuerEIt7g*^yc zW}hxZr{9^2NW`927Bx2<IH>u}DF<&l3iE~{tCO@84;dsgEEYSk8;5DEACu9UtqGoN z7*-{-+^G|hl;E?@y0O8AN7=_AWh-e5Tk_LzE4Rpi5cvV|`3`8U+{0u~c$7)!#_XpM z0f~;4AzCit4%Tf3>fd6umGo(G63Op9KR<6y)@-d>8r$=O$!@K1XYou%@X}dvFkzj! zVZ1#_qKV<Hj*LBc%zd)ji{%Hwx4QddjHs(IZ1|R?v=0pjjMeN69pm$8y}FWS#S_Nf z#RFH_Jg>};p~~ST&hGRkZ5vy>Ua#w_JE_0@*6*(C?SB2i-}>?TuCM!Oy?wD?lZMRU zc#YS1jn_XZ*KW6~&%L{-zxa3Fsqg=>pR2o*kJYdHhd)pk50z&p7*<gvU^N#a4R)VH zlvp{8&vyJneB(-W786~RvP>>#A`b2B{|;zVWFn>N6Ln#gMW5j=umKU`tl=DUK{9zB zCd@k-vDqjAsgo?DWgI&iHfKI#dZkzjpEKNrTq8<|9bJ&m*w3g4VoTdk7#U#rH}^)| zY+)9wwwgA;*je<&rjc}uT)Z`p%kwJDKHUIFuQ<N{^73*ZxRG(OJ0garWpl%vJQs4E z=y**bLIPUHv<WBB?zm(U>IB*G>%cVAJQIR02W`elCZXL69VmcZ%$e+7h)MQ$wZvr1 z%$luAW@%|xQ-A>Zvgd`9G#<d&+1a42?99^8vvkIF#lsJr%DUaI{lH8#c6-vBoC&7p zWq1QlEpN-AvI&BJb;TkH=Z4{#unvCK-Kx|IClR9Bl1|)i54zHoSvk+fZF4KWdES^{ znr_hvn=?+@#)NEwBm+JGY<%bggZG;&@tjO<I=C~oUK6f(Sh_K>$0>tLHOE~}Z-S52 zlx?lIyZVXqf1&nI&g%z$|7YqOzWTft>s@WL@;YAQHD2TOPu$hjXFhyX|M|Cly1wIU zzN-H9zw{64bD#XyTL0vqsl)w8c&iEXc@|iKlC#wXIg|a(S9JUWsv?yFfoi72u)7+Z zQ$9yh^~~@o7u*c-NzW}8^sMA%E<-}=SF2SIp*F<G#Zll>*|i|fFa$cKui<f6yu&Jw zd5+m<&qk;GK7#4w@KW%!%Ax(vd`8;~%E7of!rY%@$CTw}-tgNTU(rP&SSN`|_*6=! z8@5Ns#{Pz>NSm;^L^9=^PqR^;dCL4#sI|9^ImX1@R$;S3Wvhs8F#+46nE%asbhpdJ z=&A?POaf9CgPn7I(+;XgWKv=;Wibt-v2Vrg?d^bPVjXs}em={}681_lS<Z<-YPg$} zZPO(FmWqWp0&9I6D`<?VVRZzQJPaorNboVS!AYhGTdG%)u^%5FKY?eN%fw{1VKkj} zR1@yo#z_I`?nY3$91T(mN*Htr3>Y0FN9P1-COJ|>q`O<XLmEcPKw^}1z4QA!?>YOI zb9VOd#C=_#`?{$PUYSF<kyk74?<WMev^d%njrrNa+%6US-ZlRMEgW)D7?Jlb7f$mQ zZvNypFApa;bRIQYS?K$bt^Z7DM{3;0V&QenTlyAsIFztu-CuD=n3Q;*CM@#u=r4B~ z!(Z8pFK6E|%stU>n_bp}fUo5j3OWyyhqo#Lh$WC`%VJ#A$iJ=F=2Cv(tlv=L6mYi$ zI(rqk&9l3^#(B0|5~y5;a=yMxX#9x@)ICE(ad@M7Zk@Yyo!fNVZ%^nCj-1uOhg(G} z>B5X9-=*2OSVSKr*{A-P9deE0N}b-VSqTFSr3!({j-V<oyxQCPzw2Tro$s$bJW5{> zRE*SyizjoR=Nas9H01%~?)J;Rg!_1#q|x3iKM)jmcQd4{swqtA2G!-+o003o_bp zQMy(2L$5~fn9+suba+(R2)R~11dP!)ru3mlh+aYlvp!eLR}5liATZ8MU(zXEKF-mU zoOELaCD;@4BpjU(9VR`=zkDl0a?19>VsI*!y9e%I5lKdf=&BOQ?%TDt$uMjv5zt^+ zwvaPqKFZ+PC=QWP0#I|#bLS0XdhbmaTSK8z3$DW%bEBMH0vR_|{_IgPVeavAK;Vxw zk#BaWSC!fuUnqW}Y^tK%4u3e)$z+=Gq<s8dVqUb2?ne!Qn0r0GTPjkMRIlZ4*w)qK zy7c#UOv13=Ny~F-iaO5R-|I9Hso<9bYaq3ybOElcaZq=#&)KPSOL30erAJ%9`?D7L z)2_uB_5ZD#cEzZ(e#f4e%M4FkiJAZJy<HU2x&!Y+LXA#P(%FIov&Ky(CQ_+NSgvEO z={i#+9N$OkFa&SIIgzl0s!U@MAR1y>*g`@eu-ULA6x%q?Ox?X2%e2-&{$Qn8zJ*Y^ z1?Giqx9a#Hx|*eaqAP~eUoBB|UEm`$6nMUU!HBC!WUeIF8(@j?xEIM<pcdZt-UlT( zoiU*$yXGfhm7pZJ%*!K<x?d9+xcipa+Lkwxx4x3a#V~29tIKJ&&k39nS(R~f_I)K< z;VY8+Nu`&d_+!I%N|U~}wAigA%^M2$(y_InW@1-0mdi<gK<J%gS+lC@UTn+?w*5Su z;P6%+6nHLg?zUdHL9lslq1P8eXZQ-?WTy`-mERhY?pU=k>>TpR1yENnex_vzKXoKz z+_WplDSOwK;<p{-{H9P#2A<2ugqlxt1l3G<1cNARTS|$=5M|&wObTlTn+*Qc@h4Hi zNa?GVU#D1uTH}zLh{|`3*Vta^-DE_(@aCM@tlBGC8NovFZxJ;9of+Y_d5^qBKsAOR zW7ii9NIdF{W=c}$Jmq96e%;yqyZnHHV*gIh!#RhB65pGRT&;`dW~obaC)PFdOm@M@ zt}~DRC(+5!7atNf`Gr$q0V}TD=k{Y9Snt=~L&lC6uL5E9?`XD|^3n#=p$3WUuc9>A z47LxW$TQVMXxhC){VWw|#iUO6b5w;Lg{W_$bmTbRXL2$4rl_-gpViWdlsl#cOFX`h z53nJ^Ye;<zz!Y4jV0Ej|`*OOMSr>SoD_Yul$;9x9EAEnK^iv3x5g-$*RkeOO0F3oo z)SRVNwK}py)30(nRVL)z`J_fsBkCBC6d9M`{#fGae$A`Ir3=*MBdT<2r<<Numq~dm z?V^z_t1f}skuh7bM7bv`vF57_^rSIbn1l-x&xMx7FU0%@CDj(|`VuG-z!k_4I-@?& z@l_xKHhIJgTi1A9y^BXpikcI3k7+ymS>|m0QwGk_RUYO9r=wS1w3p#b?C%3@cJ+)` zPaxKh=bK^u+Xeo4$2Ca3g0YsWUM^J>)DX1X7ka*@mKQ#K$dfoooYCtA28#|{egHAo zyaU2(tX*1N930aNk)$F3CN@;4(bFyhez<vY_Clm*oylzT_vZ)2$Y15o`oPZrE!?Vu z%i@g3)Qqo0*_jQ3R<fd^0?+TMqVWlHS*O*Oz)i@vyKuQZ6G%fYiJz3}vvW^xm89Xp zCaZZyOb~|_MdHTgPH!}Az}E7S+lq^V*b>p@4Rh}I)@lpS&W;aHL#i<Ay3(B;NJ0bd zXQzI}3Hc+9o#MCzsqH=}%~w?%me~)$wwUUCFjzv+bb$)RjoV=>i3e|!K9!gq%Qri& ztQUQK1m(|YxkS$`j?q$HL_y?%EC4Xzu`CB4^}T<-3L<gkNPkKNQwaXaam5qjJ(B6F z)oA!k_+|CkH?hq@jR~vMb|NGx3CSZ<SW8O_=It;vBPIQ`+gW|G*=Wj-b^z2DE;77A zK~xwYBl7+HiL3CKRkbD6H?B}m8Mi{i6w{Hi$Rud0{~S8y5#y^$=a5T7F}-@Ogj5px zn@RuSO5=X~{Z_O~obsnB0UXdiHl6s5x|(S<OGSm(GAhTqTU@)R*hWgo;8ITx=xDMK z`ZjecjsRYB%l?VFBWo3_J;iPPPCfK5H^@<#aFQ`(4rhj8m9aNW!-HtsqpsUZYK`Q4 zAaC>8@$@l61^RR0?fvp0sLhBp7bx)IfGZ&EVtc=mmdQ_KP=)4i@YqdeH8_=BNxpE( zcBV^qn<~cwVuSTse^v@4>CJu$f3u5~9d_j(#Gxfw=nuWQ<Ki7WtF<M*wQqhDcegxQ zwNV!4iFe8s;@>XA+Y`5(Iw_8fq9YDh3y+?Me!>>OmUhX*wI#gu@*_HFj-XQ0$=opz zn771)>eJVQ>SUV@Q9V*!p354E3sEFl(%mhh07u2WgRI|;=_&&v3U4JgI0K{EqdcrK z)eNr}IrOn}=pP}lk-M%*&2ntqx{R;>XpAPiSNiHTtwCe*HGE(}wXmmF$V&;*>1wc^ zi!l4%B*Bey<=bD4JkNJ1Gg5|(QBNV&3F%1#31>#V!xt-|Gm!m6R)5q=qF3!wE5dMa zF<m1?Z{++dpP}=W)VmP8q)WqiMpH3wIFa9}5?1|7Z)l2NvG376ss9?bwzMZo%W%*} zI_umCge(yGu0wQb+@90Z^_dqiUAvHMjDlc5V4MV}m_Ud%TLg5b;C)V$Hrme@M0>NE z`HTgr{SK{td&F%3_)Xiqt0<nS$9(`4?&G+r*w3>+PV)WAaqL;YL?$k(QHS_R@IQdg zsPCrC_vNh;7)T-v5<d<NIC<(}7$DY^*_l7Z-5JQbkmyG7l4z2VmeBA;r~N&dt{+d7 zK$OJ~d^+gqsv{!t0)^FDP=*K@oS(LS25FBdiTsT3S*(o?)i<sg#vqG_(1t=x<J7 z^On|M;-b&x%>z53K|<t_<H)+_vXgU*jHkc+>1QsOlv5(FGVh(AkDLs8zWkb@OncP; zb;s!Kc8ZZp&d6V<j888{Nx$Sq&lSbUusyLATUaH@)3O>UmRr*)6DtWUFERgNcpW17 z4m0%kEN@pM`)j0DV?I!U0)XvZlKC65Z@|Rw;kP`pecB$HWQrS4EZ_n=Bj__dIDYve zsec}l-wFD@74h?T-3B8QBi<%@>O8h)fEmx4cW*c9ymid#_XXEve8gDmn`(LYfn;8w zWE;V|ca`KNeDCbIcX8m`s49{6*(`Z@ve6j5E&X_ya~k!b=%kzR!Y59~Oj0_YcUrE7 zl+IN*<}Ckq(6KM9e8%1s53_1)2rU&ZM4PhP<TR|2s*1bg#$>4Nv~HyaKpAgHNyFP% zNMfEu9<+dR(gv-jaz13b3w><g4-0C{hPqI)l6R!-4Ia8%rZBTBhbLj91s9J(iN)_* zdEISNmrw53@3bgt)HEx#_<QHC@6b*RHeC+&f)66o#!`WAYGE0{WSjF#&&vH36o+0X z62g&ijF>Sm6%DL12!^Rx;#s~y!RE)9fZYO7O9x#*Rg>8mVoAAkS$H^qD20WlR6Ck# zdSX=}6{sM>v6BjdrR$(xLzJ|=8U_Z+&G0b6)>-ETEhHL`<b~Sa?mOH6Y{8rE^4*|| zkB`So)9YBBigu1YS$h9+?0cf~M^OOxV=V2BkWrfl0`3vveOiQe!!y{H?0^f1{yD zj*rgowPMt)k{GRT%VlK$D0f?VQrO4v0v%piZ*mo#Pk^-_@_KTczgn23QWEpblbnyn ze%-Lx$a}sr%D7oQkI{jkCSlYn$OmWGK`6PR+@D86##g&XE!l4{Dve_Lz0h73Il3bR z{c2C7HSRDSscBgWJ$@fEvJ2kx{G65Yr=Y}Q$B==Qd-o?ZHSI_wxn#rB9k-WcK-Wju z7LT4`h7T}PG8)<3_DCV;g=7HGzLtRlrSh2)e6=QT<>CFjP4}3~(JCN~SeZ1^vH+;6 z+%a|3QhXq?V=gmzOBWbs>*l}dOn*#UWx)VFZDqnX&>bPhp$%z@@i=LNpIUxPpnT$P z0(KNFM=C{jO<cu98$;83Qev3L7g@sMOrs*2f*6Ym4LaG<-TWpDpGS95_&Kv<0;{TN z2>S&DyR9fVen(_d_?j7{6ahPlo`IL<!v%pFhyvl1Lr=`YET{DSfdPmpNFq7{<=4<E zQo)G5`#BsYO5<Bkdv|sF@I|54T>!2p_&4PieWhw~pl#8)=#QW(`pv;T^}lZ*Hqrr7 zfM<IL<_IUtl9YFeu6|RM@+DhR>Q*d?r9OG|Mm8iwWgs31Q(%l!5|=>PfVaB~%JLe+ z+)>@izp>e<yVU?KQ8qGSXZ*J}#Duzih}iqyL|o<<l-u>Z?86|LH6Hp3C1^3Q6Ou$* z(fcxwDtkk(l29DqNORa_X_nc!s}n*XbjT)fdB*C#SoUE}EJnog7Yy!4YUySugnH@$ zAJHNABUi_?ZL91_0F}3Y&%Bg8*m1z1?lyub2P<V8(zRD_FwmF=!d~RDBNTvGA<Gg~ z?IN$1TXQepe6^U-jZeOd78TUO6poLb*>%K6;k5Pg)s(4&3;7>)&XY)sh*aFn02PQ^ z--Fqu%{4`he&%bmgQ^Q?8jVe~tkB0Z-pOERzR$zVjP7cvQN^66mlwd6r@q=!A4Mr| zU79m!k5ki{Q@=}_ME8heEABD;^SZYA3-yzM9W*(yBuPo$P(}>jbXf>*i^7C&$`BK8 zo@U`RGg$qUj=~?Juo|O*2*2v<YF!$;jY}CPvO*8UZlV?S<$(y9wbFUOiHO~wj3hsW zUD%a@6>810A`N9bCxlO<vtfU6z@3=pf9$$<HQ2T~-$;gxDhX_u2Wpds(AA~=?=o>7 zb=7j!q8HSB)mL1MhS1_6=jZ3wyv=u0BZ-4wzW{k3+w32{B<ZAnVj$k%Cm+!MR!}p_ zB1hRS#x~TC7jDEnbWE!1tlX+d;>s<<wiV+7!AWY(_1Uw`&jU?RNWLoL)zj79pp^XC zF45iOBi9cYeXah8C?3p1`do%nDN-@g(Bwy5WHRACYRt9o)Gw2bv8ZQ{g^|KUerZDV zw2)Z6$G2OZ`{JdE(-3aOX@K4rPi*#&pi+?{>w}{Qgd3Q)x>smpL8j}u#4_1v$aqZ2 z_#G=g%%w@6yXM#tr{)={?M6JSBvZ=Yn>9>N(>Weq6EAJeGFO&JV>18>-SqHCC*_iJ z?KxE(F>xy^HL-m6x2Mv8@)4P|3vQ*kE~`Lz1kweV2RV`A`-sLwm_3hb%8@1?KVDQP z_>={2l@^;dPr{^Xz}>q$pBvAHy)RIwq^mjAtFzk;cHbn-8-D-sX=MBz8w!Dyw=E31 zf8B%}LO$pQaKJ82C=8I+uNBafeHFDS92>3l!h&%ZH5X@ST$i|d&uv8c1uW3t7j0Jh zjPu%{_5bFLppSX4?UMt$(<1+q0#gG=SvM%X1x8fWwglly;8`ohxVEX?bU?tjFs*%{ zPg9;X&NrO?Bk`vy1$6Hh^-WAnh}fn`4Ay-YLqmd--AA`G?<StEJ?Y6P{{#W(t-PLA zxz1xR7DK;!chX>Lxxaf@d-T3jUpCMyVl6^*=VbNV%`XE$AW*>Vi@dq0!~+5RzANW^ zQ8lP!1u=2WT0C(#bLmnH46;6-c=<`nGT*19x|zMx{rTUO<1dW(K7S=yELMaAFZYk7 ztN5ydXfmRLd{7e{bot>L8OAg3PoF>O_MrMGh9@$ZT&ZL9#xgBpKem&MQ+fFPqtrpv zpz6)|5V<p{5l7>5wiH&4dr}x8ylngSMNH0C!#58g;da`|kaGyR4>+A46eSm*wS`CD zLL>Y5Vs6?{LUH7x&kE^%e0A=1JYV1ew0w~`pWm#i|8pu5#SL+E{I+YpY)YsvPA7wI zM3;!+A&iaKd~Hy#S4Qp<_r{mhs&M>XG3Crlf<M64gz2cYG8oEdp>sTvRegK1va%8^ zvsGpBVg1OjB1-*YxBPy2_2abf+{_ZIT=D90QQP88|MJ2gRLWUu&~E*Tsa{qNYOcY5 z)FNx&3uyFTh4j(i%}U~Tx~o@6v#Wj=!n=7@KvzHK_&l#F^|P);)W`REqS1QKHeDik z@&QT8MA|dF)l_wtMBXNm2T43|=5(5VD7s3i4mjZ-AGu(x2W6916poZfP)!lWiDgJq z^_pz(C^s-^h-u+0A&-3bcP=N?*Y2R?4At}1=eCN!WGf<rg8Lf2yfLnnL_eTQqO)l1 z!Aa^d=FZ6wAaqvdoO4oRr8U4d;k(x@R!~M}?iMG|IaNv=8h3m}L#P(d!qd?vUgMV3 zltAz_HosP;ggEa#4`PUVfm?KJ3LCXs?Kz*7CdoI>H3ExW-L&cyZ6t~;puc+|(6)1) zW*Q_gnnuQ{4d_l?X2J1F74=+p7~%_KM~@kl_7pxC%m#wm6XkrE9Q_<eSS=|t$G5|{ zoZHMuiE>6l)@!u2v>w5sQo>pr^N~gsV&?=M;8#4%@mX9(#PM;&_8bfEss^wL99b~D z+B~twGB`wP64RRW2g^joM^F2f`6zT;sQO5LY3|M~`$_$6DgLvid3W=07riLha{Ya^ zU4Qj5J%7=-Ec;-ivF66H@Kr?sd(n>Rf&Dppl`lU&6kOvSqIM4|?#%->6@tuoL?1D8 zsJ&eH^WQxeP>~v(gvCWeu>Z`9-CN`r=qV<hUtJ4Mj|B9n5eOs8UEVX@IoqaWHJtcF z*W;I?SvQ)zb}@gs&;<Zlyh-RMvt?AN_o=Km5cVGm1icKWdp!I4r1Xn*oN#feVUHF` z6|VbEt>N?839nPhDe<Xu3KSrH>EJRv?y)-hk%UYpycPT#TCYx0DZ};sNy3jKQ!1Ie z``?oks}r%W^L2O*wLE-ctMZ2}bLfY`VmzY)+L*CSe*H7IUfIm98mFi%96bUXB;z?Y zd!n07KXh%-M$`7qbjTTJSiO5$mA|v6k)>o4(I5X|%eBLhdI-A=JzJWDPHZXbKyq>i zK2jjRf0dqdh|cIKd&|2%^NiI^m4Qpcz?K<CESCvNZ92angL^aWBqpYMY<3@Yd}d zqV=cw9*fNS_KuF>RO?9N<#5&UOY@kgh^LINkDFs>ijn`%0<>r%wdjpfln8F+m3vPx z@)m#I8LM@bxA%>M*@bqh@(&zE;i_~-FMsrz-W>T|ooub0ne2?fZ&n|A&%{Y=OlL|< z?yml-^Uclgm)Aef(i!E}g)Ne>S;Pm`l&Cv77`32r4K&MQ*HB`3asAEya9x6Fq%e$R z>(0-+Zs|`=O9c~`b8DYN>-|GeQ;oKMH?Bku(CgWSnIj9YtJ68SyDLf|lJI@t0&a~z zBG3WQ;~_G$tDAY8DI&<#VlW7D?^~J*Io$Tl=TO5Ub_4i-uB!PICner4;g?6I{iOBr zjx0#@$YqTEwD8@mXnc<>IVWXsq*S8%P7t@KK(<=(ne;pMv8s&nGO3*(M+&H{s`J*g zQ5(;I07OSl)v5OriN`ziz`^-%^iMBPagUFaXAXQ2S!&)&rH|o=A5`hCh4E<&-zX2C z2MxGqJPIb~X?3ps#UDnczmkqKRy^v-##V<#IRiR%`N6O319B}T>cX)U%~0+>tkGb~ ziPw@&HO>*Zxc;r=Q&mMLhZ$4DWxmy-Y2a=1=l9Q!Uc)Bh=UFPg?2NO0R^HY(CnwdU zPzkuEsfmgBAo!VprZB1;n=vE|lIu{Ucz7WbQnwM+i?RIkw^U=&m$DBO<U&k%H_lno zT~1ec$0n0=+ZToY)yH+&68_(t3>|;2P#G`tnbo|{rOf)x8WLc$>G^!%w9|PiJrj28 z?t@?@`}A?vJg8-1THF7;_&%Doskq~~rsQUSv*diQrTq`~8EfFCT>#j{ShvM@+kFmg zyABD>k=~6o@A`M#XRY3ZG+(o>6m=X$w=CX#kDt*F+E&f-h6@qNlobCdE$O&gy>$$@ zd8jSFJ~F)1UzIIVxKsEz2MP)_KC9}!Za=&?xXTOj)q|slBQB%=J^D&I^h$KQZY!tx zgfnzdqD1p%Zs&<rC#fwIFJo$3b)HhSBn*KTezM;U7=e6ri9hSnADuMEQc2-Sy<#3Q zo;;A+de5d*KVBId5*?d48IZWo9tHloX%#{jd?7jiecpD^(%*6<%rjB?$>;TuBgdp1 z;)CEg;t4UlWx-~~Y?4=f$GY6o0$dawy&<iXI=^Vrl=sfAquwed9W%?k@A0x+t)3OW z{zUh)vi0{G-7Z?=o2tO>zK(e$sv7Ye6!$#HVZb8V%N$eWBju`jbHmh2ON@USm&BHN z)*!MxrcG~IUYw}kC&+C3bRM6d+x){<om38j&AzhyG0Qya7`hk5DGP1)ySw&B%{<{E zUw>FOg5ztSn{b5&;I(kK%BXvE4n4@CN&P<8di;+j8ZY;Lhyl`nCw5xSswQ_v_eu_J zSN7A`uLZBQyq_7d#5`v`X$5;`ySdkK@sY^VB9mza$0H7HU}E&6^A?2cjmAioA!>qX zT%Q$T!1<bp*8<%K{ZxYwdK4a5P8&I<e(&T;gea*T8kTe=7G^*XvqG~SC)+_y_kG)5 zXL}vz*k^u0!*&54RcK#Tf2Ans4_^6h)>SPk@Lu=MIA}d}_tX7kIg(Yj)a5?*(^>b! zrqFCqL$)5X=I*Vl{13|ji(IuC5BVbL3_V19>ETtP<{h-6?Z@hEk>Sji)7_-P>DBe* zsMbAIpDr=#2UJh1ud_v{;&i#{3MpgLOx)>j2%cn|p)0>?^j76It#>W^zC{&WFqw zF-tZXvED!K2Lzt)^$3yJ61QE@qs%ixS&zVMDt{({<zc{ADlnq~oM?gt$1kgJCHz2V z8eUh9Ev-x$fL_28Gp>7fuUcM)W72KjD(mdy9vqrbj{7RRf=Ow#0@pDqi;7I(de2pl z7azOJeA6^P=;E1}8SMu`rH^Re0wW}7-;m2}1ZJYaG*{&wEGDFWp#u4!La{AZqca(u zBETZ}!**urGBx(2FZ+?KSw4VAUxchXOU<ma2?&!fKAc@_sc@`+kXnFrFfSShvU7)T zxrp6QPsMOwA7AxhHMiONe9>eTI2hoz^(1Q~aSX-zwNURxk=hrPa$HCInMVv3Ld+nV zX^dLqy1MO2XqL0p74>!;XtrZ*{@SJV+f!OpR)29UN+e)knu(Z#SxAL~-o0WZ5mWTf z@2ojFKnlM^-?Tc@1u$RlO<*<V_m{24C$iqac+H>UFQ=D_OOXjLU^reM`*O`)JoSV2 zD>{nxVde6-#`5nKE?okv+aFpK^n&)iGiQ$j^&bvbZz8URf^75^?te*~!Sq{-)n`~Q zQ6Kdm4myq<c0YA&mtC)cFCiagx2^T-5ETmdE)R?7(D?_>vsXb&>H)U1x@FG0742e0 zcMDcAEB_7&2UoW~_!|pFW;38r18pX@7VPYRCyC7F+<qf3KR;jb)y_<b{@orF|B1)w zgr8X<=f;pct`H;XcafR{2}dGL_E{4=-n|KI6Dhn{<<8fRwk%OkK1T(q>9FlF%3J5i znn?sLR7$)1KLZ!`$45{Qxoj+ai;rpBAc{v1nP^;pscE27OwGvss$V@@>L*mcY2NM~ zU&+EkcVVvpPl%0H0Xz38K(#UxKV89zRqlpVD#UXcg_ELG7X5dG5jlxKped-4wy(Ah zuW?nK`w^5vURd^Tc8(Rze&Co0Y`B#WtIQ4sbDs9$xI4^z<L0hqf8ktq0=E_7rV+lv z&mQr=_mF0G6(C|B9wCo~@bIc>7cLa?F)Vo1+xMf5eT+aWAL=9SP5$-QM**%@^HhdJ z8fr3gSa5gR9>W$HZrM|v1B1v&r|vhRD6a4(xwOj<0QLr2fz!0>yOi?p@ZUpl8Awc7 ziy=DcCCoWhhI_z<AtPn1AzOc0;bAOdh<o5rJ(1w%v^L58sH7armlDV>Mr%NMd$X~z zQN?hpgDQ?EQKlk6ujpw9CV^MO#2)*@BgE#}(zx*?FL@rq`MG!+Np2cTEx8RCh-4 zZun!%N4yr#fJ@5$vohM2YwEjPMEPzR?7BW)vjokWmc(&;%C>2P%~o_hfgqcIuZXYs zz-eq;nX#aLdBHR(wh{LcQ{2z*GjX3a!gfDoDrY)nis1x6>8etBUZt6fAr2r2CKj~k zzcT0|T#Gn*8rTwGvjZRxl5BVTny7@Qa~#!XG9gAqG>r=?&pXtOzqR+HTf||!r0$@- zCmWZfc60hcVAOvy%!NJixKwhul`Zjg%}I;{d+n)Td|ce4;tH*w{C~eJdjxj>11pw# zTEP@{V?sIF`?0jlZqR3pNE?XRWD$p<dX07oBZy~=fY$-K{Q@hkiap3hg!A#G-gX%U zh&zZ1wqPZ-_oD^Z#uJw^yV}y?1IInc^BI7GM{D*MAU-U%kM13hMPP@^yvgHGh%$o6 zw1(~luY3BDHK$;AgNAJbUc8vL{s*Izk@J^%o`Wy9V>_X#W6fEAO-)USzldx2;7RvA z@C=H1O_~xg+GlVAn^b`shCBTJmHq7!53}Oo)p=AM2&Uv^E>q%TcZqMobJa^dE)pxW z&*{b)S>tBa8~nu(<sK$pPeyRw=!>f@JBlL(izTGIrCSGG8w1s^x}BFO_YXUA(O}>7 z{tEtgGr_q!M5#mb(k!^9Y^ytGl+>oK;SY<n(o%D)@r-kO(H}2Uq1lhn9V<YYA!58l z{c=5K*XAGe@qAve=fe{=Z?beUyUnYz$}f+<;I!_`a6N`-8M^jw6Lr<A+6vbpFTju7 z_1^y#y&W3LPoewHw@!HTSULDoURqw@hM*g@oGi>AFSht2GUb{I^aCboDRcV5(Q9m* zhZKP8cM{`Gv=$c=V5KJM-zPJvzEvJWTxS1<AGF{s-|f#j!EYzj74#-MG7lJ27LC-J zdV1t%#@!J)PyXl6?`*ilBMCVvVZn0lslkcBamL4l_vPX4&G;xm>*5)R?4v;<La8uM zBLg%KIvzK5HQUvWFfCFu2#q%nM3-TU(J5>0Hh%_3gPS(Gx*K@Ymtf0;rnso&2vqQF z51>S7o;q#S*|SKmzxT5%v^>4vA~U~43gy-0nNca*kTqJ93;*&xR*GH|DPfWIIeZ&8 z3ZI(h4biXU0p~Ah{3EG0GQ7pq@d(AzRCeHZ!JRzAg8nTS>J;8lyts0CX0;X@irtCe z?Tf2-tB+_KEVy{DcNM%<_pK<MwlA8YJbfmuo$<Wjvd2SL;eoJXx8m-1eVi95+)<*e z;^D7FK)><QbwyB9$-`FvYFWqad3pP~tEs{ztYX)_q}XV5cj=*N^Ex&MQBw0qv(0$; z`o80w@GN~*x+3RhKl(aP-&FU4Z=d?0_}MSn{{cR==`vJpd7XBx9guS9izQMVdb55N z2vkNM+$Gq;0D<!KM4B&7_+V+_{R+%d>B4<}u1-sN<s?9w^*7Hgagl~tz&3S#9T33v zQdngX)Jo`^c?`WvCmd=Tq1R$xj3lGwi<-;ap#yAhJ7<?h7X&&R#(3OrVs!{GsktJY zz{_t^6XuA^wil!TBU(8TMEps~)yq`+VqPYKsbS#=RgaDQze3=zz<6eO#QSer3oe## z%)Im1VUiO1%T*!_KelV7%r#l*mF-Kf9F?T8&0E`bpI_$98oqMK?81=WB79G=>Qc>+ zUV)wA@#6Wys0kiTbj0IqqR%=~37s`n7QR_Tx3bgk)?0!x4CzBxd#$|cpo3#IxtklB zQ|do>a7;<>v(1;v40sry4nf#kC_yni0^Wr5WR8B6wTsarU!b>!ld-G25zb$8C{199 zAL1g~Wdk<duS?qKr28-}$O&Kv2b`O)vnUfYX;DgxMAHPtCC~J<2eE&$NPEzy17U-| zqZ}%tv5{-7`gX`0k!{wN>!OFf;`R$r#r0T!NpI=>bkNb@b^Jpe>0JEnU`|EORa5HO zr~6wcW^FIeEBg<7`b*bNt7m_%FXUHdyaM%BZ#zuqNCN|n70x9TKCWI<nwqY7oUOMN z!y~Gbc%*dnVW4Kd_zr>U@_#iyL&cnq4gNVnkK}gdKqqNPei9ja&`cl#fW@U`mzQ9Q z$>(iopHmZlIpD7@m@kSJFh)4(E*3V-m&w=&>1(I+V?M8mRnw^}#`+LmQi75-3k6I^ z=?~{CB8t&Y-U5Ma@so;?nkpk^koanjdhY1huUZE2IKs8KJ0gMnO^XQe)6^>`lsVlj zvT^BU$ulQSesvSguVWWC)pYOQ%n;R?A*%>)Sr{!Xl4^BY+&MP6Mox#0qvd=Z71qP2 zFUIESU%MO@6u%X7ze)H66b;H?sFHMCv}Jk4%kRdCjLI#{5&&>(>z)~H^53F6h0L}Q zFu6SI6n%|L%8p)9aLVM?s?}B>LDGzvVGK-Tiw|!Tnd=(FufnG4;gA2_PDZSWX&((K z`yOxfQlbwd2Y#A(;tN#pVz@VKCNst$J@hp!f}(T)sX2XAG~Mrwi^-0oPc;SVGvjlu zST@>fr<ZZTK{^{Ich3Wd#cIgXC6M!tQ|J!n@#F|c5zJxV_hnTHA;#AL3m^=9vucwS z6KnlUVDQQ;5xq|}ZGK71rA;q%)y8eZGQ40J9_Wv$X0!U}_tWc%ihz>9zY2F&0f%$U zvxfS0^Im7iAKlG@HsbxA?kZNnZ};G;0;K1=<998r6$-cGEYs**gtlM#*S}V860hUB z{l-RC{NMlD&Gs^AE_N0zf_++bt(GW4u_vaF7wY2uDh{|e)<3=arbWu_=_^^*{U>!c z{C{S<JIF@nDKB|#6VOs8s-y#F(}VhLyQqcS`a7Ij5AM?aL3F-XKiSTpm1r<Nd)+ww zo;d<nQGeG|${Q5oJ|Ig)L0{6=l>2h7t5U2d!7<XVJgjX%1L@rr?}J2_Uarm-A#0XT zfS4RmF|<O=>n@VAch)Rq!{F;OjeGQL1z4j^VGg(du(MScBfxAd0_driU#&5)yZj<0 z{xWx7S$He8rF;*~wdPsG8IH#Jz~V?+SvMHn9huw>Dxb2$E`^NLx|aD)$IAY0JEx4w zmqoq|9i3+=`}H@yis#Wna%{kU@<zlaO&Y7(aQ~B7&*I{7BEuJByJeu!;DVm)rJn-> zhIZYAlO}klCbE%w=c4|f#~U`_Rly!AM3|!DBMfH?DK;E$%Lbj3G~;CfDf63m?X27- zPoP)w-T6drmZk603H|xA#2cJV4@7PUQD-`SJ__nzu2fg>OaE?Q|77?(VodQwpN+`R zy>P6U*?H@`M_maP8i9B8iS6CBA49k4Nd)j3mebVTMj3#(8Ej}Ladh8^RX>`4+WL%{ zsZ}B;9pR;465p<ScpDY3qq$w~DSJN()}8a-lfLRyyc<-woH;ABIqgRcfOUmj4(;m} zbQ(<OR<CZ$?`Kvoj<3h%8})ykH3#k<J}3pOMwb`Er{{ufE6%^`)<GV#8=GdLM+x(= z{>WHm<(CkmtuxRM=svvKT@2VZ)79KX+30!?n+ELWKuYdW5`neFaD4%NPe==We#3vK z4HafA1$(Y0A)a#oyr0;PWrsG)qniqX<CG##QH&k|TtD<!7K~T^J%Krcp}jH9<s~&W zHHzyC5mp<l{jZ*RS<UDxkDH7*PCn-E*q@KTXd>G?M7B|dj<RC0B+H9(**x?5eHm$4 zG^u=^F47TM^_&*lS}=)jgR>u_KJw_sbjPz{cmiOlu#_|}HgUVN--t1~jfMc=HvwqP zt@Ct3t?)~>*If8^SH@B6oBPBT)40{Ap)!efMRzA=A4D^8niCv8hvN$R6XRf%wwqsd zO?TJdv`ReY-KO_Q2X11D7Y**dM=^Y}k2D4^Q$<g}VpYO1YvvwP<LP7Yhk(5OHo0PR z3XC>2KM!V@;PF7b^q=28>+hQoYp^N1M2}^lO-gQ<P~=gxhE=B$($`2-p}B=XK?Add zsw(y`B?8DO*F=odrO^<PPf!xN875??$ajG{TF{xi`3S41&L|L6-QExN!+u!gi1ZE9 z7Qu*?l}uEel3mYW0>ltUC2T*@mFKB_y5MT~JY3TzpvM1@=fTTZs617-&R?_O^#10f ziBR!g%IF-)_oeHaptIAn?vir(0Qs`8#aZo#)#&S6FJruiY2!1wjz8bdy@!qJjh?lb zw%vdYO&b{ektfckCA~IBrtq_JGZVpL`=_@e|GhA_qUpN6Cp68u_rZRr?b*?rgaVWo z5ON?PfJf|QpXj~dz!PvMu8i_9zN7%TV~zWmNRINkZ~nY3N!6(ApL0p{WZuT{XJe+r zGT1?2|Cz_L>aU-IjUO+n?&t}-_`n3Hl2|o`okiux5xuWZRn#^l^I@F8D{G|gXZrN` z7=DT4$fj*<LfmH?Mnr?XBiqv_r7;;y78_>K#J^iz!3iwVDKj>Xk=l+?N=ep>p~>MN z>X%M`zC4BA)mb%V=}4Vt)HOdwTKMGoRx^H8-h)Ni<0rDqXPcPc8Tdf6=`;G2y^v~e zU+KbgC(>p{_%ALlZhB(QsYvH#$$@u9a5m9KfZS^#DjLyLnD{sPG7c|visp~jmapbY zbd(&%CFnM$Edss_tGeFk2#_{9BO}d&*d*4C!q(Q1kY@obYa{s9$xUK7OClE}>(Gau z{ds9}LrA`VV@TIBa#8aZo!{tO$Pv|~>ye-NqHrpw#Gi|y&sye+N6{vKV0COg<ug|) zIcs|i!V=v<NLzGt*2{%6es|FP{cQB3yMe-eM@K2^T@b2xRu|SlvU_nG&02JLlhUv| zcUb07We_x(b7%Ij^dHBcI&RusI8vpl>_RJZ00YhFaq0o!nxuzFCTxcB_WLf<Kv#?h zEtStweTF}t^sO;ri2ym3`_bt#KBR#lB*eAiNA<}9PUf;gB-Q-^hx?<_9xobGNpyIG znkvt3m(7lW_upRLtNkWAJ43sb@wOAk*qF7`os6Tqg+#?NLENC2KJ}g`_F(yLG&LU7 z=bp|9G{|}qdB^ljk6R+Eip_aUNw6y0x^3OLV8d96h505OZ25c@JvsM?)^bcr{Y@Sg z=W99{cv#DoML`D@{+pdU*jSAE!dM)>8pPb}sYcvL2IZSq$o^1QKbMB3vo8OnX4CYB z*Z5HsT!4}|O!5;P4B%(j4?Y$hpvm#tg&+H`DKT<Ef<v<(&O*K?!4*&7=#~ps$5uzM z|0CFfVZ+ig{YY5F)_taxQJ^rfSkr|^yyt8-H8Eeda2M<dg&nK{y>NE{5Y|oFo%l(z z$qFG1N3>S1uCCZ1jjgTw9fS*S8th^G+xEoN<ofJW)bmzSyt?wTWq@CyahP~k`~DSn zNyvJUWI@=U+a+Uxg^vdgby?F5cPP?1@4%ZS-5NuL@}!q8+zGKFU|%)wuNwHT7sIE` zFm<LXVTgwXW8)w$It*}b$>$<P?%Ksqu-C)KdOh*!+P$y$_2;6pP&kAOH9*EGxw63| zwmKzCf`58@o`UU{Aq`fDiRC*?!ST}XlqJjg0R2M`*q$Hh@;MQ2T*H9pSj01L@G1N| zxG}{?ZVRsbS03c$SIwS55r%;as?I*|=6M=(N&25mz7X`vfJfxUhk5p=kRU^-noB~? z9_2jD8oQib*i<X13!nCJ7;6oT^1YG#ZsAVVa1a8U5Z$mj{bY0>O#=qcP1!?62)*yo z)gG*0v=zq`U|kzZc_5?gkH5%2)3-|DdSWU7v8EjR&^}?H02^YShOlFISd#4*{Cw1} zWCP=5!`%QXp!K_U3FTnf$@CZ<Jl~G^PpXzt<}Os+kDCQFU-f=-aW~*cS8SaLT+$zw zJNRh+U@IFp&D7WX@r`#uGe!tW@TKL^1}||u&WsYSdVK@0+U_d4i>g(09FZ&~vs$g5 z^ur)~Lg_Jz4C44<W+dU&4doM$*qa)0&Zq?9JR=pw3S%CnE9upT<Q>z}*(Kj&Fn)pS zhTQ)uvyy<TO!gn4I|nFVULCO30<<#_WQW};wY7!-$yOMT4w2cn>RmdnX|Krq!i#su z-=QPR<!W6j=}q=7(GMvWj-OG&>w!km9ZLZnNbqiMy%?Qk&cXY0%E?=a*suCpm(Y!) zPdKi|>5@K}6mVMgL{YED6jv6P<iw8Ke(sHly&6Xsy?ZYlr*bCO$JIvc7n~Wv++35c z{EhE=gakwVR>))+MuB$rfk2wBsGP=S4B_7sQXzJj0%r0+ry38Q1oc-Tc&polB)(IK z`^!roVRoh?qlKTcl)UR!E+mVY1Hn(k36^BZX~NbG45hrSS$^sjr;uls>y?DCMumBn zXfGJfGBG&}Y+Dtc4ZXDEx7c7ZW@e<RW`2)IwtZsP$4gP#qU)IDK|$W~Yl;8M98BT2 z3a?un4WT)wIXj~-5+{AoPV61ruI@K60=ylVzF(%&|FZOU$x1w&OqP^3TJ-@k!l+;D zlcf?C%SI}JZ0*I`NAzG?`U{;x=l<EW>R&18PZ#NAnhm+EsaT<{)fFZiYp4WV=Ko~S z)_XTor~&$}cz^q>BNKpiq{6h{ASvpfv%db!;x?10Vx|Oba+2AHy3r;IJTjk|{W9rf z$V7+bl*hyK8l{%*h0))8oEQcPCqakjpbc+4OSb%wea=nG{OI&J1^n47e@g}B{>b<# z<^KE6P=~7(;tJ7*<$5;3YO(r}Cv4Gr@^w$cU@Ey6w?VYN#<R@n=9Dt^RG##3^s7OU z|IMpj^#0Mq!@~>ss<P~qhjm&rnix{P@d%H}@`iRHG8?ifSdbh;e3K)YDB?dNT8*O{ z^~wGFHlyfV*Ec8qpQDsrV%-$J1FR<yf!0jphFdREU+LDu)YrSEr&oIVt`ytma>Q9o zKiHX_Vv3%xL)gabM=7iLDzDTXKRbp(UET$-(GPOXSYmKvRVUDcZgMNtGl1B&@x7zm zecp!W<bjFIsMs)-vWVYbAl=^dLBsBWS{<u|3)1^&<r8}yT}JWOc80oRWhSUI$|vS> zFO)?HoMWzG_Ygk!oR?yoUv?7jyAhBhZlA>)*xUo22>;tNF34WUx(XNbqN(t3xyp>3 z2Y+l1v+~;*4IfDm?-6(mtGoY0ddcoPXlhLeU6}g>!aEd_1Fu(9gII4cV(oq*t2cal z{HcZFe*enf>|fUQO$a_Y&st5tq*KGvzbM8RF>8sgdPsVgDvaCt>^;2@wY(2X`XL>4 z`b?XLD!4oT!xK~X-da}tHY)6?23ObD&8#xt3d$<IAP}jiR5@8$#L^B()`g$}fByc# z7yV2fQi58_8fH8TCx_VWW8Mo~Xq~#r_*}>%4^Z}8BfXML|8;iD6^6n<rL3{L4(>=y za9YF=v2R`#8A0EHaK;eT7!f_jFy4tvH0I@<06rP%bZc@+Nr~ddR%zBybBRdGz^Rqj z%`eiCZ}uxL{2!e~b&d(@%XVxaT{QiD@Z6;_E>=AcPQx{+dBO-yx@>$?JZ~!vXnsag zrR?zCWOG5Nvc&KV6Dn)mCR6<dz28w$JCT5UZ-`Yte8j8efReh8<(BVZbV8V>cq<W+ zfmmAFTg{Od)A~jy(+GqzeJ??m7rV3_l<Y=@G0&K3y?4_j`1ixlnm&WraXVHSFKq>+ z{#!O1(GOu?$xQHRZ}1adJU4Ltq*RC-^mKQM`N9k?TJLK0cK7v_HQu)#e59Uh-_qd- z4dIJJX5}=#sGiCI+e>HoYqXroQaWzZjUpn>|DpNnQ`+D;1)%5mX?aD(jlq<Xb`LoT zk_V=KSnyLy+fl7ks}fb^Hi@{<a$MXXeP_iDa7>SCo=@YTh{~uO2)k0GAr)p{L63@b zEJ<4sb_c-EEMLmLxm5K3ly~Oek*EtjNcS5%b$iwSvaH^N-Hg*2*~Fj;tCX@O7*j3% z`$}S1J)?~sKB&R#-n2Od{!{>7{I;q8|15wLf6no}bF9(xn7B{Oi^L+}n+bWbl(k{Z zf=$az>w3MbK+uf9wy`#V_YmM&tN$4$I?P!pjSYLgMZlgZmFC?rcrZqzFhICq<&TA& zPS`dye3j)4TYraoX|3l>^mH?kqNjGBSiSaywo--?+4hGXZ0k(32@FiIZukR$z|LCp zN`7xU_gjtg0jAL@IbGcQ_0<-B>TK5eZf>0~OS5V9p1*OyE(vY?JkT6KlG1;N4$h7L ze-w4jtA#$7x0TkN##PI3W@h4QxkT#I2(}wh!fqC_la3zac5p&iIW8FEn2{*~JVxH= zu9eQ?z@nB^e<!`o_JcC#*yIoOc6kJ$Z(N1R&Y6_;Wy2%@>1MzoDL}Q8BK1gE0sqn` zTEXeQ?n;>;O9DMdw>2i{tw7DETuLhna>h{^X8`|r6;BoE>Y)Kb)%7&Kx@(Q@XM_pt zYBbNn`N)weNJ{>Aei1m~LGAsMU&s74_URZi?FK7Pqn1(WXCz1GNc4&@Z8tpA^y<~5 zWlc69>~N?)%#FLDWVqFtL?dZNV~0bmp<B9w5t#m&YeBF6MDMjii)#IX<8@pV9~M7F z$Jm82C`;wX7Iyc`<YMb|m6IE$w=IZ)n!Jp|dNFt{-#e07G;|6RFCF9RA^M&*kf2l0 zW9A@=Y)khimE}$5YxG_@R2jk1gohw4!C$SECw|k46n;n!)BIco+OK|s>K>h8U{so% zMM@cjtt9l)EKjYxQO6NCu>`<peBC8pivJVn&-%P<@H0%Jv??U9-jC7bTKu6-{ra5S zx<OJ{@Y4FlP`XnUXGhNI{11G%8PBIVXo_GXJys9I`gh3HIL<HbQklT7d*%u?f0c(- z(8dZncbz?@O2R($rY-?1+-po@m=BKUP=%S()gz(xmbtXsO@wsj$n|j@G>#nJgt?}b z#vY9_!eB)MAx_n4gBJ_!p;hZH#^>bc>oxss?!P9)kg+m?=mgsbG8rR-s5w}WlPcf? zuj4mq^t6Dg9QN2}atB-&=(u(<iQ4v0Gl;hP^)Z_omi8|PiVb?q2^6L7oA>X=+DlhD zu{E9nyr1CfUEL9Vli{^;ZT+_pgBtK*GUgl4BSiKHvT|+FVbr(ydHR{C+2sfwpKbOa zdQbq{8;N%lhJH%F`0obV5(cb$!&V*QnfX#0Gd5EElGwVWMD=9#`^LY=wXSmYJF?n1 z%n10Q%94Xmueg1x30m@%dqcPJ{*KrSj}QXvc;>hUQvO<1Sw9(a#pQW7(!1YN6(v%i zed=6PqeT&iQHoARn?sjZo12?Ak0;a`S^uf35`TA_Ujdc7yO}HACO5D*h86$)oX@#o zj!q*Ft^SR1b85=u$$^HmEq@;$yX8#J%X7%^X0Ai~^0V!1Td0>PoPdnM;=Nj8fAuP} z<^5@CX|a92Y$ehgyT`o~*zCy4%>0WhueKQ{#jlwaNf{c@AK31lAMw;C!&Qr;dv%E? zexA2&!|}r0w)u`coe=%!0T<DiQEv6?)<1`%D2YZJ?CISi2&)9aEsE<96o*J;20xVy zpnB>fI^)x*U)2gs(l0bdUyYgYB}T8`=6wD$LY}>5;q4%Wtsd01GnM2UzY1kN8r{SA zikr<CQ6r%|+{ti#gE0FY^1Zt#031X9oPX><oua_;0a9HZ<?2$tT%%rq7k8z)45xn6 zDmh@%HYrIU-v8(f&s+VyZZ|Bw*LF+bjTl=0SbN7$<#&`umcv1KTffg;(B3}ih3vGN z!@TqNR!1u^Q@yPgFsqO>zvKkfzDKh5(!a0>D#h!z3K6}TT7_X%4qdxHxE63m9bgg8 zN%`stD?Q-RnA?Yc>XYw>ia{%Bw%jmjHbLPcc<_ucJ?!Aa#HX*YP1YO8H`a_zPTDq# z45S!K91%!7Q~?J%h+X9;cVXkxL@vfg>hHq#{^@)ZU1o%t`Hf!0s8R_rz*t^<Pzc-# z6r%E}284*?rK!Zxu?bL6$XoYHAaT1I-_iGw-i}{5>p-c2cP5Q<;i<;DGc4gqXiFvB ztszkdsddZ@m^P`H3lI?xV%-b99J&4ah2Pt8J`{BtP>;+70?7$FXoq1m9@&@ZT(mN= zY%Z}eq5}y_JL^TAWj3;};gde#?|B8uEgC5`{?!mR0sb63aoyok5V8JG%py&8xwRMm zJF;bSdm#qF1@s@VgxJ+)eY|NLFJ_my4jdg=@HaEzCc{TbnlXCSv9x77k6yw`nfHa& zSM2K;TD9~J>Yr2eoKNHde<j(}0;@|DWf^%ym*L3*8u<B1eHRey20T()ykL=vlrk>G z`T^{ySx3O$>S0Q28-dxUis#}nnmNzAO~eKhxrUh1rwu`4V)BlmYBVR(Swmakce;q& zjsIxU&9nQ1KG}UY(;2HN;xStadS!nmbXN@^H6$(yu{ny#-Oip}Rm_J8&pRw%W}NBT z63eXV4wZ?+<QF&)TfuG6dtn#p$sh#haj>(?>57{%!SQa08diGSx*ADGCIopYqrO>F zHqv_oV|DtqtMZM`Otlhq*<-0n&uVCywrX#{DiR!E2zDeA@~(7Va6ut}sg`PSckj#Q zjuQv(sU{(9x<5Q)EOzAG(6;hdP!$jQDKAaX7G#=QO)az7lMJz@+hj`@c{%;Q#;amH zcf@EjMc=FPkZlArzhtgFriE~0B%%D%6DZ<mbt*yfO^>1xmQeDuec{J;OGmtoL^$ba zLOBc|3hY)^^vwuPt6CQ$uHeW$VEwE!*x2C#8jX1UikrBgbO%|wpoFh;XBt(F^U+Jg zAA>6}#ji%k5^SY5by>z0W#S>=qtMk}BC@hpR--kX6S0{h8?+fmnI*jm92I&EGMYB> zzf9XqLcjZ_xI|l1{j~Sph5}oz73-j&bcWNF-z>P&UUhrTi>P9=Hh;qk8o0<J{eS&+ zE)q6!Wqy8TgXThypbo9_An|QF%&+Xzoxupj!Ez<v!6v#tU#Vy#7IhAPUx2e)azR+_ z@7QrNGc}<r`ZK{iO8%R4Up=9V^JMtq7jY`WsvnK{$v7{W#KI%X!+|oid}Y2itnxwG z5hVCX2m)6Qg*YZXhIK66+TH9Y+Fmx0T`<&d)3MoM$GIdiKF`v^LvZ&&zt%VH^#lfX z^!M3!qI{2}Rh_-9BH>N68@pf50OBidH8M^#WDX0jBmqE@ZaJP54N9XOZdsYx%mcn_ zEqEA!Pt#x_8q>RkCQ4R*-k{^m7tzqz7z5jHc0Rf<e#P>b6es2>_V)g0ACyS)=&81i zKC;MG*zi~BFFI}gKGWD^C3nVobYwVOhzIh=+(;MuK9PC(%4PP4b}v9uUXNF7E>uM@ zf+{BLn~dd*D1}L}NV$rL(A2SHRWG_<pJxPT@j^QIm0S$5le7G4nUPW9GHZgWAZ-2Q zlvs)_>MNtQ@;f9mccp*(s0yrS2eM_aZK;AtaVFO|Ac?&d9Y05VC6#}w2~H$Dq`X_4 zboJ}@-gX)ixpw?#;F}%7Rcu6y!Uh8mnhA*iU~Y%DEpC5_etASryxG>=ygSZ6CPJGx z^$OZHuL#dOg^+N^&ziZXEP79DU!wJBTCmix38H?aqlE&=K}X$1Kiq`ZI%wufKf%DO z&G9>U8kjmY-2)Y*tM_3E^g{BHD;Szin@0aNa=W$Mk;PS!FQjG^^@?M5;#A`3si~3+ zFDRlnmLLlrGoG5C@I@hRzcMj~27C}4VHVvARdN~QTgou7T&~I+y!KB42GVwo9(#&( zvPc&h>|I7Zc%eho>7p?~eNh_Go0gkhnT{l=@v*V&r^1F)l3REJi6H*mEx2i!us^T0 z*9Rd+CEC|aYflf3P+sZi-Vp^`<}(k2i<fKm8ubNj<aDfiehO&Ok)MjPT&;&GrUeMR z6;My1q(?(pcqoLEmrE%0;2m`(XZ4ftgDT){aSM)f7P_saM$r2{sar`u?7>FOa?aD! z*H=1NjbgvW>411;h6Np`^?y9QWmJ^!_dTqLgn&p2NC*-VLx;4|jWo;v(%s!C-AKyN zA<Ya8GL&>k=MY1e4BgE$e!jo|v(~(rm$T-+uXCNV_da`1H>szffcz9!JD0qLzz7>< zmQ^oFrcW2EJAp~R(?6!)z1xD{TYP{FY&=loHzsu~$NdkF`vSdvdD+64WIf&Wu<uWk zT_Mchpewij@$giOucXBl1GLv4Bup;^sHR7g)LDvrI#h`cbiDc{EGO^PNE4ZWnfY9s zs*80*U-@+w5zG;u6%Ee(cE@kRqH_*u8_<*6T%ryQ^A&9SwwE(Q>D}u(*D3}e#?7fY zNhM$oi&J|Wn6*o8DKen!QqGn$<Z2oxsKzCN2sL-L@)FN6e{gpxms{HjYr=9+2z!G* z`f2u~s9uAx|5=PK3X(>n3@d!vTsx@OD{d{`(PE{*bNUh2v|0tmdI${x$%?jW$JEx5 zeWjHM<{y{5<&dAdcvdYGj15xJRO&aOU8l@A`DXYb3|g3jb$M|4CScR3bvoNFHuhS$ zG6{Yv!NmOSF)2*-Vu$M`Hv;5;_`5hec(Wt+q+9-O-_-yciaX<-Rn7a@Z<-{ZNkp#G zu*b9h>}%{K4!|7H`U<sTt;`Y`aA4NpWop>ZjA7LEzDrQ_Fw^dX_bA^FienF{gXxEh z%W@bL_BWWb%VJ|F=HJt}y-XjqoK|Min#Mc2Nu3{cMJ1rOI2eZI833ljXhq!klyp6- zQ0%tr(9^<TYc!eHiJ$-r4_zjL)g{V`V3<>WVuy&y6B$u5pPc?@lCv6eEX~Fc`mtlx z=x26yv7zaNJ~`Dn!S;O)Z32DbqbLV)eN}>t5aM^<lW3X!KSQcRGf$Q#&*tes-AX7w z?JN`aCks4vLrV(G3;Wfsc4=;eYd}eKgYE{|yk*B7Jw<|%Ea6dB$rm8g?GM&t;A)9P zY-Gy;|ErT=!xAu7J#p%lolbAoc{5;hDB<gj828Ht`<*Fu)m%}O-|6Mn1x->G{Zr}) zRxBea1f40JdDVUt`WtM(2PPbc*ok2@o9!XDYF*r90M-n^z&<}O*xPL}>zkymfB=g* z^ZkMb&f*7I7Bvyqsoh0Uli+P0C+Mb$U8WJ}YbQ4Jb+AET?fM%1=z|n}mDpm8DF4|I z&M?Zis(AP#!sU{2w`;`4eQBl1@2WcCD1a0;`xAe*ZNdGIewv6}WxN6Szi#c(@Y46h zpS$b9N{zg$%Ns%U`gIoER<M}zkskNM<*rEa#2Jj_vrAkd7f&c~LGkBF2`Uif`L<cE zdBopCSW64#@A!y7EcM9;T5r0oezKr$y&u)@j(<G&-m8}E>yvg#>KuN|TQGwgke2SJ zB;Nhq>;I5uVW?|P^1$o-?YY0Y`w%viHazpuDH%`8_8R|s$TKL5^i_c9uvE1%7bY1z zbDW!8U_rK*v4(x68OJ*P>-A_DC_P8nndVn<f}#qc##_5Bsjd$SoZ0$Y6iSRq|A`1L zXQpkYRVm&|Ipj5^yf8+n+ooFZoDG@rcYSAbj!D#LkU`Wt^#soj%->f*C=)1-&=*j) zmFELymu3w*FOHa^pS>j*T01e@bSD~8iW-dScWK%qqWwvt940CEZD7km(?m}G?S2i? zMzM1qNJS#<**ijlX&SDFd$8hV=iR=lZ^xVZ-185D;vx+92~KT1Zq^45Xvi?Rsm(T! zU+s(brW0M_BBNuzij}IWDkfu{hlq;aAB4j!4fFylKgjJ->0tCiZP@Og3~*^y=dx<K zG}m$yAZdk*ziq<d&XxQ&x;6FG1vRUpn2g+KW-py2A}SU)zb27AiFl=hG4=6L&=)sn zO`vJamO6rnN@r#`oIeD!J9<>=b}YBw!Y$6&nVu!n*m``0J|2}tgobi<&YraGIb<3? zzQr3Jg>$Z|@z=TCB^6C=jeTHmh^LmeS^MSZ(EUWa-+j-jzPV1+d2hf{&|_F?2*J(- zVGj$spcUgzXKK<Sf5YfTO`nn=^I*@u;wn!6YY~b1iAfki98BE7BQXZu22ESCzE6}> z-x;}YF1(__JcUG|Kdlb-w!HWC^}T=AsH&t;pRjZE5JF}iJ)Fb`s=SDN%9IA+K0v&p zg)u^7KtkjDlAZ-uo(=fqpyr35g1T2hObaH}WOY%98zn!sNZj=_d;1Lgg#Ie;Q#;+X zp=i?Z-jm^`Pr_cRe6Lk!Hpbv=(J$f#9I{`tnK{za_lL2q9ZT|s(8tf>{i(fkVeEHk zP1i|XWM%TF7LLc$`c6D1SJ=KcHHYpgcw+hwkw)SjOk62#W<JrD@)Uh0vqmTRQ!xBP z*Lxs=uM<j2znG}w@$D72xTQ!AN|XVW%nsi2AzZ$?WbmUD=MBh^wx3X?pDwk_GkWv1 zF9`h>LdR#CLrEH6-%Q9KyK$?(<KEX>ZQQnuUD3B>=xqJvQ@*JKN#v_Xi1dYL)gj#n zM3EBjVzskhXUm%By!g0;N}Meq<oiPudw05T3MDxc5T(WopJ*M)4x;BGU}Z;N$muuj zySMx?h4xx2-sGvwknYZkJh!Pj(U<w4Y=SW#Zr^uK$mv(~mSJp$KqJF`>>QKh>u>ZU z1QQJ@9N*!t$mzpNv)cF=0a_i`eq7fYU~30(1rlnbRJy9VL~no7f9aj1IQwOt7%^Vm z%{d4{$@X8m9;UwMH%3{<usqQgG2Y9nnxLrn%M;`sNU)Y?q6jeOfiBV~?exKQOMYi$ zf^O<mj`NJ|2y5glasAlD1R|*#L}~>}yVHsu+9CsEAfN*=5%3QcG@>8(AyyxH|A)*l z@>{#fX!QR~3%RQ?=%u0*4k#^SI%59*Tx>h>S!P(8wSL;k06Qb09nohBK_h4o?FaT> zU`od~PjlX(qbSiW7qPw+r+lNGc04}FowT26j%WcRB@F|9$gz8(b)?B_9`ZLJHZu2B z^eGV?PdpTDJ>-B-y+-ryqmpoyZ!1yhS>k%z)~UC6Wkf=SMff=e*C&ZTB9(T!2U5Lv z`NZ6B8x#ZTT7L`yR09$q0z<SGEkINz-|4S0#n(Jd>oP)u-!A4ey*h-26<)@Ij5N0f z+OP<%hh2_8dVeha{PCkg{cpXdY4QqaN{0x}D9Q6g`sBA{oMv80lBU>espTBH;sF9l z)4RBJS%8l1imbTkXF$yD>^(c;)Q=;xdON>+MH=M2!cCJ1yI&S5ql<`%1<)lM(a|0; z1qdHD+Ez9bqRa#+>l|7m=Zbs7RIGb@K73$RrG4%RXc?Foa9sc&y4LqV+aY-KqbZMD z^uu>_FY!Dx%F4F!6NaAYDFvuCED916Heh1#ZQ?NVUp*oFpSJ-~68Q_4uu_dNZtI1j zgv^c$aJ6Z3t0tlMitBsq!<GZrm)#M@eC+(`NTW$<Pklm?j>EdrckP(KPk$si@5MgI z;<}I0HMDNA0kSAf;<MxtD847+b&xl!BY~5!ZgH9{SHi483@=6B7#BNw;3COeL#J=q z%K`rWq7hG3P-Rs542eWOE$iyI^AoE?1yz0OW2BAOHW)T35%u{c`!04zn>=BSPFUJ$ zO}jVc5+oHwKmJ{s&?w*!O3?f@a05PaXQP<jT)T}<&ij2kb~W4Yktm0}=3PJt>)`=~ z7nj$QZ#zy&|F&FzTV`WEla&ts)ZmlsoR-Q_7musg1gadFp^V}9@#m?YxR!WkJxFVa z>@(&vpr(yS`Ddv&Y6E=w;{ljHzUP2`go=i7!1c-irZtl$YdA+m^M^!|xNfzGh&-vj z24ZK<&ZKAe!43tURgdC`#Q&R^-rJK7wz#CcB_biDJrLk30Z1x0KXmS!7=nvU9$r1h zTCSjkZfN~3b`td7i_O*D^xHFOmm;P_wQ(@kXwtD<MVmr#-<6~5p}z?X|3LwcHr%!P z?3mA6NV(>=UmQmYwy8)RDO3-&H@$Qc6~y_{<|nvP<U*PjKLECbqI0DZuxc(}i;Zyg ziM_>)a3pk2w8-ubNQ(lx^U+SE3V3u3RTo4@HW<lyZz}yny(lz=beYi!1NbKTi|*@p z9<pH)kl<^SN&p3&(PWk22zk>p&W-1l|Mmjv5z{jF36mx`&35(-h0r&=r=pi3Ez1Y> zQ1aUUt`b_q26=KaQMETMq$qT&)KuKqJjL^URV0^+)8SXt3MenzPPJsJ<XH0^KmA@| zv@+<?5Xo(HZdO~j;Hulk+gDolEzZZ}9&08`Z(gzIaFjH?)&V9DiHil*{;sSM?e8A- zZ4}{wXeD)`a`*^)yOii?4lRTE^kPG;Xvn+Dul(Y(yy>Vxm`KACH-@`~Z(mT>X4e37 zRzP0gEo3V(OkHV<Si%W3m-61Vl1$j~=wsi+7c2e@yq^$6Dt~)FW{lP-nXk^V94DTD z(Wytu$TaaE!0pk-5+aKmb<%`wJ5NR#^-ga7Q+~{5c!ASYSNq0l7NhNf%A9-9p4C<3 zz=zwIM%rRQHew&__jr#ZR~Xlu#LxOA*bf_HpKO~^n9P^Q@nrKX*P)@!6Du5%Cx$I) zhbmhIVBC^77tX#pj>bmq%%7SW^q=1XSVG+~+j~Ud+Ic_Xlukq@UL{qdkYv;K?G2+G zbir2jY@$4;pv-F8<%E-=A;mQ&6AeGo;mJ@_Ni~|sygI(scCH5NI)!RpoDOVeUi$Cw zMBh(sbEmyaiEc6aW*!MQsC%WQ4V2{&>%gBOc53EQq*)Qn(%e`y<hX0l7%^^#Zk9c> zYf-adMxRTMT|0Bx(ea6jlJaZ-2f*7l8usJYNdtX^_mu}{y-rkNaciW7wlcR7UCzRw z+k5@k)#bTVkG}4Xmh)4{`F^NX4jF4vlcEuo+q^FX+U06*n@x3TB1d<`%we`gg&ESM z6$5w^K!`2M?{Ti|jWYQktLctloXg=`HKXh|Zp#i+OD!5fk(m8&>hNWmfQ!PWj%>V` zQp?sFfBgP+UA;(UMT;6T>xep98EAzshX>cxCvAy8*%~tDm0QgSzLjP4Q}$$aJ0-5K zY$eAFgle6FtFG@yofgnPsBz`pyZ465NW){7o?0e00BDD<bW5<W{5YE5NT{@VGDVUr zz41}0x~CNHN3bwi$Hex;=~tYQJAeqv4}o}a18gR5Y$_i64hc1S>(ovDz<K%1`{2yC z#Vp`F>#bOCI|KwRy<MLjxv^ok(q*amT9VNJP<yLZq;@uQJJyxBUCgTYisr!T>+?Eo z!6W7xi??!-;XGUs;ay10IC;&*W8<2j$2#uU-~uYCzZ5@diSau=s8eI%cW}3CMUH`u zYMS;l$GFzt8|W4L?+n=V2=FIXc$t|~VG-dc_ZV|MNu+d4jIsC7N5$)Lw~;LP9o~^L z5=BZAVgm^FlqZtrD5?1cvuRETqa1ss#fobWRI)%#@?-^s+vus=$&ks7$0HaCqD7ty z6`k_SW(LbOd$=oc8+uVSkofl2X|oAs)x#tuX=qu{5YWDj_`j3klfahtMQ$v0oAN20 zSHOtE$|^BiwXT!e3uq`S5`FQi@HlJBdo00ub@n)NpTVnA+O-PXDSutUom3d*WNHo> zw%}R$mbRS`V4bNI*1Mn@LKbQE&t#a_RYh++)mM5v)vPnBE|(n_QoJB7Ym7?K{w&AP zuy&c&B~dl%sUu4A%!w=Us^_({Gb1;4hN7gCiTvBxMUK<n(?LoqCg+1N!3%R0Uprj+ zjoOK$+npV&uRrO;)&x<J&X=PII^7t+oz0r??NC+GP~ZiUS2gB=c0ln!dl@WGEwgJ- zaE>?IF~+Hi_1KTPz&g;aR_Uqsh(1ru*qGmk$?9dlx=NB)1hC~cE021YdJ&<bb5e$` z=DH&&=#qtY@2IQ3`YrYJNVn$&jq*hfLJ;&_O`(>!rQRHNRp1COZeOA^#x4nu{1t7c zL-RZ3e0l<|@zIe6^aaN6g-8y-rJZ6@$TtHEuJH+3=h3WQRNIBA>a#}%wD9-mpx5yQ zhNb!8FQJW+#}<O>ntzJ?dCg&n`}VsE9bkAz#T2&xfB1^Lj!t~GQJ5?$!gx2Gk#T`2 z=01Zbo$j^a`$#*^rR7g15;33c-8mhpZE*s6$cF@b+8n!_)-tsF!fS{7pBFfb@Hb3Y zkq})!Zk2NLXO5#dnzwT}ak**Le1MK>hNpm%7bfT<7DO|#7tR9F%d(3Dy2XFrQQ<G7 zrrB<y!HB53ZZiAnd50Pp4m_OOkEGtGwfSAUynQ_kFOq(ST>+p}_Yu<if?(#|4BB`u z6+yu2?HGVqii@Kf{xYbNwQk~qaWHI^{nzcL+paYnd@Wg#`MjG+m>aqw?D`JLc*XZ} z;-Df-l^i(J`RU|ZdnD+0YkT{05^Ol(*z7bnF$G4qI#?epPKvgi@`~<_jS&3e>l+VQ z>7EdF#*AR^?5@YYrK|^=>@83K_K{N8vSwSsY0+n<z9L>Y-SDrXFCumJs<~Fa(gsP@ z1SQHw=F`(XD$>(!s!>Z}zrdG65BW&gKsE>OH40`TL+fAg60m@!8kXJId5_(<-MR-N zbxci}vRP*R<x`81VwWe)0kem&wm+6!w(Lgx#wfpqxM*r224{`*>ZWO>a^<q7av(3L z(xU*l=Ws-nI_t>sG@FDViTAknbY9c-Z{v?#pC`<C_q*kl2iHV@1E*kwiB`pq5`U80 z91v$d0B0I~(1ATSQ6dTxyj?yCtZ49Bd9MulDuWqvN8Ric?o5XIa7<Rc`;7ZaWR6GQ z7du)G1-9&-vT5(~6~{Pi>sz`#ZwxwT4lWnZJdQ7lCm}jN%Q)$06e8Vtu_anuBxLEz zlOiqJ*ASAn=kPc0lnuH~e>w`Uw#8R2$hWn66AhnNBz}Zf699{Jq9ia!AdzEx5&b*_ z>0kV&+!ta`mXsfR1`@cAdHDnXpB8|f{~KN`&-Et|^*6>}AiO8`@=@+t8A(Y=t?(+_ z+IPI`HgC|~C(jb=`WF`uqww95VgiYEPQVMBoF0@upNmg^fb)+S7Jj5No(EgdO@;i> zgXx0o)>a$Nsu&uXINqbnZDKnorZW!UtIHZhsP1==x{lSc>}xME<(21tu<nDgH#qoy z$GfmcX#i(ctZmBCH2RI!-Y)wfA+6zgJ@fvlkCTfHbE??J#@+yaP_a#{?~|!r)nbDf zt7!LVDZL<ojOO2NK;AP^m+bSm<y}zB_^MxJeA=kw3qyGFbVIpriX(+g(|Fy%)aaq1 za^r53!$$p_HPH|MBd}mh*N2!NH9W2@962J<DwCGIbm}EIg+@%XwXJZIon*O}K*ups zn@(3bYFRO!9!ds@dqcr)CMG6fY$Jj<&tX|a80)<Pq&&U`S6cGfCqr$9T&@y7W63RK zWvb~?6mcxhiNJ<T2F>zDkxG_TB3i9GMSQX*G6osdg=Nqavy^@Q0pz39DX}Cx^c8H2 zoEm7M$XODi-qS=J6#L}_3^wyOm2EO`9kzswQ%nbr&w>=`vKW7=Y1PUcax4+myccgq zugCayDMlQ-?qwm~S$xv6gVCQ?`g~^iJZxz2E?Iry#h~UF&Jx>C3Ss5$W$`i7uVTL~ zhA2&J97dd<ej--?Y3OmK;|@<6ulN5zl=bTk#WS$d*>&5pLz>CcvYPsVbA$S+Vp|7! zwdlfI#&PIO;iWf@wxyzBeacLzD{K6_OjObwzA`1P02ghzy+!9ikPb5|l-D#o0@`F! zTs&_uod*5Fm&&}hf^=|M($VS(3aiIfeK*6q3z}SNrq(xaXWD~Gjj-f}ZyQtgqCSe? zG2H0T5oQ897upbUzL2M{CC>~6d)@uFZWp43w~K3Z5Z6LHbnnywwPUul+UBFB={`O_ zH_1v+)KPiYnhJPXHOr_<kM(&wl}qY)Hp8*4={1f@z;~-`Lav18`E&|s>uShQ^*eK} z6NKk7;uM(hPCsFeURmNM_Kkpt7-#I;(4N=F#lEVM>eVH31&MNkg1uN!98;`yi{W_^ za8+9AYSF~Bnvew=fWCT}+724xJRusgNfO8`inuNOtV9rriBG-9yz*kZLJmQJ1l!_? znX4~^E75>KjSl+;KfU}ApbRrX_Q^t53BSRSyYa)8(-FfWkz)_o<bpFe@_V#32C^)D zF5O*X%LFW+ErdMzs9Bp%rXkFadh2`z^kcom15K1dqp`VI(sbJNGR>m(IEXi|6woU$ zN|mZpa>ZEF9IKn)J%S_QdGu<9T+3ewnP_ZK5z#u%W<_y6r#nw`X_Ld$HQ0=_gMA(~ zO_`sjo^s={ZsIq|myT9OrK3;2)L~_-y&7Y*{?i`S`w4A@^W{3H;fz|IUH0)oVHR_z zzECl>s83zF%<BqPxJGr&eN$`OV3P=ti0Xdi#&2~sE0{v~&pWlLqL1xH%XBBnU$Vz; z$Z5bIbaD6Hu@5MM%A*)nB^QDL_!6NcB3(?7yerwOL|0b77L#Jjq6<=wU7>XniIVcM z<@tdO`JZCE9)g5-382Cqt+A^$d|_^sbWgi?+8w~?X817v(=KE_?Scpt<@BlR&Yxr; zbVjv5uYt)!v^alZy)XW<LX43^`LWm1TX^m>{1nXmm2{L5*P=|3+zw?Mbe8KlfDeN+ zJm?BKR$G@a>*USaJ3oKA3&hpE-6wh`l+px@0FVi@cdjvF)G1FW*Ft5Y<?*S!-#)Jp zi@;bXyf0cckM<tKx4~cun4wqX)(<&*upimSonZ>_DBoWcc|W{k;*eFJ<_l@48VC<l z{Y1*-p=$-MNpHx?T39;$cZGme200YwVeXqSXQIq2y>eC$a>Y)VD)dctk2W433(r&S znVLi7lg}g9|DM9jb#rAikpe`tmRvg3YeC)~A-ZR5CCbp^AQ2)8#&9_FTfke=gjfNK zYSbc-i}bnh<f&?2@Q6J2h6dIreCian{gMv~W<G&qo@zu{<v_=hmcp?~kpd<W{T)9` zKi7A=649aL?Zl?K8y7K$_q6JnAfneqLxk9mOYY;X0RBW81klz1yH%%JIol4Ya&4ZV za>GQrocsi{JmdL;7^~Jyt|dr9-KDG9BQz&nxM`gq{Y>=?93{-q?k%RF%D|I2tr@iQ z3CiMhxYR1Tm%~Z<Y`zUXQ!;HXFTcj$g~mea<l_Sy86CakU4wiW!ro^bGBU8z0dVqk zFt@WAw?bv~%u?KgPydcNfP^G|fT4o~t7MQVI5it<c86D`=YD52<ESKBirE7p_`sPG z99ikEQEOVDsx+(3@CO>&;cmYl7O611+&dM_{!Piwak``p<d6zqOSJa~wj45gJKNpt zv&>@2{(`~gHERCeBW6)S?pc1uht5Q`5QGrk55OFB8H#bgQK%)7Hl0?03?3c&SG8I) zO>u6PP;UE`yEdPu{*@e0kD<Y)o?bAPGTBk3#S6XaYM!x!K2(6>K@5LF8aHh6u;6NC zZOsJr#~lxxo$j!)G$8HD%Z)fIZNTzyO*fnytvjPWa|)Xx6(FsiginE#OposR^U#+H znr8}X^=#LsdB8lnn}-o6>!-aVq$ZAwzp8@~d_P!zU~s%H)yy~HnsG=8`be7)HCwk8 z@u-ogYsZ&V2cbJZTSYF(mRhyd<#0BkxIH9a!e6k@)zK=otS*C@=^rEK7jDV@O)qm4 zEO2}AU_OxWPXWL86tG;u2bB$xFM8L3@UX;Uli#pH6$V@t2|tk-Ypm(vto`P*Dm+da zF~46pL7UEX?>D~DSK9UUG}NCAKR>$}k_)Tl;o{02&Z-g?7y$mA)Ewv$30{S%iOOlf zfP@9E$hB6_!=(dSC9yHKc6Z~(GR%${I~=zL3uU_EJ0rd3^ovn$3R{#s^-(XSj9(rE zPPd2DU+{kl1mPRr<sQ^u>6)|N;?-x}wxZA{U-@Ey=jscCB>KS>jKi#U*9fcsPEH{u zC=Bu3d>*%iVg{KtN^-{-uN@sS!kiQ<2GZzH#35iN;R%&uHZR}R?eH6`6=JX56&K|8 zhnh(G>|h15yiNIHmZ!b(tu8p=aKl^aQ_fb=<&J<!-fR<i%o{+-W}-S>jUKpX;{}-< z((v-KtTK_#9`C{G4Z=9>)!}Kg7E=m=c``oh$u7&s9_2nD@tIjfry`=T$kXJ0OxAI5 zxPd^t@dk=TYUOjB2HyxcRNP)39zFz|42HP!D<p4hvR1RtZ+E|Oh*sRh2I*tivs>`= z&4+uK8T#(mi{3k)H=yi8J$>dugn^>C&ML`~8H2>nD_E#Bn>^kf192}lDR>85-+k80 z@3G(%Ul`H0O}6C6KKqn8*1*3?th|v>vb!35Fzi7@j9J?KWfq#3I7pcE-9fhG5%M^e ztiwN`fuS*LyfAW~A+)OvyV<9DYa)lVNuy8wj)TlttYB`pQ*6Cm@~npvo4*p`Z^c%s z(&ANnsn*lLFBtud(OFbOl&CdUVuM2CL_P_xzt3@c0`kYFpo8X~+mOL*jWP^GZEP zT-tg*df^ZiMR`^7RfFB~@K68)pF>Q8arUZEs+gzN^|Sf-fcsA739djx2G_^-{kuCq z)d0N?YT9K`rK(ia)4FQoF+XoQB13i?$xY~su%vC9JIg(Iz1{~r4;>MH#I{x!@*dh8 z&|F<mG}9~FE8t?KBzAMRWr&{>DaY)w=wq-0PjwHkYGF1&=ubIU7fiUH2MiA_2i)$r z(yQ<_gYRrNSQsSx?|9M0!T4=neBP96h;B3mg_`Fx@!C{**nIGY0y@&s%gfvaK2B_& zCsUS1gUu(y4Ug%sXk}o1w{J(HLOR-jtAmdN?w?bBhPH2hdpE*W13XpBpES`zg1n}9 zCvA*pwbB5d;>$gJ-i!(yEEq-$P0Gx1ana-MT75r9Z4hZ#?)yG_LpHHB2%CP@gmCJ* z1NYgPZ-r-WSt5eW=_LcIHV2G*D$_6VpRk%kz%$YrR!G=rx<Vjm_5hjGzr7XkZwd)N z=8m0Anr!818ua)!s~P`7s0e>}gOxP%g(z}48H=5KCvyxbHBN5svRP#{B;rl!ZdMoX zb-Uk~6BWpIHebyQZzz9D+vYH(gq9&o6l)DLs2-c$RP~%;Ca5^8+fK^?JkDSBEu%!f zOPAjJot2pxS96nHmM67<p>%W=0=Cs<NGu_Ff&zujU;&95_qfOn2S1C+<s}b)a?N<U zKWSgl<t0ed-aqxHH*$i$ru`5Mo}r}EO<&O4NcF5#9k$?}j8BBynd|Jphvv1s5;>QH zxs|DKY?}2nQk2#^m)fQKcQ2!!lHllm6nQo=It@gq7rk2J!9FhYL6=lt^ZMf-V6pG< zTtNnw9Z3LyXPF6j)3vr6`E?%bRrMbxJe#~sL5B_0W6S`3U6CgHtGsHZ6PvxpwmQ}_ z&E{IZWxcwkHm&t=zU0JiI0i=mAE5<)rMy0Nm082vNXCRj-a|xlWAk>BaQ$@R>zW-# zt3)RKNj$^;kMd^Wwzh-H2mia#3n^r6IrQXGxOaXyT$Vag1fR9XK4pxNS?^k-y0p<6 zDEa~x!H$jvzVCmUZRqG9s2?)YG;&24J^~&w7VOsQ6~>&Me=W(ai*HlRC!6E=dI<Vk z%03xu06Q`8XK4ZA{dViJp5K%&Wd72h#N}405-_b54eu2n;9+eP5%r-))$H)j?=ICd z^96QfH16X2J4zaML@R`Qx$cZ~F3lF-miTOBEg<K_vH}5TXIPoejWaZzJid>_LZ8t) zmm3Q$im^f>KhG|m!mQKvKJMbZLL)A1=D<FDWHYHXd!$~|8{au?&SMlJYyf^|HhrHk z>#3UgGv%6v?!<RKq(}*>|C~w5ORF*i9#Uz~rHtJMwBs=Xq^XXA*kw!!pBoH$)E3p5 zN(m{)Cl~I``+T=Ry5V%`(P?l7I6GHQ8asBBU$~&Y&7NB!tT?qA%V)P4;g^jLyH|A< zH+RgS(unRokMjTlr{M-AH+{@cFF>_g6E|W#Ps%QM8yTzomuvgo9O$Xz>^tpsHMsqS zwhxp{@M(wtyVQT05=KXJ@vi$KA&nkST{>XBWBAk}@ZjE2lWonzAq}P5hzE~!3lLaG z;#aNQ`u51j^^6xD_pK?;tjNyh=t70gC|Y8Pw19VmtRVToqm_;Wpv06MosNtE&htmZ zb;}-f302<4&R-<p7eJl8S<4I~k0KULqkLnX4xUE(DyWj{54o=U+sjKd<l38IxNuJB z`JC3@`l!OV1ADIUx=0Fi(l1(jv9gFm`4sn);#dSwvNlOazwA};L--c%uzAl@2;bhB zsNa=S<Cet;Eme>EJ2yzC=`5Ie$98q+x7hLB8f9^@G!bWYKxeVfXZPz&GWAW&l$}YZ zQX_+x%0wkKp(q5<B9;JBF{*5l2rJG@`bqyKN9gaQq@}`M{oiSi)OC|+dx<}b8|wF* z);06BGxH3eJd%ikX^}A@=lt@)mX-DrFYWKsR}`uoxfX!#4(HVb&&sf*<QJ3AJskG5 z1w9ePTZSj#?>*LM^$dSRLFJ-52vE73v7B!uRYuHjKZ`Y*bHB1mn(<ME*?--96wd$Q zC&*Ve8E;j$e;yr;kVf|9u@o(X4^D`LwC{LEkJf1HpR9SG!8lh5309Te0Ya=oU5YAY zEz$Ek_f36=>Dn~iIvx+GWqEnI9Q~0s!0Nh({)@CP-kT}KekVn<pz5rbM?l*lR~2uI zJZq9u%^?8l(pp=*xE{90E}<iUL<cw;#BKotK38Y;46dlP_WhdSS){v&`NA03-(+oI z&oI^#=Za94%R7$8L$iL)$PJ3J#ny!*(p&s!gI}1X5!Ds>TMWu)|K-szLJ3-y`|OC$ zse^@#*>~+Rxmb46pBCdQQl*f_04fMm&{VkcpT}5)Y11da;)kmm&dpTn{Q?(<02W3p zj$xH$y4-nRh8soVsd)tk09j`M+`s>N%=seU)_qB$6d~vPjG7dKW|w~Ui=cDDLhpUX zUmkvTO}_g8kKlXivnv6XOl#s9$41!ki16XwRuNyR%sndcJBLKPWZ4~ctXxGJ(kCQK zBY_1rao?XF#%g_NHa<NnuV3V0dhkF#`CEI*-!YkiIXQ#^QM$aWiNMxr)=z};jB9P* zvPh_9tmV8g-0!Jf&tHi@VqRTOygpClfouC~M8uiMg7in_bp?LCOqk$&NFOu=)uFMj zPad+R)rPIO=-26{-C3=_5oC;F>Ced?yMjXKomtwz^d69t;$r3tl(arus(R3XWrkGs zJpdryqNb0~FCPTzkHfe=E!9vZpc-CMlWun|VRzCdNxhV}IQBYtUJ{4JV3>0~g7eVe z_=j8p`R%z9>7$h!@c3hTmm&9LhMjm=up5`c-CUx{>8FDt?Bh}swP?j`*~mEXg5P(D zpRLc737-aWmmunqoF-P;;s~s|Pyt^JN2i<vDsn<R9d+@Sh!sjq@>$aHCCvha#l%V` zu`1~8%EI_^2qzRZac6LPd(uX1VlM?>D!E=Bt#*n2n%P+Cr%5j}XKnyb!Q@FR%5P{1 zMs4CFB~I<o78c*XD-Hadkroa{uuN~2J<Q4DBwCg0^yg1ZpWY*o^MmQm%F@Knh?Bvk zz{5@2{QqHDE@W=z#-ERe@+awUi$Bf@YH`=3;6|`<M${qmR#d5oTGvA2+(+!MH?Co` zGvs!h96$10QH$Zt=peH|(~tqR0Ms;K_?x0dfx03`hqm#m=c?qYud_BHVdVD+pBjm< zINu#!<A_&abkE?()yT+ShT?gL$5i~-JL^2t9*+BA6j^L|LL07|ZOaw@JRnw6@$07e z>w<a=kU-n=hXz}nfH}+D+xcZVoQN-o$LyMATmODhM+bXOVo%lX$mL=d;HZ9kyOeCo zTyY|KaGApxssiRD25DVOh<^vTmoZlt^VmnbQz$57B?w4Gw#wUNQ&M1SG3ceg_3mml z9)0nij~`cPYZ1}pYFTM6Q0qa1v5D`CkYWo^E10oep57LZe&vW-AF$K<k}WH*e>rli zooHEKhzaRdc{jzM==5EJlz}4kcW>UfcnQ6u&_Y>DUY#js|KGoVHS8@TUFv0Sp#cjm z9>b!R3`6wQQWDsw*ndvvfjW%tVy=@512*xPA(+`!&4ha^=n(KJlTLWV)_?HHZivjA zr;&ZVue2xdV7MPbJ9OzYdX&6jq^!sbD_nyb(>v}}wR}3<E!MM(g+{DHj6WE4C%jvN zrbm_4bx+GrMtYe@qGIop;~I3yPjWw;4kR(DemV@bvQ0qcWLHa8csa6dSj^0k+gIsV z0VwtJ(C#B)*@+_8!;C@@RzdzA*eHvPhds{)&hdo*<@wuaq6QrS#U1|~lKqdmhLwM+ z&)Y_%tXMkrN>bWQ6Bg-}nfI`jPr(`3UWYnootKB#LrRgY1E-uw(mq|fNolzYM~Tfb zrK^-N-lmtW?L9)Y5*~hcka|OVgi2)F!wj~)bB2}Mz6;Nu%`dWjAg^j?MyDW)+e)xa zK7*a|OO+3@3%#8e8<^)Xh{5J_d&I>x%NO`VZGIlxr5&p(wir<sVM@RseH{be4436E z>XR7lo4X6By&~JFk97{+>=`9WNwYHs;ZcA`=&*60`5@0iO->C$bjLL*<IUaFcSnTs z+`$9jV0iqgna6*4```C(`N^#+Rj3rCBDcREos39Jo6ko}+G8bTKW|(Te>ReP3VM}` zn)X|zBsOQgUk(y9nDR7b5AJx348tL_4O4so(m}2Z%1NZX!Yjw)Xts?g*mqWfK51!z z^_-}0Jdw4oYIhsABm!lx>=HM@ZO`LbKJj62K5#iFI&n0X-Og|S&>fbN-T^z;qe|bz z%t=A4vT{*zx?yC0$Y$w#OIcZO^KAz)4b+N^syp-M*beP`SzUa}(9G=JA-F@`2|Mr5 zS9b~<o1u5TnqHcKn!oQ%kr#TA3Q3IOmb*Vy+v95-XhgIG%luf2^$BOT&+pys^x2YV zekwuD_*n@p5U|NhnCt5bXvX{A$tL@b61C-9dqt)kk=M3?mFQm}vs*BSWQdlQAWXnP zz4aiN&1^g_I^!qj*8^9`^wx}x64mQG<Ak^SjB|-~iJHhM_qqB@$H^~p5AhjkC&Sv| zcBQJ`I|r>-qjQlNRYK;?3*8%ah!$^G&)n=Ult01v|B$Oq%Fb?~V(xslw8pngF-$wU z9Zg4vV^2Kn=>2tK&SG@tYW>?n6r_0x-jKL3Vd`SVPfWZt{W>xLb&sC1uX30*x!I6b z<V*nH(Y1cwz_izMJVTtsYmy-6m4BY83knL(ed=Pl>Ul<>y$xmw1p2<f-p{H=ylGuS zX(24{aJOQkErWzZa}|1taY}xRi#nxmzqs;wrIN>ZtvKl8=v;ZQ*i>uT06mvEJj`aD z(o`qqZHG_KvYw5&GoZVSWH~ps_}ZIZB!cII&1)!V28qT68^iNBYMyV!m+fn6XFe<4 zec?j2XCt@E51;u~hb_Pgz1R7Dw=-TK+UM4)vb*y^P+}6e=if%A#+6$;Z#pBI!n_qM zMzWlItBCPAhrD)|f6VZ*QPx6Zq)OR_mE6kVrUhFx33H--+M{89y$F&3N7bNgikLUj zr`xx-!mOIPz&|ME;6a{3g3?36egIyUU1YRqmc$E2Z(E2c*H;vTu*bW#pj$C9ed4K+ z99+OwI57pHBZ4egM=&Qi-QY}D3(E1({Da*8%!92t0?u~EsS`jVfm{;Xjrt=OYil_d z>;LpCLhGz?q;4da{ij%KlY!ysoF0VgY<UKiAD(rNKu}A*2y(#dPN_nkHUe=UQXk>) z%~!T$hLmgM4vmWD97)lM11lOnN155#2joE19@(7M`-i{nT7R;l?6Nv~ByAzBP0S5Q zL*m;~7j0alAl7(E>L{x$sISB!i6UwqrOO!eWhN&P0<5V1{W~TEu_n?#ESEkqiB25a z>XE2Cj?V{P9v~Lp-HwjN2LjAZJ#Jcls4HyXpJ(tVftk73;wG^7WmzydTR&U88R#jC z^C8OT)}f-!Gl$LIBJ9!Kqb>TRa?+?1xfMbB9vK_>bCAR<rrC~*m1Kdv`4mqFt{=Lk zUfc`wwbGXL#meQR`j-mSa`><o+yOHN?gniJvnI0U2e&aTK<$mWw7CPlhZ%)K5bVW| z2qn3K41H=D#xadH&V)$9mBgSedu^DCii(G=G8}{t3;0Oo;2$=|;XbyneXRtaSa#_> zKO(;HbaAOE_Tex8MDnttj_TjTF>Z+&P#Op#S#4QCVVhb!<*O%}cpronHPeW}Z)YXb zV)R2HCYC+*Xfr{7){3DJlROdK=oAfizUn8-j(tT}7TQbF{X<gH>{eC6T6)FqvihpS zV@%>8tJb=3;#Ic@$AhBpK_`PeVuXCvS`qbQAWH3o#Ve)*uSZ6aabBo>h9{#~!pI zQEBM|LX!12!u<Ch(OLQKKmiY_J#JEQVpbIB!~dB88W&%OhS#i^EQN#@)@5wAR(F}+ znItS&9x&&SgN(GEuf5(YYo=Muq^^4~9Nv~!*u8gnA=<AIFcuXmlH?Gv-}9IK%WX9@ zBw9lYe-p2ny3(Fe!IfxoO#ZKR(#KeQCd^(lTI#-J3(X?-Ow)FAo6tYsnBfjwEcOVr zjFDeNKBRT!FTv5~3SU&sp@2xy`$!-EKRNwIZKFPy2+vD?u7$z$PzPtLviDe~8l;oY ze%5Ov8*Z(Nq3)~3vx_g9k?wp;8IB9R+OA6K3uN;fuvvR_gJ#>d2G`MKr*OSiRD=7k z$1UwWzx@{fT*llXcm(t+X`K$!;s#u=1B$4J!}WFrU$>Oi(q+p&0`8cvk}X?Io_vb2 z*lZnT5j%0m-hPgx5M*VnD{NzqmqOy<4D`nJs%B~Qyq;_gU=^!*!+_b#(}p}h&$XUp zRY8MEyy$fZXgiLrMi9SCzsub!g0oJ^xpE19aEVaXR9cIvL_xR?sp6vhtT8#<xQ<Xo zG*rO*>~My_Wv->6?`$QxmGs^kyor6+B$Y^MFw~~~xF9xukXdR$mwp*J<n_!xL0P1& zdt;8eqQ=4e%ftnJbG>dz+;dS4e}z#B=kMm(q7kJ`N|HlMjy<0$Q><^`YZ)n*4rv{~ zcJUBZVqZFa0hU@VTZ>Kd9$lKpHT5V4WTpf^EOIclCIq<D*4}NB9;$86HNdM_IX`h{ zO}y1L<~M>4N7sqH-Wr*;q~jqXsP1ZYD6VYMNUd3hRG7~`-XJRvJFdijwA3PN>Py|~ z!;9&N23f_uPs}h=G^&*!X+xiA-YA~bLN{0iz6i=a`5#{>IKnY9TTYx}!Bw~G{B4Q& z*-<9T4$)SAi_5F+rApN$-aYM@64&0ZoN<nk{hFjHm?j^sbv`0-X(jM*JSKU471!Wj zwW%vC?>4X&?79Dr*Eyf$03<T#2c6YSyl(bL9<eqR<npeVbrENC8n61fQd)fsB$c&h zSWJG<Yg^$-YtU)v1M)-z)Q(N?&;v7&Wmm<^KQ_F$LgX_iCJ>&L`&+{q&F&=Overm& zx1eWjfhk($YT<yt82A0dS_U96Ux-_RP#}q%AxN3uF7Mh0|KuMLxhvmM`~uc<dM=<0 ze3e@t?2{fzYlgb~EXyn}{;_F)@*Z$?dqa!ICyNUz2o(ILs(BvnUcBat|I-V(@E9 zyY*{+2?|p)SkT<sJ?->D^^}CPp(Inrs5WWv%>|WMKlQ6gVwXXWMqOb!pHd?W@&Bg< zcoh^E$-~#-;4n{*8hX(GZrMqrGH~$AY&iW7frnkYz{#7}eCZ$}GXbwzW%wquJ>oVv z8~d4C64G7ZeAdv{e$=lbb_La*9@4ZR-#&5rul?HQTmkne(T>o)7DD=oiv3*T=yVE+ z*QrbN92cCP<H7MbF~jlLM3%IWpzE2d(+*{6Fv|4Go_t`eYdg%K7AAFJ3b7LU{bv&w z$bUV_D3R}6wg;-fH8kHVv_YoEE6s9~%+`G#^XY2J7%cF)8fvP2=ZYedFmoohD^Cq| zv!k4Qc!s}x3!G(#<dWq|RC3)AOA<m%^E`c6&&hjJhhy=+{T=6NLjHqyjz=~un;ra$ zLMR)cfS@-5vv1R0g!&G|oCFch@6+?<v6lqZklG5+iUbxwyY{Z?e%a@RZt~pDCz4%+ zmH26GSsgi4ar71S2rJVvl)HB+o1MY`-gh?HJu34+=0_6e7+<R6-H_Ir2_*5?cNT|a zkFggPHpeqiOztTJe9nN|36DA?XH+Emd+Zj8wO{FNW;Flc8Cd8fZDikCOxf{z@*d-J zeig$4;!eROxx(?!68bOYn&pGVVV328GYa~ob<yUn=o5B!b`OQ%!Ph<?>pHT<#jb|_ zJ1c(#<Kiz?wX&WQCKYp+9-W|RuV(<Lks)OEU<shpE+vxf6^w(WU=&}ElXix*C2F<^ ze<?&3)oT(o*Ro1Q1<**G16({uyu)5Uq9SqjdK^yTx5(K~e*aX=X??Mm<(+kG(CErk z*Xqsp0IqvpiRhNimI*ZymLq!jY1b&Bio&Q2vKDf`5D6{U_Ym;6Rht&vhafm{>Jhaj zif_=>g?80dp5hTDp)hu`B^akzdJDH}Tw)9OtANGbPthKBFjqm$-Q7Q=0;s9sxG==| zQmNw?<r}R5MrL{QC}6qvmc5#L*A0Yl-nMlF`i*Sdp~L`_XH-ZG)+dw)Dl=OnOX=q! z%ek6EDO*JE%J6GC&Zcr_WqUENQB0gF`JcEUQt=X_TfHjb+5@oMPKRmnu#IX)nneLh zo+2tYmAs!F_SwbEVxf`#$aTO+^&MAXp%!1QDGzA3lRzXh<egk%CVqN*qtu{O|0Szx zNxC9@m0o(Y5d3>&Bd}cS{~&ku*aG~#k8}#j=Kx)8-l8XySCZ_K9oCUCw|8u$sS$1} z<jZL#x-o1RJ25CUq^!J_bzD&U^Bj_qFp5e!`nj|vV};6kSN#lisc$sScs)ugY3CUx zFsq<?yAbM_@mYl<`AT{;YBW>W^hxw$KsKe}@WgosvQ|2IC;mh0S~3}XWCoos$%;KA zJThsWRa|ZdZ1dZlU=v>%D2X(o=*jr_Bcu*md@p6|Bk|{KymqpIVPgt5zF-Z_$Yx%z zCJKfGo!4AEC^PdOKQIWH%Mu1M>ZxeR1Zskf1$4vDsn6!E?ImjMD-u?_!tp($6(dEc zr0|@y0@d3-L!5=#F)}f3EsFeS_9*0jvB+zr{G_kMtj8RVi_ojVuOW%9fusDoTBT&Y zv?A4`t#_+3NdAbsRI5CU?O7;G4)J?W?<Jo#WXuGMp(YhW_nBM!+9V5xK^sNvs+YZx zj2W4lRR5gsy`>%k@`<}88DB5wAfQc5tuBp;Ne7M51bL%Np#15}W&Ym2cp94j8%qi) zB^HD+aehiE%U#TR{W4k#(w8>yznYKMA_c6Zr?>)0i)g*xy{vu;Iv&t;-)F-HYAd;T zcr;k5(vC_^*Fqadb+8n)v{|=%K4{cgFbW;h?WXbSxZ7<E@W1HQ8qJ~>o@6>4FOXHe z-XLdPY7Y$bL`eJzDH7b{w^p1GZ0j-Q<F7a>$p>B9_X;@w*)Q?hPZBo^ve_#!k1CMr zaY)XgX@`x&{$5)fU;$jS%v9C-WEY6mGfV<qF+%e<HgRV6z%`&LUld`x2TW6*57JQd z^D#Mtfg$)lC~1Pgg5lyIo4e(-qPfK|V2cpdi8WwCjJ&!mrSr?aZnR+2z7R(S{k=Vh zTPJ1ohA)jVtCEG)9r8qGgaBx|p@#>EW>sujECNm2_KQ3OpmsO0r3u>uB31&$0d0xy zFgQb^Nv$t?n>6Ot<cy~C`DO6<l)v(M*Ta(Jq)c5ZLn!$Lv~B05%F{(qFtn=w;ohFz ztSHX_@;BSl9D7@?iX^GIUfp9OM($3$y+oDTv41@lN{>~>^$d3_%X4WCCoJ)cHo{e5 z)i&n+vA04`Sq$)Z8QI6}+@2wn48g)P@fg6U9W%Ai%>$Pz9Q}S|_}jLH#Ja`y@;o{^ z`ut+S@i5EvB%B3K!tuTqG<N;3c1*Rf!R1-Mo3g6X=ZGeKh@Q!35t0lxxkNC;l1Sbf z@I-3DV3))>yy8UaB{ivGX)J3L?QUVS*u*ZnXa;u$YrxPk;#EdqvAeOph%`0Z(d$OB zX!SfBFkZ;aYU<<n#BG#e6S5;1(-)1RSG=sv1CRebi`yuC6axh^YWyzY`i{R#`os9< zx6%)lYc$b_!EX60^&rRclO;SY`SQ3CJH&iGvesuTrzdnQUh=L2QHJ6>jlD@RG-=55 ztdnRoL;L6*%YpBBhnoo6e)85)Q8mj0WL~>Qj!mV#Hl6R{^0#V8X6~j|)#&qna(3PE z#+E~62b{&9Wj(FdxKL=57Osq6lc9S$vnZ@d$xNUgr`OYfEswkYcU7ASI?F(z;#kDr zguPu+vkgP2hiJ$j{g0(GryM+*$L`nkMP`m4R<ycdWGYa4hBg2A(eI`*aGv=pUvDV$ zm6aNfL|ROx(jp7v#qx^-EN4<J<2=t7HzB*P$j7{?T|P2s5im^_R9(qJi^u#&tJmIz z=7tz~e!;T|#T_Bbm6C7!+~IX<>Q|t%h<g#OXR*jCqM+xHqG-8zS3#EB6p5kUS0v$T z*&^+*&s5YGha6%5DaIitQ1;YT2Do@#E}yPSQ1SQOB#iljCm}tRed0wO-`pwKy5s6? zd9WBwT@$>MOUO7eE_sF3)vn__SFe<m$s09r&5H5n)`c?gk3v5hMCv8%guN#<%AX2; zkN@-S8LD~noi(lR{W@LIG%A2ijPt?yyNO)JZLTGSjQos_pb7Fcqxpf~Jo-8}iaF~; ze<Z-6K(004$T$5Pj7-@Gv7)Fs|BKO11)c>r67^AXD&8wZ6*~OcSVY-NtN|yJEXbBF zb}b>pl<^;?B4fp+wNE5zfAiiEOYBu@{Z7;eRsSF1v9Lo4eu?zyAa}*$n2p~<(cYda zZbhWY<VSzq^Pe^IKgF2r71-a*J|?NE%SqD@#}>6Edq-CBrfTHtlvJPVkjXmGc66-f zYn^TR_cH5q+sf7kLlom-(87FY&HBKFp=-O}G&+mTdeH)d{Wnqz7a(QM!M)<02T`7N zm7nYFZu-x>(^F(FUZ-vgLRiWN3mJ_i+BbBVesT(SABQ)rWq2=ZF=XI<UAs6i9pfJV z0F4gFsWu&}AEVQFBFXhMLAxiQ_JdJkNx#;t16u10unz-N4;l3P6QO1K9!ZM9lfr<K zu@0$ano-4)uJ65=>O5(G*X2&oSw4>yLOl1t3U3tE`fd9WMlyDB`DwYr>+GRS5O26n zA+bSIFg=<ui?j{6){%2(pMbat*xo`(%tgJ9R+z2QT<=#pf?Eeu+FN5$(LEU@9Uk~L zI4ag1FC(Z;Xrw^p!{r?<HUNs)rnLR<Q}(-!=;19bEsKh1w@RTei)7;=vwDARsD_@s zkFm<|o6g=+bYwJ$M8cIAsPgcA_T0RD_U-8=3yPb5`QKi2SpE;}9i;7Ux}O?sK035^ zSTqFC6`GiA8{Jl$NM~L1kU3V)$o&3VbCn<Hi-KGX=}1NNX~=LK7=^N2dlg;Gpirns z=-OHv`4{rf9{yRPC?$ja?>L3W=Bpx}U+_vY8J_V-If4hoA^5HUI(#J^vC6hF!ZR-= zbDXJ%u0sGF#fhD4^*Y%Y$bKamIC)#Y#F_9HsED?yJ&Zmhv3JIyPOk`*xK!XBA&!)j zGyYRxnGSgqc;0e$JM=6DQ2bpY)R2IQ1Rv%hjOsusebJuOKMpl?exKP*KY)G;sbF6a zi|N*omBenf^p14X*kehaBN<xYvqJ0n&cB+NjjO9wTw^;<ulzE0U;OoH@)vCh)$2`a zw`b~E_WK^z{ADV)GbW@tHn!6<rP1|YA5cw#Z)Q4f@y&h`E=mE^TI>|(0CPy3<Z8k+ z_$wpoBlK~;?wrXcDGR#};6&^DseMEHxpjr<RIujn%5rF8CPeudVj`!kuGLr0AkKHR zeib6h|MX(MaY$~z|GlGbp<->>%jhi&QNjPe0cKM#Jb~-!d?dHYZ`CD>`{_KIezArI zXE`M}5bpD7f8NU6PRado;@8Y;7EOwGb|mkjQ8~sYQ8V4f<4iKTH51c7Po=mR%a*A0 zR>QqitJuLWy#bwl#h7_V`PQnmcF<MFLtF>w1{{vZ(^3B&WVaKDf^?B8)lZ_~Ku_Wv ztT)6BI#ulHvQmo9u3S#oHFCu;X~>_o-GK5)nNVOQ0^K`3uMryKxaYDvTvvba(~p=# z`4)RKYg6^dZ~jJ!XP1fOv@*(RUjBs>C@|?lzc=Nr_BVO2=nmLPu(HXtCBumVVdsmR zToq{WK{b1?L;o4h|3}k#hqL{?asS()YE@BG6{WVKYVTI5Qls{Wy;o=vYPUw!-h1zz zSTRDVy>}(H)+R=S7_pvDf6w#$>vFkrIXUM(=Y7B5ubYB}wO*w&*-E0OL95skP>UH( zTeS^U*tkIwJKXuW<rPa%r3Y^@vo(46o+4-k-@TPI$<EgX;bRvU13tXZ{xNrUsa?M7 zuoJmjZM#+De#>O6M;-g=&hfE3x=IsQ;8^$M7yHaY7}kjlT$Vpe<FOyibDSH_Ox<N@ zvChtZtTMBxeftqeid>ecc;sqgV#53IEZ6$~3iF!}?>)c!zV_-7&*W6Td>61L!|rxD z`zKj%>wKL1N|6iDpO5a$#Cy`r!Tx*!=I=gke=Iwz5m#bf<ZsA1JToq6LS)fm;6WzO zSa=CX%~8`gk_xWNR>+8o|HN+rO)lx7PII1yggXhx^=_t4dMi4O%0A&`9-9b?c>R2A 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⪼mDSr{tK2+EhOBG_{{`e&G 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 NOI8XjSt(%@^gj?LcDMil diff --git a/plugins/kimchi/docs/kimchi-templates.png b/plugins/kimchi/docs/kimchi-templates.png deleted file mode 100644 index ca3ba585b02668de97015bdd9ec4af64265592bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 329678 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%0Ad3dx|<q`n;0ZSQ(k06~bLzVbUVbpXVB!PYn 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ⅅOnbhWduq*EF?|q_xg7h<I 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⪻gYAy<i$*4^-X7~$4F9lRG_zXCwb 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 kbi{8Dx< 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 IM6N<$f~8PYD*ylh diff --git a/plugins/kimchi/i18n.py b/plugins/kimchi/i18n.py deleted file mode 100644 index 253f00d..0000000 --- a/plugins/kimchi/i18n.py +++ /dev/null @@ -1,335 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import gettext - -_ = gettext.gettext - - -messages = { - "KCHAPI0001E": _("Unknown parameter %(value)s"), - - "KCHASYNC0003E": _("Timeout of %(seconds)s seconds expired while running task '%(task)s."), - - "KCHAUTH0004E": _("User %(user_id)s not found with given LDAP settings."), - - "KCHDEVS0001E": _('Unknown "_cap" specified'), - "KCHDEVS0002E": _('"_passthrough" should be "true" or "false"'), - "KCHDEVS0003E": _('"_passthrough_affected_by" should be a device name string'), - - "KCHDISKS0001E": _("Error while getting block devices. Details: %(err)s"), - "KCHDISKS0002E": _("Error while getting block device information for %(device)s."), - - "KCHDL0001E": _("Unable to find distro file: %(filename)s"), - "KCHDL0002E": _("Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."), - - "KCHISCSI0001E": _("Unable to login to iSCSI host target %(portal)s. Details: %(err)s"), - "KCHISCSI0002E": _("Unable to login to iSCSI host %(host)s target %(target)s"), - - "KCHISO0001E": _("Unable to find ISO file %(filename)s"), - "KCHISO0002E": _("The ISO file %(filename)s is not bootable"), - "KCHISO0003E": _("The ISO file %(filename)s does not have a valid El Torito boot record"), - "KCHISO0004E": _("Invalid El Torito validation entry in ISO %(filename)s"), - "KCHISO0005E": _("Invalid El Torito boot indicator in ISO %(filename)s"), - "KCHISO0006E": _("Unexpected volume type for primary volume in ISO %(filename)s"), - "KCHISO0007E": _("Bad format while reading volume descriptor in ISO %(filename)s"), - "KCHISO0008E": _("The hypervisor doesn't have permission to use this ISO %(filename)s. " - "Consider moving it under /var/lib/libvirt, or set the search permission " - "to file access control lists for '%(user)s' user if possible, or add the " - "'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x 'path_to_iso'." - "Details: %(err)s" ), - - "KCHIMG0001E": _("An error occurred when probing image OS information."), - "KCHIMG0002E": _("No OS information found in given image."), - "KCHIMG0003E": _("Unable to read image file %(filename)s"), - "KCHIMG0004E": _("Image file must be an existing file on system. %(filename)s is not a valid input."), - - "KCHVM0001E": _("Virtual machine %(name)s already exists"), - "KCHVM0002E": _("Virtual machine %(name)s does not exist"), - "KCHVM0003E": _("Unable to rename virtual machine %(name)s. The name %(new_name)s is already in use or the virtual machine is not powered off."), - "KCHVM0004E": _("Unable to retrieve screenshot for stopped virtual machine %(name)s"), - "KCHVM0005E": _("Remote ISO image is not supported by this server."), - "KCHVM0006E": _("Screenshot is not supported on virtual machine %(name)s"), - "KCHVM0007E": _("Unable to create virtual machine %(name)s. Details: %(err)s"), - "KCHVM0008E": _("Unable to update virtual machine %(name)s. Details: %(err)s"), - "KCHVM0009E": _("Unable to retrieve virtual machine %(name)s. Details: %(err)s"), - "KCHVM0010E": _("Unable to connect to powered off virtual machine %(name)s."), - "KCHVM0011E": _("Virtual machine name must be a string without slashes (/)"), - "KCHVM0012E": _("Invalid template URI %(value)s specified for virtual machine"), - "KCHVM0013E": _("Invalid storage pool URI %(value)s specified for virtual machine"), - "KCHVM0014E": _("Supported virtual machine graphics are Spice or VNC"), - "KCHVM0015E": _("Graphics address to listen on must be IPv4 or IPv6"), - "KCHVM0016E": _("Specify a template to create a virtual machine from"), - "KCHVM0019E": _("Unable to start virtual machine %(name)s. Details: %(err)s"), - "KCHVM0020E": _("Unable to power off virtual machine %(name)s. Details: %(err)s"), - "KCHVM0021E": _("Unable to delete virtual machine %(name)s. Details: %(err)s"), - "KCHVM0022E": _("Unable to reset virtual machine %(name)s. Details: %(err)s"), - "KCHVM0023E": _("User name list must be an array"), - "KCHVM0024E": _("User name must be a string"), - "KCHVM0025E": _("Group name list must be an array"), - "KCHVM0026E": _("Group name must be a string"), - "KCHVM0027E": _("User(s) '%(users)s' do not exist"), - "KCHVM0028E": _("Group(s) '%(groups)s' do not exist"), - "KCHVM0029E": _("Unable to shutdown virtual machine %(name)s. Details: %(err)s"), - "KCHVM0030E": _("Unable to get access metadata of virtual machine %(name)s. Details: %(err)s"), - "KCHVM0031E": _("The guest console password must be a string."), - "KCHVM0032E": _("The life time for the guest console password must be a number."), - "KCHVM0033E": _("Virtual machine '%(name)s' must be stopped before cloning it."), - "KCHVM0034E": _("Insufficient disk space to clone virtual machine '%(name)s'"), - "KCHVM0035E": _("Unable to clone VM '%(name)s'. Details: %(err)s"), - "KCHVM0036E": _("Invalid operation for non-persistent virtual machine %(name)s"), - "KCHVM0037E": _("Cannot suspend VM '%(name)s' because it is not running."), - "KCHVM0038E": _("Unable to suspend VM '%(name)s'. Details: %(err)s"), - "KCHVM0039E": _("Cannot resume VM '%(name)s' because it is not paused."), - "KCHVM0040E": _("Unable to resume VM '%(name)s'. Details: %(err)s"), - "KCHVM0041E": _("Memory assigned is higher then the maximum allowed in the host."), - "KCHVM0042E": _("VM '%(name)s' does not support live memory update. Update the memory with the machine offline to enable this feature."), - "KCHVM0043E": _("Only increase memory is allowed in active VMs"), - "KCHVM0044E": _("For live memory update, new memory value must be equal old memory value plus multiples of 1024 Mib"), - "KCHVM0045E": _("There are not enough free slots of 1024 Mib in the guest."), - "KCHVM0046E": _("Host's libvirt version does not support memory devices. Libvirt must be >= 1.2.14"), - "KCHVM0047E": _("Error attaching memory device. Details: %(error)s"), - - "KCHVMHDEV0001E": _("VM %(vmid)s does not contain directly assigned host device %(dev_name)s."), - "KCHVMHDEV0002E": _("The host device %(dev_name)s is not allowed to directly assign to VM."), - "KCHVMHDEV0003E": _("No IOMMU groups found. Host PCI pass through needs IOMMU group to function correctly. " - "Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify the Kernel is compiled with IOMMU support. " - "For Intel CPU, add intel_iommu=on to your Kernel parameter in /boot/grub2/grub.conf. " - "For AMD CPU, add iommu=pt iommu=1."), - "KCHVMHDEV0004E": _('"name" should be a device name string'), - "KCHVMHDEV0005E": _('The device %(name)s is probably in use by the host. Unable to attach it to the guest.'), - - "KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"), - "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"), - "KCHVMIF0004E": _("Supported virtual machine interfaces type is only network"), - "KCHVMIF0005E": _("Network name for virtual machine interface must be a string"), - "KCHVMIF0006E": _("Invalid network model card specified for virtual machine interface"), - "KCHVMIF0007E": _("Specify type and network to add a new virtual machine interface"), - "KCHVMIF0008E": _("MAC Address must respect this format FF:FF:FF:FF:FF:FF"), - "KCHVMIF0009E": _("MAC Address %(mac)s already exists in virtual machine %(name)s"), - "KCHVMIF0010E": _("Invalid MAC Address"), - "KCHVMIF0011E": _("Cannot change MAC address of a running virtual machine"), - - "KCHTMPL0001E": _("Template %(name)s already exists"), - "KCHTMPL0003E": _("Network '%(network)s' specified for template %(template)s does not exist"), - "KCHTMPL0004E": _("Storage pool %(pool)s specified for template %(template)s does not exist"), - "KCHTMPL0005E": _("Storage pool %(pool)s specified for template %(template)s is not active"), - "KCHTMPL0006E": _("Invalid parameter '%(param)s' specified for CDROM."), - "KCHTMPL0007E": _("Network %(network)s specified for template %(template)s is not active"), - "KCHTMPL0008E": _("Template name must be a string"), - "KCHTMPL0009E": _("Template icon must be a path to the image"), - "KCHTMPL0010E": _("Template distribution must be a string"), - "KCHTMPL0011E": _("Template distribution version must be a string"), - "KCHTMPL0012E": _("The number of CPUs must be an integer greater than 0"), - "KCHTMPL0013E": _("Amount of memory (MB) must be an integer greater than 512"), - "KCHTMPL0014E": _("Template CDROM must be a local or remote ISO file"), - "KCHTMPL0015E": _("Invalid storage pool URI %(value)s specified for template"), - "KCHTMPL0016E": _("Specify an ISO image as CDROM or a base image to create a template"), - "KCHTMPL0017E": _("All networks for the template must be specified in a list."), - "KCHTMPL0018E": _("Specify a volume to a template when storage pool is iSCSI or SCSI"), - "KCHTMPL0019E": _("The volume %(volume)s is not in storage pool %(pool)s"), - "KCHTMPL0020E": _("Unable to create template due error: %(err)s"), - "KCHTMPL0021E": _("Unable to delete template due error: %(err)s"), - "KCHTMPL0022E": _("Disk size must be an integer greater than 1GB."), - "KCHTMPL0023E": _("Template base image must be a valid local image file"), - "KCHTMPL0024E": _("Cannot identify base image %(path)s format"), - "KCHTMPL0025E": _("When specifying CPU topology, VCPUs must be a product of sockets, cores, and threads."), - "KCHTMPL0026E": _("When specifying CPU topology, each element must be an integer greater than zero."), - "KCHTMPL0027E": _("Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc."), - - "KCHPOOL0001E": _("Storage pool %(name)s already exists"), - "KCHPOOL0002E": _("Storage pool %(name)s does not exist"), - "KCHPOOL0004E": _("Specify %(item)s in order to create the storage pool %(name)s"), - "KCHPOOL0005E": _("Unable to delete active storage pool %(name)s"), - "KCHPOOL0006E": _("Unable to list storage pools. Details: %(err)s"), - "KCHPOOL0007E": _("Unable to create storage pool %(name)s. Details: %(err)s"), - "KCHPOOL0008E": _("Unable to get number of storage volumes in storage pool %(name)s. Details: %(err)s"), - "KCHPOOL0009E": _("Unable to activate storage pool %(name)s. Details: %(err)s"), - "KCHPOOL0010E": _("Unable to deactivate storage pool %(name)s. Details: %(err)s"), - "KCHPOOL0011E": _("Unable to delete storage pool %(name)s. Details: %(err)s"), - "KCHPOOL0012E": _("Unable to create NFS Pool as export path %(path)s may block during mount"), - "KCHPOOL0013E": _("Unable to create NFS Pool as export path %(path)s mount failed"), - "KCHPOOL0014E": _("Unsupported storage pool type: %(type)s"), - "KCHPOOL0015E": _("Error while retrieving storage pool XML to %(pool)s"), - "KCHPOOL0016E": _("Storage pool name must be a string without slashes (/)"), - "KCHPOOL0017E": _("Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-iso"), - "KCHPOOL0018E": _("Storage pool path must be a string"), - "KCHPOOL0019E": _("Storage pool host must be a IP or hostname"), - "KCHPOOL0020E": _("Storage pool device must be the absolute path to the block device"), - "KCHPOOL0021E": _("Storage pool devices parameter must be a list"), - "KCHPOOL0022E": _("Target IQN of an iSCSI pool must be a string"), - "KCHPOOL0023E": _("Port of a remote storage server must be an integer between 1 and 65535"), - "KCHPOOL0024E": _("iSCSI target username must be a string"), - "KCHPOOL0025E": _("iSCSI target password must be a string"), - "KCHPOOL0026E": _("Specify name and type to create a storage pool"), - "KCHPOOL0027E": _("%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)s."), - "KCHPOOL0028E": _("Unable to extend logical pool %(pool)s. Details: %(err)s"), - "KCHPOOL0029E": _("The parameter disks only can be updated for logical storage pool."), - "KCHPOOL0030E": _("The SCSI host adapter name must be a string."), - "KCHPOOL0031E": _("The storage pool kimchi_isos is reserved for internal use"), - "KCHPOOL0032E": _("Unable to activate NFS storage pool %(name)s. NFS server %(server)s is unreachable."), - "KCHPOOL0033E": _("Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is unreachable."), - "KCHPOOL0034E": _("Unable to deactivate pool %(name)s as it is associated with some templates"), - "KCHPOOL0035E": _("Unable to delete pool %(name)s as it is associated with some templates"), - "KCHPOOL0036E": _("A volume group named '%(name)s' already exists. Please, choose another name to create the logical pool."), - "KCHPOOL0037E": _("Unable to update database with deep scan information due error: %(err)s"), - - "KCHVOL0001E": _("Storage volume %(name)s already exists"), - "KCHVOL0002E": _("Storage volume %(name)s does not exist in storage pool %(pool)s"), - "KCHVOL0003E": _("Unable to create storage volume %(volume)s because storage pool %(pool)s is not active"), - "KCHVOL0004E": _("Specify %(item)s in order to create storage volume %(volume)s"), - "KCHVOL0006E": _("Unable to list storage volumes because storage pool %(pool)s is not active"), - "KCHVOL0007E": _("Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %(err)s"), - "KCHVOL0008E": _("Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s"), - "KCHVOL0009E": _("Unable to wipe storage volumes %(name)s. Details: %(err)s"), - "KCHVOL0010E": _("Unable to delete storage volume %(name)s. Details: %(err)s"), - "KCHVOL0011E": _("Unable to resize storage volume %(name)s. Details: %(err)s"), - "KCHVOL0012E": _("Storage type %(type)s does not support volume create and delete"), - "KCHVOL0013E": _("Storage volume name must be a string"), - "KCHVOL0014E": _("Storage volume allocation must be an integer number"), - "KCHVOL0015E": _("Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc."), - "KCHVOL0016E": _("Storage volume requires a volume name"), - "KCHVOL0017E": _("Unable to update database with storage volume information due error: %(err)s"), - "KCHVOL0018E": _("Only one of parameter %(param)s can be specified"), - "KCHVOL0019E": _("Create volume from %(param)s is not supported"), - "KCHVOL0020E": _("Storage volume capacity must be an integer number."), - "KCHVOL0021E": _("Storage volume URL must be http://, https://, ftp:// or ftps://."), - "KCHVOL0022E": _("Unable to access file %(url)s. Please, check it."), - "KCHVOL0023E": _("Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)s"), - "KCHVOL0024E": _("Specify chunk data and its size to upload a file."), - "KCHVOL0025E": _("In order to upload a storage volume, specify the 'upload' parameter."), - "KCHVOL0026E": _("Unable to upload chunk data as it does not match with requested chunk size."), - "KCHVOL0027E": _("The storage volume %(vol)s is not under an upload process."), - "KCHVOL0028E": _("The upload chunk data will exceed the storage volume size."), - "KCHVOL0029E": _("Unable to upload chunk data to storage volume. Details: %(err)s."), - - "KCHIFACE0001E": _("Interface %(name)s does not exist"), - - "KCHNET0001E": _("Network %(name)s already exists"), - "KCHNET0002E": _("Network %(name)s does not exist"), - "KCHNET0003E": _("Subnet %(subnet)s specified for network %(network)s is not valid."), - "KCHNET0004E": _("Specify a network interface to create bridged network %(name)s"), - "KCHNET0005E": _("Unable to delete active network %(name)s"), - "KCHNET0006E": _("Interface %(iface)s specified for network %(network)s is already in use"), - "KCHNET0007E": _("Interface should be bare NIC, bonding or bridge device."), - "KCHNET0008E": _("Unable to create network %(name)s. Details: %(err)s"), - "KCHNET0009E": _("Unable to find a free IP address for network '%(name)s'"), - "KCHNET0010E": _("The interface %(iface)s already exists."), - "KCHNET0011E": _("Network name must be a string without slashes (/) or quotes (\")"), - "KCHNET0012E": _("Supported network types are isolated, NAT and bridge"), - "KCHNET0013E": _("Network subnet must be a string with IP address and prefix or netmask"), - "KCHNET0014E": _("Network interface must be a string"), - "KCHNET0015E": _("Network VLAN ID must be an integer between 1 and 4094"), - "KCHNET0016E": _("Specify name and type to create a Network"), - "KCHNET0017E": _("Unable to delete network %(name)s. There are some virtual machines %(vms)s and/or templates linked to this network."), - "KCHNET0018E": _("Unable to deactivate network %(name)s. There are some virtual machines %(vms)s and/or templates linked to this network."), - "KCHNET0019E": _("Bridge device %(name)s can not be the trunk device of a VLAN."), - "KCHNET0020E": _("Failed to activate interface %(iface)s: %(err)s."), - "KCHNET0021E": _("Failed to activate interface %(iface)s. Please check the physical link status."), - "KCHNET0022E": _("Failed to start network %(name)s. Details: %(err)s"), - - "KCHDR0001E": _("Debug report %(name)s does not exist"), - "KCHDR0002E": _("Debug report tool not found in system"), - "KCHDR0003E": _("Unable to create debug report %(name)s. Details: %(err)s."), - "KCHDR0004E": _("Can not find any debug report with the given name %(name)s"), - "KCHDR0005E": _("Unable to generate debug report %(name)s. Details: %(err)s"), - "KCHDR0006E": _("You should give a name for the debug report file."), - "KCHDR0007E": _("Debug report name must be a string. Only letters, digits, underscore ('_') and hyphen ('-') are allowed."), - "KCHDR0008E": _("The debug report with specified name \"%(name)s\" already exists. Please use another one."), - - "KCHSR0001E": _("Storage server %(server)s was not used by Kimchi"), - - "KCHDISTRO0001E": _("Distro '%(name)s' does not exist"), - - "KCHPART0001E": _("Partition %(name)s does not exist in the host"), - - "KCHHOST0001E": _("Unable to shutdown host machine as there are running virtual machines"), - "KCHHOST0002E": _("Unable to reboot host machine as there are running virtual machines"), - "KCHHOST0003E": _("Node device '%(name)s' not found"), - "KCHHOST0004E": _("Conflicting flag filters specified."), - - "KCHPKGUPD0001E": _("No packages marked for update"), - "KCHPKGUPD0002E": _("Package %(name)s is not marked to be updated."), - "KCHPKGUPD0003E": _("Error while getting packages marked to be updated. Details: %(err)s"), - "KCHPKGUPD0004E": _("There is no compatible package manager for this system."), - - "KCHUTILS0003E": _("Unable to choose a virtual machine name"), - - "KCHVMSTOR0002E": _("Invalid storage type. Types supported: 'cdrom', 'disk'"), - "KCHVMSTOR0003E": _("The path '%(value)s' is not a valid local/remote path for the device"), - "KCHVMSTOR0006E": _("Only CDROM path can be update."), - "KCHVMSTOR0007E": _("The storage device %(dev_name)s does not exist in the virtual machine %(vm_name)s"), - "KCHVMSTOR0008E": _("Error while creating new storage device: %(error)s"), - "KCHVMSTOR0009E": _("Error while updating storage device: %(error)s"), - "KCHVMSTOR0010E": _("Error while removing storage device: %(error)s"), - "KCHVMSTOR0011E": _("Do not support IDE device hot plug"), - "KCHVMSTOR0012E": _("Specify type and path or type and pool/volume to add a new virtual machine disk"), - "KCHVMSTOR0013E": _("Specify path to update virtual machine disk"), - "KCHVMSTOR0014E": _("Controller type %(type)s limitation of %(limit)s devices reached"), - "KCHVMSTOR0015E": _("Cannot retrieve disk path information for given pool/volume: %(error)s"), - "KCHVMSTOR0016E": _("Volume already in use by other virtual machine."), - "KCHVMSTOR0017E": _("Only one of path or pool/volume can be specified to add a new virtual machine disk"), - "KCHVMSTOR0018E": _("Volume chosen with format %(format)s does not fit in the storage type %(type)s"), - - "KCHREPOS0001E": _("YUM Repository ID must be one word only string."), - "KCHREPOS0002E": _("Repository URL must be an http://, ftp:// or file:// URL."), - "KCHREPOS0003E": _("Repository configuration is a dictionary with specific values according to repository type."), - "KCHREPOS0004E": _("Distribution to DEB repository must be a string"), - "KCHREPOS0005E": _("Components to DEB repository must be listed in a array"), - "KCHREPOS0006E": _("Components to DEB repository must be a string"), - "KCHREPOS0007E": _("Mirror list to repository must be a string"), - "KCHREPOS0008E": _("YUM Repository name must be string."), - "KCHREPOS0009E": _("GPG check must be a boolean value."), - "KCHREPOS0010E": _("GPG key must be a URL pointing to the ASCII-armored file."), - "KCHREPOS0011E": _("Could not update repository %(repo_id)s."), - "KCHREPOS0012E": _("Repository %(repo_id)s does not exist."), - "KCHREPOS0013E": _("Specify repository base URL, mirror list or metalink in order to create or update a YUM repository."), - "KCHREPOS0014E": _("Repository management tool was not recognized for your system."), - "KCHREPOS0015E": _("Repository %(repo_id)s is already enabled."), - "KCHREPOS0016E": _("Repository %(repo_id)s is already disabled."), - "KCHREPOS0017E": _("Could not remove repository %(repo_id)s."), - "KCHREPOS0018E": _("Could not write repository configuration file %(repo_file)s"), - "KCHREPOS0019E": _("Specify repository distribution in order to create a DEB repository."), - "KCHREPOS0020E": _("Could not enable repository %(repo_id)s."), - "KCHREPOS0021E": _("Could not disable repository %(repo_id)s."), - "KCHREPOS0022E": _("YUM Repository ID already exists"), - "KCHREPOS0023E": _("YUM Repository name must be a string"), - "KCHREPOS0024E": _("Unable to list repositories. Details: '%(err)s'"), - "KCHREPOS0025E": _("Unable to retrieve repository information. Details: '%(err)s'"), - "KCHREPOS0026E": _("Unable to add repository. Details: '%(err)s'"), - "KCHREPOS0027E": _("Unable to remove repository. Details: '%(err)s'"), - "KCHREPOS0028E": _("Configuration items: '%(items)s' are not supported by repository manager"), - "KCHREPOS0029E": _("Repository metalink must be an http://, ftp:// or file:// URL."), - "KCHREPOS0030E": _("Cannot specify mirrorlist and metalink at the same time."), - - "KCHSNAP0001E": _("Virtual machine '%(vm)s' must be stopped before creating a snapshot of it."), - "KCHSNAP0002E": _("Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"), - "KCHSNAP0003E": _("Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."), - "KCHSNAP0004E": _("Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"), - "KCHSNAP0005E": _("Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"), - "KCHSNAP0006E": _("Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"), - "KCHSNAP0008E": _("Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %(err)s"), - "KCHSNAP0009E": _("Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %(err)s"), - "KCHSNAP0010E": _("Unable to create snapshot of virtual machine '%(vm)s' because it contains a disk with format '%(format)s'; only 'qcow2' is supported."), - - "KCHCPUINF0001E": _("The number of vCPUs is too large for this system."), - "KCHCPUINF0002E": _("Invalid vCPU/topology combination."), - "KCHCPUINF0003E": _("This host (or current configuration) does not allow CPU topology."), - -} diff --git a/plugins/kimchi/imageinfo.py b/plugins/kimchi/imageinfo.py deleted file mode 100644 index 8a22495..0000000 --- a/plugins/kimchi/imageinfo.py +++ /dev/null @@ -1,72 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import guestfs -import json -import os -import sys - -from wok.exception import ImageFormatError, InvalidParameter, TimeoutExpired -from wok.utils import run_command, wok_log - - -def probe_img_info(path): - cmd = ["qemu-img", "info", "--output=json", path] - info = dict() - try: - out = run_command(cmd, 10)[0] - except TimeoutExpired: - wok_log.warning("Cannot decide format of base img %s", path) - return None - - info = json.loads(out) - info['virtual-size'] = info['virtual-size'] >> 30 - info['actual-size'] = info['actual-size'] >> 30 - return info - - -def probe_image(image_path): - if not os.path.isfile(image_path): - raise InvalidParameter("KCHIMG0004E", {'filename': image_path}) - - if not os.access(image_path, os.R_OK): - raise ImageFormatError("KCHIMG0003E", {'filename': image_path}) - - g = guestfs.GuestFS(python_return_dict=True) - g.add_drive_opts(image_path, readonly=1) - g.launch() - - try: - roots = g.inspect_os() - except: - raise ImageFormatError("KCHIMG0001E") - - if len(roots) == 0: - raise ImageFormatError("KCHIMG0002E") - - for root in roots: - version = "%d.%d" % (g.inspect_get_major_version(root), - g.inspect_get_minor_version(root)) - distro = "%s" % (g.inspect_get_distro(root)) - - return (distro, version) - - -if __name__ == '__main__': - print probe_image(sys.argv[1]) diff --git a/plugins/kimchi/iscsi.py b/plugins/kimchi/iscsi.py deleted file mode 100644 index 02886ac..0000000 --- a/plugins/kimchi/iscsi.py +++ /dev/null @@ -1,88 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301USA - -import subprocess - - -from wok.exception import OperationFailed - - -class TargetClient(object): - def __init__(self, target, host, port=None, auth=None): - self.portal = host + ("" if port is None else ":%s" % port) - self.target = target - self.auth = auth - self.targetCmd = ['iscsiadm', '--mode', 'node', '--targetname', - self.target, '--portal', self.portal] - - def _update_db(self, Name, Value): - self._run_cmd(['--op=update', '--name', Name, '--value', Value]) - - def _update_auth(self): - if self.auth is None: - items = (('node.session.auth.authmethod', 'None'), - ('node.session.auth.username', ''), - ('node.session.auth.password', '')) - else: - items = (('node.session.auth.authmethod', 'CHAP'), - ('node.session.auth.username', self.auth['username']), - ('node.session.auth.password', self.auth['password'])) - for name, value in items: - self._update_db(name, value) - - def _run_cmd(self, cmd): - iscsiadm = subprocess.Popen( - self.targetCmd + cmd, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = iscsiadm.communicate() - if iscsiadm.returncode != 0: - msg_args = {'portal': self.portal, 'err': err} - raise OperationFailed("KCHISCSI0001E", msg_args) - return out - - def _discover(self): - iscsiadm = subprocess.Popen( - ['iscsiadm', '--mode', 'discovery', '--type', 'sendtargets', - '--portal', self.portal], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = iscsiadm.communicate() - if iscsiadm.returncode != 0: - msg_args = {'portal': self.portal, 'err': err} - raise OperationFailed("KCHISCSI0001E", msg_args) - return out - - def _run_op(self, op): - self._run_cmd(['--' + op]) - - def login(self): - self._discover() - self._update_auth() - self._run_op('login') - - def logout(self): - self._run_op('logout') - - def validate(self): - try: - self.login() - except OperationFailed: - return False - - self.logout() - return True diff --git a/plugins/kimchi/isoinfo.py b/plugins/kimchi/isoinfo.py deleted file mode 100644 index 8de6885..0000000 --- a/plugins/kimchi/isoinfo.py +++ /dev/null @@ -1,506 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import contextlib -import glob -import os -import platform -import re -import stat -import struct -import sys -import urllib2 - - -from wok.exception import IsoFormatError -from wok.utils import check_url_path, wok_log - - -iso_dir = [ - ## - # Portions of this data from libosinfo: http://libosinfo.org/ - # - # Each tuple has the following three members: - # Distro ID: Nickname for the distro or OS family - # Distro Version: A function or string that provides a specific version - # given a regular expression match on the volume id string - # Regular Expression: A regex to match against the ISO Volume ID - ## - ('openbsd', lambda m: m.group(2), - ('OpenBSD/(i386|amd64) (\d+\.\d+) Install CD')), - ('centos', lambda m: m.group(1), - ('CentOS_(\d+\.\d+)_Final')), - ('windows', '2000', - ('W2AFPP|SP1AFPP|SP2AFPP|YRMAFPP|ZRMAFPP|W2AOEM|SP1AOEM|SP2AOEM' + - '|YRMAOEM|ZRMAOEM|W2ASEL|SP2ASEL|W2SFPP|SP1SFPP|SP2SFPP|YRMSFPP' + - '|ZRMSFPP|W2SOEM|W2SOEM|SP1SOEM|SP2SOEM|YRMSOEM|ZRMSOEM|W2SSEL' + - '|SP2SSEL|W2PFPP|SP1PFPP|SP2PFPP|YRMPFPP|ZRMPFPP|W2POEM|SP1POEM' + - '|SP2POEM|YRMPOEM|ZRMPOEM|W2PSEL|SP2PSEL|W2PCCP|WIN2000|W2K_SP4')), - ('windows', 'xp', - ('WXPFPP|WXHFPP|WXPCCP|WXHCCP|WXPOEM|WXHOEM|WXPVOL|WXPEVL|XRMPFPP' + - '|XRMHFPP|XRMPCCP|XRMHCCP|XRMPOEM|XRMHOEM|XRMPVOL|XRMSD2|X1APFPP' + - '|X1AHFPP|X1APCCP|X1APCCP|X1AHCCP|X1APOEM|X1AHOEM|X1APVOL|VRMPFPP' + - '|VRMHFPP|VRMPCCP|VRMHCCP|VRMPOEM|VRMHOEM|VRMPVOL|VRMSD2|VX2PFPP' + - '|VX2HFPP|VX2PCCP|VX2HCCP|VX2POEM|VX2HOEM|VX2PRMFPP|VX2PVOL|GRTMUPD' + - '|GRTMPFPP|GRTMPRMFPP|GRTMHFPP|GRTMHKFPP|GRTMHKNFPP|GRTMHRMFPP' + - '|GRTMPOEM|GRTMHOEM|GRTMPVOL|GRTMPKNVOL|GRTMPKVOL|GRTMPRMVOL' + - '|MX2PFPP|MRMSD2|ARMPXFPP|ARMPXCCP|ARMPXOEM|ARMPXVOL|AX2PXCFPP' + - '|AX2PXFPP|NRMPIFPP')), - ('windows', '2003', - ('ARMECHK|ARMEVOL|ARMSVOL|ARMWVOL|ARMEEVL|ARMSEVL|ARMWEVL|ARMEOEM' + - '|ARMDOEM|ARMSOEM|ARMWOEM|ARMEFPP|ARMDFPP|ARMSFPP|ARMWFPP|NRMECHK' + - '|NRMEVOL|NRMSVOL|NRMWVOL|NRMEEVL|NRMSEVL|NRMWEVL|NRMEOEM|NRMDOEM' + - '|NRMSOEM|NRMWOEM|NRMEFPP|NRMDFPP|NRMSFPP|NRMSFPP|CRMSVOL|CRMSXVOL' + - '|BRMEVOL|BX2DVOL|ARMEEVL|BRMEEVL|CR0SP2|ARMEICHK|ARMEIFPP|ARMEIEVL' + - '|ARMEIOEM|ARMDIOEM|ARMEXFPP|ARMDFPP|ARMSXFPP|CR0SPX2|NRMEICHK' + - '|NRMEIFPP|NRMDIFPP|NRMEIOEM|NRMDIOEM|NRMEIVOL|NRMEIEVL|BRMEXVOL' + - '|BX2DXVOL|ARMEIFPP|CR0SPI2')), - ('windows', '2003r2', - ('CRMEFPP|CRMSFPP|CR0SCD2|CR0ECD2|BX2SFPP|BX2EFPP|BRMECD2FRE' + - '|BRMSCD2FRE|CRMEXFPP|CRMSXFPP|CR0SCD2X|CR0ECD2X|BX2SXFPP|BX2EXFPP' + - '|BRMECD2XFRE|BRMSCD2XFRE|CRMDVOL|CRMDXVOL')), - ('windows', '2008', - ('KRTMSVOL|KRTMSCHK|KRMWVOL|KRMSVOL|KRTMSXVOL|KRTMSXCHK|KRMWXVOL' + - '|KRMSXVOL')), - ('windows', '2008r2', - ('GRMSXVOL|GRMSXFRER|GRMSHXVOL|GRMSIAIVOL|SRVHPCR2')), - ('windows', 'vista', - ('FB1EVOL|LRMCFRE|FRTMBVOL|FRMBVOL|FRMEVOL|FB1EXVOL|LRMCXFRE' + - '|FRTMBXVOL|FRMBXVOL|FRMEXVOL|LRMEVOL|LRMEXVOL')), - ('windows', '7', - ('GRMCULFRER|GSP1RMCNPRFRER|GSP1RMCNULFRER|GSP1RMCULFRER' + - '|GSP1RMCPRFRER|GRMCENVOL|GRMCNENVOL|GRMCPRFRER|GSP1RMCPRVOL' + - '|GRMCULXFRER|GSP1RMCPRXFRER|GSP1RMCNHPXFRER|GRMCHPXFRER|GRMCXCHK' + - '|GSP1RMCENXVOL|GRMCENXVOL|GRMCNENXVOL|GRMCPRXFRER|GSP1RMCPRXVOL')), - ('windows', '8', - ('HB1_CCPA_X86FRE|HRM_CCSA_X86FRE|HRM_CCSA_X86CHK|HRM_CCSNA_X86CHK' + - '|HRM_CCSNA_X86FRE|HRM_CENA_X86FREV|HRM_CENA_X86CHKV' + - '|HRM_CENNA_X86FREV|HRM_CENNA_X86CHKV|HRM_CPRA_X86FREV' + - '|HRM_CPRNA_X86FREV|HB1_CCPA_X64FRE|HRM_CCSA_X64FRE' + - '|HRM_CCSA_X64CHK|HRM_CCSNA_X64FRE|HRM_CCSNA_X64CHK' + - '|HRM_CENNA_X64FREV|HRM_CENNA_X64CHKV|HRM_CENA_X64FREV' + - '|HRM_CENA_X64CHKV|HRM_CPRA_X64FREV|HRM_CPRNA_X64FREV')), - ('sles', '10', 'SLES10|SUSE-Linux-Enterprise-Server.001'), - ('sles', '11', 'SUSE_SLES-11-0-0'), - ('sles', '12', 'SLE-12'), - ('sles', lambda m: "11sp%s" % m.group(1), 'SLES-11-SP(\d+)'), - ('opensuse', lambda m: m.group(1), 'openSUSE[ -](\d+\.\d+)'), - ('opensuse', '11.1', 'SU1110.001'), - ('opensuse', '11.3', - 'openSUSE-DVD-i586-Build0702..001|openSUSE-DVD-x86_64.0702..001'), - ('opensuse', '11.4', - 'openSUSE-DVD-i586-Build0024|openSUSE-DVD-x86_640024'), - ('opensuse', '12.1', - 'openSUSE-DVD-i586-Build0039|openSUSE-DVD-x86_640039'), - ('opensuse', '12.2', - 'openSUSE-DVD-i586-Build0167|openSUSE-DVD-x86_640167'), - ('rhel', '4.8', 'RHEL/4-U8'), - ('rhel', lambda m: m.group(2), 'RHEL(-LE)?[_/-](\d+\.\d+)'), - ('debian', lambda m: m.group(1), 'Debian (\d+\.\d+)'), - ('ubuntu', lambda m: m.group(2), '[Uu]buntu(-Server)? (\d+\.\d+)'), - ('fedora', lambda m: m.group(1), 'Fedora[ -](\d+)'), - ('fedora', lambda m: m.group(1), 'Fedora.*-(\d+)-'), - ('gentoo', lambda m: m.group(1), 'Gentoo Linux \w+ (\d+)'), - ('powerkvm', 'live_cd', 'POWERKVM_LIVECD'), - ('arch', lambda m: m.group(1), 'ARCH_(\d+)'), -] - - -class IsoImage(object): - """ - Scan an iso9660 image to extract the Volume ID and check for boot-ability - - ISO-9660 specification: - http://www.ecma-international.org/publications/standards/Ecma-119.htm - - El-Torito specification: - http://download.intel.com/support/motherboards/desktop/sb/specscdrom.pdf - """ - SECTOR_SIZE = 2048 - VOL_DESC = struct.Struct("=B5sBB32s32s") - EL_TORITO_BOOT_RECORD = struct.Struct("=B5sB32s32sI") - EL_TORITO_VALIDATION_ENTRY = struct.Struct("=BBH24sHBB") - EL_TORITO_BOOT_ENTRY = struct.Struct("=BBHBBHL20x") - # Path table info starting in ISO9660 offset 132. We force little - # endian byte order (the '<' sign) because Power systems can run on - # both. - # First int is path table size, next 4 bytes are discarded (it is - # the same info but in big endian) and next int is the location. - PATH_TABLE_SIZE_LOC = struct.Struct("<I 4s I") - - def __init__(self, path): - self.path = path - self.remote = self._is_iso_remote() - self.volume_id = None - self.bootable = False - self._scan() - - def _is_iso_remote(self): - if os.path.exists(self.path): - st_mode = os.stat(self.path).st_mode - if stat.S_ISREG(st_mode) or stat.S_ISBLK(st_mode): - return False - - if check_url_path(self.path): - return True - - raise IsoFormatError("KCHISO0001E", {'filename': self.path}) - - def probe(self): - if not self.bootable: - raise IsoFormatError("KCHISO0002E", {'filename': self.path}) - - matcher = Matcher(self.volume_id) - - for d, v, regex in iso_dir: - if matcher.search(regex): - distro = d - if hasattr(v, '__call__'): - version = v(matcher) - else: - version = v - return (distro, version) - - msg = "probe_iso: Unable to identify ISO %s with Volume ID: %s" - wok_log.debug(msg, self.path, self.volume_id) - - return ('unknown', 'unknown') - - def _unpack(self, s, data): - return s.unpack(data[:s.size]) - - def _scan_el_torito(self, data): - """ - Search the Volume Descriptor Table for an El Torito boot record. If - found, the boot record will provide a link to a boot catalogue. The - first entry in the boot catalogue is a validation entry. The next - entry contains the default boot entry. The default boot entry will - indicate whether the image is considered bootable. - """ - vd_type = -1 - for i in xrange(1, 4): - fmt = IsoImage.EL_TORITO_BOOT_RECORD - ptr = i * IsoImage.SECTOR_SIZE - tmp_data = data[ptr:ptr + fmt.size] - if len(tmp_data) < fmt.size: - return - - (vd_type, vd_ident, vd_ver, - et_ident, pad0, boot_cat) = self._unpack(fmt, tmp_data) - if vd_type == 255: # Volume record terminator - return - if vd_type == 0: # Found El-Torito Boot Record - break - if not et_ident.startswith('EL TORITO SPECIFICATION'): - raise IsoFormatError("KCHISO0003E", - {'filename': self.path}) - - offset = IsoImage.SECTOR_SIZE * boot_cat - size = IsoImage.EL_TORITO_VALIDATION_ENTRY.size + \ - IsoImage.EL_TORITO_BOOT_ENTRY.size - data = self._get_iso_data(offset, size) - - fmt = IsoImage.EL_TORITO_VALIDATION_ENTRY - tmp_data = data[0:fmt.size] - ptr = fmt.size - (hdr_id, platform_id, pad0, - ident, csum, key55, keyAA) = self._unpack(fmt, tmp_data) - if key55 != 0x55 or keyAA != 0xaa: - raise IsoFormatError("KCHISO0004E", - {'filename': self.path}) - - fmt = IsoImage.EL_TORITO_BOOT_ENTRY - tmp_data = data[ptr:ptr + fmt.size] - (boot, media_type, load_seg, sys_type, - pad0, sectors, load_rba) = self._unpack(fmt, tmp_data) - if boot == 0x88: - self.bootable = True - elif boot == 0: - self.bootable = False - else: - raise IsoFormatError("KCHISO0005E", - {'filename': self.path}) - - def _scan_ppc(self): - """ - PowerPC firmware does not use the conventional El Torito boot - specification. Instead, it looks for a file '/ppc/bootinfo.txt' - which contains boot information. A PPC image is bootable if - this file exists in the filesystem [1]. - - To detect if a PPC ISO is bootable, we could simply mount the - ISO and search for the boot file as we would with any other - file in the filesystem. We can also look for the boot file - searching byte by byte the ISO image. This is possible because - the PPC ISO image follows the ISO9660 standard [2]. Mounting - the ISO requires extra resources and it takes longer than - searching the image data, thus we chose the latter approach - in this code. - - To locate a file we must access the Path Table, which contains - the records of all the directories in the ISO. After locating - the directory/subdirectory that contains the file, we access - the Directory Record to find it. - - - .. [1] https://www.ibm.com/developerworks/community/wikis/home?\ -lang=en#!/wiki/W51a7ffcf4dfd_4b40_9d82_446ebc23c550/page/PowerLinux\ -%20Boot%20howto - .. [2] http://wiki.osdev.org/ISO_9660 - """ - - # To locate any file we must access the Path Table, which - # contains the records of all the directories in the ISO. - # ISO9660 dictates that the Path Table location information - # is at offset 132, inside the Primary Volume Descriptor, - # after the SystemArea (16*SECTOR_SIZE). - # - # In the Path table info we're forcing little endian byte - # order (the '<' sign) because Power systems can run on - # both. - # - # First int is path table size, next 4 bytes are discarded (it is - # the same info but in big endian) and next int is the location. - PATH_TABLE_LOC_OFFSET = 16 * IsoImage.SECTOR_SIZE + 132 - PATH_TABLE_SIZE_LOC = struct.Struct("<I 4s I") - - path_table_loc_data = self._get_iso_data(PATH_TABLE_LOC_OFFSET, - PATH_TABLE_SIZE_LOC.size) - path_size, unused, path_loc = self._unpack(PATH_TABLE_SIZE_LOC, - path_table_loc_data) - # Fetch the Path Table using location and size found above - path_table_offset = path_loc * IsoImage.SECTOR_SIZE - path_table_data = self._get_iso_data(path_table_offset, path_size) - - # Loop inside the path table to find the directory 'ppc'. - # The contents of the registers are: - # - length of the directory identifier (1 byte) - # - extended attribute record length (1 byte) - # - location of directory register (4 bytes) - # - directory number of parent dir (2 bytes) - # - directory name (size varies according to length) - # - padding field - 1 byte if the length is odd, not present if even - DIR_NAMELEN_LOCATION_PARENT = struct.Struct("<B B I H") - dir_struct_size = DIR_NAMELEN_LOCATION_PARENT.size - i = 0 - while i < path_size: - dir_data = path_table_data[i: i+dir_struct_size] - i += dir_struct_size - # We won't use the Extended Attribute Record - dir_namelen, unused, dir_loc, dir_parent = \ - self._unpack(DIR_NAMELEN_LOCATION_PARENT, dir_data) - if dir_parent == 1: - # read the dir name using the namelen - dir_name = path_table_data[i: i+dir_namelen].rstrip() - if dir_name.lower() == 'ppc': - # stop searching, dir was found - break - # Need to consider the optional padding field as well - i += dir_namelen + dir_namelen % 2 - - if i > path_size: - # Didn't find the '/ppc' directory. ISO is not bootable. - self.bootable = False - return - - # Get the 'ppc' directory record using 'dir_loc'. - ppc_dir_offset = dir_loc * IsoImage.SECTOR_SIZE - - # We need to find the sector size of this dir entry. The - # size of the File Section is located 10 bytes after - # the dir location. - DIR_SIZE_FMT = struct.Struct("<10sI") - data = self._get_iso_data(ppc_dir_offset, DIR_SIZE_FMT.size) - unused, dir_size = self._unpack(DIR_SIZE_FMT, data) - # If the dir is in the middle of a sector, the sector is - # padded zero and won't be utilized. We need to round up - # the result - dir_sectorsize = dir_size / IsoImage.SECTOR_SIZE - if dir_size % IsoImage.SECTOR_SIZE: - dir_sectorsize += 1 - - # Fixed-size directory record fields: - # - length of directory record (1 byte) - # - extended attr. record length (1 byte) - # - location of extend in both-endian format (8 bytes) - # - data length (size of extend) in both-endian (8 bytes) - # - recording date and time (7 bytes) - # - file flags (1 byte) - # - file unit size interleaved (1 byte) - # - interleave gap size (1 byte) - # - volume sequence number (4 bytes) - # - length of file identifier (1 byte) - # - # Of all these fields, we will use only 3 of them, 'ignoring' - # 30 bytes total. - STATIC_DIR_RECORD_FMT = struct.Struct("<B 24s B 6s B") - static_rec_size = STATIC_DIR_RECORD_FMT.size - - # Maximum offset possible of all the records of this directory - DIR_REC_MAX = ppc_dir_offset + dir_sectorsize*IsoImage.SECTOR_SIZE - # Max size of a given directory record - MAX_DIR_SIZE = 255 - # Name of the boot file - BOOT_FILE_NAME = "bootinfo.txt" - - # Loop until one of the following happens: - # - boot file is found - # - end of directory record listing for the 'ppc' dir - while ppc_dir_offset < DIR_REC_MAX: - record_data = self._get_iso_data(ppc_dir_offset, MAX_DIR_SIZE) - dir_rec_len, unused, file_flags, unused2, file_name_len = \ - self._unpack(STATIC_DIR_RECORD_FMT, record_data) - - # if dir_rec_len = 0, increment offset (skip the - # dir_rec_len byte) and continue the loop - if dir_rec_len == 0: - ppc_dir_offset += 1 - continue - - # Get filename of the file/dir we're at. - filename = record_data[static_rec_size: - static_rec_size + file_name_len].rstrip() - # The second bit of the file_flags indicate if this record - # is a directory. - if BOOT_FILE_NAME in filename.lower() and (file_flags & 2) != 1: - self.bootable = True - return - - # Update offset and keep looking. There is a padding here - # if the length of the file identifier is EVEN. - padding = 0 - if not file_name_len % 2: - padding = 1 - ppc_dir_offset += dir_rec_len + padding - # If reached this point the file wasn't found = not bootable - self.bootable = False - - def _scan_primary_vol(self, data): - """ - Scan one sector for a Primary Volume Descriptor and extract the - Volume ID from the table - """ - primary_vol_data = data[0: -1] - info = self._unpack(IsoImage.VOL_DESC, primary_vol_data) - (vd_type, vd_ident, vd_ver, pad0, sys_id, vol_id) = info - if vd_type != 1: - raise IsoFormatError("KCHISO0006E", {'filename': self.path}) - if vd_ident != 'CD001' or vd_ver != 1: - raise IsoFormatError("KCHISO0007E", {'filename': self.path}) - if vol_id.strip() == 'RED_HAT': - # Some RHEL ISO images store the infomation of volume id in the - # location of volume set id mistakenly. - self.volume_id = self._get_volume_set_id(data) - else: - self.volume_id = vol_id - - def _get_volume_set_id(self, data): - # The index is picked from ISO-9660 specification. - return data[190: 318] - - def _get_iso_data(self, offset, size): - if self.remote: - request = urllib2.Request(self.path) - range_header = "bytes=%d-%d" % (offset, offset + size - 1) - request.add_header("range", range_header) - with contextlib.closing(urllib2.urlopen(request)) as response: - data = response.read() - else: - with open(self.path) as fd: - fd.seek(offset) - data = fd.read(size) - - return data - - def _scan(self): - offset = 16 * IsoImage.SECTOR_SIZE - size = 4 * IsoImage.SECTOR_SIZE - data = self._get_iso_data(offset, size) - if len(data) < 2 * IsoImage.SECTOR_SIZE: - return - - self._scan_primary_vol(data) - if platform.machine().startswith('ppc'): - self._scan_ppc() - else: - self._scan_el_torito(data) - - -class Matcher(object): - """ - Simple utility class to assist with matching a given string against a - series of regular expressions. - """ - def __init__(self, matchstring): - self.matchstring = matchstring - - def search(self, regex): - self.lastmatch = re.search(regex, self.matchstring) - return bool(self.lastmatch) - - def group(self, num): - return self.lastmatch.group(num) - - -def probe_iso(status_helper, params): - loc = params['path'].encode("utf-8") - updater = params['updater'] - ignore = False - ignore_list = params.get('ignore_list', []) - - def update_result(iso, ret): - path = os.path.abspath(iso) if os.path.isfile(iso) else iso - updater({'path': path, 'distro': ret[0], 'version': ret[1]}) - - if os.path.isdir(loc): - for root, dirs, files in os.walk(loc): - for dir_name in ignore_list: - if root in glob.glob(dir_name): - ignore = True - break - if ignore: - ignore = False - continue - for name in files: - if not name.lower().endswith('.iso'): - continue - iso = os.path.join(root, name) - try: - iso_img = IsoImage(iso) - ret = iso_img.probe() - update_result(iso, ret) - except: - continue - else: - iso_img = IsoImage(loc) - ret = iso_img.probe() - update_result(loc, ret) - - if status_helper is not None: - status_helper('', True) - - -if __name__ == '__main__': - iso_list = [] - - def updater(iso_info): - iso_list.append(iso_info) - - probe_iso(None, dict(path=sys.argv[1], updater=updater)) - print iso_list diff --git a/plugins/kimchi/kimchi.conf b/plugins/kimchi/kimchi.conf deleted file mode 100644 index 1bf78e4..0000000 --- a/plugins/kimchi/kimchi.conf +++ /dev/null @@ -1,37 +0,0 @@ -[wok] -enable = True -plugin_class = "KimchiRoot" -uri = "/plugins/kimchi" -extra_auth_api_class = "control.sub_nodes" - -[/] -tools.trailing_slash.on = False -request.methods_with_bodies = ('POST', 'PUT') -tools.nocache.on = True -tools.proxy.on = True -tools.sessions.on = True -tools.sessions.name = 'wok' -tools.sessions.secure = True -tools.sessions.httponly = True -tools.sessions.locking = 'explicit' -tools.sessions.storage_type = 'ram' -tools.sessions.timeout = 10 -tools.wokauth.on = True - -[/data/screenshots] -tools.staticdir.on = True -tools.staticdir.dir = wok.config.PluginPaths('kimchi').state_dir + '/screenshots' -tools.nocache.on = False - -[/data/debugreports] -tools.staticdir.on = True -tools.staticdir.dir = wok.config.PluginPaths('kimchi').state_dir + '/debugreports' -tools.nocache.on = False -tools.wokauth.on = True -tools.staticdir.content_types = {'xz': 'application/x-xz'} - -[/help] -tools.staticdir.on = True -tools.staticdir.dir = wok.config.PluginPaths('kimchi').ui_dir + '/pages/help' -tools.nocache.on = True - diff --git a/plugins/kimchi/kvmusertests.py b/plugins/kimchi/kvmusertests.py deleted file mode 100644 index 35350d8..0000000 --- a/plugins/kimchi/kvmusertests.py +++ /dev/null @@ -1,79 +0,0 @@ -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import libvirt -import platform -import psutil -import threading - - -from wok.rollbackcontext import RollbackContext - -KVMUSERTEST_VM_NAME = "KVMUSERTEST_VM" - - -class UserTests(object): - SIMPLE_VM_XML = """ - <domain type='kvm'> - <name>%(name)s</name> - <memory unit='KiB'>262144</memory> - <os> - <type arch='%(arch)s'>hvm</type> - <boot dev='hd'/> - </os> - </domain>""" - lock = threading.Lock() - user = None - - @classmethod - def probe_user(cls): - with cls.lock: - if cls.user: - return cls.user - - arch = 'ppc64' if platform.machine() == 'ppc64le' \ - else platform.machine() - - xml = cls.SIMPLE_VM_XML % {'name': KVMUSERTEST_VM_NAME, 'arch': arch} - - with RollbackContext() as rollback: - with cls.lock: - conn = libvirt.open(None) - rollback.prependDefer(conn.close) - f = libvirt.VIR_DOMAIN_START_AUTODESTROY - dom = conn.createXML(xml, flags=f) - rollback.prependDefer(dom.destroy) - filename = '/var/run/libvirt/qemu/%s.pid' % KVMUSERTEST_VM_NAME - with open(filename) as f: - pidStr = f.read() - p = psutil.Process(int(pidStr)) - - # bug fix #357 - # in psutil 2.0 and above versions, username will be a method, - # not a string - if callable(p.username): - cls.user = p.username() - else: - cls.user = p.username - - return cls.user - - -if __name__ == '__main__': - ut = UserTests() - print ut.probe_user() diff --git a/plugins/kimchi/m4/ac_python_module.m4 b/plugins/kimchi/m4/ac_python_module.m4 deleted file mode 100644 index 32b9d72..0000000 --- a/plugins/kimchi/m4/ac_python_module.m4 +++ /dev/null @@ -1,30 +0,0 @@ -dnl @synopsis AC_PYTHON_MODULE(modname[, fatal]) -dnl -dnl Checks for Python module. -dnl -dnl If fatal is non-empty then absence of a module will trigger an -dnl error. -dnl -dnl @category InstalledPackages -dnl @author Andrew Collier <colliera@nu.ac.za>. -dnl @version 2004-07-14 -dnl @license AllPermissive - -AC_DEFUN([AC_PYTHON_MODULE],[ - AC_MSG_CHECKING(python module: $1) - python -c "import $1" 2>/dev/null - if test $? -eq 0; - then - AC_MSG_RESULT(yes) - eval AS_TR_CPP(HAVE_PYMOD_$1)=yes - else - AC_MSG_RESULT(no) - eval AS_TR_CPP(HAVE_PYMOD_$1)=no - # - if test -n "$2" - then - AC_MSG_ERROR(failed to find required module $1) - exit 1 - fi - fi -]) diff --git a/plugins/kimchi/m4/gettext.m4 b/plugins/kimchi/m4/gettext.m4 deleted file mode 100644 index f84e6a5..0000000 --- a/plugins/kimchi/m4/gettext.m4 +++ /dev/null @@ -1,383 +0,0 @@ -# gettext.m4 serial 63 (gettext-0.18) -dnl Copyright (C) 1995-2010 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. -dnl Bruno Haible <haible@clisp.cons.org>, 2000-2006, 2008-2010. - -dnl Macro to add for using GNU gettext. - -dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). -dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The -dnl default (if it is not specified or empty) is 'no-libtool'. -dnl INTLSYMBOL should be 'external' for packages with no intl directory, -dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. -dnl If INTLSYMBOL is 'use-libtool', then a libtool library -dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, -dnl depending on --{enable,disable}-{shared,static} and on the presence of -dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library -dnl $(top_builddir)/intl/libintl.a will be created. -dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext -dnl implementations (in libc or libintl) without the ngettext() function -dnl will be ignored. If NEEDSYMBOL is specified and is -dnl 'need-formatstring-macros', then GNU gettext implementations that don't -dnl support the ISO C 99 <inttypes.h> formatstring macros will be ignored. -dnl INTLDIR is used to find the intl libraries. If empty, -dnl the value `$(top_builddir)/intl/' is used. -dnl -dnl The result of the configuration is one of three cases: -dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled -dnl and used. -dnl Catalog format: GNU --> install in $(datadir) -dnl Catalog extension: .mo after installation, .gmo in source tree -dnl 2) GNU gettext has been found in the system's C library. -dnl Catalog format: GNU --> install in $(datadir) -dnl Catalog extension: .mo after installation, .gmo in source tree -dnl 3) No internationalization, always use English msgid. -dnl Catalog format: none -dnl Catalog extension: none -dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. -dnl The use of .gmo is historical (it was needed to avoid overwriting the -dnl GNU format catalogs when building on a platform with an X/Open gettext), -dnl but we keep it in order not to force irrelevant filename changes on the -dnl maintainers. -dnl -AC_DEFUN([AM_GNU_GETTEXT], -[ - dnl Argument checking. - ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , - [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT -])])])])]) - ifelse(ifelse([$1], [], [old])[]ifelse([$1], [no-libtool], [old]), [old], - [AC_DIAGNOSE([obsolete], [Use of AM_GNU_GETTEXT without [external] argument is deprecated.])]) - ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , - [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT -])])])]) - define([gt_included_intl], - ifelse([$1], [external], - ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), - [yes])) - define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) - gt_NEEDS_INIT - AM_GNU_GETTEXT_NEED([$2]) - - AC_REQUIRE([AM_PO_SUBDIRS])dnl - ifelse(gt_included_intl, yes, [ - AC_REQUIRE([AM_INTL_SUBDIR])dnl - ]) - - dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - - dnl Sometimes libintl requires libiconv, so first search for libiconv. - dnl Ideally we would do this search only after the - dnl if test "$USE_NLS" = "yes"; then - dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then - dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT - dnl the configure script would need to contain the same shell code - dnl again, outside any 'if'. There are two solutions: - dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. - dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. - dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not - dnl documented, we avoid it. - ifelse(gt_included_intl, yes, , [ - AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) - ]) - - dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation. - gt_INTL_MACOSX - - dnl Set USE_NLS. - AC_REQUIRE([AM_NLS]) - - ifelse(gt_included_intl, yes, [ - BUILD_INCLUDED_LIBINTL=no - USE_INCLUDED_LIBINTL=no - ]) - LIBINTL= - LTLIBINTL= - POSUB= - - dnl Add a version number to the cache macros. - case " $gt_needs " in - *" need-formatstring-macros "*) gt_api_version=3 ;; - *" need-ngettext "*) gt_api_version=2 ;; - *) gt_api_version=1 ;; - esac - gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" - gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" - - dnl If we use NLS figure out what method - if test "$USE_NLS" = "yes"; then - gt_use_preinstalled_gnugettext=no - ifelse(gt_included_intl, yes, [ - AC_MSG_CHECKING([whether included gettext is requested]) - AC_ARG_WITH([included-gettext], - [ --with-included-gettext use the GNU gettext library included here], - nls_cv_force_use_gnu_gettext=$withval, - nls_cv_force_use_gnu_gettext=no) - AC_MSG_RESULT([$nls_cv_force_use_gnu_gettext]) - - nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" - if test "$nls_cv_force_use_gnu_gettext" != "yes"; then - ]) - dnl User does not insist on using GNU NLS library. Figure out what - dnl to use. If GNU gettext is available we use this. Else we have - dnl to fall back to GNU NLS library. - - if test $gt_api_version -ge 3; then - gt_revision_test_code=' -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION -#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) -#endif -changequote(,)dnl -typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; -changequote([,])dnl -' - else - gt_revision_test_code= - fi - if test $gt_api_version -ge 2; then - gt_expression_test_code=' + * ngettext ("", "", 0)' - else - gt_expression_test_code= - fi - - AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], - [AC_TRY_LINK([#include <libintl.h> -$gt_revision_test_code -extern int _nl_msg_cat_cntr; -extern int *_nl_domain_bindings;], - [bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings], - [eval "$gt_func_gnugettext_libc=yes"], - [eval "$gt_func_gnugettext_libc=no"])]) - - if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then - dnl Sometimes libintl requires libiconv, so first search for libiconv. - ifelse(gt_included_intl, yes, , [ - AM_ICONV_LINK - ]) - dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL - dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) - dnl because that would add "-liconv" to LIBINTL and LTLIBINTL - dnl even if libiconv doesn't exist. - AC_LIB_LINKFLAGS_BODY([intl]) - AC_CACHE_CHECK([for GNU gettext in libintl], - [$gt_func_gnugettext_libintl], - [gt_save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $INCINTL" - gt_save_LIBS="$LIBS" - LIBS="$LIBS $LIBINTL" - dnl Now see whether libintl exists and does not depend on libiconv. - AC_TRY_LINK([#include <libintl.h> -$gt_revision_test_code -extern int _nl_msg_cat_cntr; -extern -#ifdef __cplusplus -"C" -#endif -const char *_nl_expand_alias (const char *);], - [bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], - [eval "$gt_func_gnugettext_libintl=yes"], - [eval "$gt_func_gnugettext_libintl=no"]) - dnl Now see whether libintl exists and depends on libiconv. - if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then - LIBS="$LIBS $LIBICONV" - AC_TRY_LINK([#include <libintl.h> -$gt_revision_test_code -extern int _nl_msg_cat_cntr; -extern -#ifdef __cplusplus -"C" -#endif -const char *_nl_expand_alias (const char *);], - [bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], - [LIBINTL="$LIBINTL $LIBICONV" - LTLIBINTL="$LTLIBINTL $LTLIBICONV" - eval "$gt_func_gnugettext_libintl=yes" - ]) - fi - CPPFLAGS="$gt_save_CPPFLAGS" - LIBS="$gt_save_LIBS"]) - fi - - dnl If an already present or preinstalled GNU gettext() is found, - dnl use it. But if this macro is used in GNU gettext, and GNU - dnl gettext is already preinstalled in libintl, we update this - dnl libintl. (Cf. the install rule in intl/Makefile.in.) - if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ - || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ - && test "$PACKAGE" != gettext-runtime \ - && test "$PACKAGE" != gettext-tools; }; then - gt_use_preinstalled_gnugettext=yes - else - dnl Reset the values set by searching for libintl. - LIBINTL= - LTLIBINTL= - INCINTL= - fi - - ifelse(gt_included_intl, yes, [ - if test "$gt_use_preinstalled_gnugettext" != "yes"; then - dnl GNU gettext is not found in the C library. - dnl Fall back on included GNU gettext library. - nls_cv_use_gnu_gettext=yes - fi - fi - - if test "$nls_cv_use_gnu_gettext" = "yes"; then - dnl Mark actions used to generate GNU NLS library. - BUILD_INCLUDED_LIBINTL=yes - USE_INCLUDED_LIBINTL=yes - LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" - LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" - LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` - fi - - CATOBJEXT= - if test "$gt_use_preinstalled_gnugettext" = "yes" \ - || test "$nls_cv_use_gnu_gettext" = "yes"; then - dnl Mark actions to use GNU gettext tools. - CATOBJEXT=.gmo - fi - ]) - - if test -n "$INTL_MACOSX_LIBS"; then - if test "$gt_use_preinstalled_gnugettext" = "yes" \ - || test "$nls_cv_use_gnu_gettext" = "yes"; then - dnl Some extra flags are needed during linking. - LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" - LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" - fi - fi - - if test "$gt_use_preinstalled_gnugettext" = "yes" \ - || test "$nls_cv_use_gnu_gettext" = "yes"; then - AC_DEFINE([ENABLE_NLS], [1], - [Define to 1 if translation of program messages to the user's native language - is requested.]) - else - USE_NLS=no - fi - fi - - AC_MSG_CHECKING([whether to use NLS]) - AC_MSG_RESULT([$USE_NLS]) - if test "$USE_NLS" = "yes"; then - AC_MSG_CHECKING([where the gettext function comes from]) - if test "$gt_use_preinstalled_gnugettext" = "yes"; then - if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then - gt_source="external libintl" - else - gt_source="libc" - fi - else - gt_source="included intl directory" - fi - AC_MSG_RESULT([$gt_source]) - fi - - if test "$USE_NLS" = "yes"; then - - if test "$gt_use_preinstalled_gnugettext" = "yes"; then - if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then - AC_MSG_CHECKING([how to link with libintl]) - AC_MSG_RESULT([$LIBINTL]) - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) - fi - - dnl For backward compatibility. Some packages may be using this. - AC_DEFINE([HAVE_GETTEXT], [1], - [Define if the GNU gettext() function is already present or preinstalled.]) - AC_DEFINE([HAVE_DCGETTEXT], [1], - [Define if the GNU dcgettext() function is already present or preinstalled.]) - fi - - dnl We need to process the po/ directory. - POSUB=po - fi - - ifelse(gt_included_intl, yes, [ - dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL - dnl to 'yes' because some of the testsuite requires it. - if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then - BUILD_INCLUDED_LIBINTL=yes - fi - - dnl Make all variables we use known to autoconf. - AC_SUBST([BUILD_INCLUDED_LIBINTL]) - AC_SUBST([USE_INCLUDED_LIBINTL]) - AC_SUBST([CATOBJEXT]) - - dnl For backward compatibility. Some configure.ins may be using this. - nls_cv_header_intl= - nls_cv_header_libgt= - - dnl For backward compatibility. Some Makefiles may be using this. - DATADIRNAME=share - AC_SUBST([DATADIRNAME]) - - dnl For backward compatibility. Some Makefiles may be using this. - INSTOBJEXT=.mo - AC_SUBST([INSTOBJEXT]) - - dnl For backward compatibility. Some Makefiles may be using this. - GENCAT=gencat - AC_SUBST([GENCAT]) - - dnl For backward compatibility. Some Makefiles may be using this. - INTLOBJS= - if test "$USE_INCLUDED_LIBINTL" = yes; then - INTLOBJS="\$(GETTOBJS)" - fi - AC_SUBST([INTLOBJS]) - - dnl Enable libtool support if the surrounding package wishes it. - INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix - AC_SUBST([INTL_LIBTOOL_SUFFIX_PREFIX]) - ]) - - dnl For backward compatibility. Some Makefiles may be using this. - INTLLIBS="$LIBINTL" - AC_SUBST([INTLLIBS]) - - dnl Make all documented variables known to autoconf. - AC_SUBST([LIBINTL]) - AC_SUBST([LTLIBINTL]) - AC_SUBST([POSUB]) -]) - - -dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. -m4_define([gt_NEEDS_INIT], -[ - m4_divert_text([DEFAULTS], [gt_needs=]) - m4_define([gt_NEEDS_INIT], []) -]) - - -dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) -AC_DEFUN([AM_GNU_GETTEXT_NEED], -[ - m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) -]) - - -dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) -AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) diff --git a/plugins/kimchi/m4/iconv.m4 b/plugins/kimchi/m4/iconv.m4 deleted file mode 100644 index e2041b9..0000000 --- a/plugins/kimchi/m4/iconv.m4 +++ /dev/null @@ -1,214 +0,0 @@ -# iconv.m4 serial 11 (gettext-0.18.1) -dnl Copyright (C) 2000-2002, 2007-2010 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl From Bruno Haible. - -AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], -[ - dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - - dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV - dnl accordingly. - AC_LIB_LINKFLAGS_BODY([iconv]) -]) - -AC_DEFUN([AM_ICONV_LINK], -[ - dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and - dnl those with the standalone portable GNU libiconv installed). - AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles - - dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV - dnl accordingly. - AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) - - dnl Add $INCICONV to CPPFLAGS before performing the following checks, - dnl because if the user has installed libiconv and not disabled its use - dnl via --without-libiconv-prefix, he wants to use it. The first - dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. - am_save_CPPFLAGS="$CPPFLAGS" - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) - - AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ - am_cv_func_iconv="no, consider installing GNU libiconv" - am_cv_lib_iconv=no - AC_TRY_LINK([#include <stdlib.h> -#include <iconv.h>], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - [am_cv_func_iconv=yes]) - if test "$am_cv_func_iconv" != yes; then - am_save_LIBS="$LIBS" - LIBS="$LIBS $LIBICONV" - AC_TRY_LINK([#include <stdlib.h> -#include <iconv.h>], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - [am_cv_lib_iconv=yes] - [am_cv_func_iconv=yes]) - LIBS="$am_save_LIBS" - fi - ]) - if test "$am_cv_func_iconv" = yes; then - AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ - dnl This tests against bugs in AIX 5.1, HP-UX 11.11, Solaris 10. - am_save_LIBS="$LIBS" - if test $am_cv_lib_iconv = yes; then - LIBS="$LIBS $LIBICONV" - fi - AC_TRY_RUN([ -#include <iconv.h> -#include <string.h> -int main () -{ - /* Test against AIX 5.1 bug: Failures are not distinguishable from successful - returns. */ - { - iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); - if (cd_utf8_to_88591 != (iconv_t)(-1)) - { - static const char input[] = "\342\202\254"; /* EURO SIGN */ - char buf[10]; - const char *inptr = input; - size_t inbytesleft = strlen (input); - char *outptr = buf; - size_t outbytesleft = sizeof (buf); - size_t res = iconv (cd_utf8_to_88591, - (char **) &inptr, &inbytesleft, - &outptr, &outbytesleft); - if (res == 0) - return 1; - } - } - /* Test against Solaris 10 bug: Failures are not distinguishable from - successful returns. */ - { - iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); - if (cd_ascii_to_88591 != (iconv_t)(-1)) - { - static const char input[] = "\263"; - char buf[10]; - const char *inptr = input; - size_t inbytesleft = strlen (input); - char *outptr = buf; - size_t outbytesleft = sizeof (buf); - size_t res = iconv (cd_ascii_to_88591, - (char **) &inptr, &inbytesleft, - &outptr, &outbytesleft); - if (res == 0) - return 1; - } - } -#if 0 /* This bug could be worked around by the caller. */ - /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ - { - iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); - if (cd_88591_to_utf8 != (iconv_t)(-1)) - { - static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; - char buf[50]; - const char *inptr = input; - size_t inbytesleft = strlen (input); - char *outptr = buf; - size_t outbytesleft = sizeof (buf); - size_t res = iconv (cd_88591_to_utf8, - (char **) &inptr, &inbytesleft, - &outptr, &outbytesleft); - if ((int)res > 0) - return 1; - } - } -#endif - /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is - provided. */ - if (/* Try standardized names. */ - iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) - /* Try IRIX, OSF/1 names. */ - && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) - /* Try AIX names. */ - && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) - /* Try HP-UX names. */ - && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) - return 1; - return 0; -}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no], - [case "$host_os" in - aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; - *) am_cv_func_iconv_works="guessing yes" ;; - esac]) - LIBS="$am_save_LIBS" - ]) - case "$am_cv_func_iconv_works" in - *no) am_func_iconv=no am_cv_lib_iconv=no ;; - *) am_func_iconv=yes ;; - esac - else - am_func_iconv=no am_cv_lib_iconv=no - fi - if test "$am_func_iconv" = yes; then - AC_DEFINE([HAVE_ICONV], [1], - [Define if you have the iconv() function and it works.]) - fi - if test "$am_cv_lib_iconv" = yes; then - AC_MSG_CHECKING([how to link with libiconv]) - AC_MSG_RESULT([$LIBICONV]) - else - dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV - dnl either. - CPPFLAGS="$am_save_CPPFLAGS" - LIBICONV= - LTLIBICONV= - fi - AC_SUBST([LIBICONV]) - AC_SUBST([LTLIBICONV]) -]) - -dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to -dnl avoid warnings like -dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". -dnl This is tricky because of the way 'aclocal' is implemented: -dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. -dnl Otherwise aclocal's initial scan pass would miss the macro definition. -dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. -dnl Otherwise aclocal would emit many "Use of uninitialized value $1" -dnl warnings. -m4_define([gl_iconv_AC_DEFUN], - m4_version_prereq([2.64], - [[AC_DEFUN_ONCE( - [$1], [$2])]], - [[AC_DEFUN( - [$1], [$2])]])) -gl_iconv_AC_DEFUN([AM_ICONV], -[ - AM_ICONV_LINK - if test "$am_cv_func_iconv" = yes; then - AC_MSG_CHECKING([for iconv declaration]) - AC_CACHE_VAL([am_cv_proto_iconv], [ - AC_TRY_COMPILE([ -#include <stdlib.h> -#include <iconv.h> -extern -#ifdef __cplusplus -"C" -#endif -#if defined(__STDC__) || defined(__cplusplus) -size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); -#else -size_t iconv(); -#endif -], [], [am_cv_proto_iconv_arg1=""], [am_cv_proto_iconv_arg1="const"]) - am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) - am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` - AC_MSG_RESULT([ - $am_cv_proto_iconv]) - AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], - [Define as const if the declaration of iconv() needs const.]) - fi -]) diff --git a/plugins/kimchi/m4/intlmacosx.m4 b/plugins/kimchi/m4/intlmacosx.m4 deleted file mode 100644 index dd91025..0000000 --- a/plugins/kimchi/m4/intlmacosx.m4 +++ /dev/null @@ -1,51 +0,0 @@ -# intlmacosx.m4 serial 3 (gettext-0.18) -dnl Copyright (C) 2004-2010 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Checks for special options needed on MacOS X. -dnl Defines INTL_MACOSX_LIBS. -AC_DEFUN([gt_INTL_MACOSX], -[ - dnl Check for API introduced in MacOS X 10.2. - AC_CACHE_CHECK([for CFPreferencesCopyAppValue], - [gt_cv_func_CFPreferencesCopyAppValue], - [gt_save_LIBS="$LIBS" - LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" - AC_TRY_LINK([#include <CoreFoundation/CFPreferences.h>], - [CFPreferencesCopyAppValue(NULL, NULL)], - [gt_cv_func_CFPreferencesCopyAppValue=yes], - [gt_cv_func_CFPreferencesCopyAppValue=no]) - LIBS="$gt_save_LIBS"]) - if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then - AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], [1], - [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) - fi - dnl Check for API introduced in MacOS X 10.3. - AC_CACHE_CHECK([for CFLocaleCopyCurrent], [gt_cv_func_CFLocaleCopyCurrent], - [gt_save_LIBS="$LIBS" - LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" - AC_TRY_LINK([#include <CoreFoundation/CFLocale.h>], [CFLocaleCopyCurrent();], - [gt_cv_func_CFLocaleCopyCurrent=yes], - [gt_cv_func_CFLocaleCopyCurrent=no]) - LIBS="$gt_save_LIBS"]) - if test $gt_cv_func_CFLocaleCopyCurrent = yes; then - AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], [1], - [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) - fi - INTL_MACOSX_LIBS= - if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then - INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" - fi - AC_SUBST([INTL_MACOSX_LIBS]) -]) diff --git a/plugins/kimchi/m4/lib-ld.m4 b/plugins/kimchi/m4/lib-ld.m4 deleted file mode 100644 index ebb3052..0000000 --- a/plugins/kimchi/m4/lib-ld.m4 +++ /dev/null @@ -1,110 +0,0 @@ -# lib-ld.m4 serial 4 (gettext-0.18) -dnl Copyright (C) 1996-2003, 2009-2010 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl Subroutines of libtool.m4, -dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision -dnl with libtool.m4. - -dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. -AC_DEFUN([AC_LIB_PROG_LD_GNU], -[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld], -[# I'd rather use --version here, but apparently some GNU ld's only accept -v. -case `$LD -v 2>&1 </dev/null` in -*GNU* | *'with BFD'*) - acl_cv_prog_gnu_ld=yes ;; -*) - acl_cv_prog_gnu_ld=no ;; -esac]) -with_gnu_ld=$acl_cv_prog_gnu_ld -]) - -dnl From libtool-1.4. Sets the variable LD. -AC_DEFUN([AC_LIB_PROG_LD], -[AC_ARG_WITH([gnu-ld], -[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], -test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - AC_MSG_CHECKING([for ld used by GCC]) - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [[\\/]* | [A-Za-z]:[\\/]*)] - [re_direlt='/[^/][^/]*/\.\./'] - # Canonicalize the path of ld - ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` - while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - AC_MSG_CHECKING([for GNU ld]) -else - AC_MSG_CHECKING([for non-GNU ld]) -fi -AC_CACHE_VAL([acl_cv_path_LD], -[if test -z "$LD"; then - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - acl_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some GNU ld's only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in - *GNU* | *'with BFD'*) - test "$with_gnu_ld" != no && break ;; - *) - test "$with_gnu_ld" != yes && break ;; - esac - fi - done - IFS="$ac_save_ifs" -else - acl_cv_path_LD="$LD" # Let the user override the test with a path. -fi]) -LD="$acl_cv_path_LD" -if test -n "$LD"; then - AC_MSG_RESULT([$LD]) -else - AC_MSG_RESULT([no]) -fi -test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) -AC_LIB_PROG_LD_GNU -]) diff --git a/plugins/kimchi/m4/lib-link.m4 b/plugins/kimchi/m4/lib-link.m4 deleted file mode 100644 index c73bd8e..0000000 --- a/plugins/kimchi/m4/lib-link.m4 +++ /dev/null @@ -1,774 +0,0 @@ -# lib-link.m4 serial 21 (gettext-0.18) -dnl Copyright (C) 2001-2010 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl From Bruno Haible. - -AC_PREREQ([2.54]) - -dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and -dnl the libraries corresponding to explicit and implicit dependencies. -dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and -dnl augments the CPPFLAGS variable. -dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname -dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. -AC_DEFUN([AC_LIB_LINKFLAGS], -[ - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - pushdef([Name],[translit([$1],[./-], [___])]) - pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ - AC_LIB_LINKFLAGS_BODY([$1], [$2]) - ac_cv_lib[]Name[]_libs="$LIB[]NAME" - ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" - ac_cv_lib[]Name[]_cppflags="$INC[]NAME" - ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX" - ]) - LIB[]NAME="$ac_cv_lib[]Name[]_libs" - LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" - INC[]NAME="$ac_cv_lib[]Name[]_cppflags" - LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix" - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) - AC_SUBST([LIB]NAME) - AC_SUBST([LTLIB]NAME) - AC_SUBST([LIB]NAME[_PREFIX]) - dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the - dnl results of this search when this library appears as a dependency. - HAVE_LIB[]NAME=yes - popdef([NAME]) - popdef([Name]) -]) - -dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode, [missing-message]) -dnl searches for libname and the libraries corresponding to explicit and -dnl implicit dependencies, together with the specified include files and -dnl the ability to compile and link the specified testcode. The missing-message -dnl defaults to 'no' and may contain additional hints for the user. -dnl If found, it sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} -dnl and LTLIB${NAME} variables and augments the CPPFLAGS variable, and -dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs -dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. -dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname -dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. -AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], -[ - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - pushdef([Name],[translit([$1],[./-], [___])]) - pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - - dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME - dnl accordingly. - AC_LIB_LINKFLAGS_BODY([$1], [$2]) - - dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, - dnl because if the user has installed lib[]Name and not disabled its use - dnl via --without-lib[]Name-prefix, he wants to use it. - ac_save_CPPFLAGS="$CPPFLAGS" - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) - - AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ - ac_save_LIBS="$LIBS" - dnl If $LIB[]NAME contains some -l options, add it to the end of LIBS, - dnl because these -l options might require -L options that are present in - dnl LIBS. -l options benefit only from the -L options listed before it. - dnl Otherwise, add it to the front of LIBS, because it may be a static - dnl library that depends on another static library that is present in LIBS. - dnl Static libraries benefit only from the static libraries listed after - dnl it. - case " $LIB[]NAME" in - *" -l"*) LIBS="$LIBS $LIB[]NAME" ;; - *) LIBS="$LIB[]NAME $LIBS" ;; - esac - AC_TRY_LINK([$3], [$4], - [ac_cv_lib[]Name=yes], - [ac_cv_lib[]Name='m4_if([$5], [], [no], [[$5]])']) - LIBS="$ac_save_LIBS" - ]) - if test "$ac_cv_lib[]Name" = yes; then - HAVE_LIB[]NAME=yes - AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the lib][$1 library.]) - AC_MSG_CHECKING([how to link with lib[]$1]) - AC_MSG_RESULT([$LIB[]NAME]) - else - HAVE_LIB[]NAME=no - dnl If $LIB[]NAME didn't lead to a usable library, we don't need - dnl $INC[]NAME either. - CPPFLAGS="$ac_save_CPPFLAGS" - LIB[]NAME= - LTLIB[]NAME= - LIB[]NAME[]_PREFIX= - fi - AC_SUBST([HAVE_LIB]NAME) - AC_SUBST([LIB]NAME) - AC_SUBST([LTLIB]NAME) - AC_SUBST([LIB]NAME[_PREFIX]) - popdef([NAME]) - popdef([Name]) -]) - -dnl Determine the platform dependent parameters needed to use rpath: -dnl acl_libext, -dnl acl_shlibext, -dnl acl_hardcode_libdir_flag_spec, -dnl acl_hardcode_libdir_separator, -dnl acl_hardcode_direct, -dnl acl_hardcode_minus_L. -AC_DEFUN([AC_LIB_RPATH], -[ - dnl Tell automake >= 1.10 to complain if config.rpath is missing. - m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) - AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS - AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld - AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host - AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir - AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [ - CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ - ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh - . ./conftest.sh - rm -f ./conftest.sh - acl_cv_rpath=done - ]) - wl="$acl_cv_wl" - acl_libext="$acl_cv_libext" - acl_shlibext="$acl_cv_shlibext" - acl_libname_spec="$acl_cv_libname_spec" - acl_library_names_spec="$acl_cv_library_names_spec" - acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" - acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" - acl_hardcode_direct="$acl_cv_hardcode_direct" - acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" - dnl Determine whether the user wants rpath handling at all. - AC_ARG_ENABLE([rpath], - [ --disable-rpath do not hardcode runtime library paths], - :, enable_rpath=yes) -]) - -dnl AC_LIB_FROMPACKAGE(name, package) -dnl declares that libname comes from the given package. The configure file -dnl will then not have a --with-libname-prefix option but a -dnl --with-package-prefix option. Several libraries can come from the same -dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar -dnl macro call that searches for libname. -AC_DEFUN([AC_LIB_FROMPACKAGE], -[ - pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - define([acl_frompackage_]NAME, [$2]) - popdef([NAME]) - pushdef([PACK],[$2]) - pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - define([acl_libsinpackage_]PACKUP, - m4_ifdef([acl_libsinpackage_]PACKUP, [acl_libsinpackage_]PACKUP[[, ]],)[lib$1]) - popdef([PACKUP]) - popdef([PACK]) -]) - -dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and -dnl the libraries corresponding to explicit and implicit dependencies. -dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. -dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found -dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. -AC_DEFUN([AC_LIB_LINKFLAGS_BODY], -[ - AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) - pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])]) - pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])]) - dnl Autoconf >= 2.61 supports dots in --with options. - pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit(PACK,[.],[_])],PACK)]) - dnl By default, look in $includedir and $libdir. - use_additional=yes - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - AC_ARG_WITH(P_A_C_K[-prefix], -[[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib - --without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]], -[ - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - else - additional_includedir="$withval/include" - additional_libdir="$withval/$acl_libdirstem" - if test "$acl_libdirstem2" != "$acl_libdirstem" \ - && ! test -d "$withval/$acl_libdirstem"; then - additional_libdir="$withval/$acl_libdirstem2" - fi - fi - fi -]) - dnl Search the library and its dependencies in $additional_libdir and - dnl $LDFLAGS. Using breadth-first-seach. - LIB[]NAME= - LTLIB[]NAME= - INC[]NAME= - LIB[]NAME[]_PREFIX= - dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been - dnl computed. So it has to be reset here. - HAVE_LIB[]NAME= - rpathdirs= - ltrpathdirs= - names_already_handled= - names_next_round='$1 $2' - while test -n "$names_next_round"; do - names_this_round="$names_next_round" - names_next_round= - for name in $names_this_round; do - already_handled= - for n in $names_already_handled; do - if test "$n" = "$name"; then - already_handled=yes - break - fi - done - if test -z "$already_handled"; then - names_already_handled="$names_already_handled $name" - dnl See if it was already located by an earlier AC_LIB_LINKFLAGS - dnl or AC_LIB_HAVE_LINKFLAGS call. - uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` - eval value=\"\$HAVE_LIB$uppername\" - if test -n "$value"; then - if test "$value" = yes; then - eval value=\"\$LIB$uppername\" - test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" - eval value=\"\$LTLIB$uppername\" - test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" - else - dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined - dnl that this library doesn't exist. So just drop it. - : - fi - else - dnl Search the library lib$name in $additional_libdir and $LDFLAGS - dnl and the already constructed $LIBNAME/$LTLIBNAME. - found_dir= - found_la= - found_so= - found_a= - eval libname=\"$acl_libname_spec\" # typically: libname=lib$name - if test -n "$acl_shlibext"; then - shrext=".$acl_shlibext" # typically: shrext=.so - else - shrext= - fi - if test $use_additional = yes; then - dir="$additional_libdir" - dnl The same code as in the loop below: - dnl First look for a shared library. - if test -n "$acl_shlibext"; then - if test -f "$dir/$libname$shrext"; then - found_dir="$dir" - found_so="$dir/$libname$shrext" - else - if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then - ver=`(cd "$dir" && \ - for f in "$libname$shrext".*; do echo "$f"; done \ - | sed -e "s,^$libname$shrext\\\\.,," \ - | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ - | sed 1q ) 2>/dev/null` - if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then - found_dir="$dir" - found_so="$dir/$libname$shrext.$ver" - fi - else - eval library_names=\"$acl_library_names_spec\" - for f in $library_names; do - if test -f "$dir/$f"; then - found_dir="$dir" - found_so="$dir/$f" - break - fi - done - fi - fi - fi - dnl Then look for a static library. - if test "X$found_dir" = "X"; then - if test -f "$dir/$libname.$acl_libext"; then - found_dir="$dir" - found_a="$dir/$libname.$acl_libext" - fi - fi - if test "X$found_dir" != "X"; then - if test -f "$dir/$libname.la"; then - found_la="$dir/$libname.la" - fi - fi - fi - if test "X$found_dir" = "X"; then - for x in $LDFLAGS $LTLIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - case "$x" in - -L*) - dir=`echo "X$x" | sed -e 's/^X-L//'` - dnl First look for a shared library. - if test -n "$acl_shlibext"; then - if test -f "$dir/$libname$shrext"; then - found_dir="$dir" - found_so="$dir/$libname$shrext" - else - if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then - ver=`(cd "$dir" && \ - for f in "$libname$shrext".*; do echo "$f"; done \ - | sed -e "s,^$libname$shrext\\\\.,," \ - | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ - | sed 1q ) 2>/dev/null` - if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then - found_dir="$dir" - found_so="$dir/$libname$shrext.$ver" - fi - else - eval library_names=\"$acl_library_names_spec\" - for f in $library_names; do - if test -f "$dir/$f"; then - found_dir="$dir" - found_so="$dir/$f" - break - fi - done - fi - fi - fi - dnl Then look for a static library. - if test "X$found_dir" = "X"; then - if test -f "$dir/$libname.$acl_libext"; then - found_dir="$dir" - found_a="$dir/$libname.$acl_libext" - fi - fi - if test "X$found_dir" != "X"; then - if test -f "$dir/$libname.la"; then - found_la="$dir/$libname.la" - fi - fi - ;; - esac - if test "X$found_dir" != "X"; then - break - fi - done - fi - if test "X$found_dir" != "X"; then - dnl Found the library. - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" - if test "X$found_so" != "X"; then - dnl Linking with a shared library. We attempt to hardcode its - dnl directory into the executable's runpath, unless it's the - dnl standard /usr/lib. - if test "$enable_rpath" = no \ - || test "X$found_dir" = "X/usr/$acl_libdirstem" \ - || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then - dnl No hardcoding is needed. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - else - dnl Use an explicit option to hardcode DIR into the resulting - dnl binary. - dnl Potentially add DIR to ltrpathdirs. - dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $found_dir" - fi - dnl The hardcoding into $LIBNAME is system dependent. - if test "$acl_hardcode_direct" = yes; then - dnl Using DIR/libNAME.so during linking hardcodes DIR into the - dnl resulting binary. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - else - if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then - dnl Use an explicit option to hardcode DIR into the resulting - dnl binary. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - dnl Potentially add DIR to rpathdirs. - dnl The rpathdirs will be appended to $LIBNAME at the end. - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $found_dir" - fi - else - dnl Rely on "-L$found_dir". - dnl But don't add it if it's already contained in the LDFLAGS - dnl or the already constructed $LIBNAME - haveit= - for x in $LDFLAGS $LIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" - fi - if test "$acl_hardcode_minus_L" != no; then - dnl FIXME: Not sure whether we should use - dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" - dnl here. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - else - dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH - dnl here, because this doesn't fit in flags passed to the - dnl compiler. So give up. No hardcoding. This affects only - dnl very old systems. - dnl FIXME: Not sure whether we should use - dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" - dnl here. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" - fi - fi - fi - fi - else - if test "X$found_a" != "X"; then - dnl Linking with a static library. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" - else - dnl We shouldn't come here, but anyway it's good to have a - dnl fallback. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" - fi - fi - dnl Assume the include files are nearby. - additional_includedir= - case "$found_dir" in - */$acl_libdirstem | */$acl_libdirstem/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` - if test "$name" = '$1'; then - LIB[]NAME[]_PREFIX="$basedir" - fi - additional_includedir="$basedir/include" - ;; - */$acl_libdirstem2 | */$acl_libdirstem2/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` - if test "$name" = '$1'; then - LIB[]NAME[]_PREFIX="$basedir" - fi - additional_includedir="$basedir/include" - ;; - esac - if test "X$additional_includedir" != "X"; then - dnl Potentially add $additional_includedir to $INCNAME. - dnl But don't add it - dnl 1. if it's the standard /usr/include, - dnl 2. if it's /usr/local/include and we are using GCC on Linux, - dnl 3. if it's already present in $CPPFLAGS or the already - dnl constructed $INCNAME, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - for x in $CPPFLAGS $INC[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - dnl Really add $additional_includedir to $INCNAME. - INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" - fi - fi - fi - fi - fi - dnl Look for dependencies. - if test -n "$found_la"; then - dnl Read the .la file. It defines the variables - dnl dlname, library_names, old_library, dependency_libs, current, - dnl age, revision, installed, dlopen, dlpreopen, libdir. - save_libdir="$libdir" - case "$found_la" in - */* | *\\*) . "$found_la" ;; - *) . "./$found_la" ;; - esac - libdir="$save_libdir" - dnl We use only dependency_libs. - for dep in $dependency_libs; do - case "$dep" in - -L*) - additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` - dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. - dnl But don't add it - dnl 1. if it's the standard /usr/lib, - dnl 2. if it's /usr/local/lib and we are using GCC on Linux, - dnl 3. if it's already present in $LDFLAGS or the already - dnl constructed $LIBNAME, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ - && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then - haveit= - if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ - || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - haveit= - for x in $LDFLAGS $LIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - dnl Really add $additional_libdir to $LIBNAME. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" - fi - fi - haveit= - for x in $LDFLAGS $LTLIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - dnl Really add $additional_libdir to $LTLIBNAME. - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" - fi - fi - fi - fi - ;; - -R*) - dir=`echo "X$dep" | sed -e 's/^X-R//'` - if test "$enable_rpath" != no; then - dnl Potentially add DIR to rpathdirs. - dnl The rpathdirs will be appended to $LIBNAME at the end. - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $dir" - fi - dnl Potentially add DIR to ltrpathdirs. - dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $dir" - fi - fi - ;; - -l*) - dnl Handle this in the next round. - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` - ;; - *.la) - dnl Handle this in the next round. Throw away the .la's - dnl directory; it is already contained in a preceding -L - dnl option. - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` - ;; - *) - dnl Most likely an immediate library name. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" - ;; - esac - done - fi - else - dnl Didn't find the library; assume it is in the system directories - dnl known to the linker and runtime loader. (All the system - dnl directories known to the linker should also be known to the - dnl runtime loader, otherwise the system is severely misconfigured.) - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" - fi - fi - fi - done - done - if test "X$rpathdirs" != "X"; then - if test -n "$acl_hardcode_libdir_separator"; then - dnl Weird platform: only the last -rpath option counts, the user must - dnl pass all path elements in one option. We can arrange that for a - dnl single library, but not when more than one $LIBNAMEs are used. - alldirs= - for found_dir in $rpathdirs; do - alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" - done - dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. - acl_save_libdir="$libdir" - libdir="$alldirs" - eval flag=\"$acl_hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" - else - dnl The -rpath options are cumulative. - for found_dir in $rpathdirs; do - acl_save_libdir="$libdir" - libdir="$found_dir" - eval flag=\"$acl_hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" - done - fi - fi - if test "X$ltrpathdirs" != "X"; then - dnl When using libtool, the option that works for both libraries and - dnl executables is -R. The -R options are cumulative. - for found_dir in $ltrpathdirs; do - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" - done - fi - popdef([P_A_C_K]) - popdef([PACKLIBS]) - popdef([PACKUP]) - popdef([PACK]) - popdef([NAME]) -]) - -dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, -dnl unless already present in VAR. -dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes -dnl contains two or three consecutive elements that belong together. -AC_DEFUN([AC_LIB_APPENDTOVAR], -[ - for element in [$2]; do - haveit= - for x in $[$1]; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X$element"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - [$1]="${[$1]}${[$1]:+ }$element" - fi - done -]) - -dnl For those cases where a variable contains several -L and -l options -dnl referring to unknown libraries and directories, this macro determines the -dnl necessary additional linker options for the runtime path. -dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) -dnl sets LDADDVAR to linker options needed together with LIBSVALUE. -dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, -dnl otherwise linking without libtool is assumed. -AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], -[ - AC_REQUIRE([AC_LIB_RPATH]) - AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) - $1= - if test "$enable_rpath" != no; then - if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then - dnl Use an explicit option to hardcode directories into the resulting - dnl binary. - rpathdirs= - next= - for opt in $2; do - if test -n "$next"; then - dir="$next" - dnl No need to hardcode the standard /usr/lib. - if test "X$dir" != "X/usr/$acl_libdirstem" \ - && test "X$dir" != "X/usr/$acl_libdirstem2"; then - rpathdirs="$rpathdirs $dir" - fi - next= - else - case $opt in - -L) next=yes ;; - -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` - dnl No need to hardcode the standard /usr/lib. - if test "X$dir" != "X/usr/$acl_libdirstem" \ - && test "X$dir" != "X/usr/$acl_libdirstem2"; then - rpathdirs="$rpathdirs $dir" - fi - next= ;; - *) next= ;; - esac - fi - done - if test "X$rpathdirs" != "X"; then - if test -n ""$3""; then - dnl libtool is used for linking. Use -R options. - for dir in $rpathdirs; do - $1="${$1}${$1:+ }-R$dir" - done - else - dnl The linker is used for linking directly. - if test -n "$acl_hardcode_libdir_separator"; then - dnl Weird platform: only the last -rpath option counts, the user - dnl must pass all path elements in one option. - alldirs= - for dir in $rpathdirs; do - alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" - done - acl_save_libdir="$libdir" - libdir="$alldirs" - eval flag=\"$acl_hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - $1="$flag" - else - dnl The -rpath options are cumulative. - for dir in $rpathdirs; do - acl_save_libdir="$libdir" - libdir="$dir" - eval flag=\"$acl_hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - $1="${$1}${$1:+ }$flag" - done - fi - fi - fi - fi - fi - AC_SUBST([$1]) -]) diff --git a/plugins/kimchi/m4/lib-prefix.m4 b/plugins/kimchi/m4/lib-prefix.m4 deleted file mode 100644 index 1601cea..0000000 --- a/plugins/kimchi/m4/lib-prefix.m4 +++ /dev/null @@ -1,224 +0,0 @@ -# lib-prefix.m4 serial 7 (gettext-0.18) -dnl Copyright (C) 2001-2005, 2008-2010 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl From Bruno Haible. - -dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and -dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't -dnl require excessive bracketing. -ifdef([AC_HELP_STRING], -[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], -[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) - -dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed -dnl to access previously installed libraries. The basic assumption is that -dnl a user will want packages to use other packages he previously installed -dnl with the same --prefix option. -dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate -dnl libraries, but is otherwise very convenient. -AC_DEFUN([AC_LIB_PREFIX], -[ - AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) - AC_REQUIRE([AC_PROG_CC]) - AC_REQUIRE([AC_CANONICAL_HOST]) - AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - dnl By default, look in $includedir and $libdir. - use_additional=yes - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - AC_LIB_ARG_WITH([lib-prefix], -[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib - --without-lib-prefix don't search for libraries in includedir and libdir], -[ - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - else - additional_includedir="$withval/include" - additional_libdir="$withval/$acl_libdirstem" - fi - fi -]) - if test $use_additional = yes; then - dnl Potentially add $additional_includedir to $CPPFLAGS. - dnl But don't add it - dnl 1. if it's the standard /usr/include, - dnl 2. if it's already present in $CPPFLAGS, - dnl 3. if it's /usr/local/include and we are using GCC on Linux, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - for x in $CPPFLAGS; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - dnl Really add $additional_includedir to $CPPFLAGS. - CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" - fi - fi - fi - fi - dnl Potentially add $additional_libdir to $LDFLAGS. - dnl But don't add it - dnl 1. if it's the standard /usr/lib, - dnl 2. if it's already present in $LDFLAGS, - dnl 3. if it's /usr/local/lib and we are using GCC on Linux, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then - haveit= - for x in $LDFLAGS; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then - if test -n "$GCC"; then - case $host_os in - linux*) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - dnl Really add $additional_libdir to $LDFLAGS. - LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" - fi - fi - fi - fi - fi -]) - -dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, -dnl acl_final_exec_prefix, containing the values to which $prefix and -dnl $exec_prefix will expand at the end of the configure script. -AC_DEFUN([AC_LIB_PREPARE_PREFIX], -[ - dnl Unfortunately, prefix and exec_prefix get only finally determined - dnl at the end of configure. - if test "X$prefix" = "XNONE"; then - acl_final_prefix="$ac_default_prefix" - else - acl_final_prefix="$prefix" - fi - if test "X$exec_prefix" = "XNONE"; then - acl_final_exec_prefix='${prefix}' - else - acl_final_exec_prefix="$exec_prefix" - fi - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" - prefix="$acl_save_prefix" -]) - -dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the -dnl variables prefix and exec_prefix bound to the values they will have -dnl at the end of the configure script. -AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], -[ - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - $1 - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" -]) - -dnl AC_LIB_PREPARE_MULTILIB creates -dnl - a variable acl_libdirstem, containing the basename of the libdir, either -dnl "lib" or "lib64" or "lib/64", -dnl - a variable acl_libdirstem2, as a secondary possible value for -dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or -dnl "lib/amd64". -AC_DEFUN([AC_LIB_PREPARE_MULTILIB], -[ - dnl There is no formal standard regarding lib and lib64. - dnl On glibc systems, the current practice is that on a system supporting - dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under - dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine - dnl the compiler's default mode by looking at the compiler's library search - dnl path. If at least one of its elements ends in /lib64 or points to a - dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI. - dnl Otherwise we use the default, namely "lib". - dnl On Solaris systems, the current practice is that on a system supporting - dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under - dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or - dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib. - AC_REQUIRE([AC_CANONICAL_HOST]) - acl_libdirstem=lib - acl_libdirstem2= - case "$host_os" in - solaris*) - dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment - dnl <http://docs.sun.com/app/docs/doc/816-5138/dev-env?l=en&a=view>. - dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link." - dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the - dnl symlink is missing, so we set acl_libdirstem2 too. - AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit], - [AC_EGREP_CPP([sixtyfour bits], [ -#ifdef _LP64 -sixtyfour bits -#endif - ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no]) - ]) - if test $gl_cv_solaris_64bit = yes; then - acl_libdirstem=lib/64 - case "$host_cpu" in - sparc*) acl_libdirstem2=lib/sparcv9 ;; - i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; - esac - fi - ;; - *) - searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` - if test -n "$searchpath"; then - acl_save_IFS="${IFS= }"; IFS=":" - for searchdir in $searchpath; do - if test -d "$searchdir"; then - case "$searchdir" in - */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; - */../ | */.. ) - # Better ignore directories of this form. They are misleading. - ;; - *) searchdir=`cd "$searchdir" && pwd` - case "$searchdir" in - */lib64 ) acl_libdirstem=lib64 ;; - esac ;; - esac - fi - done - IFS="$acl_save_IFS" - fi - ;; - esac - test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" -]) diff --git a/plugins/kimchi/m4/nls.m4 b/plugins/kimchi/m4/nls.m4 deleted file mode 100644 index 003704c..0000000 --- a/plugins/kimchi/m4/nls.m4 +++ /dev/null @@ -1,32 +0,0 @@ -# nls.m4 serial 5 (gettext-0.18) -dnl Copyright (C) 1995-2003, 2005-2006, 2008-2010 Free Software Foundation, -dnl Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. -dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003. - -AC_PREREQ([2.50]) - -AC_DEFUN([AM_NLS], -[ - AC_MSG_CHECKING([whether NLS is requested]) - dnl Default is enabled NLS - AC_ARG_ENABLE([nls], - [ --disable-nls do not use Native Language Support], - USE_NLS=$enableval, USE_NLS=yes) - AC_MSG_RESULT([$USE_NLS]) - AC_SUBST([USE_NLS]) -]) diff --git a/plugins/kimchi/m4/po.m4 b/plugins/kimchi/m4/po.m4 deleted file mode 100644 index 8bc921d..0000000 --- a/plugins/kimchi/m4/po.m4 +++ /dev/null @@ -1,449 +0,0 @@ -# po.m4 serial 17 (gettext-0.18) -dnl Copyright (C) 1995-2010 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. -dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003. - -AC_PREREQ([2.50]) - -dnl Checks for all prerequisites of the po subdirectory. -AC_DEFUN([AM_PO_SUBDIRS], -[ - AC_REQUIRE([AC_PROG_MAKE_SET])dnl - AC_REQUIRE([AC_PROG_INSTALL])dnl - AC_REQUIRE([AC_PROG_MKDIR_P])dnl defined by autoconf - AC_REQUIRE([AM_NLS])dnl - - dnl Release version of the gettext macros. This is used to ensure that - dnl the gettext macros and po/Makefile.in.in are in sync. - AC_SUBST([GETTEXT_MACRO_VERSION], [0.18]) - - dnl Perform the following tests also if --disable-nls has been given, - dnl because they are needed for "make dist" to work. - - dnl Search for GNU msgfmt in the PATH. - dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. - dnl The second test excludes FreeBSD msgfmt. - AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, - [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && - (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], - :) - AC_PATH_PROG([GMSGFMT], [gmsgfmt], [$MSGFMT]) - - dnl Test whether it is GNU msgfmt >= 0.15. -changequote(,)dnl - case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; - *) MSGFMT_015=$MSGFMT ;; - esac -changequote([,])dnl - AC_SUBST([MSGFMT_015]) -changequote(,)dnl - case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; - *) GMSGFMT_015=$GMSGFMT ;; - esac -changequote([,])dnl - AC_SUBST([GMSGFMT_015]) - - dnl Search for GNU xgettext 0.12 or newer in the PATH. - dnl The first test excludes Solaris xgettext and early GNU xgettext versions. - dnl The second test excludes FreeBSD xgettext. - AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, - [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && - (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], - :) - dnl Remove leftover from FreeBSD xgettext call. - rm -f messages.po - - dnl Test whether it is GNU xgettext >= 0.15. -changequote(,)dnl - case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; - *) XGETTEXT_015=$XGETTEXT ;; - esac -changequote([,])dnl - AC_SUBST([XGETTEXT_015]) - - dnl Search for GNU msgmerge 0.11 or newer in the PATH. - AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, - [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) - - dnl Installation directories. - dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we - dnl have to define it here, so that it can be used in po/Makefile. - test -n "$localedir" || localedir='${datadir}/locale' - AC_SUBST([localedir]) - - dnl Support for AM_XGETTEXT_OPTION. - test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS= - AC_SUBST([XGETTEXT_EXTRA_OPTIONS]) - - AC_CONFIG_COMMANDS([po-directories], [[ - for ac_file in $CONFIG_FILES; do - # Support "outfile[:infile[:infile...]]" - case "$ac_file" in - *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; - esac - # PO directories have a Makefile.in generated from Makefile.in.in. - case "$ac_file" in */Makefile.in) - # Adjust a relative srcdir. - ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` - ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" - ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` - # In autoconf-2.13 it is called $ac_given_srcdir. - # In autoconf-2.50 it is called $srcdir. - test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" - case "$ac_given_srcdir" in - .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; - /*) top_srcdir="$ac_given_srcdir" ;; - *) top_srcdir="$ac_dots$ac_given_srcdir" ;; - esac - # Treat a directory as a PO directory if and only if it has a - # POTFILES.in file. This allows packages to have multiple PO - # directories under different names or in different locations. - if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then - rm -f "$ac_dir/POTFILES" - test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" - cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" - POMAKEFILEDEPS="POTFILES.in" - # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend - # on $ac_dir but don't depend on user-specified configuration - # parameters. - if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then - # The LINGUAS file contains the set of available languages. - if test -n "$OBSOLETE_ALL_LINGUAS"; then - test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" - fi - ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` - # Hide the ALL_LINGUAS assigment from automake < 1.5. - eval 'ALL_LINGUAS''=$ALL_LINGUAS_' - POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" - else - # The set of available languages was given in configure.in. - # Hide the ALL_LINGUAS assigment from automake < 1.5. - eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' - fi - # Compute POFILES - # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) - # Compute UPDATEPOFILES - # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) - # Compute DUMMYPOFILES - # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) - # Compute GMOFILES - # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) - case "$ac_given_srcdir" in - .) srcdirpre= ;; - *) srcdirpre='$(srcdir)/' ;; - esac - POFILES= - UPDATEPOFILES= - DUMMYPOFILES= - GMOFILES= - for lang in $ALL_LINGUAS; do - POFILES="$POFILES $srcdirpre$lang.po" - UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" - DUMMYPOFILES="$DUMMYPOFILES $lang.nop" - GMOFILES="$GMOFILES $srcdirpre$lang.gmo" - done - # CATALOGS depends on both $ac_dir and the user's LINGUAS - # environment variable. - INST_LINGUAS= - if test -n "$ALL_LINGUAS"; then - for presentlang in $ALL_LINGUAS; do - useit=no - if test "%UNSET%" != "$LINGUAS"; then - desiredlanguages="$LINGUAS" - else - desiredlanguages="$ALL_LINGUAS" - fi - for desiredlang in $desiredlanguages; do - # Use the presentlang catalog if desiredlang is - # a. equal to presentlang, or - # b. a variant of presentlang (because in this case, - # presentlang can be used as a fallback for messages - # which are not translated in the desiredlang catalog). - case "$desiredlang" in - "$presentlang"*) useit=yes;; - esac - done - if test $useit = yes; then - INST_LINGUAS="$INST_LINGUAS $presentlang" - fi - done - fi - CATALOGS= - if test -n "$INST_LINGUAS"; then - for lang in $INST_LINGUAS; do - CATALOGS="$CATALOGS $lang.gmo" - done - fi - test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" - sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" - for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do - if test -f "$f"; then - case "$f" in - *.orig | *.bak | *~) ;; - *) cat "$f" >> "$ac_dir/Makefile" ;; - esac - fi - done - fi - ;; - esac - done]], - [# Capture the value of obsolete ALL_LINGUAS because we need it to compute - # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it - # from automake < 1.5. - eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' - # Capture the value of LINGUAS because we need it to compute CATALOGS. - LINGUAS="${LINGUAS-%UNSET%}" - ]) -]) - -dnl Postprocesses a Makefile in a directory containing PO files. -AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], -[ - # When this code is run, in config.status, two variables have already been - # set: - # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, - # - LINGUAS is the value of the environment variable LINGUAS at configure - # time. - -changequote(,)dnl - # Adjust a relative srcdir. - ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` - ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" - ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` - # In autoconf-2.13 it is called $ac_given_srcdir. - # In autoconf-2.50 it is called $srcdir. - test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" - case "$ac_given_srcdir" in - .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; - /*) top_srcdir="$ac_given_srcdir" ;; - *) top_srcdir="$ac_dots$ac_given_srcdir" ;; - esac - - # Find a way to echo strings without interpreting backslash. - if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then - gt_echo='echo' - else - if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then - gt_echo='printf %s\n' - else - echo_func () { - cat <<EOT -$* -EOT - } - gt_echo='echo_func' - fi - fi - - # A sed script that extracts the value of VARIABLE from a Makefile. - sed_x_variable=' -# Test if the hold space is empty. -x -s/P/P/ -x -ta -# Yes it was empty. Look if we have the expected variable definition. -/^[ ]*VARIABLE[ ]*=/{ - # Seen the first line of the variable definition. - s/^[ ]*VARIABLE[ ]*=// - ba -} -bd -:a -# Here we are processing a line from the variable definition. -# Remove comment, more precisely replace it with a space. -s/#.*$/ / -# See if the line ends in a backslash. -tb -:b -s/\\$// -# Print the line, without the trailing backslash. -p -tc -# There was no trailing backslash. The end of the variable definition is -# reached. Clear the hold space. -s/^.*$// -x -bd -:c -# A trailing backslash means that the variable definition continues in the -# next line. Put a nonempty string into the hold space to indicate this. -s/^.*$/P/ -x -:d -' -changequote([,])dnl - - # Set POTFILES to the value of the Makefile variable POTFILES. - sed_x_POTFILES=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/POTFILES/g'` - POTFILES=`sed -n -e "$sed_x_POTFILES" < "$ac_file"` - # Compute POTFILES_DEPS as - # $(foreach file, $(POTFILES), $(top_srcdir)/$(file)) - POTFILES_DEPS= - for file in $POTFILES; do - POTFILES_DEPS="$POTFILES_DEPS "'$(top_srcdir)/'"$file" - done - POMAKEFILEDEPS="" - - if test -n "$OBSOLETE_ALL_LINGUAS"; then - test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" - fi - if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then - # The LINGUAS file contains the set of available languages. - ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` - POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" - else - # Set ALL_LINGUAS to the value of the Makefile variable LINGUAS. - sed_x_LINGUAS=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/LINGUAS/g'` - ALL_LINGUAS_=`sed -n -e "$sed_x_LINGUAS" < "$ac_file"` - fi - # Hide the ALL_LINGUAS assigment from automake < 1.5. - eval 'ALL_LINGUAS''=$ALL_LINGUAS_' - # Compute POFILES - # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) - # Compute UPDATEPOFILES - # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) - # Compute DUMMYPOFILES - # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) - # Compute GMOFILES - # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) - # Compute PROPERTIESFILES - # as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).properties) - # Compute CLASSFILES - # as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).class) - # Compute QMFILES - # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).qm) - # Compute MSGFILES - # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang)).msg) - # Compute RESOURCESDLLFILES - # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang))/$(DOMAIN).resources.dll) - case "$ac_given_srcdir" in - .) srcdirpre= ;; - *) srcdirpre='$(srcdir)/' ;; - esac - POFILES= - UPDATEPOFILES= - DUMMYPOFILES= - GMOFILES= - PROPERTIESFILES= - CLASSFILES= - QMFILES= - MSGFILES= - RESOURCESDLLFILES= - for lang in $ALL_LINGUAS; do - POFILES="$POFILES $srcdirpre$lang.po" - UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" - DUMMYPOFILES="$DUMMYPOFILES $lang.nop" - GMOFILES="$GMOFILES $srcdirpre$lang.gmo" - PROPERTIESFILES="$PROPERTIESFILES \$(top_srcdir)/\$(DOMAIN)_$lang.properties" - CLASSFILES="$CLASSFILES \$(top_srcdir)/\$(DOMAIN)_$lang.class" - QMFILES="$QMFILES $srcdirpre$lang.qm" - frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` - MSGFILES="$MSGFILES $srcdirpre$frobbedlang.msg" - frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` - RESOURCESDLLFILES="$RESOURCESDLLFILES $srcdirpre$frobbedlang/\$(DOMAIN).resources.dll" - done - # CATALOGS depends on both $ac_dir and the user's LINGUAS - # environment variable. - INST_LINGUAS= - if test -n "$ALL_LINGUAS"; then - for presentlang in $ALL_LINGUAS; do - useit=no - if test "%UNSET%" != "$LINGUAS"; then - desiredlanguages="$LINGUAS" - else - desiredlanguages="$ALL_LINGUAS" - fi - for desiredlang in $desiredlanguages; do - # Use the presentlang catalog if desiredlang is - # a. equal to presentlang, or - # b. a variant of presentlang (because in this case, - # presentlang can be used as a fallback for messages - # which are not translated in the desiredlang catalog). - case "$desiredlang" in - "$presentlang"*) useit=yes;; - esac - done - if test $useit = yes; then - INST_LINGUAS="$INST_LINGUAS $presentlang" - fi - done - fi - CATALOGS= - JAVACATALOGS= - QTCATALOGS= - TCLCATALOGS= - CSHARPCATALOGS= - if test -n "$INST_LINGUAS"; then - for lang in $INST_LINGUAS; do - CATALOGS="$CATALOGS $lang.gmo" - JAVACATALOGS="$JAVACATALOGS \$(DOMAIN)_$lang.properties" - QTCATALOGS="$QTCATALOGS $lang.qm" - frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` - TCLCATALOGS="$TCLCATALOGS $frobbedlang.msg" - frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` - CSHARPCATALOGS="$CSHARPCATALOGS $frobbedlang/\$(DOMAIN).resources.dll" - done - fi - - sed -e "s|@POTFILES_DEPS@|$POTFILES_DEPS|g" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@PROPERTIESFILES@|$PROPERTIESFILES|g" -e "s|@CLASSFILES@|$CLASSFILES|g" -e "s|@QMFILES@|$QMFILES|g" -e "s|@MSGFILES@|$MSGFILES|g" -e "s|@RESOURCESDLLFILES@|$RESOURCESDLLFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@JAVACATALOGS@|$JAVACATALOGS|g" -e "s|@QTCATALOGS@|$QTCATALOGS|g" -e "s|@TCLCATALOGS@|$TCLCATALOGS|g" -e "s|@CSHARPCATALOGS@|$CSHARPCATALOGS|g" -e 's,^#distdir:,distdir:,' < "$ac_file" > "$ac_file.tmp" - if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then - # Add dependencies that cannot be formulated as a simple suffix rule. - for lang in $ALL_LINGUAS; do - frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` - cat >> "$ac_file.tmp" <<EOF -$frobbedlang.msg: $lang.po - @echo "\$(MSGFMT) -c --tcl -d \$(srcdir) -l $lang $srcdirpre$lang.po"; \ - \$(MSGFMT) -c --tcl -d "\$(srcdir)" -l $lang $srcdirpre$lang.po || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; } -EOF - done - fi - if grep -l '@CSHARPCATALOGS@' "$ac_file" > /dev/null; then - # Add dependencies that cannot be formulated as a simple suffix rule. - for lang in $ALL_LINGUAS; do - frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` - cat >> "$ac_file.tmp" <<EOF -$frobbedlang/\$(DOMAIN).resources.dll: $lang.po - @echo "\$(MSGFMT) -c --csharp -d \$(srcdir) -l $lang $srcdirpre$lang.po -r \$(DOMAIN)"; \ - \$(MSGFMT) -c --csharp -d "\$(srcdir)" -l $lang $srcdirpre$lang.po -r "\$(DOMAIN)" || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; } -EOF - done - fi - if test -n "$POMAKEFILEDEPS"; then - cat >> "$ac_file.tmp" <<EOF -Makefile: $POMAKEFILEDEPS -EOF - fi - mv "$ac_file.tmp" "$ac_file" -]) - -dnl Initializes the accumulator used by AM_XGETTEXT_OPTION. -AC_DEFUN([AM_XGETTEXT_OPTION_INIT], -[ - XGETTEXT_EXTRA_OPTIONS= -]) - -dnl Registers an option to be passed to xgettext in the po subdirectory. -AC_DEFUN([AM_XGETTEXT_OPTION], -[ - AC_REQUIRE([AM_XGETTEXT_OPTION_INIT]) - XGETTEXT_EXTRA_OPTIONS="$XGETTEXT_EXTRA_OPTIONS $1" -]) diff --git a/plugins/kimchi/m4/progtest.m4 b/plugins/kimchi/m4/progtest.m4 deleted file mode 100644 index 2d804ac..0000000 --- a/plugins/kimchi/m4/progtest.m4 +++ /dev/null @@ -1,92 +0,0 @@ -# progtest.m4 serial 6 (gettext-0.18) -dnl Copyright (C) 1996-2003, 2005, 2008-2010 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper <drepper@cygnus.com>, 1996. - -AC_PREREQ([2.50]) - -# Search path for a program which passes the given test. - -dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, -dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) -AC_DEFUN([AM_PATH_PROG_WITH_TEST], -[ -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi - -# Find out how to test for executable files. Don't use a zero-byte file, -# as systems may use methods other than mode bits to determine executability. -cat >conf$$.file <<_ASEOF -#! /bin/sh -exit 0 -_ASEOF -chmod +x conf$$.file -if test -x conf$$.file >/dev/null 2>&1; then - ac_executable_p="test -x" -else - ac_executable_p="test -f" -fi -rm -f conf$$.file - -# Extract the first word of "$2", so it can be a program name with args. -set dummy $2; ac_word=[$]2 -AC_MSG_CHECKING([for $ac_word]) -AC_CACHE_VAL([ac_cv_path_$1], -[case "[$]$1" in - [[\\/]]* | ?:[[\\/]]*) - ac_cv_path_$1="[$]$1" # Let the user override the test with a path. - ;; - *) - ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in ifelse([$5], , $PATH, [$5]); do - IFS="$ac_save_IFS" - test -z "$ac_dir" && ac_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then - echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD - if [$3]; then - ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" - break 2 - fi - fi - done - done - IFS="$ac_save_IFS" -dnl If no 4th arg is given, leave the cache variable unset, -dnl so AC_PATH_PROGS will keep looking. -ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" -])dnl - ;; -esac])dnl -$1="$ac_cv_path_$1" -if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then - AC_MSG_RESULT([$][$1]) -else - AC_MSG_RESULT([no]) -fi -AC_SUBST([$1])dnl -]) diff --git a/plugins/kimchi/mockmodel.py b/plugins/kimchi/mockmodel.py deleted file mode 100644 index b269c26..0000000 --- a/plugins/kimchi/mockmodel.py +++ /dev/null @@ -1,627 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import libvirt -import lxml.etree as ET -import os -import random -import time -from lxml import objectify -from lxml.builder import E - -from wok.exception import NotFoundError, OperationFailed -from wok.objectstore import ObjectStore -from wok.utils import add_task, get_next_clone_name, wok_log -from wok.xmlutils.utils import xml_item_update - -import config -import imageinfo -import osinfo -from model import cpuinfo -from model.debugreports import DebugReportsModel -from model.host import DeviceModel -from model.libvirtstoragepool import IscsiPoolDef, NetfsPoolDef -from model.libvirtstoragepool import StoragePoolDef -from model.model import Model -from model.storagepools import StoragePoolModel -from model.storagevolumes import StorageVolumeModel, StorageVolumesModel -from model.templates import LibvirtVMTemplate -from model.users import PAMUsersModel -from model.groups import PAMGroupsModel -from vmtemplate import VMTemplate - - -fake_user = {'root': 'letmein!'} -mockmodel_defaults = { - 'storagepool': '/plugins/kimchi/storagepools/default-pool', - 'domain': 'test', 'arch': 'i686' -} - - -class MockModel(Model): - _mock_vms = {} - _mock_snapshots = {} - _XMLDesc = libvirt.virDomain.XMLDesc - _defineXML = libvirt.virConnect.defineXML - _undefineDomain = libvirt.virDomain.undefine - _libvirt_get_vol_path = LibvirtVMTemplate._get_volume_path - - def __init__(self, objstore_loc=None): - # Override osinfo.defaults to ajust the values according to - # test:///default driver - defaults = dict(osinfo.defaults) - defaults.update(mockmodel_defaults) - osinfo.defaults = dict(defaults) - - self._mock_devices = MockDevices() - self._mock_partitions = MockPartitions() - self._mock_storagevolumes = MockStorageVolumes() - self._mock_swupdate = MockSoftwareUpdate() - self._mock_repositories = MockRepositories() - - cpuinfo.get_topo_capabilities = \ - MockModel.get_topo_capabilities - libvirt.virConnect.defineXML = MockModel.domainDefineXML - libvirt.virDomain.XMLDesc = MockModel.domainXMLDesc - libvirt.virDomain.undefine = MockModel.undefineDomain - libvirt.virDomain.attachDeviceFlags = MockModel.attachDeviceFlags - libvirt.virDomain.detachDeviceFlags = MockModel.detachDeviceFlags - libvirt.virDomain.updateDeviceFlags = MockModel.updateDeviceFlags - libvirt.virStorageVol.resize = MockModel.volResize - libvirt.virStorageVol.wipePattern = MockModel.volWipePattern - - IscsiPoolDef.prepare = NetfsPoolDef.prepare = StoragePoolDef.prepare - - PAMUsersModel.auth_type = 'fake' - PAMGroupsModel.auth_type = 'fake' - - super(MockModel, self).__init__('test:///default', objstore_loc) - self.objstore_loc = objstore_loc - self.objstore = ObjectStore(objstore_loc) - - # The MockModel methods are instantiated on runtime according to Model - # and BaseModel - # Because that a normal method override will not work here - # Instead of that we also need to do the override on runtime - for method in dir(self): - if method.startswith('_mock_'): - mock_method = getattr(self, method) - if not callable(mock_method): - continue - - m = method[6:] - model_method = getattr(self, m) - setattr(self, '_model_' + m, model_method) - setattr(self, m, mock_method) - - DeviceModel.lookup = self._mock_device_lookup - StoragePoolModel._update_lvm_disks = self._update_lvm_disks - StorageVolumesModel.get_list = self._mock_storagevolumes_get_list - StorageVolumeModel.doUpload = self._mock_storagevolume_doUpload - DebugReportsModel._gen_debugreport_file = self._gen_debugreport_file - LibvirtVMTemplate._get_volume_path = self._get_volume_path - VMTemplate.get_iso_info = self._probe_image - imageinfo.probe_image = self._probe_image - - def reset(self): - MockModel._mock_vms = {} - MockModel._mock_snapshots = {} - self._mock_swupdate = MockSoftwareUpdate() - self._mock_repositories = MockRepositories() - - if hasattr(self, 'objstore'): - self.objstore = ObjectStore(self.objstore_loc) - - params = {'vms': [u'test'], 'templates': [], - 'networks': [u'default'], 'storagepools': [u'default-pool']} - - for res, items in params.iteritems(): - resources = getattr(self, '%s_get_list' % res)() - for i in resources: - if i in items: - continue - - try: - getattr(self, '%s_deactivate' % res[:-1])(i) - except: - pass - - getattr(self, '%s_delete' % res[:-1])(i) - - volumes = self.storagevolumes_get_list('default-pool') - for v in volumes: - self.storagevolume_delete('default-pool', v) - - @staticmethod - def get_topo_capabilities(conn): - # The libvirt test driver doesn't return topology. - xml = "<topology sockets='1' cores='2' threads='2'/>" - return ET.fromstring(xml) - - @staticmethod - def domainDefineXML(conn, xml): - name = objectify.fromstring(xml).name.text - try: - dom = conn.lookupByName(name) - if not dom.isActive(): - MockModel._mock_vms[name] = xml - except: - pass - - return MockModel._defineXML(conn, xml) - - @staticmethod - def domainXMLDesc(dom, flags=0): - return MockModel._mock_vms.get(dom.name(), - MockModel._XMLDesc(dom, flags)) - - @staticmethod - def undefineDomain(dom): - name = dom.name() - if name in MockModel._mock_vms.keys(): - del MockModel._mock_vms[dom.name()] - return MockModel._undefineDomain(dom) - - @staticmethod - def attachDeviceFlags(dom, xml, flags=0): - old_xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) - root = objectify.fromstring(old_xml) - dev = objectify.fromstring(xml) - root.devices.append(dev) - - MockModel._mock_vms[dom.name()] = ET.tostring(root, encoding="utf-8") - - @staticmethod - def _get_device_node(dom, xml): - xpath_map = {'disk': 'target', - 'interface': 'mac', - 'graphics': 'listen'} - - dev = objectify.fromstring(xml) - dev_id = dev.find(xpath_map[dev.tag]).items() - - dev_filter = '' - for key, value in dev_id: - dev_filter += "[@%s='%s']" % (key, value) - - old_xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) - root = objectify.fromstring(old_xml) - devices = root.devices - - dev = devices.find("./%s/%s%s/.." % (dev.tag, xpath_map[dev.tag], - dev_filter)) - - return (root, dev) - - @staticmethod - def detachDeviceFlags(dom, xml, flags=0): - root, dev = MockModel._get_device_node(dom, xml) - root.devices.remove(dev) - - MockModel._mock_vms[dom.name()] = ET.tostring(root, encoding="utf-8") - - @staticmethod - def updateDeviceFlags(dom, xml, flags=0): - root, old_dev = MockModel._get_device_node(dom, xml) - root.devices.replace(old_dev, objectify.fromstring(xml)) - MockModel._mock_vms[dom.name()] = ET.tostring(root, encoding="utf-8") - - @staticmethod - def volResize(vol, size, flags=0): - new_xml = xml_item_update(vol.XMLDesc(0), './capacity', str(size)) - vol.delete(0) - pool = vol.storagePoolLookupByVolume() - pool.createXML(new_xml) - - @staticmethod - def volWipePattern(vol, algorithm, flags=0): - new_xml = xml_item_update(vol.XMLDesc(0), './allocation', '0') - vol.delete(0) - pool = vol.storagePoolLookupByVolume() - pool.createXML(new_xml) - - def _probe_image(self, path): - return ('unknown', 'unknown') - - def _get_volume_path(self, pool, vol): - pool_info = self.storagepool_lookup(pool) - if pool_info['type'] == 'scsi': - return self._mock_storagevolumes.scsi_volumes[vol]['path'] - - return MockModel._libvirt_get_vol_path(pool, vol) - - def _gen_debugreport_file(self, name): - return add_task('/plugins/kimchi/debugreports/%s' % name, - self._create_log, self.objstore, name) - - def _create_log(self, cb, name): - path = config.get_debugreports_path() - tmpf = os.path.join(path, name + '.tmp') - realf = os.path.join(path, name + '.txt') - length = random.randint(1000, 10000) - with open(tmpf, 'w') as fd: - while length: - fd.write('I am logged') - length = length - 1 - os.rename(tmpf, realf) - cb("OK", True) - - def _update_lvm_disks(self, pool_name, disks): - conn = self.conn.get() - pool = conn.storagePoolLookupByName(pool_name.encode('utf-8')) - xml = pool.XMLDesc(0) - - root = ET.fromstring(xml) - source = root.xpath('./source')[0] - - for d in disks: - dev = E.device(path=d) - source.append(dev) - - conn.storagePoolDefineXML(ET.tostring(root), 0) - - def _mock_host_shutdown(self, *name): - wok_log.info("The host system will be shutted down") - - def _mock_host_reboot(self, *name): - wok_log.info("The host system will be rebooted") - - def _mock_storagevolumes_create(self, pool, params): - vol_source = ['url', 'capacity'] - index_list = list(i for i in range(len(vol_source)) - if vol_source[i] in params) - create_param = vol_source[index_list[0]] - name = params.get('name') - if name is None and create_param == 'url': - params['name'] = os.path.basename(params['url']) - del params['url'] - params['capacity'] = 1024 - - return self._model_storagevolumes_create(pool, params) - - def _mock_storagevolumes_get_list(self, pool): - pool_info = self.storagepool_lookup(pool) - if pool_info['type'] == 'scsi': - return self._mock_storagevolumes.scsi_volumes.keys() - - return self._model_storagevolumes_get_list(pool) - - def _mock_storagevolume_lookup(self, pool, vol): - pool_info = self.storagepool_lookup(pool) - if pool_info['type'] == 'scsi': - return self._mock_storagevolumes.scsi_volumes[vol] - - return self._model_storagevolume_lookup(pool, vol) - - def _mock_storagevolume_doUpload(self, cb, vol, offset, data, data_size): - vol_path = vol.path() - - # MockModel does not create the storage volume as a file - # So create it to do the file upload - if offset == 0: - dirname = os.path.dirname(vol_path) - if not os.path.exists(dirname): - os.makedirs(dirname) - open(vol_path, 'w').close() - - try: - with open(vol_path, 'a') as fd: - fd.seek(offset) - fd.write(data) - except Exception, e: - os.remove(vol_path) - cb('', False) - raise OperationFailed("KCHVOL0029E", {"err": e.message}) - - def _mock_partitions_get_list(self): - return self._mock_partitions.partitions.keys() - - def _mock_partition_lookup(self, name): - return self._mock_partitions.partitions[name] - - def _mock_devices_get_list(self, _cap=None, _passthrough=None, - _passthrough_affected_by=None): - if _cap is None: - return self._mock_devices.devices.keys() - - if _cap == 'fc_host': - _cap = 'scsi_host' - - return [dev['name'] for dev in self._mock_devices.devices.values() - if dev['device_type'] == _cap] - - def _mock_device_lookup(self, dev_name): - return self._mock_devices.devices[dev_name] - - def _mock_packagesupdate_get_list(self): - return self._mock_swupdate.pkgs.keys() - - def _mock_packageupdate_lookup(self, pkg_name): - return self._mock_swupdate.pkgs[pkg_name] - - def _mock_host_swupdate(self, args=None): - task_id = add_task('/plugins/kimchi/host/swupdate', - self._mock_swupdate.doUpdate, self.objstore) - return self.task_lookup(task_id) - - def _mock_repositories_get_list(self): - return self._mock_repositories.repos.keys() - - def _mock_repositories_create(self, params): - # Create a repo_id if not given by user. The repo_id will follow - # the format kimchi_repo_<integer>, where integer is the number of - # seconds since the Epoch (January 1st, 1970), in UTC. - repo_id = params.get('repo_id', None) - if repo_id is None: - repo_id = "kimchi_repo_%s" % str(int(time.time() * 1000)) - params.update({'repo_id': repo_id}) - - config = params.get('config', {}) - info = {'repo_id': repo_id, - 'baseurl': params['baseurl'], - 'enabled': True, - 'config': {'repo_name': config.get('repo_name', repo_id), - 'gpgkey': config.get('gpgkey', []), - 'gpgcheck': True, - 'mirrorlist': params.get('mirrorlist', '')}} - self._mock_repositories.repos[repo_id] = info - return repo_id - - def _mock_repository_lookup(self, repo_id): - return self._mock_repositories.repos[repo_id] - - def _mock_repository_delete(self, repo_id): - del self._mock_repositories.repos[repo_id] - - def _mock_repository_enable(self, repo_id): - self._mock_repositories.repos[repo_id]['enabled'] = True - - def _mock_repository_disable(self, repo_id): - self._mock_repositories.repos[repo_id]['enabled'] = False - - def _mock_repository_update(self, repo_id, params): - self._mock_repositories.repos[repo_id].update(params) - return repo_id - - def _mock_vm_clone(self, name): - new_name = get_next_clone_name(self.vms_get_list(), name) - snapshots = MockModel._mock_snapshots.get(name, []) - MockModel._mock_snapshots[new_name] = snapshots - return self._model_vm_clone(name) - - def _mock_vmsnapshots_create(self, vm_name, params): - name = params.get('name', unicode(int(time.time()))) - params = {'vm_name': vm_name, 'name': name} - taskid = add_task(u'/plugins/kimchi/vms/%s/snapshots/%s' % - (vm_name, name), self._vmsnapshots_create_task, - self.objstore, params) - return self.task_lookup(taskid) - - def _vmsnapshots_create_task(self, cb, params): - vm_name = params['vm_name'] - name = params['name'] - parent = u'' - - snapshots = MockModel._mock_snapshots.get(vm_name, []) - for sn in snapshots: - if sn.current: - sn.current = False - parent = sn.name - - snapshots.append(MockVMSnapshot(name, {'parent': parent})) - MockModel._mock_snapshots[vm_name] = snapshots - - cb('OK', True) - - def _mock_vmsnapshots_get_list(self, vm_name): - snapshots = MockModel._mock_snapshots.get(vm_name, []) - return sorted([snap.name for snap in snapshots]) - - def _mock_currentvmsnapshot_lookup(self, vm_name): - for sn in MockModel._mock_snapshots.get(vm_name, []): - if sn.current: - return sn.info - - def _mock_vmsnapshot_lookup(self, vm_name, name): - for sn in MockModel._mock_snapshots.get(vm_name, []): - if sn.name == name: - return sn.info - - raise NotFoundError('KCHSNAP0003E', {'name': name, 'vm': vm_name}) - - def _mock_vmsnapshot_delete(self, vm_name, name): - snapshots = MockModel._mock_snapshots.get(vm_name, []) - for sn in snapshots: - if sn.name == name: - del snapshots[snapshots.index(sn)] - - MockModel._mock_snapshots[vm_name] = snapshots - - def _mock_vmsnapshot_revert(self, vm_name, name): - snapshots = MockModel._mock_snapshots.get(vm_name, []) - for sn in snapshots: - if sn.current: - sn.current = False - - for sn in snapshots: - if sn.name == name: - sn.current = True - - -class MockStorageVolumes(object): - def __init__(self): - base_path = "/dev/disk/by-path/pci-0000:0e:00.0-fc-0x20-lun" - self.scsi_volumes = {'unit:0:0:1': {'capacity': 1024, - 'format': 'unknown', - 'allocation': 512, - 'type': 'block', - 'path': base_path + '1', - 'used_by': []}, - 'unit:0:0:2': {'capacity': 2048, - 'format': 'unknown', - 'allocation': 512, - 'type': 'block', - 'path': base_path + '2', - 'used_by': []}} - - -class MockPartitions(object): - def __init__(self): - self.partitions = {"vdx": {"available": True, "name": "vdx", - "fstype": "", "path": "/dev/vdx", - "mountpoint": "", "type": "disk", - "size": "2147483648"}, - "vdz": {"available": True, "name": "vdz", - "fstype": "", "path": "/dev/vdz", - "mountpoint": "", "type": "disk", - "size": "2147483648"}} - - -class MockDevices(object): - def __init__(self): - self.devices = { - 'computer': {'device_type': 'system', - 'firmware': {'release_date': '01/01/2012', - 'vendor': 'LENOVO', - 'version': 'XXXXX (X.XX )'}, - 'hardware': {'serial': 'PXXXXX', - 'uuid': - '9d660370-820f-4241-8731-5a60c97e8aa6', - 'vendor': 'LENOVO', - 'version': 'ThinkPad T420'}, - 'name': 'computer', - 'parent': None, - 'product': '4180XXX'}, - 'pci_0000_03_00_0': {'bus': 3, - 'device_type': 'pci', - 'domain': 0, - 'driver': {'name': 'iwlwifi'}, - 'function': 0, - 'iommuGroup': 7, - 'name': 'pci_0000_03_00_0', - 'parent': 'computer', - 'path': - '/sys/devices/pci0000:00/0000:03:00.0', - 'product': { - 'description': - 'Centrino Advanced-N 6205 [Taylor Peak]', - 'id': '0x0085'}, - 'slot': 0, - 'vendor': {'description': 'Intel Corporation', - 'id': '0x8086'}}, - 'pci_0000_0d_00_0': {'bus': 13, - 'device_type': 'pci', - 'domain': 0, - 'driver': {'name': 'sdhci-pci'}, - 'function': 0, - 'iommuGroup': 7, - 'name': 'pci_0000_0d_00_0', - 'parent': 'computer', - 'path': - '/sys/devices/pci0000:00/0000:0d:00.0', - 'product': {'description': - 'PCIe SDXC/MMC Host Controller', - 'id': '0xe823'}, - 'slot': 0, - 'vendor': {'description': 'Ricoh Co Ltd', - 'id': '0x1180'}}, - 'scsi_host0': {'adapter': {'fabric_wwn': '37df6c1efa1b4388', - 'type': 'fc_host', - 'wwnn': 'efb6563f06434a98', - 'wwpn': '742f32073aab45d7'}, - 'device_type': 'scsi_host', - 'host': 0, - 'name': 'scsi_host0', - 'parent': 'computer', - 'path': '/sys/devices/pci0000:00/0000:40:00.0/0'}, - 'scsi_host1': {'adapter': {'fabric_wwn': '542efa5dced34123', - 'type': 'fc_host', - 'wwnn': 'b7433a40c9b84092', - 'wwpn': '25c1f485ae42497f'}, - 'device_type': 'scsi_host', - 'host': 0, - 'name': 'scsi_host1', - 'parent': 'computer', - 'path': '/sys/devices/pci0000:00/0000:40:00.0/1'}, - 'scsi_host2': {'adapter': {'fabric_wwn': '5c373c334c20478d', - 'type': 'fc_host', - 'wwnn': 'f2030bec4a254e6b', - 'wwpn': '07dbca4164d44096'}, - 'device_type': 'scsi_host', - 'host': 0, - 'name': 'scsi_host2', - 'parent': 'computer', - 'path': '/sys/devices/pci0000:00/0000:40:00.0/2'}} - - -class MockSoftwareUpdate(object): - def __init__(self): - self.pkgs = { - 'udevmountd': {'repository': 'openSUSE-13.1-Update', - 'version': '0.81.5-14.1', - 'arch': 'x86_64', - 'package_name': 'udevmountd'}, - 'sysconfig-network': {'repository': 'openSUSE-13.1-Extras', - 'version': '0.81.5-14.1', - 'arch': 'x86_64', - 'package_name': 'sysconfig-network'}, - 'libzypp': {'repository': 'openSUSE-13.1-Update', - 'version': '13.9.0-10.1', - 'arch': 'noarch', - 'package_name': 'libzypp'}} - self._num2update = 3 - - def doUpdate(self, cb, params): - msgs = [] - for pkg in self.pkgs.keys(): - msgs.append("Updating package %s" % pkg) - cb('\n'.join(msgs)) - time.sleep(1) - - time.sleep(2) - msgs.append("All packages updated") - cb('\n'.join(msgs), True) - - # After updating all packages any package should be listed to be - # updated, so reset self._packages - self.pkgs = {} - - -class MockRepositories(object): - def __init__(self): - self.repos = {"kimchi_repo_1392167832": - {"repo_id": "kimchi_repo_1392167832", - "enabled": True, - "baseurl": "http://www.fedora.org", - "config": {"repo_name": "kimchi_repo_1392167832", - "gpgkey": [], - "gpgcheck": True, - "mirrorlist": ""}}} - - -class MockVMSnapshot(object): - def __init__(self, name, params={}): - self.name = name - self.current = True - - self.info = {'created': params.get('created', - unicode(int(time.time()))), - 'name': name, - 'parent': params.get('parent', u''), - 'state': params.get('state', u'shutoff')} diff --git a/plugins/kimchi/model/Makefile.am b/plugins/kimchi/model/Makefile.am deleted file mode 100644 index f4f4750..0000000 --- a/plugins/kimchi/model/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -model_PYTHON = *.py - -modeldir = $(pythondir)/wok/plugins/kimchi/model - -install-data-local: - $(MKDIR_P) $(DESTDIR)$(modeldir) diff --git a/plugins/kimchi/model/__init__.py b/plugins/kimchi/model/__init__.py deleted file mode 100644 index ca7ede4..0000000 --- a/plugins/kimchi/model/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/plugins/kimchi/model/config.py b/plugins/kimchi/model/config.py deleted file mode 100644 index 464ffae..0000000 --- a/plugins/kimchi/model/config.py +++ /dev/null @@ -1,176 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import cherrypy -from multiprocessing.pool import ThreadPool - -from wok.basemodel import Singleton -from wok.config import config as kconfig -from wok.config import get_version -from wok.exception import NotFoundError -from wok.utils import check_url_path, run_command, wok_log - -from ..config import find_qemu_binary -from ..distroloader import DistroLoader -from ..repositories import Repositories -from ..screenshot import VMScreenshot -from ..swupdate import SoftwareUpdate -from debugreports import DebugReportsModel -from featuretests import FeatureTests, FEATURETEST_POOL_NAME -from featuretests import FEATURETEST_VM_NAME - - -class ConfigModel(object): - def __init__(self, **kargs): - pass - - def lookup(self, name): - proxy_port = kconfig.get('display', 'display_proxy_port') - return {'display_proxy_port': proxy_port, - 'version': get_version()} - - -class CapabilitiesModel(object): - __metaclass__ = Singleton - - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.qemu_stream = False - self.libvirt_stream_protocols = [] - self.fc_host_support = False - self.metadata_support = False - self.kernel_vfio = False - self.mem_hotplug_support = False - - # Subscribe function to set host capabilities to be run when cherrypy - # server is up - # It is needed because some features tests depends on the server - cherrypy.engine.subscribe('start', self._set_capabilities) - - # Subscribe function to clean any Kimchi leftovers - cherrypy.engine.subscribe('stop', self._clean_leftovers) - - def _clean_leftovers(self): - conn = self.conn.get() - FeatureTests.disable_libvirt_error_logging() - try: - dom = conn.lookupByName(FEATURETEST_VM_NAME) - dom.undefine() - except Exception: - # Any exception can be ignored here - pass - - try: - pool = conn.storagePoolLookupByName(FEATURETEST_POOL_NAME) - pool.undefine() - except Exception: - # Any exception can be ignored here - pass - - FeatureTests.enable_libvirt_error_logging() - - def _set_capabilities(self): - wok_log.info("*** Running feature tests ***") - conn = self.conn.get() - self.qemu_stream = FeatureTests.qemu_supports_iso_stream() - self.nfs_target_probe = FeatureTests.libvirt_support_nfs_probe(conn) - self.fc_host_support = FeatureTests.libvirt_support_fc_host(conn) - self.metadata_support = FeatureTests.has_metadata_support(conn) - self.kernel_vfio = FeatureTests.kernel_support_vfio() - self.mem_hotplug_support = FeatureTests.has_mem_hotplug_support(conn) - - self.libvirt_stream_protocols = [] - for p in ['http', 'https', 'ftp', 'ftps', 'tftp']: - if FeatureTests.libvirt_supports_iso_stream(conn, p): - self.libvirt_stream_protocols.append(p) - - wok_log.info("*** Feature tests completed ***") - _set_capabilities.priority = 90 - - def _qemu_support_spice(self): - qemu_path = find_qemu_binary(find_emulator=True) - out, err, rc = run_command(['ldd', qemu_path]) - if rc != 0: - wok_log.error('Failed to find qemu binary dependencies: %s', - err) - return False - for line in out.split('\n'): - if line.lstrip().startswith('libspice-server.so'): - return True - return False - - def lookup(self, *ident): - report_tool = DebugReportsModel.get_system_report_tool() - try: - SoftwareUpdate() - except Exception: - update_tool = False - else: - update_tool = True - - try: - repo = Repositories() - except Exception: - repo_mngt_tool = None - else: - repo_mngt_tool = repo._pkg_mnger.TYPE - - return {'libvirt_stream_protocols': self.libvirt_stream_protocols, - 'qemu_spice': self._qemu_support_spice(), - 'qemu_stream': self.qemu_stream, - 'screenshot': VMScreenshot.get_stream_test_result(), - 'system_report_tool': bool(report_tool), - 'update_tool': update_tool, - 'repo_mngt_tool': repo_mngt_tool, - 'federation': kconfig.get("server", "federation"), - 'auth': kconfig.get("authentication", "method"), - 'kernel_vfio': self.kernel_vfio, - 'nm_running': FeatureTests.is_nm_running(), - 'mem_hotplug_support': self.mem_hotplug_support - } - - -class DistrosModel(object): - def __init__(self, **kargs): - distroloader = DistroLoader() - self.distros = distroloader.get() - - def get_list(self): - def validate_distro(distro): - if check_url_path(distro['path']): - return distro['name'] - - n_processes = len(self.distros.keys()) - pool = ThreadPool(processes=n_processes) - map_res = pool.map_async(validate_distro, self.distros.values()) - pool.close() - pool.join() - res = list(set(map_res.get()) - set([None])) - return sorted(res) - - -class DistroModel(object): - def __init__(self, **kargs): - self._distros = DistrosModel() - - def lookup(self, name): - try: - return self._distros.distros[name] - except KeyError: - raise NotFoundError("KCHDISTRO0001E", {'name': name}) diff --git a/plugins/kimchi/model/cpuinfo.py b/plugins/kimchi/model/cpuinfo.py deleted file mode 100644 index 299e445..0000000 --- a/plugins/kimchi/model/cpuinfo.py +++ /dev/null @@ -1,126 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import platform -from xml.etree import ElementTree as ET - -from wok.exception import InvalidParameter, InvalidOperation -from wok.utils import run_command, wok_log - - -ARCH = 'power' if platform.machine().startswith('ppc') else 'x86' - - -def get_topo_capabilities(connect): - """ - This helper function exists solely to be overridden for - mockmodel tests. Since other modules use getCapabilies(), - it can't be overridden directly. - """ - xml = connect.getCapabilities() - capabilities = ET.fromstring(xml) - return capabilities.find('host').find('cpu').find('topology') - - -class CPUInfoModel(object): - """ - Get information about a CPU for hyperthreading (on x86) - or SMT (on POWER) for logic when creating templates and VMs. - """ - - def __init__(self, **kargs): - self.guest_threads_enabled = False - self.sockets = 0 - self.cores_present = 0 - self.cores_available = 0 - self.cores_per_socket = 0 - self.threads_per_core = 0 - self.max_threads = 0 - - self.conn = kargs['conn'] - libvirt_topology = None - try: - connect = self.conn.get() - libvirt_topology = get_topo_capabilities(connect) - except Exception as e: - wok_log.info("Unable to get CPU topology capabilities: %s" - % e.message) - return - if libvirt_topology is None: - wok_log.info("cpu_info topology not supported.") - return - - if ARCH == 'power': - # IBM PowerPC - self.guest_threads_enabled = True - out, error, rc = run_command(['ppc64_cpu', '--smt']) - if rc or 'on' in out: - # SMT has to be disabled for guest to use threads as CPUs. - # rc is always zero, whether SMT is off or on. - self.guest_threads_enabled = False - out, error, rc = run_command(['ppc64_cpu', '--cores-present']) - if not rc: - self.cores_present = int(out.split()[-1]) - out, error, rc = run_command(['ppc64_cpu', '--cores-on']) - if not rc: - self.cores_available = int(out.split()[-1]) - out, error, rc = run_command(['ppc64_cpu', '--threads-per-core']) - if not rc: - self.threads_per_core = int(out.split()[-1]) - self.sockets = self.cores_present/self.threads_per_core - if self.sockets == 0: - self.sockets = 1 - self.cores_per_socket = self.cores_present/self.sockets - else: - # Intel or AMD - self.guest_threads_enabled = True - self.sockets = int(libvirt_topology.get('sockets')) - self.cores_per_socket = int(libvirt_topology.get('cores')) - self.cores_present = self.cores_per_socket * self.sockets - self.cores_available = self.cores_present - self.threads_per_core = int(libvirt_topology.get('threads')) - - def lookup(self, ident): - return { - 'guest_threads_enabled': self.guest_threads_enabled, - 'sockets': self.sockets, - 'cores_per_socket': self.cores_per_socket, - 'cores_present': self.cores_present, - 'cores_available': self.cores_available, - 'threads_per_core': self.threads_per_core, - } - - def check_topology(self, vcpus, topology): - """ - param vcpus: should be an integer - param iso_path: the path of the guest ISO - param topology: {'sockets': x, 'cores': x, 'threads': x} - """ - sockets = topology['sockets'] - cores = topology['cores'] - threads = topology['threads'] - - if not self.guest_threads_enabled: - raise InvalidOperation("KCHCPUINF0003E") - if vcpus != sockets * cores * threads: - raise InvalidParameter("KCHCPUINF0002E") - if vcpus > self.cores_available * self.threads_per_core: - raise InvalidParameter("KCHCPUINF0001E") - if threads > self.threads_per_core: - raise InvalidParameter("KCHCPUINF0002E") diff --git a/plugins/kimchi/model/debugreports.py b/plugins/kimchi/model/debugreports.py deleted file mode 100644 index 48e6b26..0000000 --- a/plugins/kimchi/model/debugreports.py +++ /dev/null @@ -1,213 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import fnmatch -import glob -import logging -import os -import shutil -import subprocess -import time - -from wok.exception import InvalidParameter, NotFoundError, OperationFailed -from wok.exception import WokException -from wok.utils import add_task, wok_log -from wok.utils import run_command -from wok.model.tasks import TaskModel - -from .. import config - - -class DebugReportsModel(object): - def __init__(self, **kargs): - self.objstore = kargs['objstore'] - self.task = TaskModel(**kargs) - - def create(self, params): - ident = params.get('name').strip() - # Generate a name with time and millisec precision, if necessary - if ident is None or ident == "": - ident = 'report-' + str(int(time.time() * 1000)) - else: - if ident in self.get_list(): - raise InvalidParameter("KCHDR0008E", {"name": ident}) - taskid = self._gen_debugreport_file(ident) - return self.task.lookup(taskid) - - def get_list(self): - path = config.get_debugreports_path() - file_pattern = os.path.join(path, '*.*') - file_lists = glob.glob(file_pattern) - file_lists = [os.path.split(file)[1] for file in file_lists] - name_lists = [file.split('.', 1)[0] for file in file_lists] - - return name_lists - - def _gen_debugreport_file(self, name): - gen_cmd = self.get_system_report_tool() - - if gen_cmd is not None: - return add_task('/plugins/kimchi/debugreports/%s' % name, gen_cmd, - self.objstore, name) - - raise OperationFailed("KCHDR0002E") - - @staticmethod - def sosreport_generate(cb, name): - def log_error(e): - log = logging.getLogger('Model') - log.warning('Exception in generating debug file: %s', e) - - try: - command = ['sosreport', '--batch', '--name=%s' % name] - output, error, retcode = run_command(command) - - if retcode != 0: - raise OperationFailed("KCHDR0003E", {'name': name, - 'err': retcode}) - - # SOSREPORT might create file in /tmp or /var/tmp - # FIXME: The right way should be passing the tar.xz file directory - # though the parameter '--tmp-dir', but it is failing in Fedora 20 - patterns = ['/tmp/sosreport-%s-*', '/var/tmp/sosreport-%s-*'] - reports = [] - reportFile = None - for p in patterns: - reports = reports + [f for f in glob.glob(p % name)] - for f in reports: - if not fnmatch.fnmatch(f, '*.md5'): - reportFile = f - break - # Some error in sosreport happened - if reportFile is None: - wok_log.error('Debug report file not found. See sosreport ' - 'output for detail:\n%s', output) - fname = (patterns[0] % name).split('/')[-1] - raise OperationFailed('KCHDR0004E', {'name': fname}) - - md5_report_file = reportFile + '.md5' - report_file_extension = '.' + reportFile.split('.', 1)[1] - path = config.get_debugreports_path() - target = os.path.join(path, name + report_file_extension) - # Moving report - msg = 'Moving debug report file "%s" to "%s"' % (reportFile, - target) - wok_log.info(msg) - shutil.move(reportFile, target) - # Deleting md5 - msg = 'Deleting report md5 file: "%s"' % (md5_report_file) - wok_log.info(msg) - with open(md5_report_file) as f: - md5 = f.read().strip() - wok_log.info('Md5 file content: "%s"', md5) - os.remove(md5_report_file) - cb('OK', True) - return - - except WokException as e: - log_error(e) - raise - - except OSError as e: - log_error(e) - raise - - except Exception, e: - # No need to call cb to update the task status here. - # The task object will catch the exception raised here - # and update the task status there - log_error(e) - raise OperationFailed("KCHDR0005E", {'name': name, 'err': e}) - - @staticmethod - def get_system_report_tool(): - # Please add new possible debug report command here - # and implement the report generating function - # based on the new report command - report_tools = ({'cmd': 'sosreport --help', - 'fn': DebugReportsModel.sosreport_generate},) - - # check if the command can be found by shell one by one - for helper_tool in report_tools: - try: - retcode = subprocess.call(helper_tool['cmd'], shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - if retcode == 0: - return helper_tool['fn'] - except Exception, e: - wok_log.info('Exception running command: %s', e) - - return None - - -class DebugReportModel(object): - def __init__(self, **kargs): - pass - - def lookup(self, name): - path = config.get_debugreports_path() - file_pattern = os.path.join(path, name) - file_pattern = file_pattern + '.*' - try: - file_target = glob.glob(file_pattern)[0] - except IndexError: - raise NotFoundError("KCHDR0001E", {'name': name}) - - ctime = os.stat(file_target).st_mtime - ctime = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(ctime)) - file_target = os.path.split(file_target)[-1] - file_target = os.path.join("plugins/kimchi/data/debugreports", - file_target) - return {'uri': file_target, - 'ctime': ctime} - - def update(self, name, params): - path = config.get_debugreports_path() - file_pattern = os.path.join(path, name + '.*') - try: - file_source = glob.glob(file_pattern)[0] - except IndexError: - raise NotFoundError("KCHDR0001E", {'name': name}) - - file_target = file_source.replace(name, params['name']) - if os.path.isfile(file_target): - raise InvalidParameter('KCHDR0008E', {'name': params['name']}) - - shutil.move(file_source, file_target) - wok_log.info('%s renamed to %s' % (file_source, file_target)) - return params['name'] - - def delete(self, name): - path = config.get_debugreports_path() - file_pattern = os.path.join(path, name + '.*') - try: - file_target = glob.glob(file_pattern)[0] - except IndexError: - raise NotFoundError("KCHDR0001E", {'name': name}) - - os.remove(file_target) - - -class DebugReportContentModel(object): - def __init__(self, **kargs): - self._debugreport = DebugReportModel() - - def lookup(self, name): - return self._debugreport.lookup(name) diff --git a/plugins/kimchi/model/diskutils.py b/plugins/kimchi/model/diskutils.py deleted file mode 100644 index 350e6eb..0000000 --- a/plugins/kimchi/model/diskutils.py +++ /dev/null @@ -1,75 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.exception import OperationFailed, NotFoundError -from wok.utils import wok_log - -from ..xmlutils.disk import get_vm_disk_info, get_vm_disks -from vms import VMModel, VMsModel - -""" - Functions that multiple storage-related models (e.g. VMStoragesModel, - VolumesModel) will need. -""" - - -def get_disk_used_by(objstore, conn, path): - try: - with objstore as session: - try: - used_by = session.get('storagevolume', path)['used_by'] - except (KeyError, NotFoundError): - wok_log.info('Volume %s not found in obj store.' % path) - used_by = [] - # try to find this volume in existing vm - vms_list = VMsModel.get_vms(conn) - for vm in vms_list: - dom = VMModel.get_vm(vm, conn) - storages = get_vm_disks(dom) - for disk in storages.keys(): - d_info = get_vm_disk_info(dom, disk) - if path == d_info['path']: - used_by.append(vm) - try: - session.store('storagevolume', path, - {'used_by': used_by}) - except Exception as e: - # Let the exception be raised. If we allow disks' - # used_by to be out of sync, data corruption could - # occour if a disk is added to two guests - # unknowingly. - wok_log.error('Unable to store storage volume id in' - ' objectstore due error: %s', - e.message) - raise OperationFailed('KCHVOL0017E', - {'err': e.message}) - except Exception as e: - # This exception is going to catch errors returned by 'with', - # specially ones generated by 'session.store'. It is outside - # to avoid conflict with the __exit__ function of 'with' - raise OperationFailed('KCHVOL0017E', {'err': e.message}) - return used_by - - -def set_disk_used_by(objstore, path, new_used_by): - try: - with objstore as session: - session.store('storagevolume', path, {'used_by': new_used_by}) - except Exception as e: - raise OperationFailed('KCHVOL0017E', {'err': e.message}) diff --git a/plugins/kimchi/model/featuretests.py b/plugins/kimchi/model/featuretests.py deleted file mode 100644 index c53d1aa..0000000 --- a/plugins/kimchi/model/featuretests.py +++ /dev/null @@ -1,259 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import cherrypy -import libvirt -import lxml.etree as ET -import platform -import subprocess -from lxml.builder import E - -from wok.rollbackcontext import RollbackContext -from wok.utils import run_command, servermethod, wok_log - - -FEATURETEST_VM_NAME = "FEATURETEST_VM" -FEATURETEST_POOL_NAME = "FEATURETEST_POOL" - -ISO_STREAM_XML = """ -<domain type='%(domain)s'> - <name>%(name)s</name> - <memory unit='KiB'>1048576</memory> - <os> - <type arch='%(arch)s'>hvm</type> - <boot dev='cdrom'/> - </os> - <devices> - <disk type='network' device='cdrom'> - <driver name='qemu' type='raw'/> - <source protocol='%(protocol)s' name='/url/path/to/iso/file'> - <host name='host.name' port='1234'/> - </source> - <target dev='hdc' bus='ide'/> - <readonly/> - <alias name='ide0-1-0'/> - <address type='drive' controller='0' bus='1' target='0' unit='0'/> - </disk> - </devices> -</domain>""" - -SIMPLE_VM_XML = """ -<domain type='%(domain)s'> - <name>%(name)s</name> - <memory unit='KiB'>10240</memory> - <os> - <type arch='%(arch)s'>hvm</type> - <boot dev='hd'/> - </os> -</domain>""" - -MAXMEM_VM_XML = """ -<domain type='%(domain)s'> - <name>%(name)s</name> - <maxMemory slots='1' unit='KiB'>20480</maxMemory> - <memory unit='KiB'>10240</memory> - <os> - <type arch='%(arch)s'>hvm</type> - <boot dev='hd'/> - </os> -</domain>""" - -DEV_MEM_XML = """ -<memory model='dimm'> - <target> - <size unit='KiB'>10240</size> - <node>0</node> - </target> -</memory>""" - -SCSI_FC_XML = """ -<pool type='scsi'> - <name>%(name)s</name> - <source> - <adapter type='fc_host' wwnn='1234567890abcdef' wwpn='abcdef1234567890'/> - </source> - <target> - <path>/dev/disk/by-path</path> - </target> -</pool> -""" - - -class FeatureTests(object): - - @staticmethod - def disable_libvirt_error_logging(): - def libvirt_errorhandler(userdata, error): - # A libvirt error handler to ignore annoying messages in stderr - pass - - # Filter functions are enable only in production env - if cherrypy.config.get('environment') != 'production': - return - # Register the error handler to hide libvirt error in stderr - libvirt.registerErrorHandler(f=libvirt_errorhandler, ctx=None) - - @staticmethod - def enable_libvirt_error_logging(): - # Filter functions are enable only in production env - if cherrypy.config.get('environment') != 'production': - return - # Unregister the error handler - libvirt.registerErrorHandler(f=None, ctx=None) - - @staticmethod - def libvirt_supports_iso_stream(conn, protocol): - conn_type = conn.getType().lower() - domain_type = 'test' if conn_type == 'test' else 'kvm' - arch = 'i686' if conn_type == 'test' else platform.machine() - arch = 'ppc64' if arch == 'ppc64le' else arch - xml = ISO_STREAM_XML % {'name': FEATURETEST_VM_NAME, - 'domain': domain_type, 'protocol': protocol, - 'arch': arch} - try: - FeatureTests.disable_libvirt_error_logging() - dom = conn.defineXML(xml) - dom.undefine() - return True - except libvirt.libvirtError, e: - wok_log.error(e.message) - return False - finally: - FeatureTests.enable_libvirt_error_logging() - - @staticmethod - def libvirt_support_nfs_probe(conn): - def _get_xml(): - obj = E.source(E.host(name='localhost'), E.format(type='nfs')) - xml = ET.tostring(obj) - return xml - try: - FeatureTests.disable_libvirt_error_logging() - conn.findStoragePoolSources('netfs', _get_xml(), 0) - except libvirt.libvirtError as e: - wok_log.error(e.message) - if e.get_error_code() == 38: - # if libvirt cannot find showmount, - # it returns 38--general system call failure - return False - finally: - FeatureTests.enable_libvirt_error_logging() - - return True - - @staticmethod - @servermethod - def qemu_supports_iso_stream(): - host = cherrypy.server.socket_host - port = cherrypy.server.socket_port - cmd = "qemu-io -r http://%s:%d/images/icon-fedora.png \ - -c 'read -v 0 512'" % (host, port) - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, shell=True) - stdout, stderr = proc.communicate() - return len(stderr) == 0 - - @staticmethod - def libvirt_support_fc_host(conn): - try: - FeatureTests.disable_libvirt_error_logging() - pool = None - pool_xml = SCSI_FC_XML % {'name': FEATURETEST_POOL_NAME} - pool = conn.storagePoolDefineXML(pool_xml, 0) - except libvirt.libvirtError as e: - if e.get_error_code() == 27: - # Libvirt requires adapter name, not needed when supports to FC - return False - finally: - FeatureTests.enable_libvirt_error_logging() - pool is None or pool.undefine() - return True - - @staticmethod - def has_metadata_support(conn): - KIMCHI_META_URL = "https://github.com/kimchi-project/kimchi/" - KIMCHI_NAMESPACE = "kimchi" - with RollbackContext() as rollback: - FeatureTests.disable_libvirt_error_logging() - rollback.prependDefer(FeatureTests.enable_libvirt_error_logging) - conn_type = conn.getType().lower() - domain_type = 'test' if conn_type == 'test' else 'kvm' - arch = 'i686' if conn_type == 'test' else platform.machine() - arch = 'ppc64' if arch == 'ppc64le' else arch - dom = conn.defineXML(SIMPLE_VM_XML % {'name': FEATURETEST_VM_NAME, - 'domain': domain_type, - 'arch': arch}) - rollback.prependDefer(dom.undefine) - try: - dom.setMetadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT, - "<metatest/>", KIMCHI_NAMESPACE, - KIMCHI_META_URL, - flags=libvirt.VIR_DOMAIN_AFFECT_CURRENT) - return True - except libvirt.libvirtError: - return False - - @staticmethod - def kernel_support_vfio(): - out, err, rc = run_command(['modprobe', 'vfio-pci']) - if rc != 0: - wok_log.warning("Unable to load Kernal module vfio-pci.") - return False - return True - - @staticmethod - def is_nm_running(): - '''Tries to determine whether NetworkManager is running.''' - - out, err, rc = run_command(['nmcli', 'dev', 'status']) - if rc != 0: - return False - - return True - - @staticmethod - def has_mem_hotplug_support(conn): - ''' - A memory device can be hot-plugged or hot-unplugged since libvirt - version 1.2.14. - ''' - # Libvirt < 1.2.14 does not support memory devices, so firstly, check - # its version, then try to attach a device. These steps avoid errors - # with Libvirt 'test' driver for KVM - version = 1000000*1 + 1000*2 + 14 - if libvirt.getVersion() < version: - return False - - with RollbackContext() as rollback: - FeatureTests.disable_libvirt_error_logging() - rollback.prependDefer(FeatureTests.enable_libvirt_error_logging) - conn_type = conn.getType().lower() - domain_type = 'test' if conn_type == 'test' else 'kvm' - arch = 'i686' if conn_type == 'test' else platform.machine() - arch = 'ppc64' if arch == 'ppc64le' else arch - dom = conn.defineXML(MAXMEM_VM_XML % {'name': FEATURETEST_VM_NAME, - 'domain': domain_type, - 'arch': arch}) - rollback.prependDefer(dom.undefine) - try: - dom.attachDeviceFlags(DEV_MEM_XML, - libvirt.VIR_DOMAIN_MEM_CONFIG) - return True - except libvirt.libvirtError: - return False diff --git a/plugins/kimchi/model/groups.py b/plugins/kimchi/model/groups.py deleted file mode 100644 index fc63d68..0000000 --- a/plugins/kimchi/model/groups.py +++ /dev/null @@ -1,67 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import grp - -from wok.config import config - - -class GroupsModel(object): - def __init__(self, **args): - auth_type = config.get("authentication", "method") - for klass in GroupsModel.__subclasses__(): - if auth_type == klass.auth_type: - self.grp = klass(**args) - - def get_list(self, **args): - if hasattr(self.grp, '_get_list'): - return self.grp._get_list(**args) - else: - return list() - - def validate(self, gid): - return self.grp._validate(gid) - - -class PAMGroupsModel(GroupsModel): - auth_type = 'pam' - - def __init__(self, **kargs): - pass - - def _get_list(self): - return sorted([group.gr_name - for group in grp.getgrall()]) - - def _validate(self, gid): - try: - grp.getgrnam(gid) - except KeyError: - return False - return True - - -class LDAPGroupsModel(GroupsModel): - auth_type = 'ldap' - - def __init__(self, **kargs): - pass - - def _validate(self, gid): - return False diff --git a/plugins/kimchi/model/host.py b/plugins/kimchi/model/host.py deleted file mode 100644 index 75d4de0..0000000 --- a/plugins/kimchi/model/host.py +++ /dev/null @@ -1,476 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import libvirt -import os -import platform -import psutil -import time -from cherrypy.process.plugins import BackgroundTask -from collections import defaultdict - -from wok.basemodel import Singleton -from wok.exception import InvalidOperation, InvalidParameter -from wok.exception import NotFoundError, OperationFailed -from wok.utils import add_task, wok_log -from wok.xmlutils.utils import xpath_get_text -from wok.model.tasks import TaskModel - -import hostdev -from .. import disks -from .. import netinfo -from ..repositories import Repositories -from ..swupdate import SoftwareUpdate -from config import CapabilitiesModel -from vms import DOM_STATE_MAP - - -HOST_STATS_INTERVAL = 1 - - -class HostModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - self.task = TaskModel(**kargs) - self.host_info = self._get_host_info() - - def _get_ppc_cpu_info(self): - res = {} - with open('/proc/cpuinfo') as f: - for line in f.xreadlines(): - # Parse CPU, CPU's revision and CPU's clock information - for key in ['cpu', 'revision', 'clock']: - if key in line: - info = line.split(':')[1].strip() - if key == 'clock': - value = float(info.split('MHz')[0].strip()) / 1000 - else: - value = info.split('(')[0].strip() - res[key] = value - - # Power machines show, for each cpu/core, a block with - # all cpu information. Here we control the scan of the - # necessary information (1st block provides - # everything), skipping the function when find all - # information. - if len(res.keys()) == 3: - return "%(cpu)s (%(revision)s) @ %(clock)s GHz\ - " % res - - return "" - - def _get_host_info(self): - res = {} - if platform.machine().startswith('ppc'): - res['cpu_model'] = self._get_ppc_cpu_info() - else: - with open('/proc/cpuinfo') as f: - for line in f.xreadlines(): - if "model name" in line: - res['cpu_model'] = line.split(':')[1].strip() - break - - res['cpus'] = 0 - res['memory'] = 0L - - # Include IBM PowerKVM name to supported distro names - _sup_distros = platform._supported_dists + ('ibm_powerkvm',) - # 'fedora' '17' 'Beefy Miracle' - distro, version, codename = platform.linux_distribution( - supported_dists=_sup_distros) - res['os_distro'] = distro - res['os_version'] = version - res['os_codename'] = unicode(codename, "utf-8") - - return res - - def lookup(self, *name): - cpus = psutil.NUM_CPUS - - # psutil is unstable on how to get the number of - # cpus, different versions call it differently - if hasattr(psutil, 'cpu_count'): - cpus = psutil.cpu_count() - - elif hasattr(psutil, '_psplatform'): - for method_name in ['_get_num_cpus', 'get_num_cpus']: - - method = getattr(psutil._psplatform, method_name, None) - if method is not None: - cpus = method() - break - - self.host_info['cpus'] = cpus - self.host_info['memory'] = psutil.phymem_usage().total - return self.host_info - - def swupdate(self, *name): - try: - swupdate = SoftwareUpdate() - except: - raise OperationFailed('KCHPKGUPD0004E') - - pkgs = swupdate.getNumOfUpdates() - if pkgs == 0: - raise OperationFailed('KCHPKGUPD0001E') - - wok_log.debug('Host is going to be updated.') - taskid = add_task('/plugins/kimchi/host/swupdate', swupdate.doUpdate, - self.objstore, None) - return self.task.lookup(taskid) - - def shutdown(self, args=None): - # Check for running vms before shutdown - running_vms = self._get_vms_list_by_state('running') - if len(running_vms) > 0: - raise OperationFailed("KCHHOST0001E") - - wok_log.info('Host is going to shutdown.') - os.system('shutdown -h now') - - def reboot(self, args=None): - # Find running VMs - running_vms = self._get_vms_list_by_state('running') - if len(running_vms) > 0: - raise OperationFailed("KCHHOST0002E") - - wok_log.info('Host is going to reboot.') - os.system('reboot') - - def _get_vms_list_by_state(self, state): - conn = self.conn.get() - return [dom.name().decode('utf-8') - for dom in conn.listAllDomains(0) - if (DOM_STATE_MAP[dom.info()[0]]) == state] - - -class HostStatsModel(object): - __metaclass__ = Singleton - - def __init__(self, **kargs): - self.host_stats = defaultdict(list) - self.host_stats_thread = BackgroundTask(HOST_STATS_INTERVAL, - self._update_host_stats) - self.host_stats_thread.start() - - def lookup(self, *name): - return {'cpu_utilization': self.host_stats['cpu_utilization'][-1], - 'memory': self.host_stats['memory'][-1], - 'disk_read_rate': self.host_stats['disk_read_rate'][-1], - 'disk_write_rate': self.host_stats['disk_write_rate'][-1], - 'net_recv_rate': self.host_stats['net_recv_rate'][-1], - 'net_sent_rate': self.host_stats['net_sent_rate'][-1]} - - def _update_host_stats(self): - preTimeStamp = self.host_stats['timestamp'] - timestamp = time.time() - # FIXME when we upgrade psutil, we can get uptime by psutil.uptime - # we get uptime by float(open("/proc/uptime").readline().split()[0]) - # and calculate the first io_rate after the OS started. - with open("/proc/uptime") as time_f: - seconds = (timestamp - preTimeStamp if preTimeStamp else - float(time_f.readline().split()[0])) - - self.host_stats['timestamp'] = timestamp - self._get_host_disk_io_rate(seconds) - self._get_host_network_io_rate(seconds) - - self._get_percentage_host_cpu_usage() - self._get_host_memory_stats() - - # store only 60 stats (1 min) - for key, value in self.host_stats.iteritems(): - if isinstance(value, list): - if len(value) == 60: - self.host_stats[key] = value[10:] - - def _get_percentage_host_cpu_usage(self): - # This is cpu usage producer. This producer will calculate the usage - # at an interval of HOST_STATS_INTERVAL. - # The psutil.cpu_percent works as non blocking. - # psutil.cpu_percent maintains a cpu time sample. - # It will update the cpu time sample when it is called. - # So only this producer can call psutil.cpu_percent in kimchi. - self.host_stats['cpu_utilization'].append(psutil.cpu_percent(None)) - - def _get_host_memory_stats(self): - virt_mem = psutil.virtual_memory() - # available: - # the actual amount of available memory that can be given - # instantly to processes that request more memory in bytes; this - # is calculated by summing different memory values depending on - # the platform (e.g. free + buffers + cached on Linux) - memory_stats = {'total': virt_mem.total, - 'free': virt_mem.free, - 'cached': virt_mem.cached, - 'buffers': virt_mem.buffers, - 'avail': virt_mem.available} - self.host_stats['memory'].append(memory_stats) - - def _get_host_disk_io_rate(self, seconds): - disk_read_bytes = self.host_stats['disk_read_bytes'] - disk_write_bytes = self.host_stats['disk_write_bytes'] - prev_read_bytes = disk_read_bytes[-1] if disk_read_bytes else 0 - prev_write_bytes = disk_write_bytes[-1] if disk_write_bytes else 0 - - disk_io = psutil.disk_io_counters(False) - read_bytes = disk_io.read_bytes - write_bytes = disk_io.write_bytes - - rd_rate = int(float(read_bytes - prev_read_bytes) / seconds + 0.5) - wr_rate = int(float(write_bytes - prev_write_bytes) / seconds + 0.5) - - self.host_stats['disk_read_rate'].append(rd_rate) - self.host_stats['disk_write_rate'].append(wr_rate) - self.host_stats['disk_read_bytes'].append(read_bytes) - self.host_stats['disk_write_bytes'].append(write_bytes) - - def _get_host_network_io_rate(self, seconds): - net_recv_bytes = self.host_stats['net_recv_bytes'] - net_sent_bytes = self.host_stats['net_sent_bytes'] - prev_recv_bytes = net_recv_bytes[-1] if net_recv_bytes else 0 - prev_sent_bytes = net_sent_bytes[-1] if net_sent_bytes else 0 - - net_ios = psutil.network_io_counters(True) - recv_bytes = 0 - sent_bytes = 0 - for key in set(netinfo.nics() + - netinfo.wlans()) & set(net_ios.iterkeys()): - recv_bytes = recv_bytes + net_ios[key].bytes_recv - sent_bytes = sent_bytes + net_ios[key].bytes_sent - - rx_rate = int(float(recv_bytes - prev_recv_bytes) / seconds + 0.5) - tx_rate = int(float(sent_bytes - prev_sent_bytes) / seconds + 0.5) - - self.host_stats['net_recv_rate'].append(rx_rate) - self.host_stats['net_sent_rate'].append(tx_rate) - self.host_stats['net_recv_bytes'].append(recv_bytes) - self.host_stats['net_sent_bytes'].append(sent_bytes) - - -class HostStatsHistoryModel(object): - def __init__(self, **kargs): - self.history = HostStatsModel(**kargs) - - def lookup(self, *name): - return {'cpu_utilization': self.history.host_stats['cpu_utilization'], - 'memory': self.history.host_stats['memory'], - 'disk_read_rate': self.history.host_stats['disk_read_rate'], - 'disk_write_rate': self.history.host_stats['disk_write_rate'], - 'net_recv_rate': self.history.host_stats['net_recv_rate'], - 'net_sent_rate': self.history.host_stats['net_sent_rate']} - - -class PartitionsModel(object): - def __init__(self, **kargs): - pass - - def get_list(self): - result = disks.get_partitions_names() - return result - - -class PartitionModel(object): - def __init__(self, **kargs): - pass - - def lookup(self, name): - return disks.get_partition_details(name) - - -class DevicesModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.caps = CapabilitiesModel(**kargs) - self.cap_map = \ - {'net': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET, - 'pci': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV, - 'scsi': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI, - 'scsi_host': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST, - 'storage': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE, - 'usb_device': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV, - 'usb': - libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE} - # TODO: when no longer supporting Libvirt < 1.0.5 distros - # (like RHEL6) remove this verification and insert the - # key 'fc_host' with the libvirt variable in the hash - # declaration above. - try: - self.cap_map['fc_host'] = \ - libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST - except AttributeError: - self.cap_map['fc_host'] = None - - def get_list(self, _cap=None, _passthrough=None, - _passthrough_affected_by=None): - if _passthrough_affected_by is not None: - # _passthrough_affected_by conflicts with _cap and _passthrough - if (_cap, _passthrough) != (None, None): - raise InvalidParameter("KCHHOST0004E") - return sorted( - self._get_passthrough_affected_devs(_passthrough_affected_by)) - - if _cap == 'fc_host': - dev_names = self._get_devices_fc_host() - else: - dev_names = self._get_devices_with_capability(_cap) - - if _passthrough is not None and _passthrough.lower() == 'true': - conn = self.conn.get() - passthrough_names = [ - dev['name'] for dev in hostdev.get_passthrough_dev_infos(conn)] - dev_names = list(set(dev_names) & set(passthrough_names)) - - dev_names.sort() - return dev_names - - def _get_devices_with_capability(self, cap): - conn = self.conn.get() - if cap is None: - cap_flag = 0 - else: - cap_flag = self.cap_map.get(cap) - if cap_flag is None: - return [] - return [name.name() for name in conn.listAllDevices(cap_flag)] - - def _get_passthrough_affected_devs(self, dev_name): - conn = self.conn.get() - info = DeviceModel(conn=self.conn).lookup(dev_name) - affected = hostdev.get_affected_passthrough_devices(conn, info) - return [dev_info['name'] for dev_info in affected] - - def _get_devices_fc_host(self): - conn = self.conn.get() - # Libvirt < 1.0.5 does not support fc_host capability - if not self.caps.fc_host_support: - ret = [] - scsi_hosts = self._get_devices_with_capability('scsi_host') - for host in scsi_hosts: - xml = conn.nodeDeviceLookupByName(host).XMLDesc(0) - path = '/device/capability/capability/@type' - if 'fc_host' in xpath_get_text(xml, path): - ret.append(host) - return ret - # Double verification to catch the case where the libvirt - # supports fc_host but does not, for some reason, recognize - # the libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST - # attribute. - if not self.cap_map['fc_host']: - return conn.listDevices('fc_host', 0) - return self._get_devices_with_capability('fc_host') - - -class DeviceModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - - def lookup(self, nodedev_name): - conn = self.conn.get() - try: - dev = conn.nodeDeviceLookupByName(nodedev_name) - except: - raise NotFoundError('KCHHOST0003E', {'name': nodedev_name}) - return hostdev.get_dev_info(dev) - - -class PackagesUpdateModel(object): - def __init__(self, **kargs): - try: - self.host_swupdate = SoftwareUpdate() - except: - self.host_swupdate = None - - def get_list(self): - if self.host_swupdate is None: - raise OperationFailed('KCHPKGUPD0004E') - - return self.host_swupdate.getUpdates() - - -class PackageUpdateModel(object): - def __init__(self, **kargs): - pass - - def lookup(self, name): - try: - swupdate = SoftwareUpdate() - except Exception: - raise OperationFailed('KCHPKGUPD0004E') - - return swupdate.getUpdate(name) - - -class RepositoriesModel(object): - def __init__(self, **kargs): - try: - self.host_repositories = Repositories() - except: - self.host_repositories = None - - def get_list(self): - if self.host_repositories is None: - raise InvalidOperation('KCHREPOS0014E') - - return sorted(self.host_repositories.getRepositories()) - - def create(self, params): - if self.host_repositories is None: - raise InvalidOperation('KCHREPOS0014E') - - return self.host_repositories.addRepository(params) - - -class RepositoryModel(object): - def __init__(self, **kargs): - try: - self._repositories = Repositories() - except: - self._repositories = None - - def lookup(self, repo_id): - if self._repositories is None: - raise InvalidOperation('KCHREPOS0014E') - - return self._repositories.getRepository(repo_id) - - def enable(self, repo_id): - if self._repositories is None: - raise InvalidOperation('KCHREPOS0014E') - - return self._repositories.enableRepository(repo_id) - - def disable(self, repo_id): - if self._repositories is None: - raise InvalidOperation('KCHREPOS0014E') - - return self._repositories.disableRepository(repo_id) - - def update(self, repo_id, params): - if self._repositories is None: - raise InvalidOperation('KCHREPOS0014E') - - return self._repositories.updateRepository(repo_id, params) - - def delete(self, repo_id): - if self._repositories is None: - raise InvalidOperation('KCHREPOS0014E') - - return self._repositories.removeRepository(repo_id) diff --git a/plugins/kimchi/model/hostdev.py b/plugins/kimchi/model/hostdev.py deleted file mode 100644 index 31211c7..0000000 --- a/plugins/kimchi/model/hostdev.py +++ /dev/null @@ -1,324 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os -from pprint import pformat -from pprint import pprint - -from wok.utils import wok_log -from wok.xmlutils.utils import dictize - -from libvirtconnection import LibvirtConnection - - -def _get_all_host_dev_infos(libvirt_conn): - node_devs = libvirt_conn.listAllDevices(0) - return [get_dev_info(node_dev) for node_dev in node_devs] - - -def _get_dev_info_tree(dev_infos): - devs = dict([(dev_info['name'], dev_info) for dev_info in dev_infos]) - root = None - for dev_info in dev_infos: - if dev_info['parent'] is None: - root = dev_info - continue - - try: - parent = devs[dev_info['parent']] - except KeyError: - wok_log.error('Parent %s of device %s does not exist.', - dev_info['parent'], dev_info['name']) - continue - - try: - children = parent['children'] - except KeyError: - parent['children'] = [dev_info] - else: - children.append(dev_info) - return root - - -def _is_pci_qualified(pci_dev): - # PCI bridge is not suitable to passthrough - # KVM does not support passthrough graphic card now - blacklist_classes = (0x030000, 0x060000) - - with open(os.path.join(pci_dev['path'], 'class')) as f: - pci_class = int(f.readline().strip(), 16) - - if pci_class & 0xff0000 in blacklist_classes: - return False - - return True - - -def get_passthrough_dev_infos(libvirt_conn): - ''' Get devices eligible to be passed through to VM. ''' - - def is_eligible(dev): - return dev['device_type'] in ('usb_device', 'scsi') or \ - (dev['device_type'] == 'pci' and _is_pci_qualified(dev)) - - dev_infos = _get_all_host_dev_infos(libvirt_conn) - - return [dev_info for dev_info in dev_infos if is_eligible(dev_info)] - - -def _get_same_iommugroup_devices(dev_infos, device_info): - dev_dict = dict([(dev_info['name'], dev_info) for dev_info in dev_infos]) - - def get_iommu_group(dev_info): - # Find out the iommu group of a given device. - # Child device belongs to the same iommu group as the parent device. - try: - return dev_info['iommuGroup'] - except KeyError: - pass - - parent = dev_info['parent'] - while parent is not None: - try: - parent_info = dev_dict[parent] - except KeyError: - wok_log.error("Parent %s of device %s does not exist", - parent, dev_info['name']) - break - - try: - iommuGroup = parent_info['iommuGroup'] - except KeyError: - pass - else: - return iommuGroup - - parent = parent_info['parent'] - - return None - - iommu_group = get_iommu_group(device_info) - - if iommu_group is None: - return [] - - return [dev_info for dev_info in dev_infos - if dev_info['name'] != device_info['name'] and - get_iommu_group(dev_info) == iommu_group] - - -def _get_children_devices(dev_infos, device_info): - def get_children_recursive(parent): - try: - children = parent['children'] - except KeyError: - return [] - - result = [] - for child in children: - result.append(child) - result.extend(get_children_recursive(child)) - - return result - - # Annotate every the dev_info element with children information - _get_dev_info_tree(dev_infos) - - for dev_info in dev_infos: - if dev_info['name'] == device_info['name']: - return get_children_recursive(dev_info) - - return [] - - -def get_affected_passthrough_devices(libvirt_conn, passthrough_dev): - dev_infos = _get_all_host_dev_infos(libvirt_conn) - - group_devices = _get_same_iommugroup_devices(dev_infos, passthrough_dev) - if not group_devices: - # On host without iommu group support, the affected devices should - # at least include all children devices - group_devices.extend(_get_children_devices(dev_infos, passthrough_dev)) - - return group_devices - - -def get_dev_info(node_dev): - ''' Parse the node device XML string into dict according to - http://libvirt.org/formatnode.html. - - scsi_generic is not documented in libvirt official website. Try to - parse scsi_generic according to the following libvirt path series. - https://www.redhat.com/archives/libvir-list/2013-June/msg00014.html - - scsi_target is not documented in libvirt official website. Try to - parse scsi_target according to the libvirt commit db19834a0a. - ''' - - xmlstr = node_dev.XMLDesc(0) - info = dictize(xmlstr)['device'] - dev_type = info['capability'].pop('type') - info['device_type'] = dev_type - cap_dict = info.pop('capability') - info.update(cap_dict) - info['parent'] = node_dev.parent() - - if dev_type in ('scsi', 'scsi_generic', 'scsi_target', 'system', 'usb'): - return info - - if dev_type in ('net', 'pci', 'scsi_host', 'storage', 'usb_device'): - return globals()['_get_%s_dev_info' % dev_type](info) - - wok_log.error("Unknown device type: %s", dev_type) - return info - - -def _get_net_dev_info(info): - cap = info.pop('capability') - links = {"80203": "IEEE 802.3", "80211": "IEEE 802.11"} - link_raw = cap['type'] - info['link_type'] = links.get(link_raw, link_raw) - - return info - - -def _get_pci_dev_info(info): - for k in ('vendor', 'product'): - try: - description = info[k].pop('pyval') - except KeyError: - description = None - info[k]['description'] = description - if 'path' not in info: - # Old libvirt does not provide syspath info - info['path'] = \ - "/sys/bus/pci/devices/" \ - "%(domain)04x:%(bus)02x:%(slot)02x.%(function)01x" % { - 'domain': info['domain'], 'bus': info['bus'], - 'slot': info['slot'], 'function': info['function']} - try: - info['iommuGroup'] = int(info['iommuGroup']['number']) - except KeyError: - # Old libvirt does not provide syspath info, figure it out ourselves - iommu_link = os.path.join(info['path'], 'iommu_group') - if os.path.exists(iommu_link): - iommu_path = os.path.realpath(iommu_link) - try: - info['iommuGroup'] = int(iommu_path.rsplit('/', 1)[1]) - except (ValueError, IndexError): - # No IOMMU group support at all. - pass - else: - # No IOMMU group support at all. - pass - return info - - -def _get_scsi_host_dev_info(info): - try: - cap_info = info.pop('capability') - except KeyError: - # kimchi.model.libvirtstoragepool.ScsiPoolDef assumes - # info['adapter']['type'] always exists. - info['adapter'] = {'type': ''} - return info - if isinstance(cap_info, list): - info['adapter'] = {} - for cap in cap_info: - if cap['type'] == 'vport_ops': - del cap['type'] - info['adapter']['vport_ops'] = cap - else: - info['adapter'].update(cap) - else: - info['adapter'] = cap_info - return info - - -def _get_storage_dev_info(info): - try: - cap_info = info.pop('capability') - except KeyError: - return info - - if cap_info['type'] == 'removable': - cap_info['available'] = bool(cap_info.pop('media_available')) - if cap_info['available']: - for k in ('size', 'label'): - try: - cap_info[k] = cap_info.pop('media_' + k) - except KeyError: - cap_info[k] = None - info['media'] = cap_info - return info - - -def _get_usb_device_dev_info(info): - for k in ('vendor', 'product'): - try: - info[k]['description'] = info[k].pop('pyval') - except KeyError: - # Some USB devices don't provide vendor/product description. - pass - return info - - -# For test and debug -def _print_host_dev_tree(libvirt_conn): - dev_infos = _get_all_host_dev_infos(libvirt_conn) - root = _get_dev_info_tree(dev_infos) - if root is None: - print "No device found" - return - print '-----------------' - print '\n'.join(_format_dev_node(root)) - - -def _format_dev_node(node): - try: - children = node['children'] - del node['children'] - except KeyError: - children = [] - - lines = [] - lines.extend([' ~' + line for line in pformat(node).split('\n')]) - - count = len(children) - for i, child in enumerate(children): - if count == 1: - lines.append(' \-----------------') - else: - lines.append(' +-----------------') - clines = _format_dev_node(child) - if i == count - 1: - p = ' ' - else: - p = ' |' - lines.extend([p + cline for cline in clines]) - lines.append('') - - return lines - - -if __name__ == '__main__': - libvirt_conn = LibvirtConnection('qemu:///system').get() - _print_host_dev_tree(libvirt_conn) - print 'Eligible passthrough devices:' - pprint(get_passthrough_dev_infos(libvirt_conn)) diff --git a/plugins/kimchi/model/interfaces.py b/plugins/kimchi/model/interfaces.py deleted file mode 100644 index 149afe3..0000000 --- a/plugins/kimchi/model/interfaces.py +++ /dev/null @@ -1,44 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.exception import NotFoundError - -from .. import netinfo -from networks import NetworksModel - - -class InterfacesModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.networks = NetworksModel(**kargs) - - def get_list(self): - return list(set(netinfo.all_favored_interfaces()) - - set(self.networks.get_all_networks_interfaces())) - - -class InterfaceModel(object): - def __init__(self, **kargs): - pass - - def lookup(self, name): - try: - return netinfo.get_interface_info(name) - except ValueError: - raise NotFoundError("KCHIFACE0001E", {'name': name}) diff --git a/plugins/kimchi/model/libvirtconnection.py b/plugins/kimchi/model/libvirtconnection.py deleted file mode 100644 index 73f3dcf..0000000 --- a/plugins/kimchi/model/libvirtconnection.py +++ /dev/null @@ -1,136 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import cherrypy -import libvirt -import threading -import time - -from wok.utils import wok_log - - -class LibvirtConnection(object): - _connections = {} - _connectionLock = threading.Lock() - - def __init__(self, uri): - self.uri = uri - if self.uri not in LibvirtConnection._connections: - LibvirtConnection._connections[self.uri] = {} - self._connections = LibvirtConnection._connections[self.uri] - self.wrappables = self.get_wrappable_objects() - - def get_wrappable_objects(self): - """ - When a wrapped function returns an instance of another libvirt object, - we also want to wrap that object so we can catch errors that happen - when calling its methods. - """ - objs = [] - for name in ('virDomain', 'virDomainSnapshot', 'virInterface', - 'virNWFilter', 'virNetwork', 'virNodeDevice', 'virSecret', - 'virStoragePool', 'virStorageVol', 'virStream'): - try: - attr = getattr(libvirt, name) - except AttributeError: - pass - objs.append(attr) - return tuple(objs) - - def get(self, conn_id=0): - """ - Return current connection to libvirt or open a new one. Wrap all - callable libvirt methods so we can catch connection errors and handle - them by restarting the server. - """ - def wrapMethod(f): - def wrapper(*args, **kwargs): - try: - ret = f(*args, **kwargs) - return ret - except libvirt.libvirtError as e: - edom = e.get_error_domain() - ecode = e.get_error_code() - EDOMAINS = (libvirt.VIR_FROM_REMOTE, - libvirt.VIR_FROM_RPC) - ECODES = (libvirt.VIR_ERR_SYSTEM_ERROR, - libvirt.VIR_ERR_INTERNAL_ERROR, - libvirt.VIR_ERR_NO_CONNECT, - libvirt.VIR_ERR_INVALID_CONN) - if edom in EDOMAINS and ecode in ECODES: - wok_log.error('Connection to libvirt broken. ' - 'Recycling. ecode: %d edom: %d' % - (ecode, edom)) - with LibvirtConnection._connectionLock: - self._connections[conn_id] = None - raise - wrapper.__name__ = f.__name__ - wrapper.__doc__ = f.__doc__ - return wrapper - - with LibvirtConnection._connectionLock: - conn = self._connections.get(conn_id) - if not conn: - retries = 5 - while True: - retries = retries - 1 - try: - conn = libvirt.open(self.uri) - break - except libvirt.libvirtError: - wok_log.error('Unable to connect to libvirt.') - if not retries: - wok_log.error("Unable to establish connection " - "with libvirt. Please check " - "your libvirt URI which is often " - "defined in " - "/etc/libvirt/libvirt.conf") - cherrypy.engine.stop() - exit(1) - time.sleep(2) - - for name in dir(libvirt.virConnect): - method = getattr(conn, name) - if callable(method) and not name.startswith('_'): - setattr(conn, name, wrapMethod(method)) - - for cls in self.wrappables: - for name in dir(cls): - method = getattr(cls, name) - if callable(method) and not name.startswith('_'): - setattr(cls, name, wrapMethod(method)) - - self._connections[conn_id] = conn - # In case we're running into troubles with keeping the - # connections alive we should place here: - # conn.setKeepAlive(interval=5, count=3) - # However the values need to be considered wisely to not affect - # hosts which are hosting a lot of virtual machines - return conn - - def isQemuURI(self): - """ - This method will return True or Value when the system libvirt - URI is a qemu based URI. For example: - qemu:///system or qemu+tcp://someipaddress/system - """ - if self.get().getURI().startswith('qemu'): - return True - else: - return False diff --git a/plugins/kimchi/model/libvirtstoragepool.py b/plugins/kimchi/model/libvirtstoragepool.py deleted file mode 100644 index b22856b..0000000 --- a/plugins/kimchi/model/libvirtstoragepool.py +++ /dev/null @@ -1,264 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import libvirt -import lxml.etree as ET -import os -import tempfile -from lxml.builder import E - -from wok.exception import InvalidParameter, OperationFailed, TimeoutExpired -from wok.rollbackcontext import RollbackContext -from wok.utils import parse_cmd_output, run_command, wok_log - -from ..iscsi import TargetClient - - -class StoragePoolDef(object): - @classmethod - def create(cls, poolArgs): - for klass in cls.__subclasses__(): - if poolArgs['type'] == klass.poolType: - return klass(poolArgs) - raise OperationFailed("KCHPOOL0014E", {'type': poolArgs['type']}) - - def __init__(self, poolArgs): - self.poolArgs = poolArgs - - def prepare(self, conn): - ''' Validate pool arguments and perform preparations. Operation which - would cause side effect should be put here. Subclasses can optionally - override this method, or it always succeeds by default. ''' - pass - - @property - def xml(self): - ''' Subclasses have to override this method to actually generate the - storage pool XML definition. Should cause no side effect and be - idempotent''' - # TODO: When add new pool type, should also add the related test in - # tests/test_storagepool.py - raise OperationFailed("KCHPOOL0015E", {'pool': self}) - - -class DirPoolDef(StoragePoolDef): - poolType = 'dir' - - @property - def xml(self): - # Required parameters - # name: - # type: - # path: - pool = E.pool(type='dir') - pool.append(E.name(self.poolArgs['name'])) - pool.append(E.target(E.path(self.poolArgs['path']))) - return ET.tostring(pool, encoding='unicode', pretty_print=True) - - -class NetfsPoolDef(StoragePoolDef): - poolType = 'netfs' - - def __init__(self, poolArgs): - super(NetfsPoolDef, self).__init__(poolArgs) - self.path = '/var/lib/kimchi/nfs_mount/' + self.poolArgs['name'] - - def prepare(self, conn): - mnt_point = tempfile.mkdtemp(dir='/tmp') - export_path = "%s:%s" % ( - self.poolArgs['source']['host'], self.poolArgs['source']['path']) - mount_cmd = ["mount", "-o", 'soft,timeo=100,retrans=3,retry=0', - export_path, mnt_point] - umount_cmd = ["umount", "-f", export_path] - mounted = False - # Due to an NFS bug (See Red Hat BZ 1023059), NFSv4 exports may take - # 10-15 seconds to mount the first time. - cmd_timeout = 15 - - with RollbackContext() as rollback: - rollback.prependDefer(os.rmdir, mnt_point) - try: - run_command(mount_cmd, cmd_timeout) - rollback.prependDefer(run_command, umount_cmd, cmd_timeout) - except TimeoutExpired: - raise InvalidParameter("KCHPOOL0012E", {'path': export_path}) - with open("/proc/mounts", "rb") as f: - rawMounts = f.read() - output_items = ['dev_path', 'mnt_point', 'type'] - mounts = parse_cmd_output(rawMounts, output_items) - for item in mounts: - if 'dev_path' in item and item['dev_path'] == export_path: - mounted = True - - if not mounted: - raise InvalidParameter("KCHPOOL0013E", {'path': export_path}) - - @property - def xml(self): - # Required parameters - # name: - # type: - # source[host]: - # source[path]: - pool = E.pool(type='netfs') - pool.append(E.name(self.poolArgs['name'])) - - source = E.source() - source.append(E.host(name=self.poolArgs['source']['host'])) - source.append(E.dir(path=self.poolArgs['source']['path'])) - - pool.append(source) - pool.append(E.target(E.path(self.path))) - return ET.tostring(pool, encoding='unicode', pretty_print=True) - - -class LogicalPoolDef(StoragePoolDef): - poolType = 'logical' - - def __init__(self, poolArgs): - super(LogicalPoolDef, self).__init__(poolArgs) - self.path = '/dev/' + self.poolArgs['name'] - - @property - def xml(self): - # Required parameters - # name: - # type: - # source[devices]: - pool = E.pool(type='logical') - pool.append(E.name(self.poolArgs['name'])) - - source = E.source() - for device_path in self.poolArgs['source']['devices']: - source.append(E.device(path=device_path)) - - pool.append(source) - pool.append(E.target(E.path(self.path))) - return ET.tostring(pool, encoding='unicode', pretty_print=True) - - -class ScsiPoolDef(StoragePoolDef): - poolType = 'scsi' - - def prepare(self, conn=None): - tmp_name = self.poolArgs['source']['name'] - self.poolArgs['source']['name'] = tmp_name.replace('scsi_', '') - # fc_host adapters type are only available in libvirt >= 1.0.5 - if not self.poolArgs['fc_host_support']: - self.poolArgs['source']['adapter']['type'] = 'scsi_host' - msg = "Libvirt version <= 1.0.5. Setting SCSI host name as '%s'; "\ - "setting SCSI adapter type as 'scsi_host'; "\ - "ignoring wwnn and wwpn." % tmp_name - wok_log.info(msg) - # Path for Fibre Channel scsi hosts - self.poolArgs['path'] = '/dev/disk/by-path' - if not self.poolArgs['source']['adapter']['type']: - self.poolArgs['source']['adapter']['type'] = 'scsi_host' - - @property - def xml(self): - # Required parameters - # name: - # source[adapter][type]: - # source[name]: - # source[adapter][wwnn]: - # source[adapter][wwpn]: - # path: - pool = E.pool(type='scsi') - pool.append(E.name(self.poolArgs['name'])) - - adapter = E.adapter(type=self.poolArgs['source']['adapter']['type']) - adapter.set('name', self.poolArgs['source']['name']) - adapter.set('wwnn', self.poolArgs['source']['adapter']['wwnn']) - adapter.set('wwpn', self.poolArgs['source']['adapter']['wwpn']) - - pool.append(E.source(adapter)) - pool.append(E.target(E.path(self.poolArgs['path']))) - return ET.tostring(pool, encoding='unicode', pretty_print=True) - - -class IscsiPoolDef(StoragePoolDef): - poolType = 'iscsi' - - def prepare(self, conn): - source = self.poolArgs['source'] - if not TargetClient(**source).validate(): - msg_args = {'host': source['host'], 'target': source['target']} - raise OperationFailed("KCHISCSI0002E", msg_args) - self._prepare_auth(conn) - - def _prepare_auth(self, conn): - try: - auth = self.poolArgs['source']['auth'] - except KeyError: - return - - try: - virSecret = conn.secretLookupByUsage( - libvirt.VIR_SECRET_USAGE_TYPE_ISCSI, self.poolArgs['name']) - except libvirt.libvirtError: - secret = E.secret(ephemeral='no', private='yes') - - description = E.description('Secret for iSCSI storage pool %s' % - self.poolArgs['name']) - secret.append(description) - secret.append(E.auth(type='chap', username=auth['username'])) - - usage = E.usage(type='iscsi') - usage.append(E.target(self.poolArgs['name'])) - secret.append(usage) - virSecret = conn.secretDefineXML(ET.tostring(secret)) - - virSecret.setValue(auth['password']) - - @property - def xml(self): - # Required parameters - # name: - # type: - # source[host]: - # source[target]: - # - # Optional parameters - # source[port]: - pool = E.pool(type='iscsi') - pool.append(E.name(self.poolArgs['name'])) - - host = E.host(name=self.poolArgs['source']['host']) - port = self.poolArgs['source'].get('port') - if port is not None: - host.set('port', str(port)) - - source = E.source(host) - source.append(E.device(path=self.poolArgs['source']['target'])) - - source_auth = self.poolArgs['source'].get('auth') - if source_auth is not None: - auth = E.auth(type='chap') - auth.set('username', source_auth['username']) - - secret = E.secret(type='iscsi') - secret.set('usage', self.poolArgs['name']) - auth.append(secret) - - source.append(auth) - - pool.append(source) - pool.append(E.target(E.path('/dev/disk/by-id'))) - return ET.tostring(pool, encoding='unicode', pretty_print=True) diff --git a/plugins/kimchi/model/model.py b/plugins/kimchi/model/model.py deleted file mode 100644 index 0c94f63..0000000 --- a/plugins/kimchi/model/model.py +++ /dev/null @@ -1,52 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import inspect -import os - -from wok.basemodel import BaseModel -from wok.objectstore import ObjectStore -from wok.utils import import_module, listPathModules - -from libvirtconnection import LibvirtConnection - - -class Model(BaseModel): - def __init__(self, libvirt_uri=None, objstore_loc=None): - - self.objstore = ObjectStore(objstore_loc) - self.conn = LibvirtConnection(libvirt_uri) - kargs = {'objstore': self.objstore, 'conn': self.conn} - - this = os.path.basename(__file__) - this_mod = os.path.splitext(this)[0] - - models = [] - for mod_name in listPathModules(os.path.dirname(__file__)): - if mod_name.startswith("_") or mod_name == this_mod: - continue - - module = import_module('plugins.kimchi.model.' + mod_name) - members = inspect.getmembers(module, inspect.isclass) - for cls_name, instance in members: - if inspect.getmodule(instance) == module: - if cls_name.endswith('Model'): - models.append(instance(**kargs)) - - return super(Model, self).__init__(models) diff --git a/plugins/kimchi/model/networks.py b/plugins/kimchi/model/networks.py deleted file mode 100644 index b579865..0000000 --- a/plugins/kimchi/model/networks.py +++ /dev/null @@ -1,382 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import ipaddr -import libvirt -import sys -import time -from xml.sax.saxutils import escape - -from wok.config import PluginPaths -from wok.exception import InvalidOperation, InvalidParameter -from wok.exception import MissingParameter, NotFoundError, OperationFailed -from wok.rollbackcontext import RollbackContext -from wok.utils import run_command, wok_log -from wok.xmlutils.utils import xpath_get_text - -from .. import netinfo -from .. import network as knetwork -from ..osinfo import defaults as tmpl_defaults -from ..xmlutils.network import create_vlan_tagged_bridge_xml -from ..xmlutils.network import to_network_xml - - -KIMCHI_BRIDGE_PREFIX = 'kb' - - -class NetworksModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - if self.conn.isQemuURI(): - self._check_default_networks() - - def _check_default_networks(self): - networks = list(set(tmpl_defaults['networks'])) - conn = self.conn.get() - - error_msg = ("Please, check the configuration in %s/template.conf to " - "ensure it lists only valid networks." % - PluginPaths('kimchi').conf_dir) - - for net_name in networks: - try: - net = conn.networkLookupByName(net_name) - except libvirt.libvirtError, e: - msg = "Fatal: Unable to find network %s." - wok_log.error(msg, net_name) - wok_log.error(error_msg) - wok_log.error("Details: %s", e.message) - sys.exit(1) - - if net.isActive() == 0: - try: - net.create() - except libvirt.libvirtError as e: - msg = "Fatal: Unable to activate network %s." - wok_log.error(msg, net_name) - wok_log.error(error_msg) - wok_log.error("Details: %s", e.message) - sys.exit(1) - - def create(self, params): - conn = self.conn.get() - name = params['name'] - if name in self.get_list(): - raise InvalidOperation("KCHNET0001E", {'name': name}) - - connection = params["connection"] - # set forward mode, isolated do not need forward - if connection != 'isolated': - params['forward'] = {'mode': connection} - - # set subnet, bridge network do not need subnet - if connection in ["nat", 'isolated']: - self._set_network_subnet(params) - - # only bridge network need bridge(linux bridge) or interface(macvtap) - if connection == 'bridge': - self._set_network_bridge(params) - - params['name'] = escape(params['name']) - xml = to_network_xml(**params) - - try: - network = conn.networkDefineXML(xml.encode("utf-8")) - network.setAutostart(True) - except libvirt.libvirtError as e: - raise OperationFailed("KCHNET0008E", - {'name': name, 'err': e.get_error_message()}) - - return name - - def get_list(self): - conn = self.conn.get() - names = conn.listNetworks() + conn.listDefinedNetworks() - return sorted(map(lambda x: x.decode('utf-8'), names)) - - def _get_available_address(self, addr_pools=[]): - invalid_addrs = [] - for net_name in self.get_list(): - network = NetworkModel.get_network(self.conn.get(), net_name) - xml = network.XMLDesc(0) - subnet = NetworkModel.get_network_from_xml(xml)['subnet'] - subnet and invalid_addrs.append(ipaddr.IPNetwork(subnet)) - addr_pools = addr_pools if addr_pools else knetwork.PrivateNets - return knetwork.get_one_free_network(invalid_addrs, addr_pools) - - def _set_network_subnet(self, params): - netaddr = params.get('subnet', '') - # lookup a free network address for nat and isolated automatically - if not netaddr: - netaddr = self._get_available_address() - if not netaddr: - raise OperationFailed("KCHNET0009E", {'name': params['name']}) - - try: - ip = ipaddr.IPNetwork(netaddr) - except ValueError: - raise InvalidParameter("KCHNET0003E", {'subent': netaddr, - 'network': params['name']}) - - if ip.ip == ip.network: - ip.ip = ip.ip + 1 - - dhcp_start = str(ip.ip + ip.numhosts / 2) - dhcp_end = str(ip.ip + ip.numhosts - 2) - params.update({'net': str(ip), - 'dhcp': {'range': {'start': dhcp_start, - 'end': dhcp_end}}}) - - def _ensure_iface_up(self, iface): - if netinfo.operstate(iface) != 'up': - _, err, rc = run_command(['ip', 'link', 'set', 'dev', iface, 'up']) - if rc != 0: - raise OperationFailed("KCHNET0020E", - {'iface': iface, 'err': err}) - # Add a delay to wait for the link change takes into effect. - for i in range(10): - time.sleep(1) - if netinfo.operstate(iface) == 'up': - break - else: - raise OperationFailed("KCHNET0021E", {'iface': iface}) - - def _set_network_bridge(self, params): - try: - iface = params['interface'] - if iface in self.get_all_networks_interfaces(): - msg_args = {'iface': iface, 'network': params['name']} - raise InvalidParameter("KCHNET0006E", msg_args) - except KeyError: - raise MissingParameter("KCHNET0004E", {'name': params['name']}) - - self._ensure_iface_up(iface) - if netinfo.is_bridge(iface): - if 'vlan_id' in params: - raise InvalidParameter('KCHNET0019E', {'name': iface}) - params['bridge'] = iface - elif netinfo.is_bare_nic(iface) or netinfo.is_bonding(iface): - if params.get('vlan_id') is None: - params['forward']['dev'] = iface - else: - params['bridge'] = \ - self._create_vlan_tagged_bridge(str(iface), - str(params['vlan_id'])) - else: - raise InvalidParameter("KCHNET0007E") - - def get_all_networks_interfaces(self): - net_names = self.get_list() - interfaces = [] - for name in net_names: - conn = self.conn.get() - network = conn.networkLookupByName(name.encode("utf-8")) - xml = network.XMLDesc(0) - net_dict = NetworkModel.get_network_from_xml(xml) - forward = net_dict['forward'] - (forward['mode'] == 'bridge' and forward['interface'] and - interfaces.append(forward['interface'][0]) is None or - interfaces.extend(forward['interface'] + forward['pf'])) - net_dict['bridge'] and interfaces.append(net_dict['bridge']) - return interfaces - - def _create_vlan_tagged_bridge(self, interface, vlan_id): - # Truncate the interface name if it exceeds 8 characters to make sure - # the length of bridge name is less than 15 (its maximum value). - br_name = KIMCHI_BRIDGE_PREFIX + interface[-8:] + '-' + vlan_id - br_xml = create_vlan_tagged_bridge_xml(br_name, interface, vlan_id) - conn = self.conn.get() - - bridges = [] - for net in conn.listAllNetworks(): - # Bridged networks do not have a bridge name - # So in those cases, libvirt raises an error when trying to get - # the bridge name - try: - bridges.append(net.bridgeName()) - except libvirt.libvirtError, e: - wok_log.error(e.message) - - if br_name in bridges: - raise InvalidOperation("KCHNET0010E", {'iface': br_name}) - - with RollbackContext() as rollback: - try: - vlan_tagged_br = conn.interfaceDefineXML(br_xml, 0) - rollback.prependDefer(vlan_tagged_br.destroy) - vlan_tagged_br.create(0) - except libvirt.libvirtError as e: - raise OperationFailed(e.message) - else: - return br_name - - -class NetworkModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - - def lookup(self, name): - network = self.get_network(self.conn.get(), name) - xml = network.XMLDesc(0) - net_dict = self.get_network_from_xml(xml) - subnet = net_dict['subnet'] - dhcp = net_dict['dhcp'] - forward = net_dict['forward'] - interface = net_dict['bridge'] - - connection = forward['mode'] or "isolated" - # FIXME, if we want to support other forward mode well. - if connection == 'bridge': - # macvtap bridge - interface = interface or forward['interface'][0] - # exposing the network on linux bridge or macvtap interface - interface_subnet = knetwork.get_dev_netaddr(interface) - subnet = subnet if subnet else interface_subnet - - # libvirt use format 192.168.0.1/24, standard should be 192.168.0.0/24 - # http://www.ovirt.org/File:Issue3.png - if subnet: - subnet = ipaddr.IPNetwork(subnet) - subnet = "%s/%s" % (subnet.network, subnet.prefixlen) - - return {'connection': connection, - 'interface': interface, - 'subnet': subnet, - 'dhcp': dhcp, - 'vms': self._get_vms_attach_to_a_network(name), - 'in_use': self._is_network_in_use(name), - 'autostart': network.autostart() == 1, - 'state': network.isActive() and "active" or "inactive", - 'persistent': True if network.isPersistent() else False} - - def _is_network_in_use(self, name): - # All the networks listed as default in template.conf file should not - # be deactivate or deleted. Otherwise, we will allow user create - # inconsistent templates from scratch - if name in tmpl_defaults['networks']: - return True - - vms = self._get_vms_attach_to_a_network(name) - return bool(vms) or self._is_network_used_by_template(name) - - def _is_network_used_by_template(self, network): - with self.objstore as session: - templates = session.get_list('template') - for tmpl in templates: - tmpl_net = session.get('template', tmpl)['networks'] - if network in tmpl_net: - return True - return False - - def _get_vms_attach_to_a_network(self, network, filter="all"): - DOM_STATE_MAP = {'nostate': 0, 'running': 1, 'blocked': 2, - 'paused': 3, 'shutdown': 4, 'shutoff': 5, - 'crashed': 6} - state = DOM_STATE_MAP.get(filter) - vms = [] - conn = self.conn.get() - for dom in conn.listAllDomains(0): - networks = self._vm_get_networks(dom) - if network.encode('utf-8') in networks and \ - (state is None or state == dom.state(0)[0]): - vms.append(dom.name()) - return vms - - def _vm_get_networks(self, dom): - xml = dom.XMLDesc(0) - xpath = "/domain/devices/interface[@type='network']/source/@network" - return xpath_get_text(xml, xpath) - - def activate(self, name): - network = self.get_network(self.conn.get(), name) - try: - network.create() - except libvirt.libvirtError, e: - raise OperationFailed('KCHNET0022E', {'name': name, - 'err': e.message}) - - def deactivate(self, name): - if self._is_network_in_use(name): - vms = self._get_vms_attach_to_a_network(name) - vms.sort() - raise InvalidOperation("KCHNET0018E", {'name': name, - 'vms': ', '.join(vms)}) - - network = self.get_network(self.conn.get(), name) - network.destroy() - - def delete(self, name): - if self._is_network_in_use(name): - vms = self._get_vms_attach_to_a_network(name) - vms.sort() - raise InvalidOperation("KCHNET0017E", {'name': name, - 'vms': ', '.join(vms)}) - - network = self.get_network(self.conn.get(), name) - if network.isActive(): - raise InvalidOperation("KCHNET0005E", {'name': name}) - - self._remove_vlan_tagged_bridge(network) - network.undefine() - - @staticmethod - def get_network(conn, name): - name = name.encode("utf-8") - try: - return conn.networkLookupByName(name) - except libvirt.libvirtError: - raise NotFoundError("KCHNET0002E", {'name': name}) - - @staticmethod - def get_network_from_xml(xml): - address = xpath_get_text(xml, "/network/ip/@address") - address = address and address[0] or '' - netmask = xpath_get_text(xml, "/network/ip/@netmask") - netmask = netmask and netmask[0] or '' - net = address and netmask and "/".join([address, netmask]) or '' - - dhcp_start = xpath_get_text(xml, "/network/ip/dhcp/range/@start") - dhcp_start = dhcp_start and dhcp_start[0] or '' - dhcp_end = xpath_get_text(xml, "/network/ip/dhcp/range/@end") - dhcp_end = dhcp_end and dhcp_end[0] or '' - dhcp = {'start': dhcp_start, 'end': dhcp_end} - - forward_mode = xpath_get_text(xml, "/network/forward/@mode") - forward_mode = forward_mode and forward_mode[0] or '' - forward_if = xpath_get_text(xml, "/network/forward/interface/@dev") - forward_pf = xpath_get_text(xml, "/network/forward/pf/@dev") - bridge = xpath_get_text(xml, "/network/bridge/@name") - bridge = bridge and bridge[0] or '' - return {'subnet': net, 'dhcp': dhcp, 'bridge': bridge, - 'forward': {'mode': forward_mode, - 'interface': forward_if, - 'pf': forward_pf}} - - def _remove_vlan_tagged_bridge(self, network): - try: - bridge = network.bridgeName() - except libvirt.libvirtError: - pass - else: - if bridge.startswith(KIMCHI_BRIDGE_PREFIX): - conn = self.conn.get() - iface = conn.interfaceLookupByName(bridge) - iface.isActive() and iface.destroy(0) - iface.undefine() diff --git a/plugins/kimchi/model/peers.py b/plugins/kimchi/model/peers.py deleted file mode 100644 index 7577364..0000000 --- a/plugins/kimchi/model/peers.py +++ /dev/null @@ -1,72 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import cherrypy -import re -import socket - -from wok.config import config -from wok.utils import run_command, wok_log - - -class PeersModel(object): - def __init__(self, **kargs): - # check federation feature is enabled on Kimchi server - if config.get("server", "federation") == "off": - return - - # register server on openslp - hostname = socket.getfqdn(config.get("server", "host")) - port = config.get("server", "ssl_port") - self.url = hostname + ":" + port - - cmd = ["slptool", "register", - "service:wokd://%s" % self.url] - out, error, ret = run_command(cmd) - if out and len(out) != 0: - wok_log.error("Unable to register server on openSLP." - " Details: %s" % out) - cherrypy.engine.subscribe('exit', self._peer_deregister) - - def _peer_deregister(self): - cmd = ["slptool", "deregister", - "service:wokd://%s" % self.url] - out, error, ret = run_command(cmd) - if out and len(out) != 0: - wok_log.error("Unable to deregister server on openSLP." - " Details: %s" % out) - - def get_list(self): - # check federation feature is enabled on Kimchi server - if config.get("server", "federation") == "off": - return [] - - cmd = ["slptool", "findsrvs", "service:wokd"] - out, error, ret = run_command(cmd) - if ret != 0: - return [] - - peers = [] - for server in out.strip().split("\n"): - match = re.match("service:wokd://(.*?),.*", server) - peer = match.group(1) - if peer != self.url: - peers.append("https://" + peer) - - return peers diff --git a/plugins/kimchi/model/storagepools.py b/plugins/kimchi/model/storagepools.py deleted file mode 100644 index 0db2ef4..0000000 --- a/plugins/kimchi/model/storagepools.py +++ /dev/null @@ -1,490 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import libvirt -import lxml.etree as ET -import sys -from lxml.builder import E - -from wok.config import config, PluginPaths -from wok.exception import InvalidOperation, MissingParameter -from wok.exception import NotFoundError, OperationFailed -from wok.utils import add_task, run_command, wok_log -from wok.xmlutils.utils import xpath_get_text - -from ..osinfo import defaults as tmpl_defaults -from ..scan import Scanner -from ..utils import pool_name_from_uri -from config import CapabilitiesModel -from host import DeviceModel -from libvirtstoragepool import StoragePoolDef - - -ISO_POOL_NAME = u'kimchi_isos' - -POOL_STATE_MAP = {0: 'inactive', - 1: 'initializing', - 2: 'active', - 3: 'degraded', - 4: 'inaccessible'} - -# Types of pools supported -STORAGE_SOURCES = {'netfs': {'addr': '/pool/source/host/@name', - 'path': '/pool/source/dir/@path'}, - 'iscsi': {'addr': '/pool/source/host/@name', - 'port': '/pool/source/host/@port', - 'path': '/pool/source/device/@path'}, - 'scsi': {'adapter_type': '/pool/source/adapter/@type', - 'adapter_name': '/pool/source/adapter/@name', - 'wwnn': '/pool/source/adapter/@wwnn', - 'wwpn': '/pool/source/adapter/@wwpn'}} - - -class StoragePoolsModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - self.scanner = Scanner(self._clean_scan) - self.scanner.delete() - self.caps = CapabilitiesModel(**kargs) - self.device = DeviceModel(**kargs) - - if self.conn.isQemuURI(): - self._check_default_pools() - - def _check_default_pools(self): - pools = {} - - default_pool = tmpl_defaults['storagepool'] - default_pool = default_pool.split('/')[-1] - - pools[default_pool] = {} - if default_pool == 'default': - pools[default_pool] = {'path': '/var/lib/libvirt/images'} - - if config.get("server", "create_iso_pool") == "true": - pools['ISO'] = {'path': '/var/lib/kimchi/isos'} - - error_msg = ("Please, check the configuration in %s/template.conf to " - "ensure it has a valid storage pool." % - PluginPaths('kimchi').conf_dir) - - conn = self.conn.get() - for pool_name in pools: - try: - pool = conn.storagePoolLookupByName(pool_name) - except libvirt.libvirtError, e: - pool_path = pools[pool_name].get('path') - if pool_path is None: - msg = "Fatal: Unable to find storage pool %s. " + error_msg - wok_log.error(msg % pool_name) - wok_log.error("Details: %s", e.message) - sys.exit(1) - - # Try to create the pool - pool = E.pool(E.name(pool_name), type='dir') - pool.append(E.target(E.path(pool_path))) - xml = ET.tostring(pool) - try: - pool = conn.storagePoolDefineXML(xml, 0) - except libvirt.libvirtError, e: - msg = "Fatal: Unable to create storage pool %s. " - msg += error_msg - wok_log.error(msg % pool_name) - wok_log.error("Details: %s", e.message) - sys.exit(1) - - # Build and set autostart value to pool - # Ignore error as the pool was already successfully created - try: - # Add build step to make sure target directory created - # The build process may fail when the pool directory - # already exists on system - pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW) - pool.setAutostart(1) - except: - pass - - if pool.isActive() == 0: - try: - pool.create(0) - except libvirt.libvirtError, e: - msg = "Fatal: Unable to craete storage pool %s. " - msg += error_msg - wok_log.error(msg % pool_name) - wok_log.error("Details: %s", e.message) - sys.exit(1) - - def get_list(self): - try: - conn = self.conn.get() - names = conn.listStoragePools() - names += conn.listDefinedStoragePools() - return sorted(map(lambda x: x.decode('utf-8'), names)) - except libvirt.libvirtError as e: - raise OperationFailed("KCHPOOL0006E", - {'err': e.get_error_message()}) - - def create(self, params): - task_id = None - conn = self.conn.get() - try: - name = params['name'] - if name == ISO_POOL_NAME: - raise InvalidOperation("KCHPOOL0031E") - - # The user may want to create a logical pool with the same name - # used before but a volume group will already exist with this name - # So check the volume group does not exist to create the pool - if params['type'] == 'logical': - vgdisplay_cmd = ['vgdisplay', name.encode('utf-8')] - output, error, returncode = run_command(vgdisplay_cmd) - # From vgdisplay error codes: - # 1 error reading VGDA - # 2 volume group doesn't exist - # 3 not all physical volumes of volume group online - # 4 volume group not found - # 5 no volume groups found at all - # 6 error reading VGDA from lvmtab - if returncode not in [2, 4, 5]: - raise InvalidOperation("KCHPOOL0036E", {'name': name}) - - if params['type'] == 'kimchi-iso': - task_id = self._do_deep_scan(params) - - if params['type'] == 'scsi': - adapter_name = params['source']['adapter_name'] - extra_params = self.device.lookup(adapter_name) - # Adds name, adapter_type, wwpn and wwnn to source information - params['source'].update(extra_params) - params['fc_host_support'] = self.caps.fc_host_support - - poolDef = StoragePoolDef.create(params) - poolDef.prepare(conn) - xml = poolDef.xml.encode("utf-8") - except KeyError, item: - raise MissingParameter("KCHPOOL0004E", - {'item': str(item), 'name': name}) - - if name in self.get_list(): - raise InvalidOperation("KCHPOOL0001E", {'name': name}) - - try: - if task_id: - # Create transient pool for deep scan - conn.storagePoolCreateXML(xml, 0) - return name - - pool = conn.storagePoolDefineXML(xml, 0) - except libvirt.libvirtError as e: - wok_log.error("Problem creating Storage Pool: %s", e) - raise OperationFailed("KCHPOOL0007E", - {'name': name, 'err': e.get_error_message()}) - - # Build and set autostart value to pool - # Ignore error as the pool was already successfully created - # The build process fails when the pool directory already exists - try: - if params['type'] in ['logical', 'dir', 'netfs', 'scsi']: - pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW) - pool.setAutostart(1) - else: - pool.setAutostart(0) - except: - pass - - if params['type'] == 'netfs': - output, error, returncode = run_command(['setsebool', '-P', - 'virt_use_nfs=1']) - if error or returncode: - wok_log.error("Unable to set virt_use_nfs=1. If you use " - "SELinux, this may prevent NFS pools from " - "being used.") - return name - - def _clean_scan(self, pool_name): - try: - conn = self.conn.get() - pool = conn.storagePoolLookupByName(pool_name.encode("utf-8")) - pool.destroy() - with self.objstore as session: - session.delete('scanning', pool_name) - except Exception, e: - err = "Exception %s occured when cleaning scan result" - wok_log.debug(err % e.message) - - def _do_deep_scan(self, params): - scan_params = dict(ignore_list=[]) - scan_params['scan_path'] = params['path'] - params['type'] = 'dir' - - for pool in self.get_list(): - try: - res = StoragePoolModel(conn=self.conn, - objstore=self.objstore).lookup(pool) - if res['state'] == 'active': - scan_params['ignore_list'].append(res['path']) - except Exception, e: - err = "Exception %s occured when get ignore path" - wok_log.debug(err % e.message) - - params['path'] = self.scanner.scan_dir_prepare(params['name']) - scan_params['pool_path'] = params['path'] - task_id = add_task('/plugins/kimchi/storagepools/%s' % ISO_POOL_NAME, - self.scanner.start_scan, self.objstore, scan_params) - # Record scanning-task/storagepool mapping for future querying - try: - with self.objstore as session: - session.store('scanning', params['name'], task_id) - return task_id - except Exception as e: - raise OperationFailed('KCHPOOL0037E', {'err': e.message}) - - -class StoragePoolModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - - @staticmethod - def get_storagepool(name, conn): - conn = conn.get() - try: - return conn.storagePoolLookupByName(name.encode("utf-8")) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL: - raise NotFoundError("KCHPOOL0002E", {'name': name}) - else: - raise - - def _get_storagepool_vols_num(self, pool): - try: - if pool.isActive(): - pool.refresh(0) - return pool.numOfVolumes() - else: - return 0 - except libvirt.libvirtError as e: - # If something (say a busy pool) prevents the refresh, - # throwing an Exception here would prevent all pools from - # displaying information -- so return None for busy - wok_log.error("ERROR: Storage Pool get vol count: %s " - % e.get_error_message()) - wok_log.error("ERROR: Storage Pool get vol count error no: %s " - % e.get_error_code()) - return 0 - except Exception as e: - raise OperationFailed("KCHPOOL0008E", - {'name': pool.name(), - 'err': e.get_error_message()}) - - def _get_storage_source(self, pool_type, pool_xml): - source = {} - if pool_type not in STORAGE_SOURCES: - return source - - for key, val in STORAGE_SOURCES[pool_type].items(): - res = xpath_get_text(pool_xml, val) - if len(res) == 1: - source[key] = res[0] - elif len(res) == 0: - source[key] = "" - else: - source[key] = res - return source - - def _nfs_status_online(self, pool, poolArgs=None): - if not poolArgs: - xml = pool.XMLDesc(0) - pool_type = xpath_get_text(xml, "/pool/@type")[0] - source = self._get_storage_source(pool_type, xml) - poolArgs = {} - poolArgs['name'] = pool.name() - poolArgs['type'] = pool_type - poolArgs['source'] = {'path': source['path'], - 'host': source['addr']} - conn = self.conn.get() - poolDef = StoragePoolDef.create(poolArgs) - try: - poolDef.prepare(conn) - return True - except Exception: - return False - - def lookup(self, name): - pool = self.get_storagepool(name, self.conn) - info = pool.info() - autostart = True if pool.autostart() else False - persistent = True if pool.isPersistent() else False - xml = pool.XMLDesc(0) - path = xpath_get_text(xml, "/pool/target/path")[0] - pool_type = xpath_get_text(xml, "/pool/@type")[0] - source = self._get_storage_source(pool_type, xml) - # FIXME: nfs workaround - prevent any libvirt operation - # for a nfs if the corresponding NFS server is down. - if pool_type == 'netfs' and not self._nfs_status_online(pool): - wok_log.debug("NFS pool %s is offline, reason: NFS " - "server %s is unreachable.", name, source['addr']) - # Mark state as '4' => inaccessible. - info[0] = 4 - # skip calculating volumes - nr_volumes = 0 - else: - nr_volumes = self._get_storagepool_vols_num(pool) - - res = {'state': POOL_STATE_MAP[info[0]], - 'path': path, - 'source': source, - 'type': pool_type, - 'autostart': autostart, - 'capacity': info[1], - 'allocated': info[2], - 'available': info[3], - 'nr_volumes': nr_volumes, - 'persistent': persistent} - - if not pool.isPersistent(): - # Deal with deep scan generated pool - try: - with self.objstore as session: - task_id = session.get('scanning', name) - res['task_id'] = str(task_id) - res['type'] = 'kimchi-iso' - except NotFoundError: - # User created normal pool - pass - return res - - def _update_lvm_disks(self, pool_name, disks): - # check if all the disks/partitions exists in the host - for disk in disks: - lsblk_cmd = ['lsblk', disk] - output, error, returncode = run_command(lsblk_cmd) - if returncode != 0: - wok_log.error('%s is not a valid disk/partition. Could not ' - 'add it to the pool %s.', disk, pool_name) - raise OperationFailed('KCHPOOL0027E', {'disk': disk, - 'pool': pool_name}) - # add disks to the lvm pool using vgextend + virsh refresh - vgextend_cmd = ["vgextend", pool_name] - vgextend_cmd += disks - output, error, returncode = run_command(vgextend_cmd) - if returncode != 0: - msg = "Could not add disks to pool %s, error: %s" - wok_log.error(msg, pool_name, error) - raise OperationFailed('KCHPOOL0028E', {'pool': pool_name, - 'err': error}) - # refreshing pool state - pool = self.get_storagepool(pool_name, self.conn) - if pool.isActive(): - pool.refresh(0) - - def update(self, name, params): - pool = self.get_storagepool(name, self.conn) - if 'autostart' in params: - if params['autostart']: - pool.setAutostart(1) - else: - pool.setAutostart(0) - - if 'disks' in params: - # check if pool is type 'logical' - xml = pool.XMLDesc(0) - pool_type = xpath_get_text(xml, "/pool/@type")[0] - if pool_type != 'logical': - raise InvalidOperation('KCHPOOL0029E') - self._update_lvm_disks(name, params['disks']) - ident = pool.name() - return ident.decode('utf-8') - - def activate(self, name): - pool = self.get_storagepool(name, self.conn) - # FIXME: nfs workaround - do not activate a NFS pool - # if the NFS server is not reachable. - xml = pool.XMLDesc(0) - pool_type = xpath_get_text(xml, "/pool/@type")[0] - if pool_type == 'netfs' and not self._nfs_status_online(pool): - # block the user from activating the pool. - source = self._get_storage_source(pool_type, xml) - raise OperationFailed("KCHPOOL0032E", - {'name': name, 'server': source['addr']}) - return - try: - pool.create(0) - except libvirt.libvirtError as e: - raise OperationFailed("KCHPOOL0009E", - {'name': name, 'err': e.get_error_message()}) - - def _pool_used_by_template(self, pool_name): - with self.objstore as session: - templates = session.get_list('template') - for tmpl in templates: - t_info = session.get('template', tmpl) - t_pool = pool_name_from_uri(t_info['storagepool']) - if t_pool == pool_name: - return True - return False - - def deactivate(self, name): - if self._pool_used_by_template(name): - raise InvalidOperation('KCHPOOL0034E', {'name': name}) - - pool = self.get_storagepool(name, self.conn) - # FIXME: nfs workaround - do not try to deactivate a NFS pool - # if the NFS server is not reachable. - xml = pool.XMLDesc(0) - pool_type = xpath_get_text(xml, "/pool/@type")[0] - if pool_type == 'netfs' and not self._nfs_status_online(pool): - # block the user from dactivating the pool. - source = self._get_storage_source(pool_type, xml) - raise OperationFailed("KCHPOOL0033E", - {'name': name, 'server': source['addr']}) - return - try: - persistent = pool.isPersistent() - pool.destroy() - except libvirt.libvirtError as e: - raise OperationFailed("KCHPOOL0010E", - {'name': name, 'err': e.get_error_message()}) - # If pool was not persistent, then it was erased by destroy() and - # must return nothing here, to trigger _redirect() and avoid errors - if not persistent: - return "" - - def delete(self, name): - if self._pool_used_by_template(name): - raise InvalidOperation('KCHPOOL0035E', {'name': name}) - - pool = self.get_storagepool(name, self.conn) - if pool.isActive(): - raise InvalidOperation("KCHPOOL0005E", {'name': name}) - try: - pool.undefine() - except libvirt.libvirtError as e: - raise OperationFailed("KCHPOOL0011E", - {'name': name, 'err': e.get_error_message()}) - - -class IsoPoolModel(object): - def __init__(self, **kargs): - pass - - def lookup(self, name): - return {'state': 'active', - 'type': 'kimchi-iso'} diff --git a/plugins/kimchi/model/storageservers.py b/plugins/kimchi/model/storageservers.py deleted file mode 100644 index accc5f5..0000000 --- a/plugins/kimchi/model/storageservers.py +++ /dev/null @@ -1,81 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.exception import NotFoundError - -from storagepools import StoragePoolModel, StoragePoolsModel - -# Types of remote storage servers supported -STORAGE_SERVERS = ['netfs', 'iscsi'] - - -class StorageServersModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.pool = StoragePoolModel(**kargs) - self.pools = StoragePoolsModel(**kargs) - - def get_list(self, _target_type=None): - if not _target_type: - target_type = STORAGE_SERVERS - else: - target_type = [_target_type] - - pools = self.pools.get_list() - - server_list = [] - for pool in pools: - try: - pool_info = self.pool.lookup(pool) - if (pool_info['type'] in target_type and - pool_info['source']['addr'] not in server_list): - # Avoid to add same server for multiple times - # if it hosts more than one storage type - server_list.append(pool_info['source']['addr']) - except NotFoundError: - pass - - return server_list - - -class StorageServerModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.pool = StoragePoolModel(**kargs) - - def lookup(self, server): - conn = self.conn.get() - pools = conn.listStoragePools() - pools += conn.listDefinedStoragePools() - for pool in pools: - try: - pool_info = self.pool.lookup(pool) - if (pool_info['type'] in STORAGE_SERVERS and - pool_info['source']['addr'] == server): - info = dict(host=server) - if (pool_info['type'] == "iscsi" and - 'port' in pool_info['source']): - info["port"] = pool_info['source']['port'] - return info - except NotFoundError: - # Avoid inconsistent pool result because of lease between list - # lookup - pass - - raise NotFoundError("KCHSR0001E", {'server': server}) diff --git a/plugins/kimchi/model/storagetargets.py b/plugins/kimchi/model/storagetargets.py deleted file mode 100644 index 4090b45..0000000 --- a/plugins/kimchi/model/storagetargets.py +++ /dev/null @@ -1,122 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import libvirt -import lxml.etree as ET -from lxml import objectify -from lxml.builder import E - -from wok.utils import patch_find_nfs_target, wok_log - -from config import CapabilitiesModel -from storageservers import STORAGE_SERVERS - - -class StorageTargetsModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.caps = CapabilitiesModel(**kargs) - - def get_list(self, storage_server, _target_type=None, _server_port=None): - target_list = list() - if not _target_type: - target_types = STORAGE_SERVERS - else: - target_types = [_target_type] - - for target_type in target_types: - if not self.caps.nfs_target_probe and target_type == 'netfs': - targets = patch_find_nfs_target(storage_server) - else: - xml = self._get_storage_server_spec(server=storage_server, - target_type=target_type, - server_port=_server_port) - conn = self.conn.get() - try: - ret = conn.findStoragePoolSources(target_type, xml, 0) - except libvirt.libvirtError as e: - err = "Query storage pool source fails because of %s" - wok_log.warning(err, e.get_error_message()) - continue - - targets = self._parse_target_source_result(target_type, ret) - - target_list.extend(targets) - - # Get all netfs and iscsi paths in use - used_paths = [] - try: - conn = self.conn.get() - # Get all existing ISCSI and NFS pools - pools = conn.listAllStoragePools( - libvirt.VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI | - libvirt.VIR_CONNECT_LIST_STORAGE_POOLS_NETFS) - for pool in pools: - pool_xml = pool.XMLDesc(0) - root = objectify.fromstring(pool_xml) - if root.get('type') == 'netfs' and \ - root.source.dir is not None: - used_paths.append(root.source.dir.get('path')) - elif root.get('type') == 'iscsi' and \ - root.source.device is not None: - used_paths.append(root.source.device.get('path')) - - except libvirt.libvirtError as e: - err = "Query storage pool source fails because of %s" - wok_log.warning(err, e.get_error_message()) - - # Filter target_list to not not show the used paths - target_list = [elem for elem in target_list - if elem.get('target') not in used_paths] - return [dict(t) for t in set(tuple(t.items()) for t in target_list)] - - def _get_storage_server_spec(self, **kwargs): - # Required parameters: - # server: - # target_type: - extra_args = [] - server_type = kwargs['target_type'] - if server_type == 'netfs': - extra_args.append(E.format(type='nfs')) - else: - extra_args.append(E.format(type=server_type)) - - host_attr = {"name": kwargs['server']} - server_port = kwargs.get("server_port") - if server_port is not None: - host_attr['port'] = server_port - - obj = E.source(E.host(host_attr), *extra_args) - xml = ET.tostring(obj) - return xml - - def _parse_target_source_result(self, target_type, xml_str): - root = objectify.fromstring(xml_str) - ret = [] - for source in root.getchildren(): - if target_type == 'netfs': - target_path = source.dir.get('path') - type = source.format.get('type') - if target_type == 'iscsi': - target_path = source.device.get('path') - type = target_type - host_name = source.host.get('name') - ret.append(dict(host=host_name, target_type=type, - target=target_path)) - return ret diff --git a/plugins/kimchi/model/storagevolumes.py b/plugins/kimchi/model/storagevolumes.py deleted file mode 100644 index 99b17d3..0000000 --- a/plugins/kimchi/model/storagevolumes.py +++ /dev/null @@ -1,542 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import contextlib -import libvirt -import lxml.etree as ET -import os -import tempfile -import threading -import time -import urllib2 -from lxml.builder import E - -from wok.exception import InvalidOperation, InvalidParameter, IsoFormatError -from wok.exception import MissingParameter, NotFoundError, OperationFailed -from wok.utils import add_task, get_next_clone_name, get_unique_file_name -from wok.utils import wok_log -from wok.xmlutils.utils import xpath_get_text -from wok.model.tasks import TaskModel - -from ..config import READONLY_POOL_TYPE -from ..isoinfo import IsoImage -from diskutils import get_disk_used_by, set_disk_used_by -from storagepools import StoragePoolModel - - -VOLUME_TYPE_MAP = {0: 'file', - 1: 'block', - 2: 'directory', - 3: 'network'} - -READ_CHUNK_SIZE = 1048576 # 1 MiB -REQUIRE_NAME_PARAMS = ['capacity'] - -upload_volumes = dict() - - -class StorageVolumesModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - self.task = TaskModel(**kargs) - - def create(self, pool_name, params): - vol_source = ['url', 'capacity'] - - name = params.get('name') - - index_list = list(i for i in range(len(vol_source)) - if vol_source[i] in params) - if len(index_list) != 1: - raise InvalidParameter("KCHVOL0018E", - {'param': ",".join(vol_source)}) - - create_param = vol_source[index_list[0]] - - # Verify if the URL is valid - if create_param == 'url': - url = params['url'] - try: - urllib2.urlopen(url).close() - except: - raise InvalidParameter('KCHVOL0022E', {'url': url}) - - all_vol_names = self.get_list(pool_name) - - if name is None: - # the methods listed in 'REQUIRE_NAME_PARAMS' cannot have - # 'name' == None - if create_param in REQUIRE_NAME_PARAMS: - raise InvalidParameter('KCHVOL0016E') - - # if 'name' is omitted - except for the methods listed in - # 'REQUIRE_NAME_PARAMS' - the default volume name will be the - # file/URL basename. - if create_param == 'url': - name = os.path.basename(params['url']) - else: - name = 'upload-%s' % int(time.time()) - - name = get_unique_file_name(all_vol_names, name) - params['name'] = name - - try: - create_func = getattr(self, '_create_volume_with_%s' % - create_param) - except AttributeError: - raise InvalidParameter("KCHVOL0019E", {'param': create_param}) - - pool_info = StoragePoolModel(conn=self.conn, - objstore=self.objstore).lookup(pool_name) - if pool_info['type'] in READONLY_POOL_TYPE: - raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']}) - if pool_info['state'] == 'inactive': - raise InvalidParameter('KCHVOL0003E', {'pool': pool_name, - 'volume': name}) - if name in all_vol_names: - raise InvalidParameter('KCHVOL0001E', {'name': name}) - - params['pool'] = pool_name - targeturi = '/plugins/kimchi/storagepools/%s/storagevolumes/%s' \ - % (pool_name, name) - taskid = add_task(targeturi, create_func, self.objstore, params) - return self.task.lookup(taskid) - - def _create_volume_with_capacity(self, cb, params): - pool_name = params.pop('pool') - vol_xml = """ - <volume> - <name>%(name)s</name> - <allocation unit='bytes'>%(allocation)s</allocation> - <capacity unit='bytes'>%(capacity)s</capacity> - <source> - </source> - <target> - <format type='%(format)s'/> - </target> - </volume> - """ - params.setdefault('allocation', 0) - params.setdefault('format', 'qcow2') - - name = params['name'] - try: - pool = StoragePoolModel.get_storagepool(pool_name, self.conn) - xml = vol_xml % params - except KeyError, item: - raise MissingParameter("KCHVOL0004E", {'item': str(item), - 'volume': name}) - - try: - pool.createXML(xml, 0) - except libvirt.libvirtError as e: - raise OperationFailed("KCHVOL0007E", - {'name': name, 'pool': pool, - 'err': e.get_error_message()}) - - vol_info = StorageVolumeModel(conn=self.conn, - objstore=self.objstore).lookup(pool_name, - name) - - vol_path = vol_info['path'] - set_disk_used_by(self.objstore, vol_info['path'], []) - - if params.get('upload', False): - upload_volumes[vol_path] = {'lock': threading.Lock(), - 'offset': 0, 'cb': cb} - cb('ready for upload') - else: - cb('OK', True) - - def _create_volume_with_url(self, cb, params): - pool_name = params['pool'] - name = params['name'] - url = params['url'] - - pool_model = StoragePoolModel(conn=self.conn, - objstore=self.objstore) - pool = pool_model.lookup(pool_name) - - if pool['type'] in ['dir', 'netfs']: - file_path = os.path.join(pool['path'], name) - else: - file_path = tempfile.mkstemp(prefix=name)[1] - - with contextlib.closing(urllib2.urlopen(url)) as response: - with open(file_path, 'w') as volume_file: - remote_size = response.info().getheader('Content-Length', '-') - downloaded_size = 0 - - try: - while True: - chunk_data = response.read(READ_CHUNK_SIZE) - if not chunk_data: - break - - volume_file.write(chunk_data) - downloaded_size += len(chunk_data) - cb('%s/%s' % (downloaded_size, remote_size)) - except (IOError, libvirt.libvirtError) as e: - if os.path.isfile(file_path): - os.remove(file_path) - - raise OperationFailed('KCHVOL0007E', {'name': name, - 'pool': pool_name, - 'err': e.message}) - - if pool['type'] in ['dir', 'netfs']: - virt_pool = StoragePoolModel.get_storagepool(pool_name, self.conn) - virt_pool.refresh(0) - else: - def _stream_handler(stream, nbytes, fd): - return fd.read(nbytes) - - virt_stream = virt_vol = None - - try: - task = self.create(pool_name, {'name': name, - 'format': 'raw', - 'capacity': downloaded_size, - 'allocation': downloaded_size}) - self.task.wait(task['id']) - virt_vol = StorageVolumeModel.get_storagevolume(pool_name, - name, - self.conn) - - virt_stream = self.conn.get().newStream(0) - virt_vol.upload(virt_stream, 0, downloaded_size, 0) - - with open(file_path) as fd: - virt_stream.sendAll(_stream_handler, fd) - - virt_stream.finish() - except (IOError, libvirt.libvirtError) as e: - try: - if virt_stream: - virt_stream.abort() - if virt_vol: - virt_vol.delete(0) - except libvirt.libvirtError, virt_e: - wok_log.error(virt_e.message) - finally: - raise OperationFailed('KCHVOL0007E', {'name': name, - 'pool': pool_name, - 'err': e.message}) - finally: - os.remove(file_path) - - vol_info = StorageVolumeModel(conn=self.conn, - objstore=self.objstore).lookup(pool_name, - name) - set_disk_used_by(self.objstore, vol_info['path'], []) - - cb('OK', True) - - def get_list(self, pool_name): - pool = StoragePoolModel.get_storagepool(pool_name, self.conn) - if not pool.isActive(): - raise InvalidOperation("KCHVOL0006E", {'pool': pool_name}) - try: - pool.refresh(0) - return sorted(map(lambda x: x.decode('utf-8'), pool.listVolumes())) - except libvirt.libvirtError as e: - raise OperationFailed("KCHVOL0008E", - {'pool': pool_name, - 'err': e.get_error_message()}) - - -class StorageVolumeModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - self.task = TaskModel(**kargs) - self.storagevolumes = StorageVolumesModel(**kargs) - self.storagepool = StoragePoolModel(**kargs) - - @staticmethod - def get_storagevolume(poolname, name, conn): - pool = StoragePoolModel.get_storagepool(poolname, conn) - if not pool.isActive(): - raise InvalidOperation("KCHVOL0006E", {'name': pool}) - try: - return pool.storageVolLookupByName(name.encode("utf-8")) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL: - raise NotFoundError("KCHVOL0002E", {'name': name, - 'pool': poolname}) - else: - raise - - def lookup(self, pool, name): - vol = StorageVolumeModel.get_storagevolume(pool, name, self.conn) - path = vol.path() - info = vol.info() - xml = vol.XMLDesc(0) - try: - fmt = xpath_get_text(xml, "/volume/target/format/@type")[0] - except IndexError: - # Not all types of libvirt storage can provide volume format - # infomation. When there is no format information, we assume - # it's 'raw'. - fmt = 'raw' - - iso_img = None - - # 'raw' volumes from 'logical' pools may actually be 'iso'; - # libvirt always reports them as 'raw' - pool_info = self.storagepool.lookup(pool) - if pool_info['type'] == 'logical' and fmt == 'raw': - try: - iso_img = IsoImage(path) - except IsoFormatError: - # not 'iso' afterall - pass - else: - fmt = 'iso' - - used_by = get_disk_used_by(self.objstore, self.conn, path) - res = dict(type=VOLUME_TYPE_MAP[info[0]], - capacity=info[1], - allocation=info[2], - path=path, - used_by=used_by, - format=fmt) - if fmt == 'iso': - if os.path.islink(path): - path = os.path.join(os.path.dirname(path), os.readlink(path)) - os_distro = os_version = 'unknown' - try: - if iso_img is None: - iso_img = IsoImage(path) - os_distro, os_version = iso_img.probe() - bootable = True - except IsoFormatError: - bootable = False - res.update( - dict(os_distro=os_distro, os_version=os_version, path=path, - bootable=bootable)) - return res - - def wipe(self, pool, name): - volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn) - try: - volume.wipePattern(libvirt.VIR_STORAGE_VOL_WIPE_ALG_ZERO, 0) - except libvirt.libvirtError as e: - raise OperationFailed("KCHVOL0009E", - {'name': name, 'err': e.get_error_message()}) - - def delete(self, pool, name): - pool_info = StoragePoolModel(conn=self.conn, - objstore=self.objstore).lookup(pool) - if pool_info['type'] in READONLY_POOL_TYPE: - raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']}) - - volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn) - try: - volume.delete(0) - except libvirt.libvirtError as e: - raise OperationFailed("KCHVOL0010E", - {'name': name, 'err': e.get_error_message()}) - - def resize(self, pool, name, size): - volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn) - - # When decreasing the storage volume capacity, the flag - # VIR_STORAGE_VOL_RESIZE_SHRINK must be used - flags = 0 - if volume.info()[1] > size: - # FIXME: Even using VIR_STORAGE_VOL_RESIZE_SHRINK flag it is not - # possible to decrease the volume capacity due a libvirt bug - # For reference: - # - https://bugzilla.redhat.com/show_bug.cgi?id=1021802 - flags = libvirt.VIR_STORAGE_VOL_RESIZE_SHRINK - - try: - volume.resize(size, flags) - except libvirt.libvirtError as e: - raise OperationFailed("KCHVOL0011E", - {'name': name, 'err': e.get_error_message()}) - - def clone(self, pool, name, new_pool=None, new_name=None): - """Clone a storage volume. - - Arguments: - pool -- The name of the original pool. - name -- The name of the original volume. - new_pool -- The name of the destination pool (optional). If omitted, - the new volume will be created on the same pool as the - original one. - new_name -- The name of the new volume (optional). If omitted, a new - value based on the original volume's name will be used. - - Return: - A Task running the clone operation. - """ - # the same pool will be used if no pool is specified - if new_pool is None: - new_pool = pool - - # a default name based on the original name will be used if no name - # is specified - if new_name is None: - base, ext = os.path.splitext(name) - new_name = get_next_clone_name(self.storagevolumes.get_list(pool), - base, ext) - - params = {'pool': pool, - 'name': name, - 'new_pool': new_pool, - 'new_name': new_name} - taskid = add_task(u'/plugins/kimchi/storagepools/%s/storagevolumes/%s' - % (pool, new_name), self._clone_task, self.objstore, - params) - return self.task.lookup(taskid) - - def _clone_task(self, cb, params): - """Asynchronous function which performs the clone operation. - - This function copies all the data inside the original volume into the - new one. - - Arguments: - cb -- A callback function to signal the Task's progress. - params -- A dict with the following values: - "pool": The name of the original pool. - "name": The name of the original volume. - "new_pool": The name of the destination pool. - "new_name": The name of the new volume. - """ - orig_pool_name = params['pool'] - orig_vol_name = params['name'] - new_pool_name = params['new_pool'] - new_vol_name = params['new_name'] - - try: - cb('setting up volume cloning') - orig_vir_vol = StorageVolumeModel.get_storagevolume(orig_pool_name, - orig_vol_name, - self.conn) - orig_vol = self.lookup(orig_pool_name, orig_vol_name) - new_vir_pool = StoragePoolModel.get_storagepool(new_pool_name, - self.conn) - - cb('building volume XML') - root_elem = E.volume() - root_elem.append(E.name(new_vol_name)) - root_elem.append(E.capacity(unicode(orig_vol['capacity']), - unit='bytes')) - target_elem = E.target() - target_elem.append(E.format(type=orig_vol['format'])) - root_elem.append(target_elem) - new_vol_xml = ET.tostring(root_elem, encoding='utf-8', - pretty_print=True) - - cb('cloning volume') - new_vir_pool.createXMLFrom(new_vol_xml, orig_vir_vol, 0) - except (InvalidOperation, NotFoundError, libvirt.libvirtError), e: - raise OperationFailed('KCHVOL0023E', - {'name': orig_vol_name, - 'pool': orig_pool_name, - 'err': e.get_error_message()}) - - new_vol = self.lookup(new_pool_name, new_vol_name) - cb('adding volume to the object store') - set_disk_used_by(self.objstore, new_vol['path'], []) - - cb('OK', True) - - def doUpload(self, cb, vol, offset, data, data_size): - try: - st = self.conn.get().newStream(0) - vol.upload(st, offset, data_size) - st.send(data) - st.finish() - except Exception as e: - st and st.abort() - cb('', False) - - try: - vol.delete(0) - except Exception as e: - pass - - raise OperationFailed("KCHVOL0029E", {"err": e.message}) - - def update(self, pool, name, params): - chunk_data = params['chunk'].fullvalue() - chunk_size = int(params['chunk_size']) - - if len(chunk_data) != chunk_size: - raise OperationFailed("KCHVOL0026E") - - vol = StorageVolumeModel.get_storagevolume(pool, name, self.conn) - vol_path = vol.path() - vol_capacity = vol.info()[1] - - vol_data = upload_volumes.get(vol_path) - if vol_data is None: - raise OperationFailed("KCHVOL0027E", {"vol": vol_path}) - - cb = vol_data['cb'] - lock = vol_data['lock'] - with lock: - offset = vol_data['offset'] - if (offset + chunk_size) > vol_capacity: - raise OperationFailed("KCHVOL0028E") - - cb('%s/%s' % (offset, vol_capacity)) - self.doUpload(cb, vol, offset, chunk_data, chunk_size) - cb('%s/%s' % (offset + chunk_size, vol_capacity)) - - vol_data['offset'] += chunk_size - if vol_data['offset'] == vol_capacity: - del upload_volumes[vol_path] - cb('OK', True) - - -class IsoVolumesModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.storagevolume = StorageVolumeModel(**kargs) - - def get_list(self): - iso_volumes = [] - conn = self.conn.get() - pools = conn.listStoragePools() - pools += conn.listDefinedStoragePools() - - for pool_name in pools: - try: - pool = StoragePoolModel.get_storagepool(pool_name, self.conn) - pool.refresh(0) - volumes = pool.listVolumes() - except Exception, e: - # Skip inactive pools - wok_log.debug("Shallow scan: skipping pool %s because of " - "error: %s", (pool_name, e.message)) - continue - - for volume in volumes: - res = self.storagevolume.lookup(pool_name, - volume.decode("utf-8")) - if res['format'] == 'iso' and res['bootable']: - res['name'] = '%s' % volume - iso_volumes.append(res) - return iso_volumes diff --git a/plugins/kimchi/model/templates.py b/plugins/kimchi/model/templates.py deleted file mode 100644 index 4f0b204..0000000 --- a/plugins/kimchi/model/templates.py +++ /dev/null @@ -1,303 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import copy -import libvirt -import os -import stat - -from wok.exception import InvalidOperation, InvalidParameter -from wok.exception import NotFoundError, OperationFailed -from wok.utils import probe_file_permission_as_user, run_setfacl_set_attr -from wok.xmlutils.utils import xpath_get_text - -from ..kvmusertests import UserTests -from ..utils import pool_name_from_uri -from ..vmtemplate import VMTemplate -from cpuinfo import CPUInfoModel - - -class TemplatesModel(object): - def __init__(self, **kargs): - self.objstore = kargs['objstore'] - self.conn = kargs['conn'] - - def create(self, params): - name = params.get('name', '').strip() - iso = params.get('cdrom') - # check search permission - if iso and iso.startswith('/') and os.path.exists(iso): - st_mode = os.stat(iso).st_mode - if stat.S_ISREG(st_mode) or stat.S_ISBLK(st_mode): - user = UserTests().probe_user() - run_setfacl_set_attr(iso, user=user) - ret, excp = probe_file_permission_as_user(iso, user) - if ret is False: - raise InvalidParameter('KCHISO0008E', - {'filename': iso, 'user': user, - 'err': excp}) - - cpu_info = params.get('cpu_info') - if cpu_info: - topology = cpu_info.get('topology') - # Check, even though currently only topology - # is supported. - if topology: - sockets = topology['sockets'] - cores = topology['cores'] - threads = topology['threads'] - if params.get('cpus') is None: - params['cpus'] = sockets * cores * threads - # check_topoology will raise the appropriate - # exception if a topology is invalid. - CPUInfoModel(conn=self.conn).\ - check_topology(params['cpus'], topology) - - conn = self.conn.get() - pool_uri = params.get(u'storagepool', '') - if pool_uri: - try: - pool_name = pool_name_from_uri(pool_uri) - pool = conn.storagePoolLookupByName(pool_name.encode("utf-8")) - except Exception: - raise InvalidParameter("KCHTMPL0004E", {'pool': pool_uri, - 'template': name}) - - tmp_volumes = [disk['volume'] for disk in params.get('disks', []) - if 'volume' in disk] - self.template_volume_validate(tmp_volumes, pool) - - for net_name in params.get(u'networks', []): - try: - conn.networkLookupByName(net_name.encode('utf-8')) - except Exception: - raise InvalidParameter("KCHTMPL0003E", {'network': net_name, - 'template': name}) - # Creates the template class with necessary information - # Checkings will be done while creating this class, so any exception - # will be raised here - t = LibvirtVMTemplate(params, scan=True, conn=self.conn) - name = params['name'] - try: - with self.objstore as session: - if name in session.get_list('template'): - raise InvalidOperation("KCHTMPL0001E", {'name': name}) - session.store('template', name, t.info) - except InvalidOperation: - raise - except Exception, e: - raise OperationFailed('KCHTMPL0020E', {'err': e.message}) - - return name - - def get_list(self): - with self.objstore as session: - return session.get_list('template') - - def template_volume_validate(self, tmp_volumes, pool): - kwargs = {'conn': self.conn, 'objstore': self.objstore} - pool_type = xpath_get_text(pool.XMLDesc(0), "/pool/@type")[0] - pool_name = unicode(pool.name(), 'utf-8') - - # as we discussion, we do not mix disks from 2 different types of - # storage pools, for instance: we do not create a template with 2 - # disks, where one comes from a SCSI pool and other is a .img in - # a DIR pool. - if pool_type in ['iscsi', 'scsi']: - if not tmp_volumes: - raise InvalidParameter("KCHTMPL0018E") - - storagevolumes = __import__("kimchi.model.storagevolumes", - fromlist=['']) - pool_volumes = storagevolumes.StorageVolumesModel( - **kwargs).get_list(pool_name) - vols = set(tmp_volumes) - set(pool_volumes) - if vols: - raise InvalidParameter("KCHTMPL0019E", {'pool': pool_name, - 'volume': vols}) - - -class TemplateModel(object): - def __init__(self, **kargs): - self.objstore = kargs['objstore'] - self.conn = kargs['conn'] - self.templates = TemplatesModel(**kargs) - - @staticmethod - def get_template(name, objstore, conn, overrides=None): - with objstore as session: - params = session.get('template', name) - if overrides: - params.update(overrides) - return LibvirtVMTemplate(params, False, conn) - - def lookup(self, name): - t = self.get_template(name, self.objstore, self.conn) - return t.validate_integrity() - - def clone(self, name): - # set default name - subfixs = [v[len(name):] for v in self.templates.get_list() - if v.startswith(name)] - indexs = [int(v.lstrip("-clone")) for v in subfixs - if v.startswith("-clone") and - v.lstrip("-clone").isdigit()] - indexs.sort() - index = "1" if not indexs else str(indexs[-1] + 1) - clone_name = name + "-clone" + index - - temp = self.lookup(name) - temp['name'] = clone_name - ident = self.templates.create(temp) - return ident - - def delete(self, name): - try: - with self.objstore as session: - session.delete('template', name) - except NotFoundError: - raise - except Exception as e: - raise OperationFailed('KCHTMPL0021E', {'err': e.message}) - - def update(self, name, params): - old_t = self.lookup(name) - new_t = copy.copy(old_t) - new_t.update(params) - - if not self._validate_updated_cpu_params(new_t): - raise InvalidParameter('KCHTMPL0025E') - - ident = name - - conn = self.conn.get() - pool_uri = new_t.get(u'storagepool', '') - - if pool_uri: - try: - pool_name = pool_name_from_uri(pool_uri) - pool = conn.storagePoolLookupByName(pool_name.encode("utf-8")) - except Exception: - raise InvalidParameter("KCHTMPL0004E", {'pool': pool_uri, - 'template': name}) - tmp_volumes = [disk['volume'] for disk in new_t.get('disks', []) - if 'volume' in disk] - self.templates.template_volume_validate(tmp_volumes, pool) - - for net_name in params.get(u'networks', []): - try: - conn.networkLookupByName(net_name.encode('utf-8')) - except Exception: - raise InvalidParameter("KCHTMPL0003E", {'network': net_name, - 'template': name}) - - self.delete(name) - try: - ident = self.templates.create(new_t) - except: - ident = self.templates.create(old_t) - raise - return ident - - def _validate_updated_cpu_params(self, info): - # Note: cpu_info is the parent of topology. cpus is vcpus - vcpus = info['cpus'] - cpu_info = info.get('cpu_info') - # cpu_info will always be at least an empty dict - topology = cpu_info.get('topology') - if topology is None: - return True - return vcpus == topology['sockets'] * topology['cores'] * \ - topology['threads'] - - -class LibvirtVMTemplate(VMTemplate): - def __init__(self, args, scan=False, conn=None): - self.conn = conn - VMTemplate.__init__(self, args, scan) - - def _storage_validate(self): - pool_uri = self.info['storagepool'] - pool_name = pool_name_from_uri(pool_uri) - try: - conn = self.conn.get() - pool = conn.storagePoolLookupByName(pool_name.encode("utf-8")) - except libvirt.libvirtError: - raise InvalidParameter("KCHTMPL0004E", {'pool': pool_uri, - 'template': self.name}) - - if not pool.isActive(): - raise InvalidParameter("KCHTMPL0005E", {'pool': pool_name, - 'template': self.name}) - - return pool - - def _get_all_networks_name(self): - conn = self.conn.get() - return sorted(conn.listNetworks() + conn.listDefinedNetworks()) - - def _get_all_storagepools_name(self): - conn = self.conn.get() - names = conn.listStoragePools() + conn.listDefinedStoragePools() - return sorted(map(lambda x: x.decode('utf-8'), names)) - - def _network_validate(self): - names = self.info['networks'] - for name in names: - try: - conn = self.conn.get() - network = conn.networkLookupByName(name.encode('utf-8')) - except libvirt.libvirtError: - raise InvalidParameter("KCHTMPL0003E", {'network': name, - 'template': self.name}) - - if not network.isActive(): - raise InvalidParameter("KCHTMPL0007E", {'network': name, - 'template': self.name}) - - def _get_storage_path(self): - pool = self._storage_validate() - xml = pool.XMLDesc(0) - return xpath_get_text(xml, "/pool/target/path")[0] - - def _get_storage_type(self): - pool = self._storage_validate() - xml = pool.XMLDesc(0) - return xpath_get_text(xml, "/pool/@type")[0] - - def _get_volume_path(self, pool, vol): - pool = self._storage_validate() - try: - return pool.storageVolLookupByName(vol).path() - except: - raise NotFoundError("KCHVOL0002E", {'name': vol, - 'pool': pool}) - - def fork_vm_storage(self, vm_uuid): - # Provision storage: - # TODO: Rebase on the storage API once upstream - pool = self._storage_validate() - vol_list = self.to_volume_list(vm_uuid) - try: - for v in vol_list: - # outgoing text to libvirt, encode('utf-8') - pool.createXML(v['xml'].encode('utf-8'), 0) - except libvirt.libvirtError as e: - raise OperationFailed("KCHVMSTOR0008E", {'error': e.message}) - return vol_list diff --git a/plugins/kimchi/model/users.py b/plugins/kimchi/model/users.py deleted file mode 100644 index 2fa65dd..0000000 --- a/plugins/kimchi/model/users.py +++ /dev/null @@ -1,90 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import ldap -import pwd - -from wok.config import config -from wok.exception import NotFoundError - - -class UsersModel(object): - def __init__(self, **args): - auth_type = config.get("authentication", "method") - for klass in UsersModel.__subclasses__(): - if auth_type == klass.auth_type: - self.user = klass(**args) - - def get_list(self, **args): - return self.user._get_list(**args) - - def validate(self, user): - return self.user._validate(user) - - -class PAMUsersModel(UsersModel): - auth_type = 'pam' - - def __init__(self, **kargs): - pass - - def _get_list(self): - return [user.pw_name for user in pwd.getpwall() - if user.pw_shell.rsplit("/")[-1] not in ["nologin", "false"]] - - def _validate(self, user): - try: - return user in self._get_list() - except: - return False - - -class LDAPUsersModel(UsersModel): - auth_type = 'ldap' - - def __init__(self, **kargs): - pass - - def _get_list(self, _user_id=''): - return self._get_user(_user_id) - - def _validate(self, user): - try: - self._get_user(user) - return True - except NotFoundError: - return False - - def _get_user(self, _user_id): - ldap_server = config.get("authentication", "ldap_server").strip('"') - ldap_search_base = config.get( - "authentication", "ldap_search_base").strip('"') - ldap_search_filter = config.get( - "authentication", "ldap_search_filter", - vars={"username": _user_id.encode("utf-8")}).strip('"') - - connect = ldap.open(ldap_server) - try: - result = connect.search_s( - ldap_search_base, ldap.SCOPE_SUBTREE, ldap_search_filter) - if len(result) == 0: - raise NotFoundError("KCHAUTH0004E", {'user_id': _user_id}) - return result[0][1] - except ldap.NO_SUCH_OBJECT: - raise NotFoundError("KCHAUTH0004E", {'user_id': _user_id}) diff --git a/plugins/kimchi/model/utils.py b/plugins/kimchi/model/utils.py deleted file mode 100644 index 53d719d..0000000 --- a/plugins/kimchi/model/utils.py +++ /dev/null @@ -1,161 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import libvirt -from lxml import etree, objectify -from lxml.builder import E, ElementMaker - -from wok.exception import OperationFailed - - -KIMCHI_META_URL = "https://github.com/kimchi-project/kimchi" -KIMCHI_NAMESPACE = "kimchi" - - -def get_vm_name(vm_name, t_name, name_list): - if vm_name: - return vm_name - for i in xrange(1, 1000): - # VM will have templace name, but without slashes - vm_name = "%s-vm-%i" % (t_name.replace('/', '-'), i) - if vm_name not in name_list: - return vm_name - raise OperationFailed("KCHUTILS0003E") - - -def get_vm_config_flag(dom, mode="persistent"): - # libvirt.VIR_DOMAIN_AFFECT_CURRENT is 0 - # VIR_DOMAIN_AFFECT_LIVE is 1, VIR_DOMAIN_AFFECT_CONFIG is 2 - flag = {"live": libvirt.VIR_DOMAIN_AFFECT_LIVE, - "persistent": libvirt.VIR_DOMAIN_AFFECT_CONFIG, - "current": libvirt.VIR_DOMAIN_AFFECT_CURRENT, - "all": libvirt.VIR_DOMAIN_AFFECT_CONFIG + - libvirt.VIR_DOMAIN_AFFECT_LIVE if dom.isActive() and - dom.isPersistent() else libvirt.VIR_DOMAIN_AFFECT_CURRENT} - - return flag[mode] - - -# avoid duplicate codes -def update_node(root, node): - old_node = root.find(node.tag) - (root.replace(old_node, node) if old_node is not None - else root.append(node)) - return root - - -def _kimchi_set_metadata_node(dom, node): - # some other tools will not let libvirt create a persistent - # configuration, raise exception. - if not dom.isPersistent(): - msg = 'The VM has not a persistent configuration' - raise OperationFailed("KCHVM0030E", - {'name': dom.name(), "err": msg}) - xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE) - root = etree.fromstring(xml) - kimchi = root.find("metadata/{%s}kimchi" % KIMCHI_META_URL) - - EM = ElementMaker(namespace=KIMCHI_META_URL, - nsmap={KIMCHI_NAMESPACE: KIMCHI_META_URL}) - kimchi = EM("kimchi") if kimchi is None else kimchi - - update_node(kimchi, node) - metadata = root.find("metadata") - metadata = E.metadata() if metadata is None else metadata - update_node(metadata, kimchi) - update_node(root, metadata) - dom.connect().defineXML(etree.tostring(root)) - - -def libvirt_get_kimchi_metadata_node(dom, mode="current"): - if not metadata_exists(dom): - return None - try: - xml = dom.metadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT, - KIMCHI_META_URL, - flags=get_vm_config_flag(dom, mode)) - return etree.fromstring(xml) - except libvirt.libvirtError: - return None - - -def set_metadata_node(dom, node, metadata_support, mode="all"): - if metadata_support: - kimchi = libvirt_get_kimchi_metadata_node(dom, mode) - kimchi = E.metadata(E.kimchi()) if kimchi is None else kimchi - - update_node(kimchi, node) - kimchi_xml = etree.tostring(kimchi) - # From libvirt doc, Passing None for @metadata says to remove that - # element from the domain XML (passing the empty string leaves the - # element present). Do not support remove the old metadata. - dom.setMetadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT, kimchi_xml, - KIMCHI_NAMESPACE, KIMCHI_META_URL, - flags=get_vm_config_flag(dom, mode)) - else: - # FIXME remove this code when all distro libvirt supports metadata - # element - _kimchi_set_metadata_node(dom, node) - - -def _kimchi_get_metadata_node(dom, tag): - # some other tools will not let libvirt create a persistent - # configuration, just return empty - if not dom.isPersistent(): - return None - xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE) - root = etree.fromstring(xml) - kimchi = root.find("metadata/{%s}kimchi" % KIMCHI_META_URL) - # remove the "kimchi" prefix of xml - if kimchi is not None: - for elem in kimchi.getiterator(): - if not hasattr(elem.tag, 'find'): - continue - i = elem.tag.find('}') - if i >= 0: - elem.tag = elem.tag[i+1:] - - objectify.deannotate(kimchi) - etree.cleanup_namespaces(kimchi) - return kimchi - return None - - -def get_metadata_node(dom, tag, metadata_support, mode="current"): - if metadata_support: - kimchi = libvirt_get_kimchi_metadata_node(dom, mode) - else: - # FIXME remove this code when all distro libvirt supports metadata - # element - kimchi = _kimchi_get_metadata_node(dom, tag) - - if kimchi is not None: - node = kimchi.find(tag) - if node is not None: - return etree.tostring(node) - return "" - - -def metadata_exists(dom): - xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE) - root = etree.fromstring(xml) - - if root.find("metadata") is None: - return False - return True diff --git a/plugins/kimchi/model/vmhostdevs.py b/plugins/kimchi/model/vmhostdevs.py deleted file mode 100644 index 0cc6bd3..0000000 --- a/plugins/kimchi/model/vmhostdevs.py +++ /dev/null @@ -1,336 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import glob -import libvirt -import os -import platform -from lxml import etree, objectify -from lxml.builder import E - -from wok.exception import InvalidOperation, InvalidParameter, NotFoundError -from wok.exception import OperationFailed -from wok.rollbackcontext import RollbackContext -from wok.utils import run_command, wok_log - -from config import CapabilitiesModel -from host import DeviceModel, DevicesModel -from utils import get_vm_config_flag -from vms import DOM_STATE_MAP, VMModel - - -class VMHostDevsModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.caps = CapabilitiesModel(**kargs) - - def get_list(self, vmid): - dom = VMModel.get_vm(vmid, self.conn) - xmlstr = dom.XMLDesc(0) - root = objectify.fromstring(xmlstr) - try: - hostdev = root.devices.hostdev - except AttributeError: - return [] - - return [self._deduce_dev_name(e) for e in hostdev] - - @staticmethod - def _toint(num_str): - if num_str.startswith('0x'): - return int(num_str, 16) - elif num_str.startswith('0'): - return int(num_str, 8) - else: - return int(num_str) - - def _deduce_dev_name(self, e): - return getattr(self, '_deduce_dev_name_%s' % e.attrib['type'])(e) - - def _deduce_dev_name_pci(self, e): - attrib = {} - for field in ('domain', 'bus', 'slot', 'function'): - attrib[field] = self._toint(e.source.address.attrib[field]) - return 'pci_%(domain)04x_%(bus)02x_%(slot)02x_%(function)x' % attrib - - def _deduce_dev_name_scsi(self, e): - attrib = {} - for field in ('bus', 'target', 'unit'): - attrib[field] = self._toint(e.source.address.attrib[field]) - attrib['host'] = self._toint( - e.source.adapter.attrib['name'][len('scsi_host'):]) - return 'scsi_%(host)d_%(bus)d_%(target)d_%(unit)d' % attrib - - def _deduce_dev_name_usb(self, e): - dev_names = DevicesModel(conn=self.conn).get_list(_cap='usb_device') - usb_infos = [DeviceModel(conn=self.conn).lookup(dev_name) - for dev_name in dev_names] - - unknown_dev = None - - try: - evendor = self._toint(e.source.vendor.attrib['id']) - eproduct = self._toint(e.source.product.attrib['id']) - except AttributeError: - evendor = 0 - eproduct = 0 - else: - unknown_dev = 'usb_vendor_%s_product_%s' % (evendor, eproduct) - - try: - ebus = self._toint(e.source.address.attrib['bus']) - edevice = self._toint(e.source.address.attrib['device']) - except AttributeError: - ebus = -1 - edevice = -1 - else: - unknown_dev = 'usb_bus_%s_device_%s' % (ebus, edevice) - - for usb_info in usb_infos: - ivendor = self._toint(usb_info['vendor']['id']) - iproduct = self._toint(usb_info['product']['id']) - if evendor == ivendor and eproduct == iproduct: - return usb_info['name'] - ibus = usb_info['bus'] - idevice = usb_info['device'] - if ebus == ibus and edevice == idevice: - return usb_info['name'] - return unknown_dev - - def _passthrough_device_validate(self, dev_name): - eligible_dev_names = \ - DevicesModel(conn=self.conn).get_list(_passthrough='true') - if dev_name not in eligible_dev_names: - raise InvalidParameter('KCHVMHDEV0002E', {'dev_name': dev_name}) - - def create(self, vmid, params): - dev_name = params['name'] - self._passthrough_device_validate(dev_name) - dev_info = DeviceModel(conn=self.conn).lookup(dev_name) - - with RollbackContext() as rollback: - try: - dev = self.conn.get().nodeDeviceLookupByName(dev_name) - dev.dettach() - except Exception: - raise OperationFailed('KCHVMHDEV0005E', {'name': dev_name}) - else: - rollback.prependDefer(dev.reAttach) - - attach_device = getattr( - self, '_attach_%s_device' % dev_info['device_type']) - - info = attach_device(vmid, dev_info) - rollback.commitAll() - - return info - - def _get_pci_device_xml(self, dev_info): - if 'detach_driver' not in dev_info: - dev_info['detach_driver'] = 'kvm' - - source = E.source(E.address(domain=str(dev_info['domain']), - bus=str(dev_info['bus']), - slot=str(dev_info['slot']), - function=str(dev_info['function']))) - driver = E.driver(name=dev_info['detach_driver']) - host_dev = E.hostdev(source, driver, - mode='subsystem', type='pci', managed='yes') - - return etree.tostring(host_dev) - - @staticmethod - def _validate_pci_passthrough_env(): - # Linux kernel < 3.5 doesn't provide /sys/kernel/iommu_groups - if os.path.isdir('/sys/kernel/iommu_groups'): - if not glob.glob('/sys/kernel/iommu_groups/*'): - raise InvalidOperation("KCHVMHDEV0003E") - - # Enable virt_use_sysfs on RHEL6 and older distributions - # In recent Fedora, there is no virt_use_sysfs. - out, err, rc = run_command(['getsebool', 'virt_use_sysfs']) - if rc == 0 and out.rstrip('\n') != "virt_use_sysfs --> on": - out, err, rc = run_command(['setsebool', '-P', - 'virt_use_sysfs=on']) - if rc != 0: - wok_log.warning("Unable to turn on sebool virt_use_sysfs") - - def _attach_pci_device(self, vmid, dev_info): - self._validate_pci_passthrough_env() - - dom = VMModel.get_vm(vmid, self.conn) - # Due to libvirt limitation, we don't support live assigne device to - # vfio driver. - driver = ('vfio' if DOM_STATE_MAP[dom.info()[0]] == "shutoff" and - self.caps.kernel_vfio else 'kvm') - - # on powerkvm systems it must be vfio driver. - distro, _, _ = platform.linux_distribution() - if distro == 'IBM_PowerKVM': - driver = 'vfio' - - # Attach all PCI devices in the same IOMMU group - dev_model = DeviceModel(conn=self.conn) - devs_model = DevicesModel(conn=self.conn) - affected_names = devs_model.get_list( - _passthrough_affected_by=dev_info['name']) - passthrough_names = devs_model.get_list( - _cap='pci', _passthrough='true') - group_names = list(set(affected_names) & set(passthrough_names)) - pci_infos = [dev_model.lookup(dev_name) for dev_name in group_names] - pci_infos.append(dev_info) - - device_flags = get_vm_config_flag(dom, mode='all') - - with RollbackContext() as rollback: - for pci_info in pci_infos: - pci_info['detach_driver'] = driver - xmlstr = self._get_pci_device_xml(pci_info) - try: - dom.attachDeviceFlags(xmlstr, device_flags) - except libvirt.libvirtError: - wok_log.error( - 'Failed to attach host device %s to VM %s: \n%s', - pci_info['name'], vmid, xmlstr) - raise - rollback.prependDefer(dom.detachDeviceFlags, - xmlstr, device_flags) - rollback.commitAll() - - return dev_info['name'] - - def _get_scsi_device_xml(self, dev_info): - adapter = E.adapter(name=('scsi_host%s' % dev_info['host'])) - address = E.address(type='scsi', bus=str(dev_info['bus']), - target=str(dev_info['target']), - unit=str(dev_info['lun'])) - host_dev = E.hostdev(E.source(adapter, address), - mode='subsystem', type='scsi', sgio='unfiltered') - return etree.tostring(host_dev) - - def _attach_scsi_device(self, vmid, dev_info): - xmlstr = self._get_scsi_device_xml(dev_info) - dom = VMModel.get_vm(vmid, self.conn) - dom.attachDeviceFlags(xmlstr, get_vm_config_flag(dom, mode='all')) - return dev_info['name'] - - def _get_usb_device_xml(self, dev_info): - source = E.source( - E.vendor(id=dev_info['vendor']['id']), - E.product(id=dev_info['product']['id']), - E.address(bus=str(dev_info['bus']), - device=str(dev_info['device'])), - startupPolicy='optional') - host_dev = E.hostdev(source, mode='subsystem', - ype='usb', managed='yes') - return etree.tostring(host_dev) - - def _attach_usb_device(self, vmid, dev_info): - xmlstr = self._get_usb_device_xml(dev_info) - dom = VMModel.get_vm(vmid, self.conn) - dom.attachDeviceFlags(xmlstr, get_vm_config_flag(dom, mode='all')) - return dev_info['name'] - - -class VMHostDevModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - - def lookup(self, vmid, dev_name): - dom = VMModel.get_vm(vmid, self.conn) - xmlstr = dom.XMLDesc(0) - root = objectify.fromstring(xmlstr) - try: - hostdev = root.devices.hostdev - except AttributeError: - raise NotFoundError('KCHVMHDEV0001E', - {'vmid': vmid, 'dev_name': dev_name}) - - devsmodel = VMHostDevsModel(conn=self.conn) - - for e in hostdev: - deduced_name = devsmodel._deduce_dev_name(e) - if deduced_name == dev_name: - return {'name': dev_name, 'type': e.attrib['type']} - - raise NotFoundError('KCHVMHDEV0001E', - {'vmid': vmid, 'dev_name': dev_name}) - - def delete(self, vmid, dev_name): - dom = VMModel.get_vm(vmid, self.conn) - xmlstr = dom.XMLDesc(0) - root = objectify.fromstring(xmlstr) - - try: - hostdev = root.devices.hostdev - except AttributeError: - raise NotFoundError('KCHVMHDEV0001E', - {'vmid': vmid, 'dev_name': dev_name}) - - devsmodel = VMHostDevsModel(conn=self.conn) - pci_devs = [(devsmodel._deduce_dev_name(e), e) for e in hostdev - if e.attrib['type'] == 'pci'] - - for e in hostdev: - if devsmodel._deduce_dev_name(e) == dev_name: - xmlstr = etree.tostring(e) - dom.detachDeviceFlags( - xmlstr, get_vm_config_flag(dom, mode='all')) - if e.attrib['type'] == 'pci': - self._delete_affected_pci_devices(dom, dev_name, pci_devs) - break - else: - raise NotFoundError('KCHVMHDEV0001E', - {'vmid': vmid, 'dev_name': dev_name}) - - def _delete_affected_pci_devices(self, dom, dev_name, pci_devs): - dev_model = DeviceModel(conn=self.conn) - try: - dev_model.lookup(dev_name) - except NotFoundError: - return - - affected_names = set( - DevicesModel( - conn=self.conn).get_list(_passthrough_affected_by=dev_name)) - - for pci_name, e in pci_devs: - if pci_name in affected_names: - xmlstr = etree.tostring(e) - dom.detachDeviceFlags( - xmlstr, get_vm_config_flag(dom, mode='all')) - - -class VMHoldersModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - - def get_list(self, device_id): - devsmodel = VMHostDevsModel(conn=self.conn) - - conn = self.conn.get() - doms = conn.listAllDomains(0) - - res = [] - for dom in doms: - dom_name = dom.name() - if device_id in devsmodel.get_list(dom_name): - state = DOM_STATE_MAP[dom.info()[0]] - res.append({"name": dom_name, "state": state}) - return res diff --git a/plugins/kimchi/model/vmifaces.py b/plugins/kimchi/model/vmifaces.py deleted file mode 100644 index 87565c8..0000000 --- a/plugins/kimchi/model/vmifaces.py +++ /dev/null @@ -1,186 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import libvirt -import random -from lxml import etree, objectify - -from wok.exception import InvalidParameter, MissingParameter -from wok.exception import NotFoundError, InvalidOperation - -from ..xmlutils.interface import get_iface_xml -from config import CapabilitiesModel -from vms import DOM_STATE_MAP, VMModel - - -class VMIfacesModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.caps = CapabilitiesModel(**kargs) - - def get_list(self, vm): - macs = [] - for iface in self.get_vmifaces(vm, self.conn): - macs.append(iface.mac.get('address')) - return macs - - def create(self, vm, params): - conn = self.conn.get() - networks = conn.listNetworks() + conn.listDefinedNetworks() - networks = map(lambda x: x.decode('utf-8'), networks) - - if params['type'] == 'network': - network = params.get("network") - - if network is None: - raise MissingParameter('KCHVMIF0007E') - - if network not in networks: - raise InvalidParameter('KCHVMIF0002E', - {'name': vm, 'network': network}) - - macs = (iface.mac.get('address') - for iface in self.get_vmifaces(vm, self.conn)) - - # user defined customized mac address - if 'mac' in params and params['mac']: - # make sure it is unique - if params['mac'] in macs: - raise InvalidParameter('KCHVMIF0009E', - {'name': vm, 'mac': params['mac']}) - - # otherwise choose a random mac address - else: - while True: - params['mac'] = VMIfacesModel.random_mac() - if params['mac'] not in macs: - break - - dom = VMModel.get_vm(vm, self.conn) - - os_data = VMModel.vm_get_os_metadata(dom, self.caps.metadata_support) - os_version, os_distro = os_data - xml = get_iface_xml(params, conn.getInfo()[0], os_distro, os_version) - - flags = 0 - if dom.isPersistent(): - flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG - if DOM_STATE_MAP[dom.info()[0]] != "shutoff": - flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE - - dom.attachDeviceFlags(xml, flags) - - return params['mac'] - - @staticmethod - def get_vmifaces(vm, conn): - dom = VMModel.get_vm(vm, conn) - xml = dom.XMLDesc(0) - root = objectify.fromstring(xml) - - return root.devices.findall("interface") - - @staticmethod - def random_mac(): - mac = [0x52, 0x54, 0x00, - random.randint(0x00, 0x7f), - random.randint(0x00, 0xff), - random.randint(0x00, 0xff)] - return ':'.join(map(lambda x: u'%02x' % x, mac)) - - -class VMIfaceModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - - def _get_vmiface(self, vm, mac): - ifaces = VMIfacesModel.get_vmifaces(vm, self.conn) - - for iface in ifaces: - if iface.mac.get('address') == mac: - return iface - return None - - def lookup(self, vm, mac): - info = {} - - iface = self._get_vmiface(vm, mac) - if iface is None: - raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac}) - - info['type'] = iface.attrib['type'] - info['mac'] = iface.mac.get('address') - if iface.find("model") is not None: - info['model'] = iface.model.get('type') - if info['type'] == 'network': - info['network'] = iface.source.get('network') - if info['type'] == 'bridge': - info['bridge'] = iface.source.get('bridge') - - return info - - def delete(self, vm, mac): - dom = VMModel.get_vm(vm, self.conn) - iface = self._get_vmiface(vm, mac) - - if iface is None: - raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac}) - - flags = 0 - if dom.isPersistent(): - flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG - if DOM_STATE_MAP[dom.info()[0]] != "shutoff": - flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE - - dom.detachDeviceFlags(etree.tostring(iface), flags) - - def update(self, vm, mac, params): - dom = VMModel.get_vm(vm, self.conn) - iface = self._get_vmiface(vm, mac) - - if iface is None: - raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac}) - - # cannot change mac address in a running system - if DOM_STATE_MAP[dom.info()[0]] != "shutoff": - raise InvalidOperation('KCHVMIF0011E') - - # mac address is a required parameter - if 'mac' not in params: - raise MissingParameter('KCHVMIF0008E') - - # new mac address must be unique - if self._get_vmiface(vm, params['mac']) is not None: - raise InvalidParameter('KCHVMIF0009E', - {'name': vm, 'mac': params['mac']}) - - flags = 0 - if dom.isPersistent(): - flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG - - # remove the current nic - xml = etree.tostring(iface) - dom.detachDeviceFlags(xml, flags=flags) - - # add the nic with the desired mac address - iface.mac.attrib['address'] = params['mac'] - xml = etree.tostring(iface) - dom.attachDeviceFlags(xml, flags=flags) - - return [vm, params['mac']] diff --git a/plugins/kimchi/model/vms.py b/plugins/kimchi/model/vms.py deleted file mode 100644 index f37b5d6..0000000 --- a/plugins/kimchi/model/vms.py +++ /dev/null @@ -1,1307 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import libvirt -import lxml.etree as ET -import os -import random -import string -import time -import uuid -from lxml import etree, objectify -from lxml.builder import E -from xml.etree import ElementTree - -from wok.config import config -from wok.exception import InvalidOperation, InvalidParameter -from wok.exception import NotFoundError, OperationFailed -from wok.rollbackcontext import RollbackContext -from wok.utils import add_task, convert_data_size, get_next_clone_name -from wok.utils import import_class, run_setfacl_set_attr, wok_log -from wok.xmlutils.utils import xpath_get_text, xml_item_update -from wok.xmlutils.utils import dictize -from wok.model.tasks import TaskModel - -from .. import model -from .. import vnc -from ..config import READONLY_POOL_TYPE -from ..kvmusertests import UserTests -from ..screenshot import VMScreenshot -from ..utils import template_name_from_uri -from ..xmlutils.cpu import get_cpu_xml, get_numa_xml -from config import CapabilitiesModel -from templates import TemplateModel -from utils import get_vm_name -from utils import get_metadata_node -from utils import set_metadata_node - - -DOM_STATE_MAP = {0: 'nostate', - 1: 'running', - 2: 'blocked', - 3: 'paused', - 4: 'shutdown', - 5: 'shutoff', - 6: 'crashed', - 7: 'pmsuspended'} - -VM_STATIC_UPDATE_PARAMS = {'name': './name', - 'cpus': './vcpu'} -VM_LIVE_UPDATE_PARAMS = {} - -XPATH_DOMAIN_DISK = "/domain/devices/disk[@device='disk']/source/@file" -XPATH_DOMAIN_DISK_BY_FILE = "./devices/disk[@device='disk']/source[@file='%s']" -XPATH_DOMAIN_NAME = '/domain/name' -XPATH_DOMAIN_MAC = "/domain/devices/interface[@type='network']/mac/@address" -XPATH_DOMAIN_MAC_BY_ADDRESS = "./devices/interface[@type='network']/"\ - "mac[@address='%s']" -XPATH_DOMAIN_MEMORY = '/domain/memory' -XPATH_DOMAIN_MEMORY_UNIT = '/domain/memory/@unit' -XPATH_DOMAIN_UUID = '/domain/uuid' - -XPATH_NUMA_CELL = './cpu/numa/cell' - - -class VMsModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - self.caps = CapabilitiesModel(**kargs) - self.task = TaskModel(**kargs) - - def create(self, params): - t_name = template_name_from_uri(params['template']) - vm_list = self.get_list() - name = get_vm_name(params.get('name'), t_name, vm_list) - # incoming text, from js json, is unicode, do not need decode - if name in vm_list: - raise InvalidOperation("KCHVM0001E", {'name': name}) - - vm_overrides = dict() - pool_uri = params.get('storagepool') - if pool_uri: - vm_overrides['storagepool'] = pool_uri - vm_overrides['fc_host_support'] = self.caps.fc_host_support - t = TemplateModel.get_template(t_name, self.objstore, self.conn, - vm_overrides) - - if not self.caps.qemu_stream and t.info.get('iso_stream', False): - raise InvalidOperation("KCHVM0005E") - - t.validate() - data = {'name': name, 'template': t, - 'graphics': params.get('graphics', {})} - taskid = add_task(u'/plugins/kimchi/vms/%s' % name, self._create_task, - self.objstore, data) - - return self.task.lookup(taskid) - - def _create_task(self, cb, params): - """ - params: A dict with the following values: - - vm_uuid: The UUID of the VM being created - - template: The template being used to create the VM - - name: The name for the new VM - """ - vm_uuid = str(uuid.uuid4()) - t = params['template'] - name = params['name'] - conn = self.conn.get() - - cb('Storing VM icon') - # Store the icon for displaying later - icon = t.info.get('icon') - if icon: - try: - with self.objstore as session: - session.store('vm', vm_uuid, {'icon': icon}) - except Exception as e: - # It is possible to continue Kimchi executions without store - # vm icon info - wok_log.error('Error trying to update database with guest ' - 'icon information due error: %s', e.message) - - # If storagepool is SCSI, volumes will be LUNs and must be passed by - # the user from UI or manually. - cb('Provisioning storage for new VM') - vol_list = [] - if t._get_storage_type() not in ["iscsi", "scsi"]: - vol_list = t.fork_vm_storage(vm_uuid) - - graphics = params.get('graphics', {}) - stream_protocols = self.caps.libvirt_stream_protocols - xml = t.to_vm_xml(name, vm_uuid, - libvirt_stream_protocols=stream_protocols, - graphics=graphics, - volumes=vol_list) - - cb('Defining new VM') - try: - conn.defineXML(xml.encode('utf-8')) - except libvirt.libvirtError as e: - if t._get_storage_type() not in READONLY_POOL_TYPE: - for v in vol_list: - vol = conn.storageVolLookupByPath(v['path']) - vol.delete(0) - raise OperationFailed("KCHVM0007E", {'name': name, - 'err': e.get_error_message()}) - - cb('Updating VM metadata') - VMModel.vm_update_os_metadata(VMModel.get_vm(name, self.conn), t.info, - self.caps.metadata_support) - cb('OK', True) - - def get_list(self): - return VMsModel.get_vms(self.conn) - - @staticmethod - def get_vms(conn): - conn_ = conn.get() - names = [dom.name().decode('utf-8') for dom in conn_.listAllDomains(0)] - names = sorted(names, key=unicode.lower) - return names - - -class VMModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - self.caps = CapabilitiesModel(**kargs) - self.vmscreenshot = VMScreenshotModel(**kargs) - self.users = import_class( - 'plugins.kimchi.model.users.UsersModel' - )(**kargs) - self.groups = import_class( - 'plugins.kimchi.model.groups.GroupsModel' - )(**kargs) - self.vms = VMsModel(**kargs) - self.task = TaskModel(**kargs) - self.storagepool = model.storagepools.StoragePoolModel(**kargs) - self.storagevolume = model.storagevolumes.StorageVolumeModel(**kargs) - self.storagevolumes = model.storagevolumes.StorageVolumesModel(**kargs) - cls = import_class('plugins.kimchi.model.vmsnapshots.VMSnapshotModel') - self.vmsnapshot = cls(**kargs) - cls = import_class('plugins.kimchi.model.vmsnapshots.VMSnapshotsModel') - self.vmsnapshots = cls(**kargs) - self.stats = {} - - def update(self, name, params): - dom = self.get_vm(name, self.conn) - dom = self._static_vm_update(dom, params) - self._live_vm_update(dom, params) - return dom.name().decode('utf-8') - - def clone(self, name): - """Clone a virtual machine based on an existing one. - - The new virtual machine will have the exact same configuration as the - original VM, except for the name, UUID, MAC addresses and disks. The - name will have the form "<name>-clone-<number>", with <number> starting - at 1; the UUID will be generated randomly; the MAC addresses will be - generated randomly with no conflicts within the original and the new - VM; and the disks will be new volumes [mostly] on the same storage - pool, with the same content as the original disks. The storage pool - 'default' will always be used when cloning SCSI and iSCSI disks and - when the original storage pool cannot hold the new volume. - - An exception will be raised if the virtual machine <name> is not - shutoff, if there is no available space to copy a new volume to the - storage pool 'default' (when there was also no space to copy it to the - original storage pool) and if one of the virtual machine's disks belong - to a storage pool not supported by Kimchi. - - Parameters: - name -- The name of the existing virtual machine to be cloned. - - Return: - A Task running the clone operation. - """ - name = name.decode('utf-8') - - # VM must be shutoff in order to clone it - info = self.lookup(name) - if info['state'] != u'shutoff': - raise InvalidParameter('KCHVM0033E', {'name': name}) - - # the new VM's name will be used as the Task's 'target_uri' so it needs - # to be defined now. - - vms_being_created = [] - - # lookup names of VMs being created right now - with self.objstore as session: - task_names = session.get_list('task') - for tn in task_names: - t = session.get('task', tn) - if t['target_uri'].startswith('/plugins/kimchi/vms/'): - uri_name = t['target_uri'].lstrip('/plugins/kimchi/vms/') - vms_being_created.append(uri_name) - - current_vm_names = self.vms.get_list() + vms_being_created - new_name = get_next_clone_name(current_vm_names, name) - - # create a task with the actual clone function - taskid = add_task(u'/plugins/kimchi/vms/%s/clone' % new_name, - self._clone_task, self.objstore, - {'name': name, 'new_name': new_name}) - - return self.task.lookup(taskid) - - def _clone_task(self, cb, params): - """Asynchronous function which performs the clone operation. - - Parameters: - cb -- A callback function to signal the Task's progress. - params -- A dict with the following values: - "name": the name of the original VM. - "new_name": the name of the new VM. - """ - name = params['name'] - new_name = params['new_name'] - vir_conn = self.conn.get() - - # fetch base XML - cb('reading source VM XML') - try: - vir_dom = vir_conn.lookupByName(name) - flags = libvirt.VIR_DOMAIN_XML_SECURE - xml = vir_dom.XMLDesc(flags).decode('utf-8') - except libvirt.libvirtError, e: - raise OperationFailed('KCHVM0035E', {'name': name, - 'err': e.message}) - - # update UUID - cb('updating VM UUID') - old_uuid = xpath_get_text(xml, XPATH_DOMAIN_UUID)[0] - new_uuid = unicode(uuid.uuid4()) - xml = xml_item_update(xml, './uuid', new_uuid) - - # update MAC addresses - cb('updating VM MAC addresses') - xml = self._clone_update_mac_addresses(xml) - - with RollbackContext() as rollback: - # copy disks - cb('copying VM disks') - xml = self._clone_update_disks(xml, rollback) - - # update objstore entry - cb('updating object store') - self._clone_update_objstore(old_uuid, new_uuid, rollback) - - # update name - cb('updating VM name') - xml = xml_item_update(xml, './name', new_name) - - # create new guest - cb('defining new VM') - try: - vir_conn.defineXML(xml) - except libvirt.libvirtError, e: - raise OperationFailed('KCHVM0035E', {'name': name, - 'err': e.message}) - - rollback.commitAll() - - cb('OK', True) - - @staticmethod - def _clone_update_mac_addresses(xml): - """Update the MAC addresses with new values in the XML descriptor of a - cloning domain. - - The new MAC addresses will be generated randomly, and their values are - guaranteed to be distinct from the ones in the original VM. - - Arguments: - xml -- The XML descriptor of the original domain. - - Return: - The XML descriptor <xml> with the new MAC addresses instead of the - old ones. - """ - old_macs = xpath_get_text(xml, XPATH_DOMAIN_MAC) - new_macs = [] - - for mac in old_macs: - while True: - new_mac = model.vmifaces.VMIfacesModel.random_mac() - # make sure the new MAC doesn't conflict with the original VM - # and with the new values on the new VM. - if new_mac not in (old_macs + new_macs): - new_macs.append(new_mac) - break - - xml = xml_item_update(xml, XPATH_DOMAIN_MAC_BY_ADDRESS % mac, - new_mac, 'address') - - return xml - - def _clone_update_disks(self, xml, rollback): - """Clone disks from a virtual machine. The disks are copied as new - volumes and the new VM's XML is updated accordingly. - - Arguments: - xml -- The XML descriptor of the original VM + new value for - "/domain/uuid". - rollback -- A rollback context so the new volumes can be removed if an - error occurs during the cloning operation. - - Return: - The XML descriptor <xml> with the new disk paths instead of the - old ones. - """ - # the UUID will be used to create the disk paths - uuid = xpath_get_text(xml, XPATH_DOMAIN_UUID)[0] - all_paths = xpath_get_text(xml, XPATH_DOMAIN_DISK) - - vir_conn = self.conn.get() - - def _delete_disk_from_objstore(path): - with self.objstore as session: - session.delete('storagevolume', path) - - domain_name = xpath_get_text(xml, XPATH_DOMAIN_NAME)[0] - - for i, path in enumerate(all_paths): - try: - vir_orig_vol = vir_conn.storageVolLookupByPath(path) - vir_pool = vir_orig_vol.storagePoolLookupByVolume() - - orig_pool_name = vir_pool.name().decode('utf-8') - orig_vol_name = vir_orig_vol.name().decode('utf-8') - except libvirt.libvirtError, e: - raise OperationFailed('KCHVM0035E', {'name': domain_name, - 'err': e.message}) - - orig_pool = self.storagepool.lookup(orig_pool_name) - orig_vol = self.storagevolume.lookup(orig_pool_name, orig_vol_name) - - new_pool_name = orig_pool_name - new_pool = orig_pool - - if orig_pool['type'] in ['dir', 'netfs', 'logical']: - # if a volume in a pool 'dir', 'netfs' or 'logical' cannot hold - # a new volume with the same size, the pool 'default' should - # be used - if orig_vol['capacity'] > orig_pool['available']: - wok_log.warning('storage pool \'%s\' doesn\'t have ' - 'enough free space to store image ' - '\'%s\'; falling back to \'default\'', - orig_pool_name, path) - new_pool_name = u'default' - new_pool = self.storagepool.lookup(u'default') - - # ...and if even the pool 'default' cannot hold a new - # volume, raise an exception - if orig_vol['capacity'] > new_pool['available']: - domain_name = xpath_get_text(xml, XPATH_DOMAIN_NAME)[0] - raise InvalidOperation('KCHVM0034E', - {'name': domain_name}) - - elif orig_pool['type'] in ['scsi', 'iscsi']: - # SCSI and iSCSI always fall back to the storage pool 'default' - wok_log.warning('cannot create new volume for clone in ' - 'storage pool \'%s\'; falling back to ' - '\'default\'', orig_pool_name) - new_pool_name = u'default' - new_pool = self.storagepool.lookup(u'default') - - # if the pool 'default' cannot hold a new volume, raise - # an exception - if orig_vol['capacity'] > new_pool['available']: - domain_name = xpath_get_text(xml, XPATH_DOMAIN_NAME)[0] - raise InvalidOperation('KCHVM0034E', {'name': domain_name}) - - else: - # unexpected storage pool type - raise InvalidOperation('KCHPOOL0014E', - {'type': orig_pool['type']}) - - # new volume name: <UUID>-<loop-index>.<original extension> - # e.g. 1234-5678-9012-3456-0.img - ext = os.path.splitext(path)[1] - new_vol_name = u'%s-%d%s' % (uuid, i, ext) - task = self.storagevolume.clone(orig_pool_name, orig_vol_name, - new_name=new_vol_name) - self.task.wait(task['id'], 3600) # 1 h - - # get the new volume path and update the XML descriptor - new_vol = self.storagevolume.lookup(new_pool_name, new_vol_name) - xml = xml_item_update(xml, XPATH_DOMAIN_DISK_BY_FILE % path, - new_vol['path'], 'file') - - # set the new disk's used_by - with self.objstore as session: - session.store('storagevolume', new_vol['path'], - {'used_by': [domain_name]}) - rollback.prependDefer(_delete_disk_from_objstore, new_vol['path']) - - # remove the new volume should an error occur later - rollback.prependDefer(self.storagevolume.delete, new_pool_name, - new_vol_name) - - return xml - - def _clone_update_objstore(self, old_uuid, new_uuid, rollback): - """Update Kimchi's object store with the cloning VM. - - Arguments: - old_uuid -- The UUID of the original VM. - new_uuid -- The UUID of the new, clonning VM. - rollback -- A rollback context so the object store entry can be removed - if an error occurs during the cloning operation. - """ - with self.objstore as session: - try: - vm = session.get('vm', old_uuid) - icon = vm['icon'] - session.store('vm', new_uuid, {'icon': icon}) - except NotFoundError: - # if we cannot find an object store entry for the original VM, - # don't store one with an empty value. - pass - else: - # we need to define a custom function to prepend to the - # rollback context because the object store session needs to be - # opened and closed correctly (i.e. "prependDefer" only - # accepts one command at a time but we need more than one to - # handle an object store). - def _rollback_objstore(): - with self.objstore as session_rb: - session_rb.delete('vm', new_uuid, ignore_missing=True) - - # remove the new object store entry should an error occur later - rollback.prependDefer(_rollback_objstore) - - def _build_access_elem(self, dom, users, groups): - auth = config.get("authentication", "method") - access_xml = get_metadata_node(dom, "access", - self.caps.metadata_support) - - auth_elem = None - - if not access_xml: - # there is no metadata element 'access' - access_elem = E.access() - else: - access_elem = ET.fromstring(access_xml) - - same_auth = access_elem.xpath('./auth[@type="%s"]' % auth) - if len(same_auth) > 0: - # there is already a sub-element 'auth' with the same type; - # update it. - auth_elem = same_auth[0] - - if users is not None: - for u in auth_elem.findall('user'): - auth_elem.remove(u) - - if groups is not None: - for g in auth_elem.findall('group'): - auth_elem.remove(g) - - if auth_elem is None: - # there is no sub-element 'auth' with the same type - # (or no 'auth' at all); create it. - auth_elem = E.auth(type=auth) - access_elem.append(auth_elem) - - if users is not None: - for u in users: - auth_elem.append(E.user(u)) - - if groups is not None: - for g in groups: - auth_elem.append(E.group(g)) - - return access_elem - - def _vm_update_access_metadata(self, dom, params): - users = groups = None - if "users" in params: - users = params["users"] - for user in users: - if not self.users.validate(user): - raise InvalidParameter("KCHVM0027E", - {'users': user}) - if "groups" in params: - groups = params["groups"] - for group in groups: - if not self.groups.validate(group): - raise InvalidParameter("KCHVM0028E", - {'groups': group}) - - if users is None and groups is None: - return - - node = self._build_access_elem(dom, users, groups) - set_metadata_node(dom, node, self.caps.metadata_support) - - def _get_access_info(self, dom): - users = groups = list() - access_xml = (get_metadata_node(dom, "access", - self.caps.metadata_support) or - """<access></access>""") - access_info = dictize(access_xml) - auth = config.get("authentication", "method") - if ('auth' in access_info['access'] and - ('type' in access_info['access']['auth'] or - len(access_info['access']['auth']) > 1)): - users = xpath_get_text(access_xml, - "/access/auth[@type='%s']/user" % auth) - groups = xpath_get_text(access_xml, - "/access/auth[@type='%s']/group" % auth) - elif auth == 'pam': - # Compatible to old permission tagging - users = xpath_get_text(access_xml, "/access/user") - groups = xpath_get_text(access_xml, "/access/group") - return users, groups - - @staticmethod - def vm_get_os_metadata(dom, metadata_support): - os_xml = (get_metadata_node(dom, "os", metadata_support) or - """<os></os>""") - os_elem = ET.fromstring(os_xml) - return (os_elem.attrib.get("version"), os_elem.attrib.get("distro")) - - @staticmethod - def vm_update_os_metadata(dom, params, metadata_support): - distro = params.get("os_distro") - version = params.get("os_version") - if distro is None: - return - os_elem = E.os({"distro": distro, "version": version}) - set_metadata_node(dom, os_elem, metadata_support) - - def _update_graphics(self, dom, xml, params): - root = objectify.fromstring(xml) - graphics = root.devices.find("graphics") - if graphics is None: - return xml - - password = params['graphics'].get("passwd") - if password is not None and len(password.strip()) == 0: - password = "".join(random.sample(string.ascii_letters + - string.digits, 8)) - - if password is not None: - graphics.attrib['passwd'] = password - - expire = params['graphics'].get("passwdValidTo") - to = graphics.attrib.get('passwdValidTo') - if to is not None: - if (time.mktime(time.strptime(to, '%Y-%m-%dT%H:%M:%S')) - - time.time() <= 0): - expire = expire if expire is not None else 30 - - if expire is not None: - expire_time = time.gmtime(time.time() + float(expire)) - valid_to = time.strftime('%Y-%m-%dT%H:%M:%S', expire_time) - graphics.attrib['passwdValidTo'] = valid_to - - if not dom.isActive(): - return ET.tostring(root, encoding="utf-8") - - xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) - dom.updateDeviceFlags(etree.tostring(graphics), - libvirt.VIR_DOMAIN_AFFECT_LIVE) - return xml - - def _backup_snapshots(self, snap, all_info): - """ Append "snap" and the children of "snap" to the list "all_info". - - The list *must* always contain the parent snapshots before their - children so the function "_redefine_snapshots" can work correctly. - - Arguments: - snap -- a native domain snapshot. - all_info -- a list of dict keys: - "{'xml': <snap XML>, 'current': <is snap current?>'}" - """ - all_info.append({'xml': snap.getXMLDesc(0), - 'current': snap.isCurrent(0)}) - - for child in snap.listAllChildren(0): - self._backup_snapshots(child, all_info) - - def _redefine_snapshots(self, dom, all_info): - """ Restore the snapshots stored in "all_info" to the domain "dom". - - Arguments: - dom -- the domain which will have its snapshots restored. - all_info -- a list of dict keys, as described in "_backup_snapshots", - containing the original snapshot information. - """ - for info in all_info: - flags = libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE - - if info['current']: - flags |= libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT - - dom.snapshotCreateXML(info['xml'], flags) - - def _static_vm_update(self, dom, params): - old_xml = new_xml = dom.XMLDesc(0) - - for key, val in params.items(): - if key in VM_STATIC_UPDATE_PARAMS: - if type(val) == int: - val = str(val) - xpath = VM_STATIC_UPDATE_PARAMS[key] - new_xml = xml_item_update(new_xml, xpath, val) - - # Updating memory and NUMA if necessary, if vm is offline - if not dom.isActive(): - if 'memory' in params: - new_xml = self._update_memory_config(new_xml, params) - elif 'cpus' in params and \ - (xpath_get_text(new_xml, XPATH_NUMA_CELL + '/@memory') != []): - vcpus = params['cpus'] - new_xml = xml_item_update( - new_xml, - XPATH_NUMA_CELL, - value='0-' + str(vcpus - 1) if vcpus > 1 else '0', - attr='cpus') - - if 'graphics' in params: - new_xml = self._update_graphics(dom, new_xml, params) - - snapshots_info = [] - vm_name = dom.name() - conn = self.conn.get() - try: - if 'name' in params: - state = DOM_STATE_MAP[dom.info()[0]] - if state != 'shutoff': - msg_args = {'name': vm_name, 'new_name': params['name']} - raise InvalidParameter("KCHVM0003E", msg_args) - - lflags = libvirt.VIR_DOMAIN_SNAPSHOT_LIST_ROOTS - dflags = (libvirt.VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | - libvirt.VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) - - for virt_snap in dom.listAllSnapshots(lflags): - snapshots_info.append({'xml': virt_snap.getXMLDesc(0), - 'current': virt_snap.isCurrent(0)}) - self._backup_snapshots(virt_snap, snapshots_info) - - virt_snap.delete(dflags) - - # Undefine old vm, only if name is going to change - dom.undefine() - - dom = conn.defineXML(new_xml) - if 'name' in params: - self._redefine_snapshots(dom, snapshots_info) - except libvirt.libvirtError as e: - dom = conn.defineXML(old_xml) - if 'name' in params: - self._redefine_snapshots(dom, snapshots_info) - - raise OperationFailed("KCHVM0008E", {'name': vm_name, - 'err': e.get_error_message()}) - return dom - - def _update_memory_config(self, xml, params): - # Checks if NUMA memory is already configured, if not, checks if CPU - # element is already configured (topology). Then add NUMA element as - # apropriated - root = ET.fromstring(xml) - numa_mem = xpath_get_text(xml, XPATH_NUMA_CELL + '/@memory') - vcpus = params.get('cpus') - if numa_mem == []: - if vcpus is None: - vcpus = int(xpath_get_text(xml, - VM_STATIC_UPDATE_PARAMS['cpus'])[0]) - cpu = root.find('./cpu') - if cpu is None: - cpu = get_cpu_xml(vcpus, params['memory'] << 10) - root.insert(0, ET.fromstring(cpu)) - else: - numa_element = get_numa_xml(vcpus, params['memory'] << 10) - cpu.insert(0, ET.fromstring(numa_element)) - else: - if vcpus is not None: - xml = xml_item_update( - xml, - XPATH_NUMA_CELL, - value='0-' + str(vcpus - 1) if vcpus > 1 else '0', - attr='cpus') - root = ET.fromstring(xml_item_update(xml, XPATH_NUMA_CELL, - str(params['memory'] << 10), - attr='memory')) - - # Remove currentMemory, automatically set later by libvirt - currentMem = root.find('.currentMemory') - if currentMem is not None: - root.remove(currentMem) - - memory = root.find('.memory') - # Update/Adds maxMemory accordingly - if not self.caps.mem_hotplug_support: - if memory is not None: - memory.text = str(params['memory'] << 10) - else: - if memory is not None: - root.remove(memory) - maxMem = root.find('.maxMemory') - host_mem = self.conn.get().getInfo()[1] - slots = (host_mem - params['memory']) >> 10 - # Libvirt does not accepts slots <= 1 - if slots < 0: - raise OperationFailed("KCHVM0041E") - elif slots == 0: - slots = 1 - if maxMem is None: - max_mem_xml = E.maxMemory( - str(host_mem * 1024), - unit='Kib', - slots=str(slots)) - root.insert(0, max_mem_xml) - new_xml = ET.tostring(root, encoding="utf-8") - else: - # Update slots only - new_xml = xml_item_update(ET.tostring(root, encoding="utf-8"), - './maxMemory', - str(slots), - attr='slots') - return new_xml - return ET.tostring(root, encoding="utf-8") - - def _live_vm_update(self, dom, params): - self._vm_update_access_metadata(dom, params) - if 'memory' in params and dom.isActive(): - self._update_memory_live(dom, params) - - def _update_memory_live(self, dom, params): - # Check if host supports memory device - if not self.caps.mem_hotplug_support: - raise InvalidOperation("KCHVM0046E") - - # Check if the vm xml supports memory hotplug, if not, static update - # must be done firstly, then Kimchi is going to update the xml - xml = dom.XMLDesc(0) - numa_mem = xpath_get_text(xml, XPATH_NUMA_CELL + '/@memory') - max_mem = xpath_get_text(xml, './maxMemory') - if numa_mem == [] or max_mem == []: - raise OperationFailed('KCHVM0042E', {'name': dom.name()}) - - # Memory live update must be done in chunks of 1024 Mib or 1Gib - new_mem = params['memory'] - old_mem = int(xpath_get_text(xml, XPATH_DOMAIN_MEMORY)[0]) >> 10 - if new_mem < old_mem: - raise OperationFailed('KCHVM0043E') - if (new_mem - old_mem) % 1024 != 0: - raise OperationFailed('KCHVM0044E') - - # Check slot spaces: - total_slots = int(xpath_get_text(xml, './maxMemory/@slots')[0]) - needed_slots = (new_mem - old_mem) / 1024 - used_slots = len(xpath_get_text(xml, './devices/memory')) - if needed_slots > (total_slots - used_slots): - raise OperationFailed('KCHVM0045E') - elif needed_slots == 0: - # New memory value is same that current memory set - return - - # Finally, we are ok to hot add the memory devices - try: - self._hot_add_memory_devices(dom, needed_slots) - except Exception as e: - raise OperationFailed("KCHVM0047E", {'error': e.message}) - - def _hot_add_memory_devices(self, dom, amount): - # Hot add given number of memory devices in the guest - flags = libvirt.VIR_DOMAIN_MEM_CONFIG | libvirt.VIR_DOMAIN_MEM_LIVE - # Create memory device xml - mem_dev_xml = etree.tostring( - E.memory( - E.target( - E.size('1', unit='GiB'), - E.node('0')), - model='dimm')) - # Add chunks of 1G of memory - for i in range(amount): - dom.attachDeviceFlags(mem_dev_xml, flags) - - def _has_video(self, dom): - dom = ElementTree.fromstring(dom.XMLDesc(0)) - return dom.find('devices/video') is not None - - def _update_guest_stats(self, name): - try: - dom = VMModel.get_vm(name, self.conn) - - vm_uuid = dom.UUIDString() - info = dom.info() - state = DOM_STATE_MAP[info[0]] - - if state != 'running': - self.stats[vm_uuid] = {} - return - - if self.stats.get(vm_uuid, None) is None: - self.stats[vm_uuid] = {} - - timestamp = time.time() - prevStats = self.stats.get(vm_uuid, {}) - seconds = timestamp - prevStats.get('timestamp', 0) - self.stats[vm_uuid].update({'timestamp': timestamp}) - - self._get_percentage_cpu_usage(vm_uuid, info, seconds) - self._get_network_io_rate(vm_uuid, dom, seconds) - self._get_disk_io_rate(vm_uuid, dom, seconds) - except Exception as e: - # VM might be deleted just after we get the list. - # This is OK, just skip. - wok_log.debug('Error processing VM stats: %s', e.message) - - def _get_percentage_cpu_usage(self, vm_uuid, info, seconds): - prevCpuTime = self.stats[vm_uuid].get('cputime', 0) - - cpus = info[3] - cpuTime = info[4] - prevCpuTime - - base = (((cpuTime) * 100.0) / (seconds * 1000.0 * 1000.0 * 1000.0)) - percentage = max(0.0, min(100.0, base / cpus)) - - self.stats[vm_uuid].update({'cputime': info[4], 'cpu': percentage}) - - def _get_network_io_rate(self, vm_uuid, dom, seconds): - prevNetRxKB = self.stats[vm_uuid].get('netRxKB', 0) - prevNetTxKB = self.stats[vm_uuid].get('netTxKB', 0) - currentMaxNetRate = self.stats[vm_uuid].get('max_net_io', 100) - - rx_bytes = 0 - tx_bytes = 0 - - tree = ElementTree.fromstring(dom.XMLDesc(0)) - for target in tree.findall('devices/interface/target'): - dev = target.get('dev') - io = dom.interfaceStats(dev) - rx_bytes += io[0] - tx_bytes += io[4] - - netRxKB = float(rx_bytes) / 1000 - netTxKB = float(tx_bytes) / 1000 - - rx_stats = (netRxKB - prevNetRxKB) / seconds - tx_stats = (netTxKB - prevNetTxKB) / seconds - - rate = rx_stats + tx_stats - max_net_io = round(max(currentMaxNetRate, int(rate)), 1) - - self.stats[vm_uuid].update({'net_io': rate, 'max_net_io': max_net_io, - 'netRxKB': netRxKB, 'netTxKB': netTxKB}) - - def _get_disk_io_rate(self, vm_uuid, dom, seconds): - prevDiskRdKB = self.stats[vm_uuid].get('diskRdKB', 0) - prevDiskWrKB = self.stats[vm_uuid].get('diskWrKB', 0) - currentMaxDiskRate = self.stats[vm_uuid].get('max_disk_io', 100) - - rd_bytes = 0 - wr_bytes = 0 - - tree = ElementTree.fromstring(dom.XMLDesc(0)) - for target in tree.findall("devices/disk/target"): - dev = target.get("dev") - io = dom.blockStats(dev) - rd_bytes += io[1] - wr_bytes += io[3] - - diskRdKB = float(rd_bytes) / 1024 - diskWrKB = float(wr_bytes) / 1024 - - rd_stats = (diskRdKB - prevDiskRdKB) / seconds - wr_stats = (diskWrKB - prevDiskWrKB) / seconds - - rate = rd_stats + wr_stats - max_disk_io = round(max(currentMaxDiskRate, int(rate)), 1) - - self.stats[vm_uuid].update({'disk_io': rate, - 'max_disk_io': max_disk_io, - 'diskRdKB': diskRdKB, - 'diskWrKB': diskWrKB}) - - def lookup(self, name): - dom = self.get_vm(name, self.conn) - info = dom.info() - state = DOM_STATE_MAP[info[0]] - screenshot = None - # (type, listen, port, passwd, passwdValidTo) - graphics = self._vm_get_graphics(name) - graphics_port = graphics[2] - graphics_port = graphics_port if state == 'running' else None - try: - if state == 'running' and self._has_video(dom): - screenshot = self.vmscreenshot.lookup(name) - elif state == 'shutoff': - # reset vm stats when it is powered off to avoid sending - # incorrect (old) data - self.stats[dom.UUIDString()] = {} - except NotFoundError: - pass - - with self.objstore as session: - try: - extra_info = session.get('vm', dom.UUIDString()) - except NotFoundError: - extra_info = {} - icon = extra_info.get('icon') - - self._update_guest_stats(name) - vm_stats = self.stats.get(dom.UUIDString(), {}) - res = {} - res['cpu_utilization'] = vm_stats.get('cpu', 0) - res['net_throughput'] = vm_stats.get('net_io', 0) - res['net_throughput_peak'] = vm_stats.get('max_net_io', 100) - res['io_throughput'] = vm_stats.get('disk_io', 0) - res['io_throughput_peak'] = vm_stats.get('max_disk_io', 100) - users, groups = self._get_access_info(dom) - - if state == 'shutoff': - xml = dom.XMLDesc(0) - val = xpath_get_text(xml, XPATH_DOMAIN_MEMORY)[0] - unit_list = xpath_get_text(xml, XPATH_DOMAIN_MEMORY_UNIT) - if len(unit_list) > 0: - unit = unit_list[0] - else: - unit = 'KiB' - memory = convert_data_size(val, unit, 'MiB') - else: - memory = info[2] >> 10 - - return {'name': name, - 'state': state, - 'stats': res, - 'uuid': dom.UUIDString(), - 'memory': memory, - 'cpus': info[3], - 'screenshot': screenshot, - 'icon': icon, - # (type, listen, port, passwd, passwdValidTo) - 'graphics': {"type": graphics[0], - "listen": graphics[1], - "port": graphics_port, - "passwd": graphics[3], - "passwdValidTo": graphics[4]}, - 'users': users, - 'groups': groups, - 'access': 'full', - 'persistent': True if dom.isPersistent() else False - } - - def _vm_get_disk_paths(self, dom): - xml = dom.XMLDesc(0) - xpath = "/domain/devices/disk[@device='disk']/source/@file" - return xpath_get_text(xml, xpath) - - @staticmethod - def get_vm(name, conn): - conn = conn.get() - try: - # outgoing text to libvirt, encode('utf-8') - return conn.lookupByName(name.encode("utf-8")) - except libvirt.libvirtError as e: - if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: - raise NotFoundError("KCHVM0002E", {'name': name}) - else: - raise OperationFailed("KCHVM0009E", {'name': name, - 'err': e.message}) - - def delete(self, name): - conn = self.conn.get() - dom = self.get_vm(name, self.conn) - if not dom.isPersistent(): - raise InvalidOperation("KCHVM0036E", {'name': name}) - - self._vmscreenshot_delete(dom.UUIDString()) - paths = self._vm_get_disk_paths(dom) - info = self.lookup(name) - - if info['state'] != 'shutoff': - self.poweroff(name) - - # delete existing snapshots before deleting VM - - # libvirt's Test driver does not support the function - # "virDomainListAllSnapshots", so "VMSnapshots.get_list" will raise - # "OperationFailed" in that case. - try: - snapshot_names = self.vmsnapshots.get_list(name) - except OperationFailed, e: - wok_log.error('cannot list snapshots: %s; ' - 'skipping snapshot deleting...' % e.message) - else: - for s in snapshot_names: - self.vmsnapshot.delete(name, s) - - try: - dom.undefine() - except libvirt.libvirtError as e: - raise OperationFailed("KCHVM0021E", - {'name': name, 'err': e.get_error_message()}) - - for path in paths: - try: - vol = conn.storageVolLookupByPath(path) - pool = vol.storagePoolLookupByVolume() - xml = pool.XMLDesc(0) - pool_type = xpath_get_text(xml, "/pool/@type")[0] - if pool_type not in READONLY_POOL_TYPE: - vol.delete(0) - # Update objstore to remove the volume - with self.objstore as session: - session.delete('storagevolume', path, - ignore_missing=True) - except libvirt.libvirtError as e: - wok_log.error('Unable to get storage volume by path: %s' % - e.message) - except Exception as e: - raise OperationFailed('KCHVOL0017E', {'err': e.message}) - - try: - with self.objstore as session: - if path in session.get_list('storagevolume'): - used_by = session.get('storagevolume', path)['used_by'] - used_by.remove(name) - session.store('storagevolume', path, - {'used_by': used_by}) - except Exception as e: - raise OperationFailed('KCHVOL0017E', {'err': e.message}) - - try: - with self.objstore as session: - session.delete('vm', dom.UUIDString(), ignore_missing=True) - except Exception as e: - # It is possible to delete vm without delete its database info - wok_log.error('Error deleting vm information from database: ' - '%s', e.message) - - vnc.remove_proxy_token(name) - - def start(self, name): - # make sure the ISO file has read permission - dom = self.get_vm(name, self.conn) - xml = dom.XMLDesc(0) - xpath = "/domain/devices/disk[@device='cdrom']/source/@file" - isofiles = xpath_get_text(xml, xpath) - - user = UserTests.probe_user() - for iso in isofiles: - run_setfacl_set_attr(iso, user=user) - - dom = self.get_vm(name, self.conn) - try: - dom.create() - except libvirt.libvirtError as e: - raise OperationFailed("KCHVM0019E", - {'name': name, 'err': e.get_error_message()}) - - def poweroff(self, name): - dom = self.get_vm(name, self.conn) - try: - dom.destroy() - except libvirt.libvirtError as e: - raise OperationFailed("KCHVM0020E", - {'name': name, 'err': e.get_error_message()}) - - def shutdown(self, name): - dom = self.get_vm(name, self.conn) - try: - dom.shutdown() - except libvirt.libvirtError as e: - raise OperationFailed("KCHVM0029E", - {'name': name, 'err': e.get_error_message()}) - - def reset(self, name): - dom = self.get_vm(name, self.conn) - try: - dom.reset(flags=0) - except libvirt.libvirtError as e: - raise OperationFailed("KCHVM0022E", - {'name': name, 'err': e.get_error_message()}) - - def _vm_get_graphics(self, name): - dom = self.get_vm(name, self.conn) - xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) - - expr = "/domain/devices/graphics/@type" - res = xpath_get_text(xml, expr) - graphics_type = res[0] if res else None - - expr = "/domain/devices/graphics/@listen" - res = xpath_get_text(xml, expr) - graphics_listen = res[0] if res else None - - graphics_port = graphics_passwd = graphics_passwdValidTo = None - if graphics_type: - expr = "/domain/devices/graphics[@type='%s']/@port" - res = xpath_get_text(xml, expr % graphics_type) - graphics_port = int(res[0]) if res else None - - expr = "/domain/devices/graphics[@type='%s']/@passwd" - res = xpath_get_text(xml, expr % graphics_type) - graphics_passwd = res[0] if res else None - - expr = "/domain/devices/graphics[@type='%s']/@passwdValidTo" - res = xpath_get_text(xml, expr % graphics_type) - if res: - to = time.mktime(time.strptime(res[0], '%Y-%m-%dT%H:%M:%S')) - graphics_passwdValidTo = to - time.mktime(time.gmtime()) - - return (graphics_type, graphics_listen, graphics_port, - graphics_passwd, graphics_passwdValidTo) - - def connect(self, name): - # (type, listen, port, passwd, passwdValidTo) - graphics_port = self._vm_get_graphics(name)[2] - if graphics_port is not None: - vnc.add_proxy_token(name, graphics_port) - else: - raise OperationFailed("KCHVM0010E", {'name': name}) - - def _vmscreenshot_delete(self, vm_uuid): - screenshot = VMScreenshotModel.get_screenshot(vm_uuid, self.objstore, - self.conn) - screenshot.delete() - try: - with self.objstore as session: - session.delete('screenshot', vm_uuid) - except Exception as e: - # It is possible to continue Kimchi executions without delete - # screenshots - wok_log.error('Error trying to delete vm screenshot from ' - 'database due error: %s', e.message) - - def suspend(self, name): - """Suspend the virtual machine's execution and puts it in the - state 'paused'. Use the function "resume" to restore its state. - If the VM is not running, an exception will be raised. - - Parameters: - name -- the name of the VM to be suspended. - """ - vm = self.lookup(name) - if vm['state'] != 'running': - raise InvalidOperation('KCHVM0037E', {'name': name}) - - vir_dom = self.get_vm(name, self.conn) - - try: - vir_dom.suspend() - except libvirt.libvirtError, e: - raise OperationFailed('KCHVM0038E', {'name': name, - 'err': e.message}) - - def resume(self, name): - """Resume the virtual machine's execution and puts it in the - state 'running'. The VM should have been suspended previously by the - function "suspend" and be in the state 'paused', otherwise an exception - will be raised. - - Parameters: - name -- the name of the VM to be resumed. - """ - vm = self.lookup(name) - if vm['state'] != 'paused': - raise InvalidOperation('KCHVM0039E', {'name': name}) - - vir_dom = self.get_vm(name, self.conn) - - try: - vir_dom.resume() - except libvirt.libvirtError, e: - raise OperationFailed('KCHVM0040E', {'name': name, - 'err': e.message}) - - -class VMScreenshotModel(object): - def __init__(self, **kargs): - self.objstore = kargs['objstore'] - self.conn = kargs['conn'] - - def lookup(self, name): - dom = VMModel.get_vm(name, self.conn) - d_info = dom.info() - vm_uuid = dom.UUIDString() - if DOM_STATE_MAP[d_info[0]] != 'running': - raise NotFoundError("KCHVM0004E", {'name': name}) - - screenshot = self.get_screenshot(vm_uuid, self.objstore, self.conn) - img_path = screenshot.lookup() - # screenshot info changed after scratch generation - try: - with self.objstore as session: - session.store('screenshot', vm_uuid, screenshot.info) - except Exception as e: - # It is possible to continue Kimchi executions without store - # screenshots - wok_log.error('Error trying to update database with guest ' - 'screenshot information due error: %s', e.message) - return img_path - - @staticmethod - def get_screenshot(vm_uuid, objstore, conn): - try: - with objstore as session: - try: - params = session.get('screenshot', vm_uuid) - except NotFoundError: - params = {'uuid': vm_uuid} - session.store('screenshot', vm_uuid, params) - except Exception as e: - # The 'except' outside of 'with' is necessary to catch possible - # exception from '__exit__' when calling 'session.store' - # It is possible to continue Kimchi vm executions without - # screenshots - wok_log.error('Error trying to update database with guest ' - 'screenshot information due error: %s', e.message) - return LibvirtVMScreenshot(params, conn) - - -class LibvirtVMScreenshot(VMScreenshot): - def __init__(self, vm_uuid, conn): - VMScreenshot.__init__(self, vm_uuid) - self.conn = conn - - def _generate_scratch(self, thumbnail): - def handler(stream, buf, opaque): - fd = opaque - os.write(fd, buf) - - fd = os.open(thumbnail, os.O_WRONLY | os.O_TRUNC | os.O_CREAT, 0644) - try: - conn = self.conn.get() - dom = conn.lookupByUUIDString(self.vm_uuid) - vm_name = dom.name() - stream = conn.newStream(0) - dom.screenshot(stream, 0, 0) - stream.recvAll(handler, fd) - except libvirt.libvirtError: - try: - stream.abort() - except: - pass - raise NotFoundError("KCHVM0006E", {'name': vm_name}) - else: - stream.finish() - finally: - os.close(fd) diff --git a/plugins/kimchi/model/vmsnapshots.py b/plugins/kimchi/model/vmsnapshots.py deleted file mode 100644 index fff1908..0000000 --- a/plugins/kimchi/model/vmsnapshots.py +++ /dev/null @@ -1,204 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import libvirt -import lxml.etree as ET -import time -from lxml import objectify -from lxml.builder import E - -from wok.exception import InvalidOperation, NotFoundError, OperationFailed -from wok.utils import add_task -from wok.xmlutils.utils import xpath_get_text -from wok.model.tasks import TaskModel - -from vms import DOM_STATE_MAP, VMModel -from vmstorages import VMStorageModel, VMStoragesModel - - -class VMSnapshotsModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - self.task = TaskModel(**kargs) - self.vmstorages = VMStoragesModel(**kargs) - self.vmstorage = VMStorageModel(**kargs) - - def create(self, vm_name, params={}): - """Create a snapshot with the current domain state. - - The VM must be stopped and contain only disks with format 'qcow2'; - otherwise an exception will be raised. - - Parameters: - vm_name -- the name of the VM where the snapshot will be created. - params -- a dict with the following values: - "name": The snapshot name (optional). If omitted, a default value - based on the current time will be used. - - Return: - A Task running the operation. - """ - vir_dom = VMModel.get_vm(vm_name, self.conn) - if DOM_STATE_MAP[vir_dom.info()[0]] != u'shutoff': - raise InvalidOperation('KCHSNAP0001E', {'vm': vm_name}) - - # if the VM has a non-CDROM disk with type 'raw', abort. - for storage_name in self.vmstorages.get_list(vm_name): - storage = self.vmstorage.lookup(vm_name, storage_name) - type = storage['type'] - format = storage['format'] - - if type != u'cdrom' and format != u'qcow2': - raise InvalidOperation('KCHSNAP0010E', {'vm': vm_name, - 'format': format}) - - name = params.get('name', unicode(int(time.time()))) - - task_params = {'vm_name': vm_name, 'name': name} - taskid = add_task(u'/plugins/kimchi/vms/%s/snapshots/%s' % (vm_name, - name), self._create_task, self.objstore, task_params) - return self.task.lookup(taskid) - - def _create_task(self, cb, params): - """Asynchronous function which actually creates the snapshot. - - Parameters: - cb -- a callback function to signal the Task's progress. - params -- a dict with the following values: - "vm_name": the name of the VM where the snapshot will be created. - "name": the snapshot name. - """ - vm_name = params['vm_name'] - name = params['name'] - - cb('building snapshot XML') - root_elem = E.domainsnapshot() - root_elem.append(E.name(name)) - xml = ET.tostring(root_elem, encoding='utf-8') - - try: - cb('fetching snapshot domain') - vir_dom = VMModel.get_vm(vm_name, self.conn) - cb('creating snapshot') - vir_dom.snapshotCreateXML(xml, 0) - except (NotFoundError, OperationFailed, libvirt.libvirtError), e: - raise OperationFailed('KCHSNAP0002E', - {'name': name, 'vm': vm_name, - 'err': e.message}) - - cb('OK', True) - - def get_list(self, vm_name): - vir_dom = VMModel.get_vm(vm_name, self.conn) - - try: - vir_snaps = vir_dom.listAllSnapshots(0) - return sorted([s.getName().decode('utf-8') for s in vir_snaps], - key=unicode.lower) - except libvirt.libvirtError, e: - raise OperationFailed('KCHSNAP0005E', - {'vm': vm_name, 'err': e.message}) - - -class VMSnapshotModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - - def lookup(self, vm_name, name): - vir_snap = self.get_vmsnapshot(vm_name, name) - - try: - snap_xml_str = vir_snap.getXMLDesc(0).decode('utf-8') - except libvirt.libvirtError, e: - raise OperationFailed('KCHSNAP0004E', {'name': name, - 'vm': vm_name, - 'err': e.message}) - - snap_xml = objectify.fromstring(snap_xml_str) - - try: - parent = unicode(snap_xml.parent.name) - except AttributeError: - parent = u'' - - return {'created': unicode(snap_xml.creationTime), - 'name': unicode(snap_xml.name), - 'parent': parent, - 'state': unicode(snap_xml.state)} - - def delete(self, vm_name, name): - try: - vir_snap = self.get_vmsnapshot(vm_name, name) - vir_snap.delete(0) - except libvirt.libvirtError, e: - raise OperationFailed('KCHSNAP0006E', {'name': name, - 'vm': vm_name, - 'err': e.message}) - - def revert(self, vm_name, name): - try: - vir_dom = VMModel.get_vm(vm_name, self.conn) - vir_snap = self.get_vmsnapshot(vm_name, name) - vir_dom.revertToSnapshot(vir_snap, 0) - - # get vm name recorded in the snapshot and return new uri params - vm_new_name = xpath_get_text(vir_snap.getXMLDesc(0), - 'domain/name')[0] - return [vm_new_name, name] - except libvirt.libvirtError, e: - raise OperationFailed('KCHSNAP0009E', {'name': name, - 'vm': vm_name, - 'err': e.message}) - - def get_vmsnapshot(self, vm_name, name): - vir_dom = VMModel.get_vm(vm_name, self.conn) - - try: - return vir_dom.snapshotLookupByName(name, 0) - except libvirt.libvirtError, e: - code = e.get_error_code() - if code == libvirt.VIR_ERR_NO_DOMAIN_SNAPSHOT: - raise NotFoundError('KCHSNAP0003E', {'name': name, - 'vm': vm_name}) - else: - raise OperationFailed('KCHSNAP0004E', {'name': name, - 'vm': vm_name, - 'err': e.message}) - - -class CurrentVMSnapshotModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.vmsnapshot = VMSnapshotModel(**kargs) - - def lookup(self, vm_name): - vir_dom = VMModel.get_vm(vm_name, self.conn) - - try: - vir_snap = vir_dom.snapshotCurrent(0) - snap_name = vir_snap.getName().decode('utf-8') - except libvirt.libvirtError, e: - if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN_SNAPSHOT: - return {} - - raise OperationFailed('KCHSNAP0008E', - {'vm': vm_name, 'err': e.message}) - - return self.vmsnapshot.lookup(vm_name, snap_name) diff --git a/plugins/kimchi/model/vmstorages.py b/plugins/kimchi/model/vmstorages.py deleted file mode 100644 index bec16c6..0000000 --- a/plugins/kimchi/model/vmstorages.py +++ /dev/null @@ -1,252 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import string -from lxml import etree - -from wok.exception import InvalidOperation, InvalidParameter, NotFoundError -from wok.exception import OperationFailed -from wok.utils import wok_log - -from ..osinfo import lookup -from ..xmlutils.disk import get_device_node, get_disk_xml -from ..xmlutils.disk import get_vm_disk_info, get_vm_disks -from config import CapabilitiesModel -from diskutils import get_disk_used_by, set_disk_used_by -from storagevolumes import StorageVolumeModel -from utils import get_vm_config_flag -from vms import DOM_STATE_MAP, VMModel - - -HOTPLUG_TYPE = ['scsi', 'virtio'] - - -def _get_device_bus(dev_type, dom, metadata_support): - try: - version, distro = VMModel.vm_get_os_metadata(dom, metadata_support) - except: - version, distro = ('unknown', 'unknown') - return lookup(distro, version)[dev_type+'_bus'] - - -class VMStoragesModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - self.caps = CapabilitiesModel(**kargs) - - def _get_available_bus_address(self, bus_type, vm_name): - if bus_type not in ['ide']: - return dict() - # libvirt limitation of just 1 ide controller - # each controller have at most 2 buses and each bus 2 units. - dom = VMModel.get_vm(vm_name, self.conn) - disks = self.get_list(vm_name) - valid_id = [('0', '0'), ('0', '1'), ('1', '0'), ('1', '1')] - controller_id = '0' - for dev_name in disks: - disk = get_device_node(dom, dev_name) - if disk.target.attrib['bus'] == 'ide': - controller_id = disk.address.attrib['controller'] - bus_id = disk.address.attrib['bus'] - unit_id = disk.address.attrib['unit'] - if (bus_id, unit_id) in valid_id: - valid_id.remove((bus_id, unit_id)) - continue - if not valid_id: - raise OperationFailed('KCHVMSTOR0014E', - {'type': 'ide', 'limit': 4}) - else: - address = {'controller': controller_id, - 'bus': valid_id[0][0], 'unit': valid_id[0][1]} - return dict(address=address) - - def create(self, vm_name, params): - vol_model = None - # Path will never be blank due to API.json verification. - # There is no need to cover this case here. - if not ('vol' in params) ^ ('path' in params): - raise InvalidParameter("KCHVMSTOR0017E") - - dom = VMModel.get_vm(vm_name, self.conn) - params['bus'] = _get_device_bus(params['type'], dom, - self.caps.metadata_support) - params['format'] = 'raw' - - dev_list = [dev for dev, bus in get_vm_disks(dom).iteritems() - if bus == params['bus']] - dev_list.sort() - if len(dev_list) == 0: - params['index'] = 0 - else: - char = dev_list.pop()[2] - params['index'] = string.ascii_lowercase.index(char) + 1 - - if (params['bus'] not in HOTPLUG_TYPE and - DOM_STATE_MAP[dom.info()[0]] != 'shutoff'): - raise InvalidOperation('KCHVMSTOR0011E') - - if params.get('vol'): - try: - pool = params['pool'] - vol_model = StorageVolumeModel(conn=self.conn, - objstore=self.objstore) - vol_info = vol_model.lookup(pool, params['vol']) - except KeyError: - raise InvalidParameter("KCHVMSTOR0012E") - except Exception as e: - raise InvalidParameter("KCHVMSTOR0015E", {'error': e}) - if len(vol_info['used_by']) != 0: - raise InvalidParameter("KCHVMSTOR0016E") - - valid_format = { - "disk": ["raw", "bochs", "qcow", "qcow2", "qed", "vmdk"], - "cdrom": "iso"} - - if vol_info['type'] == 'file': - if (params['type'] == 'disk' and - vol_info['format'] in valid_format[params['type']]): - params['format'] = vol_info['format'] - else: - raise InvalidParameter("KCHVMSTOR0018E", - {"format": vol_info['format'], - "type": params['type']}) - - params['path'] = vol_info['path'] - params['disk'] = vol_info['type'] - - params.update(self._get_available_bus_address(params['bus'], vm_name)) - - # Add device to VM - dev, xml = get_disk_xml(params) - try: - conn = self.conn.get() - dom = conn.lookupByName(vm_name) - dom.attachDeviceFlags(xml, get_vm_config_flag(dom, 'all')) - except Exception as e: - raise OperationFailed("KCHVMSTOR0008E", {'error': e.message}) - - # Don't put a try-block here. Let the exception be raised. If we - # allow disks used_by to be out of sync, data corruption could - # occour if a disk is added to two guests unknowingly. - if params.get('vol'): - used_by = vol_info['used_by'] - used_by.append(vm_name) - set_disk_used_by(self.objstore, params['path'], used_by) - - return dev - - def get_list(self, vm_name): - dom = VMModel.get_vm(vm_name, self.conn) - return get_vm_disks(dom).keys() - - -class VMStorageModel(object): - def __init__(self, **kargs): - self.conn = kargs['conn'] - self.objstore = kargs['objstore'] - self.caps = CapabilitiesModel(**kargs) - - def lookup(self, vm_name, dev_name): - # Retrieve disk xml and format return dict - dom = VMModel.get_vm(vm_name, self.conn) - return get_vm_disk_info(dom, dev_name) - - def delete(self, vm_name, dev_name): - conn = self.conn.get() - - try: - bus_type = self.lookup(vm_name, dev_name)['bus'] - dom = conn.lookupByName(vm_name) - except NotFoundError: - raise - - if (bus_type not in HOTPLUG_TYPE and - DOM_STATE_MAP[dom.info()[0]] != 'shutoff'): - raise InvalidOperation('KCHVMSTOR0011E') - - try: - disk = get_device_node(dom, dev_name) - path = get_vm_disk_info(dom, dev_name)['path'] - if path is None or len(path) < 1: - path = self.lookup(vm_name, dev_name)['path'] - # This has to be done before it's detached. If it wasn't - # in the obj store, its ref count would have been updated - # by get_disk_used_by() - if path is not None: - used_by = get_disk_used_by(self.objstore, self.conn, path) - else: - wok_log.error("Unable to decrement volume used_by on" - " delete because no path could be found.") - dom.detachDeviceFlags(etree.tostring(disk), - get_vm_config_flag(dom, 'all')) - except Exception as e: - raise OperationFailed("KCHVMSTOR0010E", {'error': e.message}) - - if used_by is not None and vm_name in used_by: - used_by.remove(vm_name) - set_disk_used_by(self.objstore, path, used_by) - else: - wok_log.error("Unable to update %s:%s used_by on delete." - % (vm_name, dev_name)) - - def update(self, vm_name, dev_name, params): - old_disk_used_by = None - new_disk_used_by = None - - dom = VMModel.get_vm(vm_name, self.conn) - - dev_info = self.lookup(vm_name, dev_name) - if dev_info['type'] != 'cdrom': - raise InvalidOperation("KCHVMSTOR0006E") - - params['path'] = params.get('path', '') - old_disk_path = dev_info['path'] - new_disk_path = params['path'] - if new_disk_path != old_disk_path: - # An empty path means a CD-ROM was empty or ejected: - if old_disk_path is not '': - old_disk_used_by = get_disk_used_by( - self.objstore, self.conn, old_disk_path) - if new_disk_path is not '': - new_disk_used_by = get_disk_used_by( - self.objstore, self.conn, new_disk_path) - - dev_info.update(params) - dev, xml = get_disk_xml(dev_info) - - try: - dom.updateDeviceFlags(xml, get_vm_config_flag(dom, 'all')) - except Exception as e: - raise OperationFailed("KCHVMSTOR0009E", {'error': e.message}) - - try: - if old_disk_used_by is not None and \ - vm_name in old_disk_used_by: - old_disk_used_by.remove(vm_name) - set_disk_used_by(self.objstore, old_disk_path, - old_disk_used_by) - if new_disk_used_by is not None: - new_disk_used_by.append(vm_name) - set_disk_used_by(self.objstore, new_disk_path, - new_disk_used_by) - except Exception as e: - wok_log.error("Unable to update dev used_by on update due to" - " %s:" % e.message) - return dev diff --git a/plugins/kimchi/netinfo.py b/plugins/kimchi/netinfo.py deleted file mode 100644 index c5746d7..0000000 --- a/plugins/kimchi/netinfo.py +++ /dev/null @@ -1,216 +0,0 @@ -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -import ethtool -import glob -import os - - -NET_PATH = '/sys/class/net' -NIC_PATH = '/sys/class/net/*/device' -BRIDGE_PATH = '/sys/class/net/*/bridge' -BONDING_PATH = '/sys/class/net/*/bonding' -WLAN_PATH = '/sys/class/net/*/wireless' -NET_BRPORT = '/sys/class/net/%s/brport' -NET_MASTER = '/sys/class/net/%s/master' -NET_STATE = '/sys/class/net/%s/carrier' -PROC_NET_VLAN = '/proc/net/vlan/' -BONDING_SLAVES = '/sys/class/net/%s/bonding/slaves' -BRIDGE_PORTS = '/sys/class/net/%s/brif' - - -def wlans(): - return [b.split('/')[-2] for b in glob.glob(WLAN_PATH)] - - -def is_wlan(iface): - return iface in wlans() - - -# FIXME if we do not want to list usb nic -def nics(): - return list(set([b.split('/')[-2] for b in glob.glob(NIC_PATH)]) - - set(wlans())) - - -def is_nic(iface): - return iface in nics() - - -def bondings(): - return [b.split('/')[-2] for b in glob.glob(BONDING_PATH)] - - -def is_bonding(iface): - return iface in bondings() - - -def vlans(): - return list(set([b.split('/')[-1] - for b in glob.glob(NET_PATH + '/*')]) & - set([b.split('/')[-1] - for b in glob.glob(PROC_NET_VLAN + '*')])) - - -def is_vlan(iface): - return iface in vlans() - - -def bridges(): - return [b.split('/')[-2] for b in glob.glob(BRIDGE_PATH)] - - -def is_bridge(iface): - return iface in bridges() - - -def all_interfaces(): - return [d.rsplit("/", 1)[-1] for d in glob.glob(NET_PATH + '/*')] - - -def slaves(bonding): - with open(BONDING_SLAVES % bonding) as bonding_file: - res = bonding_file.readline().split() - return res - - -def ports(bridge): - return os.listdir(BRIDGE_PORTS % bridge) - - -def is_brport(nic): - return os.path.exists(NET_BRPORT % nic) - - -def is_bondlave(nic): - return os.path.exists(NET_MASTER % nic) - - -def operstate(dev): - link_status = link_detected(dev) - return "down" if link_status == "n/a" else "up" - - -def link_detected(dev): - # try to read interface carrier (link) status - try: - with open(NET_STATE % dev) as dev_file: - carrier = dev_file.readline().strip() - # when IOError is raised, interface is down - except IOError: - return "n/a" - - # if value is 1, interface up with cable connected - # 0 corresponds to interface up with cable disconnected - return "yes" if carrier == '1' else "no" - - -def get_vlan_device(vlan): - """ Return the device of the given VLAN. """ - dev = None - - if os.path.exists(PROC_NET_VLAN + vlan): - with open(PROC_NET_VLAN + vlan) as vlan_file: - for line in vlan_file: - if "Device:" in line: - dummy, dev = line.split() - break - return dev - - -def get_bridge_port_device(bridge): - """Return the nics list that belongs to bridge.""" - # br --- v --- bond --- nic1 - if bridge not in bridges(): - raise ValueError('unknown bridge %s' % bridge) - nics = [] - for port in ports(bridge): - if port in vlans(): - device = get_vlan_device(port) - if device in bondings(): - nics.extend(slaves(device)) - else: - nics.append(device) - if port in bondings(): - nics.extend(slaves(port)) - else: - nics.append(port) - return nics - - -def aggregated_bridges(): - return [bridge for bridge in bridges() if - (set(get_bridge_port_device(bridge)) & set(nics()))] - - -def bare_nics(): - "The nic is not a port of a bridge or a slave of bond." - return [nic for nic in nics() if not (is_brport(nic) or is_bondlave(nic))] - - -def is_bare_nic(iface): - return iface in bare_nics() - - -# The nic will not be exposed when it is a port of a bridge or -# a slave of bond. -# The bridge will not be exposed when all it's port are tap. -def all_favored_interfaces(): - return aggregated_bridges() + bare_nics() + bondings() - - -def get_interface_type(iface): - # FIXME if we want to get more device type - # just support nic, bridge, bondings and vlan, for we just - # want to expose this 4 kinds of interface - try: - if is_nic(iface): - return "nic" - if is_bonding(iface): - return "bonding" - if is_bridge(iface): - return "bridge" - if is_vlan(iface): - return "vlan" - return 'unknown' - except IOError: - return 'unknown' - - -def get_interface_info(iface): - if iface not in ethtool.get_devices(): - raise ValueError('unknown interface: %s' % iface) - - ipaddr = '' - netmask = '' - try: - ipaddr = ethtool.get_ipaddr(iface) - netmask = ethtool.get_netmask(iface) - except IOError: - pass - - iface_link_detected = link_detected(iface) - iface_status = 'active' if iface_link_detected != "n/a" else "inactive" - - return {'name': iface, - 'type': get_interface_type(iface), - 'status': iface_status, - 'link_detected': iface_link_detected, - 'ipaddr': ipaddr, - 'netmask': netmask} diff --git a/plugins/kimchi/network.py b/plugins/kimchi/network.py deleted file mode 100644 index 1433b8a..0000000 --- a/plugins/kimchi/network.py +++ /dev/null @@ -1,62 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -import ethtool -import ipaddr - - -APrivateNets = ipaddr.IPNetwork("10.0.0.0/8") -BPrivateNets = ipaddr.IPNetwork("172.16.0.0/12") -CPrivateNets = ipaddr.IPNetwork('192.168.0.0/16') -PrivateNets = [CPrivateNets, BPrivateNets, APrivateNets] -DefaultNetsPool = [ipaddr.IPNetwork('192.168.122.0/23'), - ipaddr.IPNetwork('192.168.124.0/22'), - ipaddr.IPNetwork('192.168.128.0/17')] - - -def get_dev_netaddr(dev): - info = ethtool.get_interfaces_info(dev)[0] - return (info.ipv4_address and - "%s/%s" % (info.ipv4_address, info.ipv4_netmask) or '') - - -def get_dev_netaddrs(): - nets = [] - for dev in ethtool.get_devices(): - devnet = get_dev_netaddr(dev) - devnet and nets.append(ipaddr.IPNetwork(devnet)) - return nets - - -# used_nets should include all the subnet allocated in libvirt network -# will get host network by get_dev_netaddrs -def get_one_free_network(used_nets, nets_pool=PrivateNets): - def _get_free_network(nets, used_nets): - for net in nets.subnet(new_prefix=24): - if not any(net.overlaps(used) for used in used_nets): - return str(net) - return None - - used_nets = used_nets + get_dev_netaddrs() - for nets in nets_pool: - net = _get_free_network(nets, used_nets) - if net: - return net - return None diff --git a/plugins/kimchi/osinfo.py b/plugins/kimchi/osinfo.py deleted file mode 100644 index 5b1277c..0000000 --- a/plugins/kimchi/osinfo.py +++ /dev/null @@ -1,213 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import copy -import glob -import os -import psutil -from collections import defaultdict -from configobj import ConfigObj -from distutils.version import LooseVersion - -from wok.config import PluginPaths - - -SUPPORTED_ARCHS = {'x86': ('i386', 'i686', 'x86_64'), - 'power': ('ppc', 'ppc64'), - 'ppc64le': ('ppc64le')} - - -template_specs = {'x86': {'old': dict(disk_bus='ide', - nic_model='e1000', sound_model='ich6'), - 'modern': dict(disk_bus='virtio', - nic_model='virtio', - sound_model='ich6')}, - 'power': {'old': dict(disk_bus='scsi', - nic_model='spapr-vlan', - cdrom_bus='scsi', - kbd_type="kbd", - kbd_bus='usb', mouse_bus='usb', - tablet_bus='usb', memory=1280), - 'modern': dict(disk_bus='virtio', - nic_model='virtio', - cdrom_bus='scsi', - kbd_bus='usb', - kbd_type="kbd", - mouse_bus='usb', tablet_bus='usb', - memory=1280)}, - 'ppc64le': {'old': dict(disk_bus='virtio', - nic_model='virtio', - cdrom_bus='scsi', - kbd_bus='usb', - kbd_type="keyboard", - mouse_bus='usb', tablet_bus='usb', - memory=1280), - 'modern': dict(disk_bus='virtio', - nic_model='virtio', - cdrom_bus='scsi', - kbd_bus='usb', - kbd_type="keyboard", - mouse_bus='usb', tablet_bus='usb', - memory=1280)}} - - -custom_specs = {'fedora': {'22': dict(video_model='qxl')}} - - -modern_version_bases = {'x86': {'debian': '6.0', 'ubuntu': '7.10', - 'opensuse': '10.3', 'centos': '5.3', - 'rhel': '6.0', 'fedora': '16', 'gentoo': '0', - 'sles': '11', 'arch': '0'}, - 'power': {'rhel': '6.5', 'fedora': '19', - 'ubuntu': '14.04', - 'opensuse': '13.1', - 'sles': '11sp3'}, - 'ppc64le': {'rhel': '6.5', 'fedora': '19', - 'ubuntu': '14.04', - 'opensuse': '13.1', - 'sles': '11sp3'}} - - -icon_available_distros = [icon[5:-4] for icon in glob.glob1('%s/images/' - % PluginPaths('kimchi').ui_dir, 'icon-*.png')] - - -def _get_tmpl_defaults(): - """ - ConfigObj returns a dict like below when no changes were made in the - template configuration file (template.conf) - - {'main': {}, 'storage': {'disk.0': {}}, 'processor': {}, 'graphics': {}} - - The default values should be like below: - - {'main': {'networks': ['default'], 'memory': '1024'}, - 'storage': {'pool': 'default', - 'disk.0': {'format': 'qcow2', 'size': '10'}}, - 'processor': {'cpus': '1'}, - 'graphics': {'type': 'spice', 'listen': '127.0.0.1'}} - """ - # Create dict with default values - tmpl_defaults = defaultdict(dict) - tmpl_defaults['main']['networks'] = ['default'] - tmpl_defaults['main']['memory'] = 1024 - tmpl_defaults['storage']['pool'] = 'default' - tmpl_defaults['storage']['disk.0'] = {'size': 10, 'format': 'qcow2'} - tmpl_defaults['processor']['cpus'] = 1 - tmpl_defaults['graphics'] = {'type': 'vnc', 'listen': '127.0.0.1'} - - default_config = ConfigObj(tmpl_defaults) - - # Load template configuration file - config_file = os.path.join(PluginPaths('kimchi').conf_dir, 'template.conf') - config = ConfigObj(config_file) - - # Merge default configuration with file configuration - default_config.merge(config) - - # Create a dict with default values according to data structure - # expected by VMTemplate - defaults = {'domain': 'kvm', 'arch': os.uname()[4], - 'cdrom_bus': 'ide', 'cdrom_index': 2, 'mouse_bus': 'ps2'} - - # Parse main section to get networks and memory values - main_section = default_config.pop('main') - defaults.update(main_section) - - # Parse storage section to get storage pool and disks values - storage_section = default_config.pop('storage') - defaults['storagepool'] = '/plugins/kimchi/storagepools/' + \ - storage_section.pop('pool') - defaults['disks'] = [] - for disk in storage_section.keys(): - data = storage_section[disk] - data['index'] = int(disk.split('.')[1]) - defaults['disks'].append(data) - - # Parse processor section to get cpus and cpu_topology values - processor_section = default_config.pop('processor') - defaults['cpus'] = processor_section.pop('cpus') - defaults['cpu_info'] = {} - if len(processor_section.keys()) > 0: - defaults['cpu_info']['topology'] = processor_section - - # Update defaults values with graphics values - defaults['graphics'] = default_config.pop('graphics') - - return defaults - - -# Set defaults values according to template.conf file -defaults = _get_tmpl_defaults() - - -def _get_arch(): - for arch, sub_archs in SUPPORTED_ARCHS.iteritems(): - if os.uname()[4] in sub_archs: - return arch - - -def get_template_default(template_type, field): - host_arch = _get_arch() - # Assuming 'power' = 'ppc64le' because lookup() does the same, - # claiming libvirt compatibility. - host_arch = 'power' if host_arch == 'ppc64le' else host_arch - tmpl_defaults = copy.deepcopy(defaults) - tmpl_defaults.update(template_specs[host_arch][template_type]) - return tmpl_defaults[field] - - -def lookup(distro, version): - """ - Lookup all parameters needed to run a VM of a known or unknown operating - system type and version. The data is constructed by starting with the - 'defaults' and merging the parameters given for the identified OS. If - known, a link to a remote install CD is added. - """ - params = copy.deepcopy(defaults) - params['os_distro'] = distro - params['os_version'] = version - arch = _get_arch() - - # Setting maxMemory of the VM, which will be equal total Host memory in Kib - params['max_memory'] = psutil.TOTAL_PHYMEM >> 10 - - # set up arch to ppc64 instead of ppc64le due to libvirt compatibility - if params["arch"] == "ppc64le": - params["arch"] = "ppc64" - - if distro in modern_version_bases[arch]: - if LooseVersion(version) >= LooseVersion( - modern_version_bases[arch][distro]): - params.update(template_specs[arch]['modern']) - else: - params.update(template_specs[arch]['old']) - else: - params['os_distro'] = params['os_version'] = "unknown" - params.update(template_specs[arch]['old']) - - # Get custom specifications - params.update(custom_specs.get(distro, {}).get(version, {})) - - if distro in icon_available_distros: - params['icon'] = 'plugins/kimchi/images/icon-%s.png' % distro - else: - params['icon'] = 'plugins/kimchi/images/icon-vm.png' - - return params diff --git a/plugins/kimchi/po/LINGUAS b/plugins/kimchi/po/LINGUAS deleted file mode 100644 index 3fcb18f..0000000 --- a/plugins/kimchi/po/LINGUAS +++ /dev/null @@ -1,11 +0,0 @@ -en_US -pt_BR -zh_CN -de_DE -es_ES -fr_FR -it_IT -ja_JP -ko_KR -ru_RU -zh_TW diff --git a/plugins/kimchi/po/Makefile.in.in b/plugins/kimchi/po/Makefile.in.in deleted file mode 100644 index d01fb31..0000000 --- a/plugins/kimchi/po/Makefile.in.in +++ /dev/null @@ -1,398 +0,0 @@ -# Makefile for PO directory in any package using GNU gettext. -# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper@gnu.ai.mit.edu> -# -# This file can be copied and used freely without restrictions. It can -# be used in projects which are not available under the GNU General Public -# License but which still want to provide support for the GNU gettext -# functionality. -# Please note that the actual code of GNU gettext is covered by the GNU -# General Public License and is *not* in the public domain. -# -# Origin: gettext-0.18 -GETTEXT_MACRO_VERSION = 0.18 - -PACKAGE = @PACKAGE@ -VERSION = @VERSION@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ - -SHELL = /bin/sh -@SET_MAKE@ - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ -datarootdir = @datarootdir@ -datadir = @datadir@ -localedir = @prefix@/share/locale -gettextsrcdir = $(datadir)/gettext/po - -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ - -# We use $(MKDIR_P). -# This macro uses the 'mkdir -p' command if possible. Otherwise, it falls back -# on invoking install-sh with the -d option, so your package should contain -# install-sh as described under AC_PROG_INSTALL. -mkinstalldirs = $(SHELL) @install_sh@ -d -install_sh = $(SHELL) @install_sh@ -MKDIR_P = @MKDIR_P@ -MKDIR_P = @MKDIR_P@ - -GMSGFMT_ = @GMSGFMT@ -GMSGFMT_no = @GMSGFMT@ -GMSGFMT_yes = @GMSGFMT_015@ -GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) -MSGFMT_ = @MSGFMT@ -MSGFMT_no = @MSGFMT@ -MSGFMT_yes = @MSGFMT_015@ -MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) -XGETTEXT_ = @XGETTEXT@ -XGETTEXT_no = @XGETTEXT@ -XGETTEXT_yes = @XGETTEXT_015@ -XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) -MSGMERGE = msgmerge -MSGMERGE_UPDATE = @MSGMERGE@ --update -MSGINIT = msginit -MSGCONV = msgconv -MSGFILTER = msgfilter - -POFILES = @POFILES@ -GMOFILES = @GMOFILES@ -UPDATEPOFILES = @UPDATEPOFILES@ -DUMMYPOFILES = @DUMMYPOFILES@ -DISTFILES.common = Makefile.in.in \ -$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) -DISTFILES = $(DISTFILES.common) Makevars POTFILES.in gen-pot.in \ -$(POFILES) $(GMOFILES) \ -$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) - -POTFILES = \ - -CATALOGS = @CATALOGS@ - -# Makevars gets inserted here. (Don't remove this line!) - -.SUFFIXES: -.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update - -.po.mo: - @echo "$(MSGFMT) -c -o $@ $<"; \ - $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ - -.po.gmo: - @lang=`echo $* | sed -e 's,.*/,,'`; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \ - cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo - -.sin.sed: - sed -e '/^#/d' $< > t-$@ - mv t-$@ $@ - - -all: check-macro-version update-gmo all-@USE_NLS@ - -all-yes: stamp-po -all-no: - -# Ensure that the gettext macros and this Makefile.in.in are in sync. -check-macro-version: - @test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \ - || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \ - exit 1; \ - } - -# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no -# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because -# we don't want to bother translators with empty POT files). We assume that -# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. -# In this case, stamp-po is a nop (i.e. a phony target). - -# stamp-po is a timestamp denoting the last time at which the CATALOGS have -# been loosely updated. Its purpose is that when a developer or translator -# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, -# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent -# invocations of "make" will do nothing. This timestamp would not be necessary -# if updating the $(CATALOGS) would always touch them; however, the rule for -# $(POFILES) has been designed to not touch files that don't need to be -# changed. -stamp-po: $(srcdir)/$(DOMAIN).pot - test ! -f $(srcdir)/$(DOMAIN).pot || \ - test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) - @test ! -f $(srcdir)/$(DOMAIN).pot || { \ - echo "touch stamp-po" && \ - echo timestamp > stamp-poT && \ - mv stamp-poT stamp-po; \ - } - -# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', -# otherwise packages like GCC can not be built if only parts of the source -# have been downloaded. - -$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in - $(srcdir)/gen-pot $(POTFILES) - -# This rule has no dependencies: we don't need to update $(DOMAIN).pot at -# every "make" invocation, only create it when it is missing. -# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. -$(srcdir)/$(DOMAIN).pot: - $(MAKE) $(DOMAIN).pot-update - -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot - @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ - if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ - else \ - $(MAKE) $${lang}.po-create; \ - fi - - -install: install-exec install-data -install-exec: -install-data: install-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(MKDIR_P) $(DESTDIR)$(gettextsrcdir); \ - for file in $(DISTFILES.common) Makevars.template; do \ - $(INSTALL_DATA) $(srcdir)/$$file \ - $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - for file in Makevars; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi -install-data-no: all -install-data-yes: all - @catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - dir=$(localedir)/$$lang/LC_MESSAGES; \ - $(MKDIR_P) $(DESTDIR)$$dir; \ - if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ - $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ - echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ - for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ - if test -n "$$lc"; then \ - if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ - link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ - mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ - for file in *; do \ - if test -f $$file; then \ - ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ - fi; \ - done); \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - else \ - if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ - :; \ - else \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - fi; \ - fi; \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ - ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ - cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ - fi; \ - done; \ - done - -install-strip: install - -installdirs: installdirs-exec installdirs-data -installdirs-exec: -installdirs-data: installdirs-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(MKDIR_P) $(DESTDIR)$(gettextsrcdir); \ - else \ - : ; \ - fi -installdirs-data-no: -installdirs-data-yes: - @catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - dir=$(localedir)/$$lang/LC_MESSAGES; \ - $(MKDIR_P) $(DESTDIR)$$dir; \ - for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ - if test -n "$$lc"; then \ - if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ - link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ - mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ - for file in *; do \ - if test -f $$file; then \ - ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ - fi; \ - done); \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - else \ - if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ - :; \ - else \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - fi; \ - fi; \ - fi; \ - done; \ - done - -# Define this as empty until I found a useful application. -installcheck: - -uninstall: uninstall-exec uninstall-data -uninstall-exec: -uninstall-data: uninstall-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - for file in $(DISTFILES.common) Makevars.template; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi -uninstall-data-no: -uninstall-data-yes: - catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - done; \ - done - -check: all - -info dvi ps pdf html tags TAGS ctags CTAGS ID: - -mostlyclean: - rm -f remove-potcdate.sed - rm -f stamp-poT - rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po - rm -fr *.o - -clean: mostlyclean - -distclean: clean - rm -f Makefile Makefile.in POTFILES *.mo - -maintainer-clean: distclean - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." - rm -f stamp-po $(GMOFILES) - -distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) -dist distdir: - $(MAKE) update-po - @$(MAKE) dist2 -# This is a separate target because 'update-po' must be executed before. -dist2: stamp-po $(DISTFILES) - dists="$(DISTFILES)"; \ - if test "$(PACKAGE)" = "gettext-tools"; then \ - dists="$$dists Makevars.template"; \ - fi; \ - if test -f $(srcdir)/$(DOMAIN).pot; then \ - dists="$$dists $(DOMAIN).pot stamp-po"; \ - fi; \ - if test -f $(srcdir)/ChangeLog; then \ - dists="$$dists ChangeLog"; \ - fi; \ - for i in 0 1 2 3 4 5 6 7 8 9; do \ - if test -f $(srcdir)/ChangeLog.$$i; then \ - dists="$$dists ChangeLog.$$i"; \ - fi; \ - done; \ - if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ - for file in $$dists; do \ - if test -f $$file; then \ - cp -p $$file $(distdir) || exit 1; \ - else \ - cp -p $(srcdir)/$$file $(distdir) || exit 1; \ - fi; \ - done - -update-po: Makefile - $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) - $(MAKE) update-gmo - -# General rule for creating PO files. - -.nop.po-create: - @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ - echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ - exit 1 - -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - -$(DUMMYPOFILES): - -update-gmo: Makefile $(GMOFILES) - @: - -# Recreate Makefile by invoking config.status. Explicitly invoke the shell, -# because execution permission bits may not work on the current file system. -# Use @SHELL@, which is the shell determined by autoconf for the use by its -# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient. -Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ - cd $(top_builddir) \ - && @SHELL@ ./config.status $(subdir)/$@.in po-directories - -force: - -# Tell versions [3.59,3.63) of GNU make not to export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/plugins/kimchi/po/Makevars b/plugins/kimchi/po/Makevars deleted file mode 100644 index c29a807..0000000 --- a/plugins/kimchi/po/Makevars +++ /dev/null @@ -1,41 +0,0 @@ -# Makefile variables for PO directory in any package using GNU gettext. - -# Usually the message domain is the same as the package name. -DOMAIN = kimchi - -# These two variables depend on the location of this directory. -subdir = po -top_builddir = .. - -# These options get passed to xgettext. -XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ - -# This is the copyright holder that gets inserted into the header of the -# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding -# package. (Note that the msgstr strings, extracted from the package's -# sources, belong to the copyright holder of the package.) Translators are -# expected to transfer the copyright for their translations to this person -# or entity, or to disclaim their copyright. The empty string stands for -# the public domain; in this case the translators are expected to disclaim -# their copyright. -COPYRIGHT_HOLDER = - -# This is the email address or URL to which the translators shall report -# bugs in the untranslated strings: -# - Strings which are not entire sentences, see the maintainer guidelines -# in the GNU gettext documentation, section 'Preparing Strings'. -# - Strings which use unclear terms or require additional context to be -# understood. -# - Strings which make invalid assumptions about notation of date, time or -# money. -# - Pluralisation problems. -# - Incorrect English spelling. -# - Incorrect formatting. -# It can be your email address, or a mailing list address where translators -# can write to without being subscribed, or the URL of a web page through -# which the translators can contact you. -MSGID_BUGS_ADDRESS = project-kimchi@googlegroups.com - -# This is the list of locale categories, beyond LC_MESSAGES, for which the -# message catalogs shall be used. It is usually empty. -EXTRA_LOCALE_CATEGORIES = diff --git a/plugins/kimchi/po/POTFILES.in b/plugins/kimchi/po/POTFILES.in deleted file mode 100644 index 92eef1e..0000000 --- a/plugins/kimchi/po/POTFILES.in +++ /dev/null @@ -1,3 +0,0 @@ -# List of source files which contain translatable strings. -i18n.py -ui/pages/*.tmpl diff --git a/plugins/kimchi/po/de_DE.po b/plugins/kimchi/po/de_DE.po deleted file mode 100644 index d3f3cc3..0000000 --- a/plugins/kimchi/po/de_DE.po +++ /dev/null @@ -1,2288 +0,0 @@ -# English translations for kimchi package. -# Copyright (C) 2013 ORGANIZATION -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2013-07-11 17:32-0400\n" -"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" -"Language-Team: English\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: de_DE\n" -"Generated-By: pygettext.py 1.5\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "" - -msgid "Unknown \"_cap\" specified" -msgstr "" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "Fehler beim Abrufen von Blockeinheiten. Details: %(err)s" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "Fehler beim Abrufen von Blockeinheitinformationen f��r %(device)s." - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "Distro-Datei konnte nicht gefunden werden: %(filename)s" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "" -"Distro-Datei konnte nicht analysiert werden: %(filename)s. Stellen Sie " -"sicher, dass es sich um eine JSON-Datei handelt." - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "Fehler beim Anmelden bei iSCSI-Hostziel %(portal)s. Details: %(err)s" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "Anmeldung bei iSCSI-Host %(host)s Ziel %(target)s nicht m��glich" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "Die ISO-Datei %(filename)s ist nicht bootf��hig" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "Die ISO-Datei %(filename)s hat keinen g��ltigen El Torito-Bootsatz" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "Ung��ltiger El Torito-Pr��feintrag in ISO-Datei %(filename)s" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "Ung��ltiger El Torito-Boot-Indikator in ISO-Datei %(filename)s" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "" -"Unerwarteter Datentr��gertyp f��r Prim��rdatentr��ger in ISO-Datei %(filename)s" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "" -"Ung��ltiges Format beim Lesen des Datentr��gerdeskriptors in ISO-Datei %" -"(filename)s" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" -"Der Hypervisor hat nicht die Berechtigung, die ISO-Datei %(filename)s zu " -"verwenden. Verschieben Sie sie entweder nach /var/lib/libvirt oder setzen " -"Sie, sofern m��glich, die Suchberechtigung auf Dateizugriffssteuerungslisten " -"f��r den Benutzer '%(user)s' oder f��gen Sie '%(user)s' der ISO-Pfadgruppe " -"hinzu oder (nicht empfohlen) 'chmod -R o+x 'path_to_iso'. Details: %(err)s" - -msgid "An error occurred when probing image OS information." -msgstr "" - -msgid "No OS information found in given image." -msgstr "" - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "Virtuelle Maschine %(name)s ist bereits vorhanden" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "Virtuelle Maschine %(name)s ist nicht vorhanden" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "" -"Screenshot f��r gestoppte virtuelle Maschine %(name)s konnte nicht abgerufen " -"werden" - -msgid "Remote ISO image is not supported by this server." -msgstr "Fernes ISO-Image wird von diesem Server nicht unterst��tzt." - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Virtuelle Maschine %(name)s konnte nicht erstellt werden. Details: %(err)s" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Virtuelle Maschine %(name)s konnte nicht erstellt werden. Details: %(err)s" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Virtuelle Maschine %(name)s konnte nicht abgerufen werden. Details: %(err)s" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "" -"Verbindung zur abgeschalteten Maschine %(name)s konnte nicht hergestellt " -"werden." - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "Zu ��berwachende Grafikadresse muss IPv4 oder IPv6 sein" - -msgid "Specify a template to create a virtual machine from" -msgstr "Vorlage angeben, aus der eine virtuelle Maschine erstellt werden soll" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Virtuelle Maschine %(name)s konnte nicht gestartet werden. Details: %(err)s" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Virtuelle Maschine %(name)s konnte nicht gestoppt werden. Details: %(err)s" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Virtuelle Maschine %(name)s konnte nicht gel��scht werden. Details: %(err)s" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Virtuelle Maschine %(name)s konnte nicht umbenannt werden. Details: %(err)s" - -msgid "User name list must be an array" -msgstr "" - -msgid "User name must be a string" -msgstr "Netzname muss eine Zeichenfolge sein" - -msgid "Group name list must be an array" -msgstr "" - -msgid "Group name must be a string" -msgstr "Netzname muss eine Zeichenfolge sein" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "Benutzer '%(users)s' ist nicht vorhanden." - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "Benutzer '%(groups)s' ist nicht vorhanden." - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Virtuelle Maschine %(name)s konnte nicht gestoppt werden. Details: %(err)s" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Virtuelle Maschine %(name)s konnte nicht gestartet werden. Details: %(err)s" - -msgid "The guest console password must be a string." -msgstr "" - -msgid "The life time for the guest console password must be a number." -msgstr "" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" - -msgid "\"name\" should be a device name string" -msgstr "" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "" -"Schnittstelle %(iface)s ist in virtueller Maschine %(name)s nicht vorhanden" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "" -"Das f��r die virtuelle Maschine %(name)s angegebene Netz %(network)s ist " -"nicht vorhanden" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "Unterst��tzter Schnittstellentyp einer virtuellen Maschine ist nur Netz" - -msgid "Network name for virtual machine interface must be a string" -msgstr "" -"Netzname f��r Schnittstelle einer virtuellen Maschine muss eine Zeichenfolge " -"sein" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "" -"Ung��ltige Netzmodellkarte f��r Schnittstelle einer virtuellen Maschine " -"angegeben" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "" -"Geben Sie Typ und Netz an, um eine neue Schnittstelle f��r eine virtuelle " -"Maschine hinzuzuf��gen" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "Vorlage %(name)s ist bereits vorhanden" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "" -"Das f��r Vorlage %(template)s angegebene Netz '%(network)s' ist nicht " -"vorhanden" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "" -"Der f��r Vorlage %(template)s angegebene Speicherpool '%(pool)s' ist nicht " -"vorhanden" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "" -"Der f��r Vorlage %(template)s angegebene Speicherpool '%(pool)s' ist nicht " -"aktiv" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "Ung��ltiger Parameter '%(param)s' f��r CD-ROM angegeben." - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "" -"Das f��r Vorlage %(template)s angegebene Netz %(network)s ist nicht aktiv" - -msgid "Template name must be a string" -msgstr "Vorlagenname muss eine Zeichenfolge sein" - -msgid "Template icon must be a path to the image" -msgstr "Vorlagensymbol muss ein Pfad zum Image sein" - -msgid "Template distribution must be a string" -msgstr "Vorlagenverteilung muss eine Zeichenfolge sein" - -msgid "Template distribution version must be a string" -msgstr "Vorlagenverteilungsversion muss eine Zeichenfolge sein" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "Die Anzahl der CPUs muss eine Ganzzahl sein" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "Speicherkapazit��t (MB) muss eine Ganzzahl gr����er als 512 sein" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "Vorlagen-CD-ROM muss eine lokale oder ferne ISO-Datei sein" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "Ung��ltiger Speicherpool-URI %(value)s f��r Vorlage angegeben" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "Geben Sie ein ISO-Image als CD-ROM an, um eine Vorlage zu erstellen" - -msgid "All networks for the template must be specified in a list." -msgstr "Alle Netze f��r die Vorlage m��ssen in einer Liste angegeben werden." - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "" -"Vorlage kann aufgrund des folgenden Fehlers nicht erstellt werden: %(err)s" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "" -"Vorlage kann aufgrund des folgenden Fehlers nicht gel��scht werden: %(err)s" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "" - -msgid "Template base image must be a valid local image file" -msgstr "Vorlagen-CD-ROM muss eine lokale oder ferne ISO-Datei sein" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "Speicherpool %(name)s ist bereits vorhanden" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "Speicherpool %(name)s ist nicht vorhanden" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "Geben Sie %(item)s an, um den Speicherpool %(name)s zu erstellen" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "Aktiver Speicherpool %(name)s konnte nicht gel��scht werden" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "Speicherpools konnten nicht aufgelistet werden. Details: %(err)s" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "Speicherpool %(name)s konnte nicht erstellt werden. Details: %(err)s" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "" -"Anzahl der Speicherdatentr��ger im Speicherpool %(name)s konnte nicht " -"abgerufen werden. Details: %(err)s" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "Speicherpool %(name)s konnte nicht aktiviert werden. Details: %(err)s" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "" -"Speicherpool %(name)s konnte nicht inaktiviert werden. Details: %(err)s" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "Speicherpool %(name)s konnte nicht gel��scht werden. Details: %(err)s" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "" -"NFS-Pool konnte nicht erstellt werden, weil Exportpfad %(path)s beim Mounten " -"blockieren kann" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "" -"NFS-Pool konnte nicht erstellt werden, weil das Mounten des Exportpfads%" -"(path)s fehlgeschlagen ist" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "Nicht unterst��tzter Speicherpooltyp: %(type)s" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" - -msgid "Storage pool path must be a string" -msgstr "Speicherpoolpfad muss eine Zeichenfolge sein" - -msgid "Storage pool host must be a IP or hostname" -msgstr "Speicherpoolhost muss eine IP oder ein Hostname sein" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" - -msgid "Storage pool devices parameter must be a list" -msgstr "Einheitenparameter des Speicherpools muss eine Liste sein" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "Ziel-IQN eines iSCSI-Pools muss eine Zeichenfolge sein" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "" -"Port eines fernen Speicherservers muss eine Ganzzahl zwischen 1 und 65535 " -"sein" - -msgid "iSCSI target username must be a string" -msgstr "" - -msgid "iSCSI target password must be a string" -msgstr "" - -msgid "Specify name and type to create a storage pool" -msgstr "Geben Sie Name und Typ an, um einen Speicherpool zu erstellen" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "" -"%(disk)s ist keine g��ltige Platte/Partition. Sie konnte nicht hinzugef��gt " -"werden zum Pool %(pool)s." - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "" -"Die Parameterplatten k��nnen nur f��r den logischen Speicherpool aktualisiert " -"werden." - -msgid "The SCSI host adapter name must be a string." -msgstr "Der Name des SCSI-Hostadapters muss eine Zeichenfolge sein." - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "Der Speicherpool kimchi_isos ist f��r die interne Verwendung reserviert" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"Der NFS-Speicherpool %(name)s konnte nicht aktiviert werden. NFS-Server %" -"(server)s ist nicht erreichbar." - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"Der NFS-Speicherpool %(name)s konnte nicht inaktiviert werden. NFS-Server %" -"(server)s ist nicht erreichbar." - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "" -"Pool %(name)s konnte nicht inaktiviert werden, weil er einigen Vorlagen " -"zugeordnet ist" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "" -"Pool %(name)s konnte nicht gel��scht werden, weil er einigen Vorlagen " -"zugeordnet ist" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "" -"Eine Datentr��gergruppe mit dem Namen '%(name)s' ist bereits vorhanden. " -"W��hlen Sie einen anderen Namen aus, um den logischen Pool zu erstellen." - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "" -"Datenbank mit Tiefenscaninformationen kann aufgrund des folgenden Fehlers " -"nicht aktualisiert werden: %(err)s" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "Speicherdatentr��ger %(name)s ist bereits vorhanden" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "" -"Speicherdatentr��ger %(name)s ist nicht im Speicherpool %(pool)s vorhanden" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "Geben Sie %(item)s an, um Speicherdatentr��ger %(volume)s zu erstellen" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "" -"Speicherdatentr��ger konnten nicht aufgelistet werden, weil Speicherpool %" -"(pool)s nicht aktiv ist" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "" -"Speicherdatentr��ger %(name)s konnte nicht in Speicherpool %(pool)s erstellt " -"werden. Details: %(err)s" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "" -"Speicherdatentr��ger konnten nicht in Speicherpool %(pool)s aufgelistet " -"werden. Details: %(err)s" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "" -"Speicherdatentr��ger %(name)s konnten nicht bereinigt werden. Details: %(err)s" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "" -"Speicherdatentr��ger %(name)s konnte nicht gel��scht werden. Details: %(err)s" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "" -"Gr����e des Speicherdatentr��gers %(name)s konnte nicht ge��ndert werden. " -"Details: %(err)s" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "" -"Speichertyp %(type)s unterst��tzt nicht das Erstellen und L��schen von " -"Datentr��gern" - -msgid "Storage volume name must be a string" -msgstr "Name des Speicherdatentr��gers muss eine Zeichenfolge sein" - -msgid "Storage volume allocation must be an integer number" -msgstr "Zuordnung des Speicherdatentr��gers muss eine Ganzzahl sein" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" - -msgid "Storage volume requires a volume name" -msgstr "Speicherdatentr��ger erfordert einen Datentr��gernamen" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "" -"Datenbank mit Datentr��gerinformationen kann aufgrund des folgenden Fehlers " -"nicht aktualisiert werden: %(err)s" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "" - -msgid "Storage volume capacity must be an integer number." -msgstr "" - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "" - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "Schnittstelle %(name)s ist nicht vorhanden" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "Netz %(name)s ist bereits vorhanden" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "Netz %(name)s ist nicht vorhanden" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "" -"Das f��r das Netz %(network)s angegebene Teilnetz %(subnet)s ist nicht g��ltig." - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "" -"Geben Sie eine Netzschnittstelle an, um ��berbr��cktes Netz %(name)s zu " -"erstellen" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "Aktives Netz %(name)s konnte nicht gel��scht werden" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "" -"Die f��r das Netz %(network)s angegebene Schnittstelle %(iface)s wird bereits " -"verwendet" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "Schnittstelle sollte blo��es NIC, Bonding oder Br��ckeneinheit sein." - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "Netz %(name)s konnte nicht erstellt werden. Details: %(err)s" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "Es konnte keine freie IP-Adresse f��r Netz '%(name)s' gefunden werden" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "Unterst��tzte Netztypen sind Isoliert, NAT und Br��cke" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "" -"Teilnetz des Netzes muss eine Zeichenfolge mit IP-Adresse und Pr��fix oder " -"Netzmaske sein" - -msgid "Network interface must be a string" -msgstr "Netzschnittstelle muss eine Zeichenfolge sein" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "Netz-VLAN-ID muss eine Ganzzahl zwischen 1 und 4094 sein" - -msgid "Specify name and type to create a Network" -msgstr "Geben Sie Name und Typ an, um ein Netz zu erstellen" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" -"Netz %(name)s konnte nicht inaktiviert werden. Es sind einige virtuellen " -"Maschinen %(vms)s und/oder Vorlagen mit diesem Netz verkn��pft." - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" -"Netz %(name)s konnte nicht inaktiviert werden. Es sind einige virtuellen " -"Maschinen %(vms)s und/oder Vorlagen mit diesem Netz verkn��pft." - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "Br��ckeneinheit %(name)s kann nicht die Trunkeinheit eines VLAN sein." - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "Schnittstelle %(iface)s konnte nicht aktiviert werden: %(err)s." - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "" -"Schnittstelle %(iface)s konnte nicht aktiviert werden. Bitte ��berpr��fen Sie " -"den Status der physischen Verbindung." - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "Debugbericht %(name)s ist nicht vorhanden" - -msgid "Debug report tool not found in system" -msgstr "Debugberichtstool nicht im System gefunden" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "Debugbericht %(name)s konnte nicht erstellt werden. Details: %(err)s." - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "Debugbericht %(name)s konnte nicht generiert werden. Details: %(err)s" - -msgid "You should give a name for the debug report file." -msgstr "" - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "" -"Eine Datentr��gergruppe mit dem Namen '%(name)s' ist bereits vorhanden. " -"W��hlen Sie einen anderen Namen aus, um den logischen Pool zu erstellen." - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "Speicherserver %(server)s wurde nicht von Kimchi verwendet" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "Distro '%(name)s' ist nicht vorhanden" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "Partition %(name)s ist nicht im Host vorhanden" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "" -"Hostmaschine konnte nicht heruntergefahren werden, weil virtuelle Maschinen " -"ausgef��hrt werden" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "" -"Hostmaschine konnte nicht neu gestartet werden, weil virtuelle Maschinen " -"ausgef��hrt werden" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "Knoteneinheit '%(name)s' nicht gefunden" - -msgid "Conflicting flag filters specified." -msgstr "" - -msgid "No packages marked for update" -msgstr "Keine Pakete f��r Aktualisierung markiert" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "Paket %(name)s ist nicht f��r Aktualisierung markiert." - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "" -"Fehler beim Abrufen von Paketen, die f��r die Aktualsierung markiert sind. " -"Details: %(err)s" - -msgid "There is no compatible package manager for this system." -msgstr "Es gibt keinen kompatiblen Paketmanager f��r dieses System." - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "Ung��ltiger URI %(uri)s" - -msgid "Unable to choose a virtual machine name" -msgstr "" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "Ung��ltiger Speichertyp. Unterst��tzte Typen: 'cdrom'" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" - -msgid "Only CDROM path can be update." -msgstr "" - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "Fehler beim Erstellen einer neuen Speichereinheit: %(error)s" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "Fehler beim Aktualisieren einer Speichereinheit: %(error)s" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "Fehler beim Entfernen einer Speichereinheit: %(error)s" - -msgid "Do not support IDE device hot plug" -msgstr "" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "" -"Geben Sie Typ und Pfad an, um einen neuen Datentr��ger f��r eine virtuelle " -"Maschine hinzuzf��gen" - -msgid "Specify path to update virtual machine disk" -msgstr "" -"Geben Sie einen Pfad an, um die Platte der virtuellen Maschine zu " -"aktualisieren" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" - -msgid "Volume already in use by other virtual machine." -msgstr "" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "" -"Geben Sie Typ und Pfad an, um einen neuen Datentr��ger f��r eine virtuelle " -"Maschine hinzuzf��gen" - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" - -msgid "YUM Repository ID must be one word only string." -msgstr "" -"YUM-Repository-ID darf nur ein aus einer Zeichenfolge bestehendes Wort sein." - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "Repository-URL muss ein http://-, ftp://- oder file://-URL sein." - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "" -"Repository-Konfiguration ist ein W��rterbuch mit bestimmten Werten " -"hinsichtlich Repository-Typ." - -msgid "Distribution to DEB repository must be a string" -msgstr "Verteilung an DEB-Repository muss eine Zeichenfolge sein" - -msgid "Components to DEB repository must be listed in a array" -msgstr "Komponenten f��r DEB-Repository m��ssen in einem Array aufgelistet sein" - -msgid "Components to DEB repository must be a string" -msgstr "Komponenten f��r DEB-Repository m��ssen eine Zeichenfolge sein" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "Name des YUM-Repositorys muss eine Zeichenfolge sein." - -msgid "GPG check must be a boolean value." -msgstr "GPG-Pr��fung muss ein boolescher Wert sein." - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "GPG-Schl��ssel muss ein URL sein, der auf die ASCII-Armor-Datei zeigt." - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "Repository %(repo_id)s konnte nicht aktualisiert werden." - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "Repository %(repo_id)s ist nicht vorhanden." - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "Repository-Verwaltungstool wurde f��r Ihr System nicht erkannt." - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "Repository %(repo_id)s ist bereits aktiviert." - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "Repository %(repo_id)s ist bereits inaktiviert." - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "Repository %(repo_id)s konnte nicht entfernt werden." - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "" -"Repository-Konfigurationsdatei %(repo_file)s konnte nicht geschrieben werden" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "" -"Geben Sie die Repository-Verteilung an, um ein DEB-Repository zu erstellen." - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "Repository %(repo_id)s konnte nicht aktiviert werden." - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "Repository %(repo_id)s konnte nicht inaktiviert werden." - -msgid "YUM Repository ID already exists" -msgstr "YUM-Repository-ID ist bereits vorhanden" - -msgid "YUM Repository name must be a string" -msgstr "YUM-Repository-Name muss eine Zeichenfolge sein" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "Repositorys konnten nicht aufgelistet werden. Details: '%(err)s'" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "" -"Repository-Informationen konnten nicht abgerufen werden. Details: '%(err)s'" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "Repository konnte nicht hinzugef��gt werden. Details: '%(err)s'" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "Repository konnte nicht entfernt werden. Details: '%(err)s'" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" - -msgid "The number of vCPUs is too large for this system." -msgstr "" - -msgid "Invalid vCPU/topology combination." -msgstr "" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "" - -msgid "ERROR CODE" -msgstr "FEHLERCODE" - -msgid "REASON" -msgstr "GRUND" - -msgid "STACK" -msgstr "STACK" - -msgid "Go to Homepage" -msgstr "Gehe zu Homepage" - -msgid "Create a New Virtual Machine" -msgstr "Neue virtuelle Maschine erstellen" - -msgid "Virtual Machine Name" -msgstr "Name der virtuellen Maschine" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "" -"Der f��r die Kennzeichnung der virtuellen Maschine verwendete Name. Falls er " -"ausgelassen wird, wird ein Name anhand der verwendeten Vorlage ausgew��hlt." - -msgid "Template" -msgstr "Vorlage" - -msgid "Please create a template first." -msgstr "Erstellen Sie zun��chst eine Vorlage." - -msgid "Create a Template" -msgstr "Vorlage erstellen" - -msgid "Please choose a template." -msgstr "W��hlen Sie eine Vorlage aus." - -msgid "OS" -msgstr "BS" - -msgid "OS Version" -msgstr "BS-Version" - -msgid "CPUS" -msgstr "CPUS" - -msgid "Memory" -msgstr "Speicher" - -msgid "Create" -msgstr "Erstellen" - -msgid "Creating..." -msgstr "" - -msgid "Cancel" -msgstr "Abbrechen" - -msgid "Edit Guest" -msgstr "Gast bearbeiten" - -msgid "General" -msgstr "Allgemein" - -msgid "Storage" -msgstr "Speicher" - -msgid "Interface" -msgstr "Schnittstelle" - -msgid "Permission" -msgstr "Version" - -msgid "Host PCI Device" -msgstr "" - -msgid "Snapshot" -msgstr "" - -msgid "Name" -msgstr "Name" - -msgid "CPUs" -msgstr "CPUs" - -msgid "Memory (MB)" -msgstr "Speicher" - -msgid "Icon" -msgstr "Symbol" - -msgid "Device" -msgstr "Einheitenname" - -msgid "Path" -msgstr "NFS-Pfad" - -msgid "Network" -msgstr "Netz" - -msgid "Type" -msgstr "Typ" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "" - -msgid "Selected system users and groups" -msgstr "" - -msgid "User" -msgstr "" - -msgid "All" -msgstr "Alle" - -msgid "To Add" -msgstr "" - -msgid "Added" -msgstr "" - -msgid "filter" -msgstr "" - -msgid "Product" -msgstr "" - -msgid "Vendor" -msgstr "Anbieter" - -msgid "Created" -msgstr "" - -msgid "Save" -msgstr "Speichern" - -msgid "Replace" -msgstr "Ersetzen" - -msgid "Detach" -msgstr "Abh��ngen" - -msgid "revert" -msgstr "" - -msgid "Start" -msgstr "Starten" - -msgid "Reset" -msgstr "Zur��cksetzen" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "" - -msgid "Actions" -msgstr "Aktionen" - -msgid "Connect" -msgstr "Verbinden" - -msgid "Clone" -msgstr "" - -msgid "Edit" -msgstr "Bearbeiten" - -msgid "Shut Down" -msgstr "Herunterfahren" - -msgid "Delete" -msgstr "L��schen" - -msgid "CPU" -msgstr "CPU" - -msgid "Disk I/O" -msgstr "Platten-E/A" - -msgid "Network I/O" -msgstr "Netz-E/A" - -msgid "Livetile" -msgstr "Live Tile" - -msgid "No guests found." -msgstr "Keine G��ste gefunden." - -msgid "Add a Storage Device to VM" -msgstr "Speichereinheit zur virtuellen Maschine hinzuf��gen" - -msgid "Device Type" -msgstr "Einheitentyp" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "Der Einheitentyp. Derzeit wird nur \"cdrom\" unterst��tzt." - -msgid "Storage Pool" -msgstr "Speicherpool" - -msgid "Storage pool which volume located in" -msgstr "Speicherpoolpfad muss eine Zeichenfolge sein" - -msgid "Storage Volume" -msgstr "Speicherpoolname" - -msgid "Storage volume to be attached" -msgstr "Name des Speicherdatentr��gers muss eine Zeichenfolge sein" - -msgid "File Path" -msgstr "Dateipfad" - -msgid "The ISO file path in the server for CDROM." -msgstr "Der ISO-Dateipfad auf dem Server f��r die CD-ROM." - -msgid "Attach" -msgstr "Anh��ngen" - -msgid "Shut down" -msgstr "Herunterfahren" - -msgid "Restart" -msgstr "Erneut starten" - -msgid "Basic Information" -msgstr "Basisinformationen" - -msgid "OS Distro" -msgstr "BS-Distro" - -msgid "OS Code Name" -msgstr "BS-Codename" - -msgid "Processor" -msgstr "Prozessor" - -msgid "CPU(s)" -msgstr "" - -msgid "System Statistics" -msgstr "Systemstatistik" - -msgid "Software Updates" -msgstr "Software-Updates" - -msgid "Update Progress" -msgstr "Aktualisierungsfortschritt" - -msgid "Repositories" -msgstr "Repositorys" - -msgid "Debug Reports" -msgstr "Debugberichte" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "" -"Der Benutzername oder das Kennwort, den bzw. das Sie eingegeben haben, ist " -"falsch. Versuchen Sie es bitte erneut." - -msgid "This field is required." -msgstr "Dieses Feld ist erforderlich." - -msgid "Log in" -msgstr "Anmelden" - -msgid "Logging in..." -msgstr "Wird angemeldet..." - -msgid "Host" -msgstr "Host" - -msgid "Guests" -msgstr "G��ste" - -msgid "Templates" -msgstr "Vorlagen" - -msgid "Failed to get application configuration" -msgstr "Anwendungskonfiguration konnte nicht abgerufen werden" - -msgid "This is not a valid Linux path" -msgstr "Dies ist kein g��ltiger Linux-Pfad" - -msgid "This is not a valid URL." -msgstr "Dies ist kein g��ltiger URL." - -msgid "No such data available." -msgstr "Keine solchen Daten verf��gbar." - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" -"Hostsystem kann nicht kontaktiert werden. Pr��fen Sie, ob das Hostsystem " -"aktiv ist und obNetzkonnektivit��t besteht. HTTP-Anforderungsantwort %1. " - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "L��schbest��tigung" - -msgid "OK" -msgstr "OK" - -msgid "Confirm" -msgstr "Best��tigen" - -msgid "Warning" -msgstr "Warnung" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "Wird geladen..." - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "Wiederholen" - -msgid "Detailed message:" -msgstr "Detaillierte Meldung:" - -msgid "No ISO found" -msgstr "" - -msgid "This is not a valid ISO file." -msgstr "Dies ist keine g��ltige ISO-Datei." - -msgid "This may take a long time. Do you want to continue?" -msgstr "Dies wird einige Zeit dauern. M��chten Sie fortfahren?" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "Hiermit wird die Vorlage dauerhaft gel��scht. M��chten Sie fortfahren?" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "" -"System konnte nicht heruntergefahren werden, weil einige virtuellen " -"Maschinen ausgef��hrt werden!" - -msgid "Max:" -msgstr "Max:" - -msgid "Utilization" -msgstr "Auslastung" - -msgid "Available" -msgstr "Verf��gbar" - -msgid "Read Rate" -msgstr "Leserate" - -msgid "Write Rate" -msgstr "Schreibrate" - -msgid "Received" -msgstr "Empfangen" - -msgid "Sent" -msgstr "Gesendet" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"Durch das Herunterfahren oder Neustarten des Hosts k��nnen ungesicherte " -"Arbeiten verloren gehen. M��chten Sie mit dem Herunterfahren/Neustarten " -"fortfahren?" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"Repository wird dauerhaft entfernt und kann nicht wiederhergestellt werden. " -"M��chten Sie fortfahren?" - -msgid "ID" -msgstr "ID" - -msgid "Base URL" -msgstr "Basis-URL" - -msgid "Is Mirror" -msgstr "Ist Spiegel" - -msgid "URL Args" -msgstr "URL-Args" - -msgid "Enabled" -msgstr "Aktiviert" - -msgid "GPG Check" -msgstr "GPG-Pr��fung" - -msgid "GPG Key" -msgstr "GPG-Schl��ssel" - -msgid "Add" -msgstr "Hinzuf��gen" - -msgid "Remove" -msgstr "Entfernen" - -msgid "Enable" -msgstr "Aktivieren" - -msgid "Disable" -msgstr "Inaktivieren" - -msgid "Package Name" -msgstr "Paketname" - -msgid "Version" -msgstr "Version" - -msgid "Architecture" -msgstr "Architektur" - -msgid "Repository" -msgstr "Repository" - -msgid "Update All" -msgstr "Alle aktualisieren" - -msgid "Updating..." -msgstr "Wird aktualisiert..." - -msgid "Failed to retrieve packages update information." -msgstr "" - -msgid "Failed to update package(s)." -msgstr "Pakete konnten nicht aktualisiert werden." - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"Debugbericht wird dauerhaft entfernt und kann nicht wiederhergestellt " -"werden. M��chten Sie fortfahren?" - -msgid "Generated Time" -msgstr "Generierte Zeit" - -msgid "Generate" -msgstr "Generieren" - -msgid "Generating..." -msgstr "Wird generiert..." - -msgid "Rename" -msgstr "Umbenennen" - -msgid "Download" -msgstr "Herunterladen" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "" -"Berichtsname darf nur Buchstaben, Zahlen und/oder Bindestriche ('-') " -"enthalten." - -msgid "Pending..." -msgstr "Wird geladen..." - -msgid "Report name is the same as the original one." -msgstr "" - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "" -"Hiermit werden die virtuelle Maschine und deren virtuellen Platten gel��scht. " -"Diese Operation kann nicht r��ckg��ngig gemacht werden. M��chten Sie fortfahren?" - -msgid "Power off Confirmation" -msgstr "L��schbest��tigung" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" - -msgid "Reset Confirmation" -msgstr "L��schbest��tigung" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" - -msgid "Shut Down Confirmation" -msgstr "L��schbest��tigung" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "Hiermit wird die Vorlage dauerhaft gel��scht. M��chten Sie fortfahren?" - -msgid "Virtual Machine delete Confirmation" -msgstr "" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" -"Diese CD-ROM wird dauerhaft abgeh��ngt und Sie k��nnen sie neu anh��ngen. " -"M��chten Sie mit dem Abh��ngen fortfahren?" - -msgid "Attaching..." -msgstr "Wird angeh��ngt..." - -msgid "Replacing..." -msgstr "Wird ersetzt..." - -msgid "Successfully attached!" -msgstr "Erfolgreich angeh��ngt!" - -msgid "Successfully replaced!" -msgstr "Erfolgreich ersetzt!" - -msgid "Successfully detached!" -msgstr "Erfolgreich abgeh��ngt!" - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" - -msgid "interface:" -msgstr "" - -msgid "address:" -msgstr "" - -msgid "link_type:" -msgstr "" - -msgid "block:" -msgstr "" - -msgid "drive_type:" -msgstr "" - -msgid "model:" -msgstr "" - -msgid "Affected devices:" -msgstr "" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "Die VLAN-ID muss zwischen 1 und 4094 liegen." - -msgid "unavailable" -msgstr "nicht verf��gbar" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" -"Diese Aktion unterbricht die Netzkonnektivit��t f��r jede virtuelle Maschine, " -"die von diesem Netz abh��ngt." - -msgid "Create a network" -msgstr "Netz erstellen" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"Dieser Speicherpool ist nicht permanent. Durch diese Aktion wird er nicht " -"inaktiviert, sondern permanent gel��scht. M��chten Sie fortfahren?" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "" -"Hiermit wird der Speicherpool dauerhaft gel��scht. M��chten Sie fortfahren?" - -msgid "This storage pool is empty." -msgstr "Dieser Speicherpool ist leer." - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" -"Hiermit wird Ihre Platte formatiert und Sie verlieren s��mtliche Daten " -"darauf. Sind Sie sicher, dass Sie fortfahren m��chten? " - -msgid "SCSI Fibre Channel" -msgstr "SCSI-Fibre Channel" - -msgid "No SCSI adapters found." -msgstr "Keine SCSI-Adapter gefunden." - -msgid "Loading iSCSI targets..." -msgstr "" - -msgid "No iSCSI found. Please input one." -msgstr "" - -msgid "Failed to load iSCSI targets." -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "Der Speicherpoolname darf nicht leer sein." - -msgid "The storage pool path can not be blank." -msgstr "Der Speicherpoolpfad darf nicht leer sein." - -msgid "NFS server mount path can not be blank." -msgstr "Der Mountpfad des NFS-Servers darf nicht leer sein." - -msgid "Invalid NFS mount path." -msgstr "Ung��ltiger NFS-Mountpfad." - -msgid "No logical device selected." -msgstr "Keine logische Einheit ausgew��hlt." - -msgid "The iSCSI target can not be blank." -msgstr "Das iSCSI-Ziel darf nicht leer sein." - -msgid "Server name can not be blank." -msgstr "Servername darf nicht leer sein." - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "" - -msgid "Looking for available partitions ..." -msgstr "Es wird nach verf��gbaren Partitionen gesucht..." - -msgid "No available partitions found." -msgstr "Keine g��ltigen Partitionen gefunden." - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"Dieser Speicherpool ist nicht permanent. Durch diese Aktion wird er nicht " -"inaktiviert, sondern permanent gel��scht. M��chten Sie fortfahren?" - -msgid "Unable to retrieve partitions information." -msgstr "" -"Repository-Informationen konnten nicht abgerufen werden. Details: '%(err)s'" - -msgid "In progress..." -msgstr "" - -msgid "Failed!" -msgstr "" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" - -msgid "Disk pool or volume cannot be blank." -msgstr "Der Speicherpoolname darf nicht leer sein." - -msgid "Filter" -msgstr "" - -msgid "Network Name" -msgstr "Netzname" - -msgid "State" -msgstr "Status" - -msgid "Network Type" -msgstr "Netztyp" - -msgid "Address Space" -msgstr "Adressraum" - -msgid "Name should not contain '/' and '\"'." -msgstr "Ung��ltiger Speicherpoolname. Er darf nicht '/' enthalten." - -msgid "Isolated: no external network connection" -msgstr "Isolatiert: keine physisische Netzverbindung" - -msgid "NAT: outbound physical network connection only" -msgstr "NAT: nur ausgehende physische Netzverbindung" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "" -"��berbr��ckt: Virtuelle Maschinen sind direkt mit physischem Netz verbunden" - -msgid "(No interfaces found)" -msgstr "" - -msgid "Destination" -msgstr "Ziel:" - -msgid "Enable VLAN" -msgstr "Virtuelles LAN (VLAN) aktivieren:" - -msgid "VLAN ID" -msgstr "VLAN-ID:" - -msgid "Stop" -msgstr "Stoppen" - -msgid "Generate a New Debug Report" -msgstr "Neuen Debugbericht erstellen" - -msgid "Report Name" -msgstr "Berichtsname" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" -"Der Name, mit dem der Bericht gekennzeichnet wird. Falls er ausgelassen " -"wird, wird ein Name basierend auf der aktuellen Zeit ausgew��hlt. Der Name " -"darf Buchstaben, Zahlen und Bindestriche (\"-\") enthalten." - -msgid "Rename a Debug Report" -msgstr "Neuen Debugbericht erstellen" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" -"Der Name, mit dem der Bericht gekennzeichnet wird. Falls er ausgelassen " -"wird, wird ein Name basierend auf der aktuellen Zeit ausgew��hlt. Der Name " -"darf Buchstaben, Zahlen und Bindestriche (\"-\") enthalten." - -msgid "Submit" -msgstr "" - -msgid "Add a Repository" -msgstr "Repository hinzuf��gen" - -msgid "Identifier" -msgstr "Kennung" - -msgid "Single word, unique identifier for the repository." -msgstr "Einzelnes Wort, eindeutige Kennung f��r das Repository." - -msgid "Textual name for the repository." -msgstr "Textname f��r das Repository." - -msgid "URL" -msgstr "URL" - -msgid "Required Field" -msgstr "Erforderliches Feld" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "URL zum Repository. Unterst��tzte Protokolle sind http, ftp und file." - -msgid "Repository is a mirror" -msgstr "Repository ist ein Spiegel." - -msgid "Distribution" -msgstr "Verteilung" - -msgid "Distribution of the DEB repository." -msgstr "Verteilung des DEB-Repositorys." - -msgid "Components" -msgstr "Komponenten" - -msgid "List of components in DEB repository." -msgstr "Liste der Komponenten im DEB-Repository." - -msgid "Edit Repository" -msgstr "Repository bearbeiten" - -msgid "Mirror List URL" -msgstr "Spiegellisten-URL" - -msgid "Yes" -msgstr "Ja" - -msgid "No" -msgstr "Nein" - -msgid "Capacity" -msgstr "Kapazit��t" - -msgid "Allocated" -msgstr "Zugeordnet" - -msgid "Location" -msgstr "Position" - -msgid "Device path" -msgstr "Einheitenpfad" - -msgid "active" -msgstr "aktiv" - -msgid "inactive" -msgstr "inaktiv" - -msgid "Deactivate" -msgstr "Inaktivieren" - -msgid "Activate" -msgstr "Aktivieren" - -msgid "Add Volume" -msgstr "" - -msgid "Extend" -msgstr "" - -msgid "Undefine" -msgstr "Definition aufheben" - -msgid "Format" -msgstr "Format:" - -msgid "Allocation" -msgstr "Zuordnung:" - -msgid "Define a New Storage Pool" -msgstr "Neuen Speicherpool definieren" - -msgid "Storage Pool Name" -msgstr "Speicherpoolname" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "" -"Der Name, mit dem die Speicherpools gekennzeichnet werden. Er darf nicht " -"leer sein." - -msgid "Storage Pool Type" -msgstr "Speicherpooltyp" - -msgid "Storage Path" -msgstr "Speicherpfad" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "" -"Der Pfad des Speicherpools. Jeder Speicherpool muss einen eindeutigen Pfad " -"haben." - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "" -"Kimchi versucht, das Verzeichnis zu erstellen, wenn es noch nicht in Ihrem " -"System vorhanden ist." - -msgid "NFS Server IP" -msgstr "NFS-Server-IP" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "" -"IP oder Hostname des NFS-Servers. Diese(r) kann eingegeben oder aus dem " -"Verlauf ausgew��hlt werden." - -msgid "NFS Path" -msgstr "NFS-Pfad" - -msgid "The NFS exported path on NFS server." -msgstr "Der NFS-Exportpfad auf dem NFS-Server." - -msgid "iSCSI Server" -msgstr "iSCSI-Server" - -msgid "Server" -msgstr "Server" - -msgid "Port" -msgstr "Port" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "IP oder Hostname des iSCSI-Servers. Diese(r) darf nicht leer sein." - -msgid "Target" -msgstr "Ziel" - -msgid "The iSCSI target on iSCSI server" -msgstr "Das iSCSI-Ziel auf dem iSCSI-Server" - -msgid "Add iSCSI Authentication" -msgstr "iSCSI-Authentifizierung hinzuf��gen" - -msgid "iSCSI Authentication" -msgstr "iSCSI-Authentifizierung" - -msgid "User Name" -msgstr "Benutzername" - -msgid "Password" -msgstr "Kennwort" - -msgid "SCSI Adapter" -msgstr "SCSI-Adapter" - -msgid "Please, wait..." -msgstr "Bitte warten..." - -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - -msgid "Add Template" -msgstr "Vorlage hinzuf��gen" - -msgid "Where is the source media for this template? " -msgstr "Wo ist der Quellendatentr��ger f��r diese Vorlage?" - -msgid "Local ISO Image" -msgstr "Lokales ISO-Image" - -msgid "Local Image File" -msgstr "" - -msgid "Remote ISO Image" -msgstr "Fernes ISO-Image" - -msgid "Search ISOs" -msgstr "ISOs suchen" - -msgid "The following ISOs are available:" -msgstr "Die folgenden ISOs sind verf��gbar:" - -msgid "OS: " -msgstr "BS: " - -msgid "Version: " -msgstr "Version: " - -msgid "Size: " -msgstr "Gr����e: " - -msgid "Search more ISOs" -msgstr "Weitere ISOs suchen" - -msgid "Create Templates from Selected ISO" -msgstr "Vorlagen aus ausgew��hltem ISO erstellen" - -msgid "I want to use a specific ISO file" -msgstr "Ich m��chte eine bestimmte ISO-Datei verwenden" - -msgid "Loading default remote ISOs ..." -msgstr "Standardm����ige ferne ISOs werden geladen ..." - -msgid "Arch: " -msgstr "Arch: " - -msgid "I want to use a custom URL" -msgstr "Ich m��chte einen benutzerdefinierten URL verwenden" - -msgid "Edit Template" -msgstr "Vorlage bearbeiten" - -msgid "CDROM" -msgstr "CD-ROM" - -msgid "Image File" -msgstr "" - -msgid "Graphics" -msgstr "Grafik" - -msgid "Disk(GB)" -msgstr "" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "CPU-Anzahl" - -msgid "Manually set CPU topology" -msgstr "" - -msgid "Cores" -msgstr "" - -msgid "Threads" -msgstr "" - -msgid "No templates found." -msgstr "Keine Vorlagen gefunden." - -#~ msgid "Delete is not allowed for %(resource)s" -#~ msgstr "L��schen ist nicht zul��ssig f��r %(resource)s" - -#~ msgid "%(resource)s does not implement update method" -#~ msgstr "%(resource)s implementiert keine Aktualisierungsmethode" - -#~ msgid "Create is not allowed for %(resource)s" -#~ msgstr "Erstellen ist nicht zul��ssig f��r %(resource)s" - -#~ msgid "Unable to parse JSON request" -#~ msgstr "JSON-Anfrage konnte nicht analysiert werden" - -#~ msgid "This API only supports JSON" -#~ msgstr "Diese API unterst��tzt nur JSON" - -#~ msgid "Datastore is not initiated in the model object." -#~ msgstr "Datenspeicher wird nicht im Modellobjekt initialisiert." - -#~ msgid "Unable to start task due error: %(err)s" -#~ msgstr "" -#~ "Task kann aufgrund des folgenden Fehlers nicht gestartet werden: %(err)s" - -#~ msgid "" -#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" -#~ msgstr "" -#~ "Authentifizierung f��r Benutzer '%(username)s' fehlgeschlagen. " -#~ "[Fehlercode: %(code)s]" - -#~ msgid "You are not authorized to access Kimchi" -#~ msgstr "Sie sind nicht berechtigt, auf Kimchi zuzugreifen" - -#~ msgid "Specify %(item)s to login into Kimchi" -#~ msgstr "Geben Sie %(item)s an, um sich bei Kimchi anzumelden" - -#~ msgid "Unable to find %(item)s in datastore" -#~ msgstr "%(item)s konnten nicht im Datenspeicher gefunden werden" - -#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" -#~ msgstr "" -#~ "Zeitlimit��berschreitung beim Ausf��hren des Befehls '%(cmd)s' nach %" -#~ "(seconds)s Sekunden" - -#~ msgid "Help" -#~ msgstr "Hilfe" - -#~ msgid "About" -#~ msgstr "Informationen" - -#~ msgid "Log out" -#~ msgstr "Abmelden" - -#~ msgid "Version:" -#~ msgstr "Version:" diff --git a/plugins/kimchi/po/en_US.po b/plugins/kimchi/po/en_US.po deleted file mode 100644 index a5d0d44..0000000 --- a/plugins/kimchi/po/en_US.po +++ /dev/null @@ -1,2075 +0,0 @@ -# English translations for kimchi package. -# Copyright (C) 2013 ORGANIZATION -# Adam Litke <agl@us.ibm.com>, 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2013-07-11 17:32-0400\n" -"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" -"Language-Team: English\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: en_US\n" -"Generated-By: pygettext.py 1.5\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "" - -msgid "Unknown \"_cap\" specified" -msgstr "" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "" - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "" - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" - -msgid "An error occurred when probing image OS information." -msgstr "" - -msgid "No OS information found in given image." -msgstr "" - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "" - -msgid "Remote ISO image is not supported by this server." -msgstr "" - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "" - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "" - -msgid "Specify a template to create a virtual machine from" -msgstr "" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "" - -msgid "User name list must be an array" -msgstr "" - -msgid "User name must be a string" -msgstr "" - -msgid "Group name list must be an array" -msgstr "" - -msgid "Group name must be a string" -msgstr "" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "" - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "" - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "" - -msgid "The guest console password must be a string." -msgstr "" - -msgid "The life time for the guest console password must be a number." -msgstr "" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" - -msgid "\"name\" should be a device name string" -msgstr "" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "" - -msgid "Network name for virtual machine interface must be a string" -msgstr "" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "" - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "" - -msgid "Template name must be a string" -msgstr "" - -msgid "Template icon must be a path to the image" -msgstr "" - -msgid "Template distribution must be a string" -msgstr "" - -msgid "Template distribution version must be a string" -msgstr "" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "" - -msgid "All networks for the template must be specified in a list." -msgstr "" - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "" - -msgid "Template base image must be a valid local image file" -msgstr "" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" - -msgid "Storage pool path must be a string" -msgstr "" - -msgid "Storage pool host must be a IP or hostname" -msgstr "" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" - -msgid "Storage pool devices parameter must be a list" -msgstr "" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "" - -msgid "iSCSI target username must be a string" -msgstr "" - -msgid "iSCSI target password must be a string" -msgstr "" - -msgid "Specify name and type to create a storage pool" -msgstr "" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "" - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "" - -msgid "The SCSI host adapter name must be a string." -msgstr "" - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "" - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "" - -msgid "Storage volume name must be a string" -msgstr "" - -msgid "Storage volume allocation must be an integer number" -msgstr "" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" - -msgid "Storage volume requires a volume name" -msgstr "" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "" - -msgid "Storage volume capacity must be an integer number." -msgstr "" - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "" - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "" - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "" - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "" - -msgid "Network interface must be a string" -msgstr "" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "" - -msgid "Specify name and type to create a Network" -msgstr "" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "" - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "" - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "" - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "" - -msgid "Debug report tool not found in system" -msgstr "" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "" - -msgid "You should give a name for the debug report file." -msgstr "" - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "" - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "" - -msgid "Conflicting flag filters specified." -msgstr "" - -msgid "No packages marked for update" -msgstr "" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "" - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "" - -msgid "There is no compatible package manager for this system." -msgstr "" - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "" - -msgid "Unable to choose a virtual machine name" -msgstr "" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" - -msgid "Only CDROM path can be update." -msgstr "" - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "" - -msgid "Do not support IDE device hot plug" -msgstr "" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "" - -msgid "Specify path to update virtual machine disk" -msgstr "" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" - -msgid "Volume already in use by other virtual machine." -msgstr "" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "" - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" - -msgid "YUM Repository ID must be one word only string." -msgstr "" - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "" - -msgid "Distribution to DEB repository must be a string" -msgstr "" - -msgid "Components to DEB repository must be listed in a array" -msgstr "" - -msgid "Components to DEB repository must be a string" -msgstr "" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "" - -msgid "GPG check must be a boolean value." -msgstr "" - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "" - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "" - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "" - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "" - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "" - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "" - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "" - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "" - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "" - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "" - -msgid "YUM Repository ID already exists" -msgstr "" - -msgid "YUM Repository name must be a string" -msgstr "" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" - -msgid "The number of vCPUs is too large for this system." -msgstr "" - -msgid "Invalid vCPU/topology combination." -msgstr "" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "" - -msgid "ERROR CODE" -msgstr "" - -msgid "REASON" -msgstr "" - -msgid "STACK" -msgstr "" - -msgid "Go to Homepage" -msgstr "" - -msgid "Create a New Virtual Machine" -msgstr "" - -msgid "Virtual Machine Name" -msgstr "" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "" - -msgid "Template" -msgstr "" - -msgid "Please create a template first." -msgstr "" - -msgid "Create a Template" -msgstr "" - -msgid "Please choose a template." -msgstr "" - -msgid "OS" -msgstr "" - -msgid "OS Version" -msgstr "" - -msgid "CPUS" -msgstr "" - -msgid "Memory" -msgstr "" - -msgid "Create" -msgstr "" - -msgid "Creating..." -msgstr "" - -msgid "Cancel" -msgstr "" - -msgid "Edit Guest" -msgstr "" - -msgid "General" -msgstr "" - -msgid "Storage" -msgstr "" - -msgid "Interface" -msgstr "" - -msgid "Permission" -msgstr "" - -msgid "Host PCI Device" -msgstr "" - -msgid "Snapshot" -msgstr "" - -msgid "Name" -msgstr "" - -msgid "CPUs" -msgstr "" - -msgid "Memory (MB)" -msgstr "" - -msgid "Icon" -msgstr "" - -msgid "Device" -msgstr "" - -msgid "Path" -msgstr "" - -msgid "Network" -msgstr "" - -msgid "Type" -msgstr "" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "" - -msgid "Selected system users and groups" -msgstr "" - -msgid "User" -msgstr "" - -msgid "All" -msgstr "" - -msgid "To Add" -msgstr "" - -msgid "Added" -msgstr "" - -msgid "filter" -msgstr "" - -msgid "Product" -msgstr "" - -msgid "Vendor" -msgstr "" - -msgid "Created" -msgstr "" - -msgid "Save" -msgstr "" - -msgid "Replace" -msgstr "" - -msgid "Detach" -msgstr "" - -msgid "revert" -msgstr "" - -msgid "Start" -msgstr "" - -msgid "Reset" -msgstr "" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "" - -msgid "Actions" -msgstr "" - -msgid "Connect" -msgstr "" - -msgid "Clone" -msgstr "" - -msgid "Edit" -msgstr "" - -msgid "Shut Down" -msgstr "" - -msgid "Delete" -msgstr "" - -msgid "CPU" -msgstr "" - -msgid "Disk I/O" -msgstr "" - -msgid "Network I/O" -msgstr "" - -msgid "Livetile" -msgstr "" - -msgid "No guests found." -msgstr "" - -msgid "Add a Storage Device to VM" -msgstr "" - -msgid "Device Type" -msgstr "" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "" - -msgid "Storage Pool" -msgstr "" - -msgid "Storage pool which volume located in" -msgstr "" - -msgid "Storage Volume" -msgstr "" - -msgid "Storage volume to be attached" -msgstr "" - -msgid "File Path" -msgstr "" - -msgid "The ISO file path in the server for CDROM." -msgstr "" - -msgid "Attach" -msgstr "" - -msgid "Shut down" -msgstr "" - -msgid "Restart" -msgstr "" - -msgid "Basic Information" -msgstr "" - -msgid "OS Distro" -msgstr "" - -msgid "OS Code Name" -msgstr "" - -msgid "Processor" -msgstr "" - -msgid "CPU(s)" -msgstr "" - -msgid "System Statistics" -msgstr "" - -msgid "Software Updates" -msgstr "" - -msgid "Update Progress" -msgstr "" - -msgid "Repositories" -msgstr "" - -msgid "Debug Reports" -msgstr "" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "" - -msgid "This field is required." -msgstr "" - -msgid "Log in" -msgstr "" - -msgid "Logging in..." -msgstr "" - -msgid "Host" -msgstr "" - -msgid "Guests" -msgstr "" - -msgid "Templates" -msgstr "" - -msgid "Failed to get application configuration" -msgstr "" - -msgid "This is not a valid Linux path" -msgstr "" - -msgid "This is not a valid URL." -msgstr "" - -msgid "No such data available." -msgstr "" - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "" - -msgid "OK" -msgstr "" - -msgid "Confirm" -msgstr "" - -msgid "Warning" -msgstr "" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "" - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "" - -msgid "Detailed message:" -msgstr "" - -msgid "No ISO found" -msgstr "" - -msgid "This is not a valid ISO file." -msgstr "" - -msgid "This may take a long time. Do you want to continue?" -msgstr "" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "" - -msgid "Max:" -msgstr "" - -msgid "Utilization" -msgstr "" - -msgid "Available" -msgstr "" - -msgid "Read Rate" -msgstr "" - -msgid "Write Rate" -msgstr "" - -msgid "Received" -msgstr "" - -msgid "Sent" -msgstr "" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" - -msgid "ID" -msgstr "" - -msgid "Base URL" -msgstr "" - -msgid "Is Mirror" -msgstr "" - -msgid "URL Args" -msgstr "" - -msgid "Enabled" -msgstr "" - -msgid "GPG Check" -msgstr "" - -msgid "GPG Key" -msgstr "" - -msgid "Add" -msgstr "" - -msgid "Remove" -msgstr "" - -msgid "Enable" -msgstr "" - -msgid "Disable" -msgstr "" - -msgid "Package Name" -msgstr "" - -msgid "Version" -msgstr "" - -msgid "Architecture" -msgstr "" - -msgid "Repository" -msgstr "" - -msgid "Update All" -msgstr "" - -msgid "Updating..." -msgstr "" - -msgid "Failed to retrieve packages update information." -msgstr "" - -msgid "Failed to update package(s)." -msgstr "" - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" - -msgid "Generated Time" -msgstr "" - -msgid "Generate" -msgstr "" - -msgid "Generating..." -msgstr "" - -msgid "Rename" -msgstr "" - -msgid "Download" -msgstr "" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "" - -msgid "Pending..." -msgstr "" - -msgid "Report name is the same as the original one." -msgstr "" - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "" - -msgid "Power off Confirmation" -msgstr "" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" - -msgid "Reset Confirmation" -msgstr "" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" - -msgid "Shut Down Confirmation" -msgstr "" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "" - -msgid "Virtual Machine delete Confirmation" -msgstr "" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" - -msgid "Attaching..." -msgstr "" - -msgid "Replacing..." -msgstr "" - -msgid "Successfully attached!" -msgstr "" - -msgid "Successfully replaced!" -msgstr "" - -msgid "Successfully detached!" -msgstr "" - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" - -msgid "interface:" -msgstr "" - -msgid "address:" -msgstr "" - -msgid "link_type:" -msgstr "" - -msgid "block:" -msgstr "" - -msgid "drive_type:" -msgstr "" - -msgid "model:" -msgstr "" - -msgid "Affected devices:" -msgstr "" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "" - -msgid "unavailable" -msgstr "" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" - -msgid "Create a network" -msgstr "" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "" - -msgid "This storage pool is empty." -msgstr "" - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" - -msgid "SCSI Fibre Channel" -msgstr "" - -msgid "No SCSI adapters found." -msgstr "" - -msgid "Loading iSCSI targets..." -msgstr "" - -msgid "No iSCSI found. Please input one." -msgstr "" - -msgid "Failed to load iSCSI targets." -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "" - -msgid "The storage pool path can not be blank." -msgstr "" - -msgid "NFS server mount path can not be blank." -msgstr "" - -msgid "Invalid NFS mount path." -msgstr "" - -msgid "No logical device selected." -msgstr "" - -msgid "The iSCSI target can not be blank." -msgstr "" - -msgid "Server name can not be blank." -msgstr "" - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "" - -msgid "Looking for available partitions ..." -msgstr "" - -msgid "No available partitions found." -msgstr "" - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" - -msgid "Unable to retrieve partitions information." -msgstr "" - -msgid "In progress..." -msgstr "" - -msgid "Failed!" -msgstr "" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" - -msgid "Disk pool or volume cannot be blank." -msgstr "" - -msgid "Filter" -msgstr "" - -msgid "Network Name" -msgstr "" - -msgid "State" -msgstr "" - -msgid "Network Type" -msgstr "" - -msgid "Address Space" -msgstr "" - -msgid "Name should not contain '/' and '\"'." -msgstr "" - -msgid "Isolated: no external network connection" -msgstr "" - -msgid "NAT: outbound physical network connection only" -msgstr "" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "" - -msgid "(No interfaces found)" -msgstr "" - -msgid "Destination" -msgstr "" - -msgid "Enable VLAN" -msgstr "" - -msgid "VLAN ID" -msgstr "" - -msgid "Stop" -msgstr "" - -msgid "Generate a New Debug Report" -msgstr "" - -msgid "Report Name" -msgstr "" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" - -msgid "Rename a Debug Report" -msgstr "" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" - -msgid "Submit" -msgstr "" - -msgid "Add a Repository" -msgstr "" - -msgid "Identifier" -msgstr "" - -msgid "Single word, unique identifier for the repository." -msgstr "" - -msgid "Textual name for the repository." -msgstr "" - -msgid "URL" -msgstr "" - -msgid "Required Field" -msgstr "" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "" - -msgid "Repository is a mirror" -msgstr "" - -msgid "Distribution" -msgstr "" - -msgid "Distribution of the DEB repository." -msgstr "" - -msgid "Components" -msgstr "" - -msgid "List of components in DEB repository." -msgstr "" - -msgid "Edit Repository" -msgstr "" - -msgid "Mirror List URL" -msgstr "" - -msgid "Yes" -msgstr "" - -msgid "No" -msgstr "" - -msgid "Capacity" -msgstr "" - -msgid "Allocated" -msgstr "" - -msgid "Location" -msgstr "" - -msgid "Device path" -msgstr "" - -msgid "active" -msgstr "" - -msgid "inactive" -msgstr "" - -msgid "Deactivate" -msgstr "" - -msgid "Activate" -msgstr "" - -msgid "Add Volume" -msgstr "" - -msgid "Extend" -msgstr "" - -msgid "Undefine" -msgstr "" - -msgid "Format" -msgstr "" - -msgid "Allocation" -msgstr "" - -msgid "Define a New Storage Pool" -msgstr "" - -msgid "Storage Pool Name" -msgstr "" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "" - -msgid "Storage Pool Type" -msgstr "" - -msgid "Storage Path" -msgstr "" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "" - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "" - -msgid "NFS Server IP" -msgstr "" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "" - -msgid "NFS Path" -msgstr "" - -msgid "The NFS exported path on NFS server." -msgstr "" - -msgid "iSCSI Server" -msgstr "" - -msgid "Server" -msgstr "" - -msgid "Port" -msgstr "" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "" - -msgid "Target" -msgstr "" - -msgid "The iSCSI target on iSCSI server" -msgstr "" - -msgid "Add iSCSI Authentication" -msgstr "" - -msgid "iSCSI Authentication" -msgstr "" - -msgid "User Name" -msgstr "" - -msgid "Password" -msgstr "" - -msgid "SCSI Adapter" -msgstr "" - -msgid "Please, wait..." -msgstr "" - -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - -msgid "Add Template" -msgstr "" - -msgid "Where is the source media for this template? " -msgstr "" - -msgid "Local ISO Image" -msgstr "" - -msgid "Local Image File" -msgstr "" - -msgid "Remote ISO Image" -msgstr "" - -msgid "Search ISOs" -msgstr "" - -msgid "The following ISOs are available:" -msgstr "" - -msgid "OS: " -msgstr "" - -msgid "Version: " -msgstr "" - -msgid "Size: " -msgstr "" - -msgid "Search more ISOs" -msgstr "" - -msgid "Create Templates from Selected ISO" -msgstr "" - -msgid "I want to use a specific ISO file" -msgstr "" - -msgid "Loading default remote ISOs ..." -msgstr "" - -msgid "Arch: " -msgstr "" - -msgid "I want to use a custom URL" -msgstr "" - -msgid "Edit Template" -msgstr "" - -msgid "CDROM" -msgstr "" - -msgid "Image File" -msgstr "" - -msgid "Graphics" -msgstr "" - -msgid "Disk(GB)" -msgstr "" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "" - -msgid "Manually set CPU topology" -msgstr "" - -msgid "Cores" -msgstr "" - -msgid "Threads" -msgstr "" - -msgid "No templates found." -msgstr "" diff --git a/plugins/kimchi/po/es_ES.po b/plugins/kimchi/po/es_ES.po deleted file mode 100644 index d71e621..0000000 --- a/plugins/kimchi/po/es_ES.po +++ /dev/null @@ -1,2305 +0,0 @@ -# English translations for kimchi package. -# Copyright (C) 2013 ORGANIZATION -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2013-07-11 17:32-0400\n" -"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" -"Language-Team: English\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: es_ES\n" -"Generated-By: pygettext.py 1.5\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "" - -msgid "Unknown \"_cap\" specified" -msgstr "" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "" -"Se ha producido un error al obtener dispositivos de bloque. Detalles: %(err)s" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "" -"Se ha producido un error al obtener informaci��n de dispositivo de bloque " -"para %(device)s." - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "No se puede encontrar el archivo distro: %(filename)s" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "" -"No se puede analizar el archivo distro: %(filename)s. Aseg��rese de que es un " -"archivo JSON." - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "" -"No se puede iniciar la sesi��n en %(portal)s del destino de host iSCSI. " -"Detalles: %(err)s" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "" -"No se puede iniciar la sesi��n en el destino %(target)s del %(host)s host de " -"iSCSI" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "El archivo ISO %(filename)s no es arrancable" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "" -"El archivo ISO %(filename)s no tiene un registro de arranque de El Torito " -"v��lido" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "Entrada de validaci��n de El Torito no v��lida en ISO %(filename)s" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "Indicador de arranque de El Torito no v��lido en ISO %(filename)s" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "" -"Tipo de volumen inesperado para el volumen primario en ISO %(filename)s" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "" -"Formato incorrecto mientras se le��a el descriptor de volumen en ISO %" -"(filename)s" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" -"El hipervisor no tiene permiso para utilizar este ISO %(filename)s. " -"Considere moverlo a /var/lib/libvirt, o establezca el permiso de b��squeda en " -"listas de control de accesos de archivo para el usuario '%(user)s' si es " -"posible, o a��ada el '%(user)s' al grupo de v��as de acceso ISO, o (no " -"recomendado) 'chmod -R o+x 'path_to_iso'.Detalles: %(err)s" - -msgid "An error occurred when probing image OS information." -msgstr "" - -msgid "No OS information found in given image." -msgstr "" - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "La m��quina virtual %(name)s ya existe" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "La m��quina virtual %(name)s no existe" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "" -"No se puede recuperar la captura de pantalla para la m��quina virtual " -"detenida %(name)s" - -msgid "Remote ISO image is not supported by this server." -msgstr "La imagen ISO remota no est�� soportada por este servidor." - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "No se puede crear la m��quina virtual %(name)s. Detalles: %(err)s" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "No se puede crear la m��quina virtual %(name)s. Detalles: %(err)s" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "No se puede recuperar la m��quina virtual %(name)s. Detalles: %(err)s" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "" - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "" -"La direcci��n de gr��ficos en que hay que estar a la escucha debe ser IPv4 o " -"IPv6" - -msgid "Specify a template to create a virtual machine from" -msgstr "" -"Especifique una plantilla a partir de la que se crear�� una m��quina virtual" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "No se puede iniciar la m��quina virtual %(name)s. Detalles: %(err)s" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "No se puede detener la m��quina virtual %(name)s. Detalles: %(err)s" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "No se puede suprimir la m��quina virtual %(name)s. Detalles: %(err)s" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "No se puede redenominar la m��quina virtual %(name)s. Detalles: %(err)s" - -msgid "User name list must be an array" -msgstr "" - -msgid "User name must be a string" -msgstr "El nombre de red debe ser una serie" - -msgid "Group name list must be an array" -msgstr "" - -msgid "Group name must be a string" -msgstr "El nombre de red debe ser una serie" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "El usuario '%(users)s' no existe." - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "El usuario '%(groups)s' no existe." - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "No se puede detener la m��quina virtual %(name)s. Detalles: %(err)s" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "No se puede iniciar la m��quina virtual %(name)s. Detalles: %(err)s" - -msgid "The guest console password must be a string." -msgstr "" - -msgid "The life time for the guest console password must be a number." -msgstr "" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" - -msgid "\"name\" should be a device name string" -msgstr "" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "La interfaz %(iface)s no existe en la m��quina virtual %(name)s" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "" -"La red %(network)s especificada para la m��quina virtual %(name)s no existe" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "El tipo de interfaces de m��quina virtual soportado es de red solamente" - -msgid "Network name for virtual machine interface must be a string" -msgstr "" -"El nombre de red para la interfaz de m��quina virtual debe ser una serie" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "" -"Especificada tarjeta de modelo de red no v��lida para la interfaz de m��quina " -"virtual" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "" -"Especifique el tipo y la red para a��adir una interfaz de m��quina virtual " -"nueva" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "La plantilla %(name)s ya existe" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "" -"La red '%(network)s' especificada para la plantilla %(template)s no existe" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "" -"La agrupaci��n de almacenamiento %(pool)s especificada para la plantilla %" -"(template)s no existe" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "" -"La agrupaci��n de almacenamiento %(pool)s especificada para la plantilla %" -"(template)s no est�� activa" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "Par��metro no v��lido '%(param)s' especificado para CDROM." - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "" -"La red %(network)s especificada para la plantilla %(template)s no est�� activa" - -msgid "Template name must be a string" -msgstr "El nombre de plantilla debe ser una serie" - -msgid "Template icon must be a path to the image" -msgstr "El icono de plantilla debe ser una v��a de acceso a la imagen" - -msgid "Template distribution must be a string" -msgstr "La distribuci��n de plantilla debe ser una serie" - -msgid "Template distribution version must be a string" -msgstr "La versi��n de distribuci��n de plantilla debe ser una serie" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "El n��mero de CPUs debe ser un entero" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "La cantidad de memoria (MB) debe ser un entero mayor que 512" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "El CDROM de plantilla debe ser un archivo ISO local o remoto" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "" -"URI de agrupaci��n de almacenamiento no v��lido %(value)s especificado para la " -"plantilla" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "Especifique una imagen de ISO como CDROM para crear una plantilla" - -msgid "All networks for the template must be specified in a list." -msgstr "Todas las redes para la plantilla deben especificarse en una lista." - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "No se puede crear la plantilla debido a un error: %(err)s" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "No se puede suprimir la plantilla debido a un error: %(err)s" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "" - -msgid "Template base image must be a valid local image file" -msgstr "El CDROM de plantilla debe ser un archivo ISO local o remoto" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "La agrupaci��n de almacenamiento %(name)s ya existe" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "La agrupaci��n de almacenamiento %(name)s no existe" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "" -"Especifique %(item)s para poder crear la agrupaci��n de almacenamiento %(name)" -"s" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "No se puede suprimir la agrupaci��n de almacenamiento activa %(name)s" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "No se pueden listar agrupaciones de almacenamiento. Detalles: %(err)s" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "" -"No se puede crear la agrupaci��n de almacenamiento %(name)s. Detalles: %(err)s" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "" -"No se puede obtener el n��mero de vol��menes de almacenamiento en la " -"agrupaci��n de almacenamiento %(name)s. Detalles: %(err)s" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "" -"No se puede activar la agrupaci��n de almacenamiento %(name)s. Detalles: %" -"(err)s" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "" -"No se puede desactivar la agrupaci��n de almacenamiento %(name)s. Detalles: %" -"(err)s" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "" -"No se puede suprimir la agrupaci��n de almacenamiento %(name)s. Detalles: %" -"(err)s" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "" -"No se puede crear la agrupaci��n de NFS ya que la v��a de acceso de " -"exportaci��n %(path)s podr��a bloquearse durante el montaje" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "" -"No se puede crear la agrupaci��n de NFS ya que el montaje de la v��a de acceso " -"de exportaci��n %(path)s ha fallado" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "Tipo de agrupaci��n de almacenamiento no soportado: %(type)s" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" - -msgid "Storage pool path must be a string" -msgstr "La v��a de acceso de la agrupaci��n de almacenamiento debe ser una serie" - -msgid "Storage pool host must be a IP or hostname" -msgstr "" -"El host de la agrupaci��n de almacenamiento debe ser un IP o nombre de host" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" - -msgid "Storage pool devices parameter must be a list" -msgstr "" -"El par��metro de los dispositivos de agrupaci��n de almacenamiento debe ser " -"una lista" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "El IQN destino de una agrupaci��n de iSCSI debe ser una serie" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "" -"El puerto de un servidor de almacenamiento remoto debe ser un entero entre 1 " -"y 65535" - -msgid "iSCSI target username must be a string" -msgstr "" - -msgid "iSCSI target password must be a string" -msgstr "" - -msgid "Specify name and type to create a storage pool" -msgstr "" -"Especifique el nombre y el tipo para crear una agrupaci��n de almacenamiento" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "" -"%(disk)s no es un disco/partici��n. No se ha podido a��adir a la agrupaci��n %" -"(pool)s." - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "" -"Los discos de par��metro s��lo pueden actualizarse para la agrupaci��n de " -"almacenamiento l��gico." - -msgid "The SCSI host adapter name must be a string." -msgstr "El nombre del adaptador de host SCSI debe ser una serie." - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "" -"La agrupaci��n de almacenamiento kimchi_isos est�� reservada para uso interno" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"No se puede activar la agrupaci��n de almacenamiento NFS %(name)s. El " -"servidor NFS %(server)s est�� fuera de alcance." - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"No se puede desactivar la agrupaci��n de almacenamiento NFS %(name)s. El " -"servidor NFS %(server)s est�� fuera de alcance." - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "" -"No se puede desactivar la agrupaci��n %(name)s ya que est�� asociada con " -"algunas plantillas" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "" -"No se puede suprimir la agrupaci��n %(name)s ya que est�� asociada con algunas " -"plantillas" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "" -"Un grupo de vol��menes denominado '%(name)s' ya existe. Elija otro nombre " -"para crear la agrupaci��n l��gica." - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "" -"No se puede actualizar la base de datos con la informaci��n de exploraci��n " -"profunda debido a un error: %(err)s" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "El volumen de almacenamiento %(name)s ya existe" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "" -"El volumen de almacenamiento %(name)s no existe en la agrupaci��n de " -"almacenamiento %(pool)s" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "" -"Especifique %(item)s para poder crear el volumen de almacenamiento %(volume)s" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "" -"No se pueden listar los vol��menes de almacenamiento porque la agrupaci��n de " -"almacenamiento %(pool)s no est�� activa" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "" -"No se puede crear el volumen de almacenamiento %(name)s en la agrupaci��n de " -"almacenamiento %(pool)s. Detalles: %(err)s" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "" -"No se pueden listar vol��menes de almacenamiento en la agrupaci��n de " -"almacenamiento %(pool)s. Detalles: %(err)s" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "" -"No se pueden borrar los vol��menes de almacenamiento %(name)s. Detalles: %" -"(err)s" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "" -"No se puede suprimir el volumen de almacenamiento %(name)s. Detalles: %(err)s" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "" -"No se puede redimensionar el volumen de almacenamiento %(name)s. Detalles: %" -"(err)s" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "" -"El tipo de almacenamiento %(type)s no da soporte a crear y suprimir vol��menes" - -msgid "Storage volume name must be a string" -msgstr "El nombre de volumen de almacenamiento debe ser una serie" - -msgid "Storage volume allocation must be an integer number" -msgstr "La asignaci��n de volumen de almacenamiento debe ser un n��mero entero" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" - -msgid "Storage volume requires a volume name" -msgstr "El volumen de almacenamiento requiere un nombre de volumen" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "" -"No se puede actualizar la base de datos con la informaci��n de volumen de " -"almacenamiento debido a un error: %(err)s" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "" - -msgid "Storage volume capacity must be an integer number." -msgstr "" - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "" - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "La interfaz %(name)s no existe" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "La red %(name)s ya existe" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "La red %(name)s no existe" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "" -"La subred %(subnet)s especificada para la red %(network)s no es v��lida." - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "Especifique una interfaz de red para crear una red puenteada %(name)s" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "No se puede suprimir la red activa %(name)s" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "" -"La interfaz %(iface)s especificada para la red %(network)s ya est�� en uso" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "La interfaz debe ser dispositivo de puente, enlazado o NIC simple." - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "No se puede crear la red %(name)s. Detalles: %(err)s" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "No se puede encontrar una direcci��n IP libre para la red '%(name)s'" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "La interfaz %(iface)s ya existe" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "Los tipos de red soportados son aislada, NAT y puente" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "" -"La subred de red debe ser una serie con direcci��n IP y prefijo o m��scara de " -"red" - -msgid "Network interface must be a string" -msgstr "La interfaz de red debe ser una serie" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "El ID de VLAN de red debe ser un entero entre 1 y 4094" - -msgid "Specify name and type to create a Network" -msgstr "Especifique el nombre y el tipo para crear una red" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" -"No se puede suprimir la red %(name)s. Hay algunas m��quinas virtuales %(vms)s " -"y/o plantillas enlazadas a esta red." - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" -"No se puede desactivar la red %(name)s. Hay algunas m��quinas virtuales %(vms)" -"s y/o plantillas enlazadas a esta red." - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "" -"El dispositivo de puente %(name)s no puede ser el dispositivo de conexi��n " -"troncal de una VLAN." - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "No se puede activar la interfaz %(iface)s: %(err)s." - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "" -"No se puede activar la interfaz %(iface)s. Compruebe el estado del enlace " -"f��sico." - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "El informe de depuraci��n %(name)s no existe" - -msgid "Debug report tool not found in system" -msgstr "Herramienta de informes de depuraci��n no encontrada en el sistema" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "" -"No se puede crear el informe de depuraci��n %(name)s. Detalles: %(err)s." - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "" -"No se puede generar el informe de depuraci��n %(name)s. Detalles: %(err)s" - -msgid "You should give a name for the debug report file." -msgstr "" - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "" -"Un grupo de vol��menes denominado '%(name)s' ya existe. Elija otro nombre " -"para crear la agrupaci��n l��gica." - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "Kimchi no utilizaba el servidor de almacenamiento %(server)s" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "Distro '%(name)s' no existe" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "La partici��n %(name)s no existe en el host" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "" -"No se puede concluir la m��quina host ya que hay m��quinas virtuales en " -"ejecuci��n" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "" -"No se puede rearrancar la m��quina host ya que hay m��quinas virtuales en " -"ejecuci��n" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "No se ha encontrado el dispositivo de nodo '%(name)s'" - -msgid "Conflicting flag filters specified." -msgstr "" - -msgid "No packages marked for update" -msgstr "No hay paquetes marcados para su actualizaci��n" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "El paquete %(name)s no est�� marcado para su actualizaci��n." - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "" -"Se ha producido un error al obtener paquetes marcados para su actualizaci��n. " -"Detalles: %(err)s" - -msgid "There is no compatible package manager for this system." -msgstr "No hay ning��n gestor de paquetes compatible para este sistema." - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "URI %(uri)s no v��lido" - -msgid "Unable to choose a virtual machine name" -msgstr "" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "Tipo de almacenamiento no v��lido. Tipos soportados: 'cdrom'" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" - -msgid "Only CDROM path can be update." -msgstr "" - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "" -"Se ha producido un error al crear el nuevo dispositivo de almacenamiento: %" -"(error)s" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "" -"Se ha producido un error al actualizar el dispositivo de almacenamiento: %" -"(error)s" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "" -"Se ha producido un error al eliminar el dispositivo de almacenamiento: %" -"(error)s" - -msgid "Do not support IDE device hot plug" -msgstr "" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "" -"Especifique el tipo y la v��a de acceso para a��adir un disco de m��quina " -"virtual nuevo" - -msgid "Specify path to update virtual machine disk" -msgstr "" -"Especifique la v��a de acceso para actualizar el disco de m��quina virtual" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" - -msgid "Volume already in use by other virtual machine." -msgstr "" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "" -"Especifique el tipo y la v��a de acceso para a��adir un disco de m��quina " -"virtual nuevo" - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" - -msgid "YUM Repository ID must be one word only string." -msgstr "El ID de repositorio YUM debe ser una serie de una sola palabra." - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "El URL de repositorio debe ser http://, ftp:// o archivo:// URL." - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "" -"La configuraci��n de repositorio es un diccionario con valores espec��ficos " -"seg��n el tipo de repositorio." - -msgid "Distribution to DEB repository must be a string" -msgstr "El repositorio de Distribuci��n a DEB debe ser una serie" - -msgid "Components to DEB repository must be listed in a array" -msgstr "El repositorio de Componentes a DEB debe estar listado en una matriz" - -msgid "Components to DEB repository must be a string" -msgstr "El repositorio de Componentes a DEB debe ser una serie" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "El nombre del repositorio YUM debe ser una serie." - -msgid "GPG check must be a boolean value." -msgstr "La comprobaci��n de GPG debe ser un valor booleano." - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "La clave GPG debe ser un URL que apunta al archivo blindado por ASCII." - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "No se ha podido actualizar el repositorio %(repo_id)s." - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "El repositorio %(repo_id)s no existe." - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "" -"La herramienta de gesti��n de repositorio no se ha reconocido para su sistema." - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "El repositorio %(repo_id)s ya est�� habilitado." - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "El repositorio %(repo_id)s ya est�� inhabilitado." - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "No se ha podido eliminar el repositorio %(repo_id)s." - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "" -"No se ha podido grabar el archivo de configuraci��n del repositorio %" -"(repo_file)s" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "" -"Especifique la distribuci��n del repositorio para crear un repositorio de DEB." - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "No se ha podido habilitar el repositorio %(repo_id)s." - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "No se ha podido inhabilitar el repositorio %(repo_id)s." - -msgid "YUM Repository ID already exists" -msgstr "El ID de repositorio de YUM ya existe" - -msgid "YUM Repository name must be a string" -msgstr "El nombre del repositorio de YUM debe ser una serie" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "No se pueden listar repositorios. Detalles: '%(err)s'" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "No se puede recuperar informaci��n del repositorio. Detalles: '%(err)s'" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "No se puede a��adir el repositorio. Detalles: '%(err)s'" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "No se puede eliminar el repositorio. Detalles: '%(err)s'" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" - -msgid "The number of vCPUs is too large for this system." -msgstr "" - -msgid "Invalid vCPU/topology combination." -msgstr "" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "" - -msgid "ERROR CODE" -msgstr "C��DIGO DE ERROR" - -msgid "REASON" -msgstr "RAZ��N" - -msgid "STACK" -msgstr "PILA" - -msgid "Go to Homepage" -msgstr "Ir a la p��gina inicial" - -msgid "Create a New Virtual Machine" -msgstr "Crear una nueva m��quina virtual" - -msgid "Virtual Machine Name" -msgstr "Nombre de m��quina virtual" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "" -"El nombre que se utiliza para identificar la m��quina virtual. Si se omite, " -"se elegir�� un nombre bas��ndose en la plantilla utilizada." - -msgid "Template" -msgstr "Plantilla" - -msgid "Please create a template first." -msgstr "Cree una plantilla primero." - -msgid "Create a Template" -msgstr "Crear una plantilla" - -msgid "Please choose a template." -msgstr "Elija una plantilla." - -msgid "OS" -msgstr "SO" - -msgid "OS Version" -msgstr "Versi��n del SO" - -msgid "CPUS" -msgstr "CPUS" - -msgid "Memory" -msgstr "Memoria" - -msgid "Create" -msgstr "Crear" - -msgid "Creating..." -msgstr "" - -msgid "Cancel" -msgstr "Cancelar" - -msgid "Edit Guest" -msgstr "Editar invitado" - -msgid "General" -msgstr "General" - -msgid "Storage" -msgstr "Almacenamiento" - -msgid "Interface" -msgstr "Interfaz" - -msgid "Permission" -msgstr "Versi��n" - -msgid "Host PCI Device" -msgstr "" - -msgid "Snapshot" -msgstr "" - -msgid "Name" -msgstr "Nombre" - -msgid "CPUs" -msgstr "CPUs" - -msgid "Memory (MB)" -msgstr "Memoria" - -msgid "Icon" -msgstr "Icono" - -msgid "Device" -msgstr "Nombre de dispositivo" - -msgid "Path" -msgstr "V��a de acceso NFS" - -msgid "Network" -msgstr "Red" - -msgid "Type" -msgstr "Tipo" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "" - -msgid "Selected system users and groups" -msgstr "" - -msgid "User" -msgstr "" - -msgid "All" -msgstr "Todo" - -msgid "To Add" -msgstr "" - -msgid "Added" -msgstr "" - -msgid "filter" -msgstr "" - -msgid "Product" -msgstr "" - -msgid "Vendor" -msgstr "Proveedor" - -msgid "Created" -msgstr "" - -msgid "Save" -msgstr "Guardar" - -msgid "Replace" -msgstr "Sustituir" - -msgid "Detach" -msgstr "Desconectar" - -msgid "revert" -msgstr "" - -msgid "Start" -msgstr "Iniciar" - -msgid "Reset" -msgstr "Restablecer" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "" - -msgid "Actions" -msgstr "Acciones" - -msgid "Connect" -msgstr "Conectar" - -msgid "Clone" -msgstr "" - -msgid "Edit" -msgstr "Editar" - -msgid "Shut Down" -msgstr "Concluir" - -msgid "Delete" -msgstr "Suprimir" - -msgid "CPU" -msgstr "CPU" - -msgid "Disk I/O" -msgstr "E/S de disco" - -msgid "Network I/O" -msgstr "E/S de red" - -msgid "Livetile" -msgstr "Livetile" - -msgid "No guests found." -msgstr "No se ha encontrado invitados." - -msgid "Add a Storage Device to VM" -msgstr "A��adir un dispositivo de almacenamiento a VM" - -msgid "Device Type" -msgstr "Tipo de dispositivo" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "El tipo de dispositivo. Actualmente s��lo est�� soportado \"cdrom\"." - -msgid "Storage Pool" -msgstr "Agrupaci��n de almacenamiento" - -msgid "Storage pool which volume located in" -msgstr "La v��a de acceso de la agrupaci��n de almacenamiento debe ser una serie" - -msgid "Storage Volume" -msgstr "Nombre de agrupaci��n de almacenamiento" - -msgid "Storage volume to be attached" -msgstr "El nombre de volumen de almacenamiento debe ser una serie" - -msgid "File Path" -msgstr "V��a de acceso de archivo" - -msgid "The ISO file path in the server for CDROM." -msgstr "La v��a de acceso del archivo ISO en el servidor para el CDROM." - -msgid "Attach" -msgstr "Conectar" - -msgid "Shut down" -msgstr "Concluir" - -msgid "Restart" -msgstr "Reiniciar" - -msgid "Basic Information" -msgstr "Informaci��n b��sica" - -msgid "OS Distro" -msgstr "Distro de SO" - -msgid "OS Code Name" -msgstr "Nombre de c��digo de SO" - -msgid "Processor" -msgstr "Procesador" - -msgid "CPU(s)" -msgstr "" - -msgid "System Statistics" -msgstr "Estad��sticas del sistema" - -msgid "Software Updates" -msgstr "Actualizaciones de software" - -msgid "Update Progress" -msgstr "Actualizar progreso" - -msgid "Repositories" -msgstr "Repositorios" - -msgid "Debug Reports" -msgstr "Informes de depuraci��n" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "" -"El nombre de usuario o contrase��a que ha especificado es incorrecto. Por " -"favor, vuelva a intentarlo." - -msgid "This field is required." -msgstr "Este campo es obligatorio." - -msgid "Log in" -msgstr "Iniciar sesi��n" - -msgid "Logging in..." -msgstr "Iniciando sesi��n..." - -msgid "Host" -msgstr "Host" - -msgid "Guests" -msgstr "Invitados" - -msgid "Templates" -msgstr "Plantillas" - -msgid "Failed to get application configuration" -msgstr "No se ha podido obtener la configuraci��n de la aplicaci��n" - -msgid "This is not a valid Linux path" -msgstr "No es una v��a de acceso de Linux v��lida" - -msgid "This is not a valid URL." -msgstr "No es un URL v��lido." - -msgid "No such data available." -msgstr "No hay datos de ese tipo disponibles." - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" -"No se puede contactar con el sistema host, Verifique que el sistema host " -"est�� activo y que tiene conectividad de red con ��l. Respuesta de solicitud " -"HTTP %1. " - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "Confirmaci��n de supresi��n" - -msgid "OK" -msgstr "Aceptar" - -msgid "Confirm" -msgstr "Confirmar" - -msgid "Warning" -msgstr "Aviso" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "Cargando..." - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "Reintentar" - -msgid "Detailed message:" -msgstr "Mensaje detallado:" - -msgid "No ISO found" -msgstr "" - -msgid "This is not a valid ISO file." -msgstr "No es un archivo ISO v��lido." - -msgid "This may take a long time. Do you want to continue?" -msgstr "Tardar�� mucho tiempo. ��Desea continuar?" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "Esto suprimir�� permanentemente la plantilla. ��Desea continuar?" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "" -"No se puede concluir el sistema ya que hay algunas m��quinas virtuales en " -"ejecuci��n." - -msgid "Max:" -msgstr "M��x.:" - -msgid "Utilization" -msgstr "Utilizaci��n" - -msgid "Available" -msgstr "Disponible" - -msgid "Read Rate" -msgstr "Velocidad de lectura" - -msgid "Write Rate" -msgstr "Velocidad de escritura" - -msgid "Received" -msgstr "Recibido" - -msgid "Sent" -msgstr "Enviado" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"Concluir o reiniciar el host har�� que se pierda el trabajo no guardado. " -"��Desea continuar para concluir/reiniciar?" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"El repositorio se eliminar�� de forma permanente y no se puede recuperar. " -"��Desea continuar?" - -msgid "ID" -msgstr "ID" - -msgid "Base URL" -msgstr "URL base" - -msgid "Is Mirror" -msgstr "Es duplicado" - -msgid "URL Args" -msgstr "Args de URL" - -msgid "Enabled" -msgstr "Habilitado" - -msgid "GPG Check" -msgstr "Comprobaci��n GPG" - -msgid "GPG Key" -msgstr "Clave GPG" - -msgid "Add" -msgstr "A��adir" - -msgid "Remove" -msgstr "Eliminar" - -msgid "Enable" -msgstr "Habilitar" - -msgid "Disable" -msgstr "Inhabilitar" - -msgid "Package Name" -msgstr "Nombre de paquete" - -msgid "Version" -msgstr "Versi��n" - -msgid "Architecture" -msgstr "Arquitectura" - -msgid "Repository" -msgstr "Repositorio" - -msgid "Update All" -msgstr "Actualizar todo" - -msgid "Updating..." -msgstr "Actualizando..." - -msgid "Failed to retrieve packages update information." -msgstr "" - -msgid "Failed to update package(s)." -msgstr "No se han podido actualizar paquetes." - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"El informe de depuraci��n se eliminar�� permanentemente y no se puede " -"recuperar. ��Desea continuar?" - -msgid "Generated Time" -msgstr "Tiempo generado" - -msgid "Generate" -msgstr "Generar" - -msgid "Generating..." -msgstr "Generando..." - -msgid "Rename" -msgstr "Redenominar" - -msgid "Download" -msgstr "Descargar" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "" -"El nombre de informe debe contener s��lo letras, d��gitos y/o gui��n ('-')." - -msgid "Pending..." -msgstr "Cargando..." - -msgid "Report name is the same as the original one." -msgstr "" - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "" -"Esto suprimir�� la m��quina virtual y sus discos virtuales. Esta operaci��n no " -"puede deshacerse. ��Desea continuar?" - -msgid "Power off Confirmation" -msgstr "Confirmaci��n de supresi��n" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" - -msgid "Reset Confirmation" -msgstr "Confirmaci��n de supresi��n" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" - -msgid "Shut Down Confirmation" -msgstr "Confirmaci��n de supresi��n" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "Esto suprimir�� permanentemente la plantilla. ��Desea continuar?" - -msgid "Virtual Machine delete Confirmation" -msgstr "" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" -"Este CDROM se desconectar�� de forma permanente pero puede volver a " -"conectarlo. ��Desea continuar para desconectarlo?" - -msgid "Attaching..." -msgstr "Conectando..." - -msgid "Replacing..." -msgstr "Sustituyendo..." - -msgid "Successfully attached!" -msgstr "��Conectado correctamente!" - -msgid "Successfully replaced!" -msgstr "��Sustituido correctamente!" - -msgid "Successfully detached!" -msgstr "��Desconectado correctamente!" - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" - -msgid "interface:" -msgstr "" - -msgid "address:" -msgstr "" - -msgid "link_type:" -msgstr "" - -msgid "block:" -msgstr "" - -msgid "drive_type:" -msgstr "" - -msgid "model:" -msgstr "" - -msgid "Affected devices:" -msgstr "" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "El ID de VLAN debe estar entre 1 y 4094." - -msgid "unavailable" -msgstr "no disponible" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" -"Esta acci��n interrumpir�� la conectividad de red para cualquier m��quina " -"virtual que dependa de esta red." - -msgid "Create a network" -msgstr "Crear una red" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"Esta agrupaci��n de almacenamiento no es persistente. En lugar de desactivar, " -"esta acci��n la suprimir�� permanentemente. ��Desea continuar?" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "" -"Esto suprimir�� permanentemente la agrupaci��n de almacenamiento. ��Desea " -"continuar?" - -msgid "This storage pool is empty." -msgstr "Esta agrupaci��n de almacenamiento est�� vac��a." - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" -"Dar�� formato al disco y se perder��n los datos que tenga en ��l. ��Est�� seguro " -"de que desea continuar? " - -msgid "SCSI Fibre Channel" -msgstr "Canal de fibra de SCSI" - -msgid "No SCSI adapters found." -msgstr "No se han encontrado adaptadores SCSI." - -msgid "Loading iSCSI targets..." -msgstr "" - -msgid "No iSCSI found. Please input one." -msgstr "" - -msgid "Failed to load iSCSI targets." -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "El nombre de la agrupaci��n de almacenamiento no puede estar en blanco." - -msgid "The storage pool path can not be blank." -msgstr "" -"La v��a de acceso de la agrupaci��n de almacenamiento no puede estar en blanco." - -msgid "NFS server mount path can not be blank." -msgstr "La v��a de acceso de montaje del servidor NFS no puede estar en blanco." - -msgid "Invalid NFS mount path." -msgstr "V��a de acceso de montaje de NFS no v��lida." - -msgid "No logical device selected." -msgstr "No se ha seleccionado ning��n dispositivo l��gico." - -msgid "The iSCSI target can not be blank." -msgstr "El destino iSCSI no puede estar en blanco." - -msgid "Server name can not be blank." -msgstr "El nombre de servidor no puede estar en blanco." - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "" - -msgid "Looking for available partitions ..." -msgstr "Buscando particiones disponibles..." - -msgid "No available partitions found." -msgstr "No se han encontrado particiones disponibles." - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"Esta agrupaci��n de almacenamiento no es persistente. En lugar de desactivar, " -"esta acci��n la suprimir�� permanentemente. ��Desea continuar?" - -msgid "Unable to retrieve partitions information." -msgstr "No se puede recuperar informaci��n del repositorio. Detalles: '%(err)s'" - -msgid "In progress..." -msgstr "" - -msgid "Failed!" -msgstr "" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" - -msgid "Disk pool or volume cannot be blank." -msgstr "El nombre de la agrupaci��n de almacenamiento no puede estar en blanco." - -msgid "Filter" -msgstr "" - -msgid "Network Name" -msgstr "Nombre de red" - -msgid "State" -msgstr "Estado" - -msgid "Network Type" -msgstr "Tipo de red" - -msgid "Address Space" -msgstr "Espacio de direcciones" - -msgid "Name should not contain '/' and '\"'." -msgstr "" -"Nombre de agrupaci��n de almacenamiento no v��lido. No debe contener '/'." - -msgid "Isolated: no external network connection" -msgstr "Aislado: no hay conexi��n de red f��sica" - -msgid "NAT: outbound physical network connection only" -msgstr "NAT: conexi��n de red f��sica saliente solamente" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "" -"Puenteado: Las m��quinas virtuales est��n conectadas a la red f��sica " -"directamente" - -msgid "(No interfaces found)" -msgstr "" - -msgid "Destination" -msgstr "Destino:" - -msgid "Enable VLAN" -msgstr "Habilitar VLAN:" - -msgid "VLAN ID" -msgstr "ID de VLAN:" - -msgid "Stop" -msgstr "Detener" - -msgid "Generate a New Debug Report" -msgstr "Generar un Informe de depuraci��n nuevo" - -msgid "Report Name" -msgstr "Nombre de informe" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" -"El nombre que se utiliza para identificar el informe. Si se omite, se " -"elegir�� un nombre bas��ndose en la hora actual. El nombre puede contener: " -"letras, d��gitos y gui��n (\"-\")." - -msgid "Rename a Debug Report" -msgstr "Generar un Informe de depuraci��n nuevo" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" -"El nombre que se utiliza para identificar el informe. Si se omite, se " -"elegir�� un nombre bas��ndose en la hora actual. El nombre puede contener: " -"letras, d��gitos y gui��n (\"-\")." - -msgid "Submit" -msgstr "" - -msgid "Add a Repository" -msgstr "A��adir un repositorio" - -msgid "Identifier" -msgstr "Identificador" - -msgid "Single word, unique identifier for the repository." -msgstr "Identificador exclusivo de una sola palabra para el repositorio." - -msgid "Textual name for the repository." -msgstr "Nombre textual para el repositorio." - -msgid "URL" -msgstr "URL" - -msgid "Required Field" -msgstr "Campo obligatorio" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "URL al repositorio. Los protocolos soportados son http, ftp y archivo." - -msgid "Repository is a mirror" -msgstr "El repositorio es un duplicado." - -msgid "Distribution" -msgstr "Distribuci��n" - -msgid "Distribution of the DEB repository." -msgstr "Distribuci��n del repositorio DEB." - -msgid "Components" -msgstr "Componentes" - -msgid "List of components in DEB repository." -msgstr "Lista de componentes en el repositorio DEB." - -msgid "Edit Repository" -msgstr "Editar repositorio" - -msgid "Mirror List URL" -msgstr "URL de lista duplicada" - -msgid "Yes" -msgstr "S��" - -msgid "No" -msgstr "No" - -msgid "Capacity" -msgstr "Capacidad" - -msgid "Allocated" -msgstr "Asignado" - -msgid "Location" -msgstr "Ubicaci��n" - -msgid "Device path" -msgstr "V��a de acceso del dispositivo" - -msgid "active" -msgstr "activo" - -msgid "inactive" -msgstr "inactivo" - -msgid "Deactivate" -msgstr "Desactivar" - -msgid "Activate" -msgstr "Activar" - -msgid "Add Volume" -msgstr "" - -msgid "Extend" -msgstr "" - -msgid "Undefine" -msgstr "No definir" - -msgid "Format" -msgstr "Formato:" - -msgid "Allocation" -msgstr "Asignado:" - -msgid "Define a New Storage Pool" -msgstr "Definir una agrupaci��n de almacenamiento nueva" - -msgid "Storage Pool Name" -msgstr "Nombre de agrupaci��n de almacenamiento" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "" -"El nombre que se utiliza para identificar las agrupaciones de almacenamiento " -"y no debe estar vac��o." - -msgid "Storage Pool Type" -msgstr "Tipo de agrupaci��n de almacenamiento" - -msgid "Storage Path" -msgstr "V��a de acceso de almacenamiento" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "" -"La v��a de acceso de la agrupaci��n de almacenamiento. Cada agrupaci��n de " -"almacenamiento debe tener una v��a de acceso exclusiva." - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "Kimchi intentar�� crear el directorio cuando no existe en el sistema." - -msgid "NFS Server IP" -msgstr "IP de Servidor NFS" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "" -"IP o nombre de host de servidor NFS. Puede especificarse o elegirse del " -"historial." - -msgid "NFS Path" -msgstr "V��a de acceso NFS" - -msgid "The NFS exported path on NFS server." -msgstr "La v��a de acceso exportada de NFS en el servidor NFS." - -msgid "iSCSI Server" -msgstr "Servidor iSCSI" - -msgid "Server" -msgstr "Servidor" - -msgid "Port" -msgstr "Puerto" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "IP o nombre de host de servidor iSCSI. No debe estar vac��o." - -msgid "Target" -msgstr "Destino" - -msgid "The iSCSI target on iSCSI server" -msgstr "El destino iSCSI en el servidor iSCSI" - -msgid "Add iSCSI Authentication" -msgstr "A��adir Autenticaci��n iSCSI" - -msgid "iSCSI Authentication" -msgstr "Autenticaci��n iSCSI" - -msgid "User Name" -msgstr "Nombre de usuario" - -msgid "Password" -msgstr "Contrase��a" - -msgid "SCSI Adapter" -msgstr "Adaptador SCSI" - -msgid "Please, wait..." -msgstr "Por favor, espere..." - -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - -msgid "Add Template" -msgstr "A��adir plantilla" - -msgid "Where is the source media for this template? " -msgstr "��D��nde est�� el soporte de origen para esta plantilla?" - -msgid "Local ISO Image" -msgstr "Imagen ISO local" - -msgid "Local Image File" -msgstr "" - -msgid "Remote ISO Image" -msgstr "Imagen ISO remota" - -msgid "Search ISOs" -msgstr "Buscar ISOs" - -msgid "The following ISOs are available:" -msgstr "Las siguientes ISO est��n disponibles:" - -msgid "OS: " -msgstr "SO: " - -msgid "Version: " -msgstr "Versi��n: " - -msgid "Size: " -msgstr "Tama��o: " - -msgid "Search more ISOs" -msgstr "Buscar m��s ISO" - -msgid "Create Templates from Selected ISO" -msgstr "Crear plantillas a partir de ISO seleccionadas" - -msgid "I want to use a specific ISO file" -msgstr "Deseo utilizar un archivo ISO espec��fico" - -msgid "Loading default remote ISOs ..." -msgstr "Cargando ISO remotas predeterminadas ..." - -msgid "Arch: " -msgstr "Arch: " - -msgid "I want to use a custom URL" -msgstr "Deseo utilizar un URL personalizado" - -msgid "Edit Template" -msgstr "Editar plantilla" - -msgid "CDROM" -msgstr "CDROM" - -msgid "Image File" -msgstr "" - -msgid "Graphics" -msgstr "Gr��ficos" - -msgid "Disk(GB)" -msgstr "" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "N��mero de CPU" - -msgid "Manually set CPU topology" -msgstr "" - -msgid "Cores" -msgstr "" - -msgid "Threads" -msgstr "" - -msgid "No templates found." -msgstr "No se han encontrado plantillas." - -#~ msgid "Delete is not allowed for %(resource)s" -#~ msgstr "Suprimir no est�� permitido para %(resource)s" - -#~ msgid "%(resource)s does not implement update method" -#~ msgstr "%(resource)s no implementa m��todo de actualizaci��n" - -#~ msgid "Create is not allowed for %(resource)s" -#~ msgstr "Crear no est�� permitido para %(resource)s" - -#~ msgid "Unable to parse JSON request" -#~ msgstr "No se puede analizar la solicitud JSON" - -#~ msgid "This API only supports JSON" -#~ msgstr "Esta API s��lo da soporte a JSON" - -#~ msgid "Datastore is not initiated in the model object." -#~ msgstr "El almac��n de datos no se ha iniciado en el objeto de modelo." - -#~ msgid "Unable to start task due error: %(err)s" -#~ msgstr "No se puede iniciar la tarea debido a un error: %(err)s" - -#~ msgid "" -#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" -#~ msgstr "" -#~ "La autenticaci��n ha fallado para el usuario '%(username)s'. [C��digo de " -#~ "error: %(code)s]" - -#~ msgid "You are not authorized to access Kimchi" -#~ msgstr "No tiene autorizaci��n para acceder a Kimchi" - -#~ msgid "Specify %(item)s to login into Kimchi" -#~ msgstr "Especifique %(item)s para iniciar la sesi��n en Kimchi" - -#~ msgid "Unable to find %(item)s in datastore" -#~ msgstr "No se puede encontrar %(item)s en el almac��n de datos" - -#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" -#~ msgstr "" -#~ "Tiempo de espera excedido al ejecutar el mandato '%(cmd)s' despu��s de %" -#~ "(seconds)s segundos" - -#~ msgid "Help" -#~ msgstr "Ayuda" - -#~ msgid "About" -#~ msgstr "Acerca de" - -#~ msgid "Log out" -#~ msgstr "Finalizar sesi��n" - -#~ msgid "Version:" -#~ msgstr "Versi��n:" diff --git a/plugins/kimchi/po/fr_FR.po b/plugins/kimchi/po/fr_FR.po deleted file mode 100644 index b996e8a..0000000 --- a/plugins/kimchi/po/fr_FR.po +++ /dev/null @@ -1,2338 +0,0 @@ -# English translations for kimchi package. -# Copyright (C) 2013 ORGANIZATION -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2014-08-27 21:30+0000\n" -"Last-Translator: BobSynfig\n" -"Language-Team: French (http://www.transifex.com/projects/p/kimchi/language/" -"fr/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fr_FR\n" -"Generated-By: pygettext.py 1.5\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "Param��tre inconnu %(value)s" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "" - -msgid "Unknown \"_cap\" specified" -msgstr "\"_cap\" sp��cifi��e inconnue" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "\"_passthrough\" doit ��tre \"true\" ou \"false\"" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "\"_passthrough_affected_by\" doit ��tre un nom de p��riph��rique" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "Erreur durant l'acc��s aux p��riph��riques de bloc. D��tails: %(err)s" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "" -"Erreur durant l'obtention de l'information sur le p��riph��rique de bloc %" -"(device)s." - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "Impossible de trouver le fichier de distro: %(filename)s" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "" -"Impossible de parser le fichier de distro: %(filename)s. Veuillez vous " -"assurer qu'il s'agit d'un fichier JSON." - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "" -"Impossible de se connecter �� l'h��te cible iSCSI %(portal)s. D��tails: %(err)s " - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "Impossible de se connecter �� l'h��te iSCSI %(host)s cible %(target)s" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "Impossible de trouver le fichier ISO %(filename)s" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "Le fichier ISO %(filename)s n'est pas bootable" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "" -"Le fichier ISO %(filename)s n'a pas d'enregistrement de boot El Torito valide" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "Entr��e de validation El Torito invalide dans l'ISO %(filename)s" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "Indicateur de boot El Torito invalide dans l'ISO %(filename)s" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "" -"Type de volume inattendu pour le volume primaire dans l'ISO %(filename)s" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "" -"Mauvais format durant la lecture du descripteur de volume dans l'ISO %" -"(filename)s" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" -"L'hyperviseur n'a pas la permission d'utiliser cet ISO %(filename)s. " -"Veuillez consid��rer de le d��placer sous /var/lib/libvirt,, ou de d��finir la " -"permission de recherche sur les listes de contrpole d'acc��s fichier pour " -"l'utilisateur '%(user)s' si possible, ou ajouter le '%(user)s' au groupe de " -"chemins d'ISO, ou (non recommand��) 'chmod -R o+x 'chemin_vers_iso'.D��tails: " -"%(err)s" - -msgid "An error occurred when probing image OS information." -msgstr "" -"Une erreur est survenue lors de la d��tection de l'information d'OS de " -"l'image." - -msgid "No OS information found in given image." -msgstr "Aucune information d'OS trouv��e sur l'image donn��e." - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "Impossible de lire le fichier image %(filename)s" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" -"Le fichier image doit ��tre un fichier existant sur le syst��me. %(filename)s " -"n'est pas une donn��e valide." - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "La machine virtuelle %(name)s existe d��j��" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "La machine virtuelle %(name)s n'existe pas" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" -"Impossible de renommer la machine virtuelle %(name)s. Le nom %(new_name)s " -"est d��ja utilis�� ou la machine virtuelle n'est pas ��teinte." - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "" -"Impossible de r��cup��rer une capture d'��cran pour la machine virtuelle " -"stopp��e %(name)s" - -msgid "Remote ISO image is not supported by this server." -msgstr "L'image ISO distante n'est pas support��e par le serveur." - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "Copie d'��cran non support��e par la machine virtuelle %(name)s" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "Impossible de cr��er la machine virtuelle %(name)s. D��tails: %(err)s" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Impossible de mettre �� jour la machine virtuelle %(name)s. D��tails: %(err)s" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Impossible de r��cup��rer la machine virtuelle %(name)s. D��tails: %(err)s" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "Impossible de se connecter �� la machine virtuelle ��teinte %(name)s." - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "L'adresse d'��coute du graphics doit ��tre IPv4 ou IPv6" - -msgid "Specify a template to create a virtual machine from" -msgstr "Sp��cifier un mod��le �� partir duquel cr��er une machine virtuelle" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "Impossible de d��marrer la machine virtuelle %(name)s. D��tails: %(err)s" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Impossible de mettre hors tension la machine virtuelle %(name)s. D��tails: %" -"(err)s" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Impossible de supprimer la machine virtuelle %(name)s. D��tails: %(err)s" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Impossible de r��initrialiser la machine virtuelle %(name)s. D��tails: %(err)s" - -msgid "User name list must be an array" -msgstr "" - -msgid "User name must be a string" -msgstr "Le nom d'utilisateur doit ��tre une cha��ne de caract��res" - -msgid "Group name list must be an array" -msgstr "" - -msgid "Group name must be a string" -msgstr "Le nom de groupe doit ��tre une cha��ne de caract��res" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "Le(s) utilisateur(s) '%(users)s' n'existe(nt) pas" - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "Le(s) groupe(s) '%(groups)s' n'existe(nt) pas" - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "Impossible d'��teindre la machine virtuelle %(name)s. D��tails: %(err)s" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Impossible d'acc��der aux metadata de la machine virtuelle %(name)s. D��tails: " -"%(err)s" - -msgid "The guest console password must be a string." -msgstr "Le mot de passe de console invit��e doit ��tre une cha��ne de caract��res." - -msgid "The life time for the guest console password must be a number." -msgstr "La dur��e de vie du mot de passe de console invit��e doit ��tre un nombre" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" -"La machine virtuelle %(vmid)s ne peut pas contenir le p��riph��rique h��te " -"directement assign�� %(dev_name)s." - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" -"The p��riph��rique h��te %(dev_name)s ne peut ��tre directement assign�� �� la " -"machine virtuelle" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" - -msgid "\"name\" should be a device name string" -msgstr "\"name\" doit ��tre un nom de p��riph��rique" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "L'interface %(iface)s n'existe pas dans la machine virtuelle %(name)s" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "" -"Le r��seau %(network)s sp��cifi�� pour la machine virtuelle %(name)s n'existe " -"pas" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "" -"Le type d'interface de machine virtuelle support�� est r��seau uniquement" - -msgid "Network name for virtual machine interface must be a string" -msgstr "" -"Le nom de r��seau pour l'interface de la machine virtuelle doit ��tre une " -"cha��ne de caract��res" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "" -"Mod��le de carte r��seau sp��cifi�� invalide pour l'interface de machine " -"virtuelle" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "" -"Sp��cifier le type et le r��seau �� ajouter �� la nouvelle interface de la " -"machine virtuelle" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "Le mod��le %(name)s existe d��j��" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "" -"Le r��seau '%(network)s' sp��cifi�� pour le mod��le %(template)s n'existe pas" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "" -"Le pool de stockage sp��cifi�� %(pool)s pour le mod��le %(template)s n'existe " -"pas" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "" -"Le pool de stockage sp��cifi�� %(pool)s pour le mod��le %(template)s n'est pas " -"actif" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "Param��tres '%(param)s' sp��cifi�� invalide pour le CDROM" - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "" -"Le r��seau %(network)s sp��cifi�� pour le mod��le %(template)s n'est pas actif" - -msgid "Template name must be a string" -msgstr "Le mod��le de nom doit ��tre une cha��ne de caract��res" - -msgid "Template icon must be a path to the image" -msgstr "Le mod��le d'icone doit ��tre un chemin vers l'image" - -msgid "Template distribution must be a string" -msgstr "Le mod��le de distribution doit ��tre une cha��ne de caract��res" - -msgid "Template distribution version must be a string" -msgstr "" -"Le mod��le de version de distribution doit ��tre une cha��ne de caract��res" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "Le nombre de CPU doit ��tre un nombre entier sup��rieur �� 0" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "La quantit�� de m��moire (Mo) doit ��tre un nombre entier sup��rieur �� 512" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "Le CDROM mod��le doit ��tre un fichier ISO local ou distant" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "URI %(value)s du pool de stockage sp��cifi��e invalide pour le mod��le" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "" -"Sp��cifiez une image ISO comme CDROM ou une image de base pour cr��er un mod��le" - -msgid "All networks for the template must be specified in a list." -msgstr "Tous les r��seaux pour le mod��le doivent ��tre sp��cifi��s dans une liste" - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "Le volume %(volume)s n'est pas dans le pool de stockage %(pool)s" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "Impossible de cr��er le mod��le �� cause de l'erreur: %(err)s" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "Impossilbe de supprimer le mod��le �� cause de l'erreur: %(err)s" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "La taille de disque doit ��tre un entier sup��rieur �� 1Go." - -msgid "Template base image must be a valid local image file" -msgstr "L'image de base de mod��le doit petre un fichier image local valide" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "Ne peut identifier le format de l'image de base %(path)s" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" -"Dans la topologie de CPU, chaque ��l��ment doit ��tre un entier strictement " -"positif." - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "Le pool de stockage %(name)s existe d��j��" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "Le pool de stockage %(name)s n'existe pas" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "Sp��cifier %(item)s afin de cr��er le pool de stockage %(name)s" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "Impossible de supprimer le pool de stockage actif %(name)s" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "Impossible de lister les pools de stockage. D��tails: %(err)s" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "Impossilble de cr��er le pool de stockage %(name)s. D��tails: %(err)s" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "" -"Impossible d'obtenir le nombre de volumes de stockage dans le pool de " -"stockage%(name)s. D��tails: %(err)s" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "Impossible d'activer le pool de stockage %(name)s. D��tails: %(err)s" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "" -"Impossible de d��sactiver le pool de stockage %(name)s. D��tails: %(err)s" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "" -"Impossible de supprimer le pool de stockage %(name)s. D��tails: %(err)s " - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "" -"Impossible de cr��er le Pool NFS du fait que le chemin d'export %(path)s " -"pourrait se bloquer durant le montage" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "" -"Impossible de cr��er le pool NFS du fait que le montage du chemin d'export %" -"(path)s a ��chou��" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "Type de pool de stockage non support��: %(type)s" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" -"Les types de pool de stockage support��s sont: dir, netfs, logical, iscsi, " -"isci et kimchi-iso" - -msgid "Storage pool path must be a string" -msgstr "Le chemin du pool de stockage doit ��tre une cha��ne de caract��res" - -msgid "Storage pool host must be a IP or hostname" -msgstr "L'h��te du pool de stockage doit ��tre une IP ou un nom d'h��te" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" - -msgid "Storage pool devices parameter must be a list" -msgstr "Le param��tre de p��riph��rique de pool de stockage doit ��tre une list" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "La cible IQN d'un pool iSCSI doit ��tre une cha��ne de caract��res" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "" -"Le port d'un serveur de stockage distant doit ��tre un nombre entier entre 1 " -"et 65535" - -msgid "iSCSI target username must be a string" -msgstr "" -"Le nom d'utilisateur de la cible iSCSI doit ��tre une cha��ne de caract��res" - -msgid "iSCSI target password must be a string" -msgstr "Le mot de passe de la cible iSCSI doit ��tre une cha��ne de caract��res" - -msgid "Specify name and type to create a storage pool" -msgstr "Sp��cifier un nom et un type pour cr��er un pool de stockage" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "" -"%(disk)s n'est pas un(e) disque/partition valide. N'a pu l'ajouter au pool %" -"(pool)s." - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "Impossible d'agrandir le pool logique %(pool)s. D��tails: %(err)s" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "" -"Les disques en param��tre peuvent seulement ��tre mis �� jour pour un pool de " -"stockage logique." - -msgid "The SCSI host adapter name must be a string." -msgstr "Le nom d'adaptateur de l'h��te SCSI doit ��tre une chapine de caract��res" - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "Le pool de stockage kimchi_isos est r��serv�� �� un usage interne" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"Impossible d'activer le pool de stockage NFS%(name)s. Le serveur NFS %" -"(server)s n'est pas joignable." - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"Impossible de d��sactiver le pool de stockage NFS%(name)s. Le serveur NFS %" -"(server)s n'est pas joignable." - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "" -"Impossible de d��sactiver le pool %(name)s du fait qu'il est associ�� �� des " -"mod��les" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "" -"Impossible de supprimer le pool %(name)s du fait qu'il est associ�� �� des " -"mod��les" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "" -"Un groupe de volume appel�� '%(name)s' existe d��j��. Veuillez choisir un autre " -"nom pour cr��er le pool logique." - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "" -"Impossible de mettre �� jour la base de donn��es avec les informations de scan " -"profond �� cause de l'erreur: %(err)s" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "Le volume de stockage %(name)s existe d��j��" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "" -"Le volume de stockage %(name)s n'existe pas dans le pool de stockage %(pool)s" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" -"Impossible de cr��er le volume de stockage %(volume)s car le pool de stockage " -"%(pool)s n'est pas actif" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "Sp��cifier %(item)s afin de cr��er le volume de stockage %(volume)s" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "" -"Impossible de lister les volumes de stockage car le pool de stockage %(pool)" -"s n'est pas actif" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "" -"Impossible de cr��er le volume de stockage %(name)s dans le pool de stockage %" -"(pool)s. D��tails: %(err)s" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "" -"Impossible de lister les volumes de stockage dans le pool de stockage %(pool)" -"s. D��tails: %(err)s" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "Impossible de wiper les volumes de stockage %(name)s. D��tails: %(err)s" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "" -"Impossible de supprimer le volume de stockage %(name)s. D��tails: %(err)s " - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "" -"Impossible de redimensionner le volume de stockage %(name)s. D��tails: %(err)s" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "" -"Le type de stockage %(type)s ne supporte pas ni la cr��ation ni la " -"suppression de volume" - -msgid "Storage volume name must be a string" -msgstr "Le nom de volume de stockage doit ��tre une cha��ne de caract��res" - -msgid "Storage volume allocation must be an integer number" -msgstr "L'allocation de volume de stockage doit ��tre une nombre entier" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" - -msgid "Storage volume requires a volume name" -msgstr "Le volume de stockage requiert un nom de volume" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "" -"Impossible de mettre �� jour la base de donn��es avec les informations du " -"volume de stockage �� cause de l'erreur: %(err)s" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "Seulement un seul des param��tre %(param)s peut ��tre sp��cifi��" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "La cr��ation de volume avec %(param)s n'est pas support��e" - -msgid "Storage volume capacity must be an integer number." -msgstr "La capacit�� du volume de stockage doit ��tre un nombre entier." - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" -"L'URL du volume de stockage doit ��tre http://, https://, ftp:// ou ftps://." - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "Impossible d'acc��der au fichier %(url)s. Veuillez le v��rifier." - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "L'interface %(name)s n'existe pas" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "Le r��seau %(name)s existe d��j��" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "Le r��seau %(name)s n'existe pas" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "" -"Le sous-r��seau %(subnet)s sp��cifi�� pour le r��seau %(network)s n'est pas " -"valide" - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "Sp��cifier une interface r��seau pour cr��er le r��seau bridge %(name)s" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "Impossible de supprimer le r��seau actif %(name)s" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "" -"L'interface %(iface)s sp��cifi��e pour le r��seau %(network)s est d��j�� utilis��e" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "L'interface doit ��tre un p��riph��rique NIC vide, bonding ou bridg��." - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "Impossible de cr��er le r��seau %(name)s. D��tails: %(err)s" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "Impossible de trouver une adresse IP libre pour le r��seau '%(name)s'" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "L'interface %(iface)s existe d��j��" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "Les types de r��seaux support��s sont isolated, NAT et bridge" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "" -"Le sous-r��seau doit ��tre une chaine de caract��res avec une adresse IP et un " -"pr��fixe ou un masque de r��seau" - -msgid "Network interface must be a string" -msgstr "L'interface de r��seau doit ��tre une cha��ne de caract��res" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "L'ID de VLAN du r��seau doit ��tre un nombre entier entre 1 et 4094" - -msgid "Specify name and type to create a Network" -msgstr "Sp��cifiez un nom et un type pour cr��er un r��seau" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" -"Impossible de supprimer le r��seau %(name)s. Il y a des machines virtuelles %" -"(vms)s et/ou des mod��les li��s �� ce r��seau. " - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" -"Impossible de d��sactiver r��seau %(name)s. Il y a des machines virtuelles%" -"(vms)s et/ou des mod��les li��s �� ce r��seau. " - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "" -"Le p��riph��rique bridge %(name)s ne peut ��tre le p��riph��rique tronc d'un VLAN." - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "��chec durant l'activation de l'interface %(iface)s: %(err)s." - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "" -"��chec durant l'activation de l'interface %(iface)s. Veuillez v��rifier le " -"statut du lien physique." - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "Le rapport de d��boggage %(name)s n'existe pas" - -msgid "Debug report tool not found in system" -msgstr "L'outil de rapport de d��boggage n'a pas ��t�� trouv�� dans le syst��me" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "" -"Impossible de cr��er le rapport de d��boggage %(name)s. D��tails: %(err)s." - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "" -"Impossible de trouver un rapport de d��boggage avec le nom fourni %(name)s" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "" -"Impossible de g��n��rer le rapport de d��boggage %(name)s. D��tails: %(err)s" - -msgid "You should give a name for the debug report file." -msgstr "Vous devriez donner un nom au fichier de rapport de d��boggage." - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" -"Le nom du rapport de d��boggage doit ��tre une cha��ne de caract��res. Seulement " -"les lettres, chiffres, blanc soulign�� ('_') et tirets ('-') sont accept��s." - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "" -"Le rapport de d��boggage avec le nom sp��cifi�� \"%(name)s\" existe d��j��. " -"Veuillez en utiliser un autre." - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "Le server de stockage %(server)s n'��tait pas utilis�� par Kimchi" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "La distro '%(name)s' n'existe pas" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "La partition %(name)s n'existe pas sur cet h��te" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "" -"Impossible d'��teindre la machine h��te car des machines virtuelles en sont " -"cours d'ex��cution" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "" -"Impossible de red��marrer la machine h��te car des machines virtuelles en sont " -"cours d'ex��cution" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "P��riph��rique de noeud '%(name)s' non trouv��" - -msgid "Conflicting flag filters specified." -msgstr "Filtres incompatibles sp��cifi��s." - -msgid "No packages marked for update" -msgstr "Aucun paquet marqu�� pour mise �� jour" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "Le paquet %(name)s n'est pas marqu�� pour mise �� jour" - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "" -"Erreur durant la r��cup��ration des paquets marqu��s pour la mise�� jour. " -"D��tails: %(err)s" - -msgid "There is no compatible package manager for this system." -msgstr "Il n'y a pas de gestionnaire de paquets compatible avec ce syst��me." - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "URI %(uri)s invalide" - -msgid "Unable to choose a virtual machine name" -msgstr "Impossible de s��lectionner un nom de machine virtuelle" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "Type de stockage invalide. Les Types support��s sont: 'cdrom', 'disk'" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" - -msgid "Only CDROM path can be update." -msgstr "Seulement le chemin d'un CDROM peut ��tre modifi��." - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "" -"Le p��riph��rique de stockage %(dev_name)s n'existe pas dans la machine " -"virtuelle %(vm_name)s" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "" -"Erreur durant la cr��ation du nouveau p��riph��rique de stockage: %(error)s" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "Erreur durant la mise �� jour du p��riph��rique de stockage: %(error)s" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "Erreur durant le retrait du p��riph��rique de stockage: %(error)s" - -msgid "Do not support IDE device hot plug" -msgstr "Ne pas supporter le branchement �� chaud de p��riph��rique IDE" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "" -"Sp��cifier le type et le chemin ou le type et le pool/volume pour ajouter un " -"nouveau disque de machine virtuelle." - -msgid "Specify path to update virtual machine disk" -msgstr "Sp��cifier un chemin pour mettre �� jour le disque de machine virtuelle" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" -"La limitation de %(limit)s p��riph��riques a ��t�� atteinte pour le contr��leur " -"de type %(type)s " - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" - -msgid "Volume already in use by other virtual machine." -msgstr "" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "" -"Seul un chemin ou pool/volume peut ��tre sp��cifi�� pour ajouter un nouveau " -"disque de machine virtuelle" - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" -"Le volume de format %(format)s s��lectionn�� ne correspond pas au type de " -"stockage %(type)s" - -msgid "YUM Repository ID must be one word only string." -msgstr "" -"L'ID du d��p��t YUM doit ��tre une cha��ne de caract��res ne comportant qu'un " -"seul mot" - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "L'URL du d��p��t doit ��tre une URL en http://, ftp:// ou file://." - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "" -"La configuration du d��p��t est un dictionaire avec des valeurs sp��cifiques en " -"accord avec le type de d��p��t." - -msgid "Distribution to DEB repository must be a string" -msgstr "" -"La distribution dans le nom de d��p��t DEB doit ��tre une cha��ne de caract��res" - -msgid "Components to DEB repository must be listed in a array" -msgstr "Les composants dans le d��p��t DEB doivent ��tre list��s dans un tableau" - -msgid "Components to DEB repository must be a string" -msgstr "Les composants dans le d��p��t DEB doivent ��tre une cha��ne de caract��res" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "Le nom du d��p��t YUM doit ��tre une cha��ne de caract��res" - -msgid "GPG check must be a boolean value." -msgstr "La v��rification GPG doit ��tre une valeur bool��enne." - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "La cl�� GPG doit ��tre une URL pointant vers un fichier ASCII non arm��." - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "Ne peut mettre �� jour le d��p��t %(repo_id)s." - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "Le d��p��t %(repo_id)s n'existe pas." - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "L'outil de gestion de d��p��t n'a pas ��t�� reconnu pour votre syst��me." - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "Le d��p��t %(repo_id)s est d��j�� activ��." - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "Le d��p��t %(repo_id)s est d��j�� d��sactiv��." - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "Ne peut supprimer le d��p��t %(repo_id)s. " - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "Ne peut ��crire le fichier de configuration du d��p��t %(repo_file)s" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "Sp��cifier la distribution du d��p��t afin de cr��er un d��p��t DEB." - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "Ne peut activer le d��p��t %(repo_id)s." - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "Ne peut d��sactiver le d��p��t %(repo_id)s." - -msgid "YUM Repository ID already exists" -msgstr "L'ID du d��p��t YUM existe d��j��" - -msgid "YUM Repository name must be a string" -msgstr "Le nom du d��p��t YUM doit ��tre une cha��ne de caract��res" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "Impossible de lister les d��p��ts. D��tails: '%(err)s'" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "Impossible de r��cup��rer les informations du d��p��t. D��tails: '%(err)s'" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "Impossible d'ajouter un d��p��t. D��tails: '%(err)s'" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "Impossible de supprimer un d��p��t. D��tails: '%(err)s'" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" -"��l��ments de configurations: %(items)s ne sont pas support��s par le " -"gestionnaire de d��p��t" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" - -msgid "The number of vCPUs is too large for this system." -msgstr "" - -msgid "Invalid vCPU/topology combination." -msgstr "" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "" - -msgid "ERROR CODE" -msgstr "ERROR CODE" - -msgid "REASON" -msgstr "REASON" - -msgid "STACK" -msgstr "STACK" - -msgid "Go to Homepage" -msgstr "Aller �� la page d'accueil" - -msgid "Create a New Virtual Machine" -msgstr "Cr��er une nouvelle Machine Virtuelle" - -msgid "Virtual Machine Name" -msgstr "Nom de Machine Virtuelle" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "" -"Le nm est utilis�� pour identifier une machine virtuelle. Si omis, un nom " -"sera choisi en se basant sur le mod��le utilis��." - -msgid "Template" -msgstr "Mod��le" - -msgid "Please create a template first." -msgstr "Veuillez d'abord cr��er un mod��le." - -msgid "Create a Template" -msgstr "Cr��er un mod��le" - -msgid "Please choose a template." -msgstr "Veuillez choisir un mod��le" - -msgid "OS" -msgstr "OS" - -msgid "OS Version" -msgstr "Version de l'OS" - -msgid "CPUS" -msgstr "CPUS" - -msgid "Memory" -msgstr "M��moire" - -msgid "Create" -msgstr "Cr��er" - -msgid "Creating..." -msgstr "Cr��ation en cours..." - -msgid "Cancel" -msgstr "Annuler" - -msgid "Edit Guest" -msgstr "��diter l'Invit��" - -msgid "General" -msgstr "G��n��ral" - -msgid "Storage" -msgstr "Stockage" - -msgid "Interface" -msgstr "Interface" - -msgid "Permission" -msgstr "Permission" - -msgid "Host PCI Device" -msgstr "P��riph��rique PCI H��te" - -msgid "Snapshot" -msgstr "" - -msgid "Name" -msgstr "Nom" - -msgid "CPUs" -msgstr "CPUs" - -msgid "Memory (MB)" -msgstr "M��moire (Mo)" - -msgid "Icon" -msgstr "Icone" - -msgid "Device" -msgstr "P��riph��rique" - -msgid "Path" -msgstr "Chemin" - -msgid "Network" -msgstr "R��seau" - -msgid "Type" -msgstr "Type" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "Utilisateurs et groupes syst��mes disponibles" - -msgid "Selected system users and groups" -msgstr "Utilisateurs et groupes syst��mes s��lectionn��s" - -msgid "User" -msgstr "" - -msgid "All" -msgstr "Tous" - -msgid "To Add" -msgstr "�� Ajouter" - -msgid "Added" -msgstr "Ajouter" - -msgid "filter" -msgstr "Filtre" - -msgid "Product" -msgstr "Produit" - -msgid "Vendor" -msgstr "Vendeur" - -msgid "Created" -msgstr "" - -msgid "Save" -msgstr "Enregistrer" - -msgid "Replace" -msgstr "Remplacer" - -msgid "Detach" -msgstr "D��tacher" - -msgid "revert" -msgstr "" - -msgid "Start" -msgstr "D��marrer" - -msgid "Reset" -msgstr "R��initialiser" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "Mettre hors tension" - -msgid "Actions" -msgstr "Actions" - -msgid "Connect" -msgstr "Connecter" - -msgid "Clone" -msgstr "Cloner" - -msgid "Edit" -msgstr "��diter" - -msgid "Shut Down" -msgstr "��teindre" - -msgid "Delete" -msgstr "Supprimer" - -msgid "CPU" -msgstr "CPU" - -msgid "Disk I/O" -msgstr "E/S Disque" - -msgid "Network I/O" -msgstr "E/S R��seau" - -msgid "Livetile" -msgstr "Livetile" - -msgid "No guests found." -msgstr "Aucun invit�� trouv��." - -msgid "Add a Storage Device to VM" -msgstr "Ajouter un P��riph��rique de Stockage �� la VM" - -msgid "Device Type" -msgstr "Type de P��riph��rique" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "" -"Le type de p��riph��rique. Actuellement, \"cdrom\" et \"disk\" sont support��s." - -msgid "Storage Pool" -msgstr "Pool de Stockage" - -msgid "Storage pool which volume located in" -msgstr "Pool de Stockage dans lequel le volume est situ��" - -msgid "Storage Volume" -msgstr "Volume de Stockage" - -msgid "Storage volume to be attached" -msgstr "Le volume de stockage �� attacher" - -msgid "File Path" -msgstr "Chemin de Fichier" - -msgid "The ISO file path in the server for CDROM." -msgstr "Le chemin de fichier ISO sur le serveur comme CDROM." - -msgid "Attach" -msgstr "Attacher" - -msgid "Shut down" -msgstr "��teindre" - -msgid "Restart" -msgstr "Red��marrer" - -msgid "Basic Information" -msgstr "Informations de Base" - -msgid "OS Distro" -msgstr "Distro de l'OS" - -msgid "OS Code Name" -msgstr "Nom de code de l'OS" - -msgid "Processor" -msgstr "Processeur" - -msgid "CPU(s)" -msgstr "" - -msgid "System Statistics" -msgstr "Statistiques Syst��me" - -msgid "Software Updates" -msgstr "Mises �� jour Logiciel" - -msgid "Update Progress" -msgstr "Progr��s de la Mise �� Jour" - -msgid "Repositories" -msgstr "D��p��ts" - -msgid "Debug Reports" -msgstr "Rapports de D��boggage" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "" -"Le nom d'utilisateur ou le mot de passe que vous avez entr�� est incorrect. " -"Veuillez essayer �� nouveau." - -msgid "This field is required." -msgstr "Ce champ est requis." - -msgid "Log in" -msgstr "Se connecter" - -msgid "Logging in..." -msgstr "En cours de connexion..." - -msgid "Host" -msgstr "H��te" - -msgid "Guests" -msgstr "Invit��s" - -msgid "Templates" -msgstr "Mod��les" - -msgid "Failed to get application configuration" -msgstr "��chec lors de l'obtention de la configuration de l'application" - -msgid "This is not a valid Linux path" -msgstr "Ce n'est pas un chemin Linux valide" - -msgid "This is not a valid URL." -msgstr "Ce n'est pas une URL valide." - -msgid "No such data available." -msgstr "De telles donn��es ne sont pas disponibles." - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" -"Ne peut contacter le syst��me h��te. V��rifiez que le syst��me h��te est allum�� " -"et que vous avez une connectivit�� r��seau avec lui. R��ponse de requ��te HTTP %" -"1." - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "Confirmation de Suppression" - -msgid "OK" -msgstr "OK" - -msgid "Confirm" -msgstr "Confirmer" - -msgid "Warning" -msgstr "Avertissement" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "Chargement en cours..." - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "Essayer �� nouveau" - -msgid "Detailed message:" -msgstr "Message d��taill��:" - -msgid "No ISO found" -msgstr "Aucune ISO d��tect��e" - -msgid "This is not a valid ISO file." -msgstr "Ce n'est pas un fichier ISO valide." - -msgid "This may take a long time. Do you want to continue?" -msgstr "Cela va prendre un long moment. Voulez-vous continuer ?" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "" -"Cela va supprimer de mani��re permanent le mod��le. Souhaites-vous continuer ?" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "" -"Impossible d'��teindre le syst��me du fait que certaines machines virtuelles " -"sont lanc��es !" - -msgid "Max:" -msgstr "Max:" - -msgid "Utilization" -msgstr "Utilisation" - -msgid "Available" -msgstr "Disponible" - -msgid "Read Rate" -msgstr "Taux en Lecture" - -msgid "Write Rate" -msgstr "Taux en ��criture" - -msgid "Received" -msgstr "Re��u" - -msgid "Sent" -msgstr "Envoy��" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"��teindre ou red��marrer l'h��te causera la perte de tout travail non " -"enregistr��. Continuer �� ��teindre/red��marrer ?" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"Le d��p��t sera retir�� de fa��on permanente et ne pourra ��tre r��tabli. Voulez-" -"vous continuer ?" - -msgid "ID" -msgstr "ID" - -msgid "Base URL" -msgstr "URL de base" - -msgid "Is Mirror" -msgstr "Est un miroir" - -msgid "URL Args" -msgstr "Arguments d'URL" - -msgid "Enabled" -msgstr "Activ��" - -msgid "GPG Check" -msgstr "V��rification GPG" - -msgid "GPG Key" -msgstr "Cl�� GPG" - -msgid "Add" -msgstr "Ajouter" - -msgid "Remove" -msgstr "Retirer" - -msgid "Enable" -msgstr "Activer" - -msgid "Disable" -msgstr "D��sactiver" - -msgid "Package Name" -msgstr "Nom de paquet" - -msgid "Version" -msgstr "Version" - -msgid "Architecture" -msgstr "Architecture" - -msgid "Repository" -msgstr "D��p��t" - -msgid "Update All" -msgstr "Tout mettre �� jour" - -msgid "Updating..." -msgstr "En cours de mise �� jour..." - -msgid "Failed to retrieve packages update information." -msgstr "��chec de r��cup��ration des informations de mise-��-jour des paquets." - -msgid "Failed to update package(s)." -msgstr "��chec durant la mise �� jour du/des paquet(s)" - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"Le rapport de d��boggage sera enlev�� de fa��on permanente et ne pourra ��tre " -"r��tabli. Voulez-vous continuer ?" - -msgid "Generated Time" -msgstr "Horodatage de g��n��ration" - -msgid "Generate" -msgstr "G��n��rer" - -msgid "Generating..." -msgstr "En cours de g��n��ration..." - -msgid "Rename" -msgstr "Renommer" - -msgid "Download" -msgstr "T��l��charger" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "" -"Le nom de rapport devrait contenir uniquement des lettres, nombres, " -"soulignement ('_') et/ou tiret ('-')." - -msgid "Pending..." -msgstr "En attente..." - -msgid "Report name is the same as the original one." -msgstr "Le nom du rapport est le m��me que celui d'origine." - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "" -"Cela va supprimer la machine virtuelle et tous ses disques virtuels. Cette " -"op��ration est irr��versible. Voulez-vous continuer ?" - -msgid "Power off Confirmation" -msgstr "Confirmation de mise hors tension" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" -"Cette action pourrait produire des r��sultats ind��sirables, par exemple un " -"cache disque non flush�� dans l'invit��. Voulez-vous continuer ?" - -msgid "Reset Confirmation" -msgstr "Confirmation de R��initialisation" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" -"Il y a un risque de perte de donn��es caus��es par une r��initialisation sans " -"extinction de l'OS invit��. Voulez-vous continuer ?" - -msgid "Shut Down Confirmation" -msgstr "Confirmation d'Extinction" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "" -"Noter que l'OS invit�� pourrait ignorer cette requ��te. Voulez-vous continuer ?" - -msgid "Virtual Machine delete Confirmation" -msgstr "Confirmation de suppression de Machine Virtuelle" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" -"Ce CDROM sera d��tach�� de fa��on permanente et vous pourrez le r��-attacher. " -"Continuer le d��tachement ?" - -msgid "Attaching..." -msgstr "En cours d'attachement..." - -msgid "Replacing..." -msgstr "En cours de Remplacement..." - -msgid "Successfully attached!" -msgstr "Attach�� avec succ��s !" - -msgid "Successfully replaced!" -msgstr "Remplac�� avec succ��s !" - -msgid "Successfully detached!" -msgstr "D��tach�� avec Succ��s !" - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" -"Ce disque sera d��finitivement d��tach�� et peut ��tre r��-attach��. Continuer �� " -"le d��tacher ?" - -msgid "interface:" -msgstr "" - -msgid "address:" -msgstr "" - -msgid "link_type:" -msgstr "" - -msgid "block:" -msgstr "" - -msgid "drive_type:" -msgstr "" - -msgid "model:" -msgstr "" - -msgid "Affected devices:" -msgstr "" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "L'id du VLAN doit ��tre entre 1 et 4094." - -msgid "unavailable" -msgstr "non disponible" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" -"Cette action va interrompre la connectivit�� r��seau pour tout machine " -"virtuelle qui d��pend de ce r��seau." - -msgid "Create a network" -msgstr "Cr��er un r��seau" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"Ce r��seau n'est pas persistant. Au lieu de s'arr��ter, cette actionva le " -"suppromer de mani��re permanente. Voulez-vous continuer ?" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "" -"Cela va effacer de mani��re permanente le pool de stockage. Voulez-vous " -"continuer ?" - -msgid "This storage pool is empty." -msgstr "Ce pool de stockage est vide." - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" -"Cela va formater votre disque et vous allez perdre toutes les donn��es qui " -"s'y trouvent, ��tes-vous s��r de continuer ?" - -msgid "SCSI Fibre Channel" -msgstr "Canal Fibre SCSI" - -msgid "No SCSI adapters found." -msgstr "Aucun adaptateur SCSI trouv��." - -msgid "Loading iSCSI targets..." -msgstr "" - -msgid "No iSCSI found. Please input one." -msgstr "" - -msgid "Failed to load iSCSI targets." -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "Le nom de pool de stockage ne peut ��tre vierge." - -msgid "The storage pool path can not be blank." -msgstr "Le chemin de pool de stockage ne peut ��tre vierge." - -msgid "NFS server mount path can not be blank." -msgstr "Le chemin de montage du serveur NFS ne peut ��tre vierge." - -msgid "Invalid NFS mount path." -msgstr "Chemin de montage NFS invalide." - -msgid "No logical device selected." -msgstr "Aucun p��riph��rique logique s��lectionn��." - -msgid "The iSCSI target can not be blank." -msgstr "La cible iSCSI ne peut ��tre vierge." - -msgid "Server name can not be blank." -msgstr "Le nom de serveur ne peut ��tre vierge." - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "" - -msgid "Looking for available partitions ..." -msgstr "En cours de recherche de partitions disponibles..." - -msgid "No available partitions found." -msgstr "Aucune partition disponible trouv��e." - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"Le pool de stockage n'est pas persistent. Au lieu de le d��sactiver, cette " -"action va le supprimer de mani��re permanente. Voulez-vous continuer ?" - -msgid "Unable to retrieve partitions information." -msgstr "Impossible de r��cup��rer les informations des partitions." - -msgid "In progress..." -msgstr "En cours..." - -msgid "Failed!" -msgstr "��chec!" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" -"Le chemin de CDROM doit ��tre un chemin local/distant valide et ne peut ��tre " -"virge." - -msgid "Disk pool or volume cannot be blank." -msgstr "Le pool de disque ou le volume ne peut ��tre vierge." - -#, fuzzy -msgid "Filter" -msgstr "Filtre" - -msgid "Network Name" -msgstr "Nom de R��seau" - -msgid "State" -msgstr "��tat" - -msgid "Network Type" -msgstr "Type de R��seau" - -msgid "Address Space" -msgstr "Espace d'adressage" - -msgid "Name should not contain '/' and '\"'." -msgstr "Le nom ne devrait pas contenir '/' et '\"'." - -msgid "Isolated: no external network connection" -msgstr "Isol��: pas de connexion �� un r��seau externe" - -msgid "NAT: outbound physical network connection only" -msgstr "NAT: connexion physique au r��seau sortant uniquement" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "" -"Bridg��: Les macines virtuelles sont connect��es directement au r��seau physique" - -msgid "(No interfaces found)" -msgstr "(Aucune interface trouv��e)" - -msgid "Destination" -msgstr "Destination" - -msgid "Enable VLAN" -msgstr "Activer le VLAN" - -msgid "VLAN ID" -msgstr "ID de VLAN" - -msgid "Stop" -msgstr "Arr��ter" - -msgid "Generate a New Debug Report" -msgstr "G��n��rer un Nouveau Rapport de D��boggage" - -msgid "Report Name" -msgstr "Nom du Rapport" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" -"Le nom utilis�� pour identifier le rapport. Si omis, un nom sera choisi bas�� " -"sur l'heure courante. Le nom peut contenir des lettres, des nombres, le " -"soulignement (\"_\") et le tiret (\"-\")." - -msgid "Rename a Debug Report" -msgstr "Renommer un Rapport de D��boggage" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" -"Le nom utilis�� pour identifer le rapport. Le nom peut contenir des lettres, " -"nombres et tirets (\"-\")." - -msgid "Submit" -msgstr "Soumettre" - -msgid "Add a Repository" -msgstr "Ajouter un D��p��t" - -msgid "Identifier" -msgstr "Identificateur" - -msgid "Single word, unique identifier for the repository." -msgstr "Mot unique, identifiant unique pour le d��p��t." - -msgid "Textual name for the repository." -msgstr "Nom textuel pour le d��p��t." - -msgid "URL" -msgstr "URL" - -msgid "Required Field" -msgstr "Champ requis" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "URL du d��p��t. Les protocoles support��s sont http, ftp et ficheir." - -msgid "Repository is a mirror" -msgstr "Le d��p��t est un miroir" - -msgid "Distribution" -msgstr "Distribution" - -msgid "Distribution of the DEB repository." -msgstr "Distribution du d��p��t DEB." - -msgid "Components" -msgstr "Composants" - -msgid "List of components in DEB repository." -msgstr "Liste des composants dans le d��p��t DEB." - -msgid "Edit Repository" -msgstr "Editer le D��p��t" - -msgid "Mirror List URL" -msgstr "URL de Liste de Miroir" - -msgid "Yes" -msgstr "Oui" - -msgid "No" -msgstr "Non" - -msgid "Capacity" -msgstr "Capacit��" - -msgid "Allocated" -msgstr "Allou��" - -msgid "Location" -msgstr "Emplacement" - -msgid "Device path" -msgstr "Chemin du P��riph��rique" - -msgid "active" -msgstr "actif" - -msgid "inactive" -msgstr "inactif" - -msgid "Deactivate" -msgstr "D��sactiver" - -msgid "Activate" -msgstr "Activer" - -msgid "Add Volume" -msgstr "Ajouter un Volume" - -msgid "Extend" -msgstr "��tendre" - -msgid "Undefine" -msgstr "Supprimer" - -msgid "Format" -msgstr "Format" - -msgid "Allocation" -msgstr "Allocation" - -msgid "Define a New Storage Pool" -msgstr "D��finir un Nouveau Pool de Stockage" - -msgid "Storage Pool Name" -msgstr "Nom de Pool de Stockage" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "" -"Le nom utilis�� pour identifier les pools de stockage, et il ne doit pas ��tre " -"vide." - -msgid "Storage Pool Type" -msgstr "Type de Pool de Stockage" - -msgid "Storage Path" -msgstr "Chemin de Stockage" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "" -"Le chemin du Pool de Stockage. Chaque Pool de Stockage doit avoir un chemin " -"unique." - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "" -"Kimchi va essayer de cr��er un r��pertoire quand il n'existe pas d��j�� dans " -"votre syst��me." - -msgid "NFS Server IP" -msgstr "IP du Serveur NFS" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "" -"IP du Serveur NFS ou nom d'h��te. Il peut ��tre saisi ou entr�� �� partir de " -"l'historique." - -msgid "NFS Path" -msgstr "Chemin NFS" - -msgid "The NFS exported path on NFS server." -msgstr "Le chemin NFS export�� sur le serveur NFS." - -msgid "iSCSI Server" -msgstr "Serveur iSCSI" - -msgid "Server" -msgstr "Serveur" - -msgid "Port" -msgstr "Port" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "IP du Serveur iSCSI ou nom d'h��te. Il ne devrait pas ��tre vide." - -msgid "Target" -msgstr "Cible" - -msgid "The iSCSI target on iSCSI server" -msgstr "La cible iSCSI sur le serveur iSCSI" - -msgid "Add iSCSI Authentication" -msgstr "Ajouter l'Authentification iSCSI" - -msgid "iSCSI Authentication" -msgstr "Authentification iSCSI" - -msgid "User Name" -msgstr "Nom d'Utilisateur" - -msgid "Password" -msgstr "Mot de Passe" - -msgid "SCSI Adapter" -msgstr "Adaptateur SCSI" - -msgid "Please, wait..." -msgstr "Veuillez patienter..." - -msgid "Add a Volume to Storage Pool" -msgstr "iAjouter un Volume au Pool de Stockage" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "Saisir une URL distante ici" - -msgid "Upload a file" -msgstr "Charger un fichier" - -msgid "Choose the file you want to upload." -msgstr "" - -msgid "Add Template" -msgstr "Ajouter un Mod��le" - -msgid "Where is the source media for this template? " -msgstr "O�� se trouve le media source pour le mod��le ?" - -msgid "Local ISO Image" -msgstr "Image ISO Locale" - -msgid "Local Image File" -msgstr "Fichier Image Local" - -msgid "Remote ISO Image" -msgstr "Image ISO Distante" - -msgid "Search ISOs" -msgstr "Rechercher des ISOs" - -msgid "The following ISOs are available:" -msgstr "Les ISOs suivants sont disponibles:" - -msgid "OS: " -msgstr "OS: " - -msgid "Version: " -msgstr "Version: " - -msgid "Size: " -msgstr "Taille: " - -msgid "Search more ISOs" -msgstr "Chercher plus d'ISOs" - -msgid "Create Templates from Selected ISO" -msgstr "Cr��er des mod��les depuis l'ISO s��lectionn��" - -msgid "I want to use a specific ISO file" -msgstr "Je veux utiliser un fichier ISO sp��cifique" - -msgid "Loading default remote ISOs ..." -msgstr "Chargement des ISOs distants par d��faut en cours..." - -msgid "Arch: " -msgstr "Arch: " - -msgid "I want to use a custom URL" -msgstr "Je veux utiliser une URL personnalis��e" - -msgid "Edit Template" -msgstr "��diter un Mod��le" - -msgid "CDROM" -msgstr "CDROM" - -msgid "Image File" -msgstr "Fichier Image" - -msgid "Graphics" -msgstr "Graphiques" - -msgid "Disk(GB)" -msgstr "" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "Nombre de CPU" - -msgid "Manually set CPU topology" -msgstr "" - -msgid "Cores" -msgstr "" - -msgid "Threads" -msgstr "" - -msgid "No templates found." -msgstr "Aucun mod��le trouv��." - -#~ msgid "Delete is not allowed for %(resource)s" -#~ msgstr "La suppression n'est pas autoris��e pour %(resource)s" - -#~ msgid "%(resource)s does not implement update method" -#~ msgstr "%(resource)s n'impl��mente pas de m��thode de mise �� jour" - -#~ msgid "Create is not allowed for %(resource)s" -#~ msgstr "La cr��ation n'est pas autoris��e pour %(resource)s" - -#~ msgid "Unable to parse JSON request" -#~ msgstr "Impossible de parser la requ��te JSON" - -#~ msgid "This API only supports JSON" -#~ msgstr "Cette API supporte uniquement le JSON" - -#~ msgid "Parameters does not match requirement in schema: %(err)s" -#~ msgstr "" -#~ "Les param��tres ne correspondent pas �� ce qui est requis dans le sch��ma: %" -#~ "(err)s" - -#~ msgid "You don't have permission to perform this operation." -#~ msgstr "Vous n'avez pas la permission d'effectuer cette op��ration." - -#~ msgid "Datastore is not initiated in the model object." -#~ msgstr "Le magasin de donn��es n'est pas initi�� dans l'objet mod��le." - -#~ msgid "Unable to start task due error: %(err)s" -#~ msgstr "Impossible de d��marrer la t��che �� cause de l'erreur: %(err)s" - -#~ msgid "" -#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" -#~ msgstr "" -#~ "L'authentification a ��chou�� pour l'utilisateur '%(username)s'. [Code " -#~ "d'Erreur: %(code)s]" - -#~ msgid "You are not authorized to access Kimchi" -#~ msgstr "Vous n'��tes pas autoris�� �� acc��der �� Kimchi" - -#~ msgid "Specify %(item)s to login into Kimchi" -#~ msgstr "Sp��cifiez %(item)s pour vous logguer dans Kimchi" - -#~ msgid "Unable to find %(item)s in datastore" -#~ msgstr "Impossible de trouver %(item)s dans le magasin de donn��es" - -#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" -#~ msgstr "" -#~ "Timeout durant l'ex��cution de la commande '%(cmd)s' apr��s %(seconds)s " -#~ "secondes" - -#~ msgid "Help" -#~ msgstr "Aide" - -#~ msgid "About" -#~ msgstr "A propos..." - -#~ msgid "Log out" -#~ msgstr "Se d��connecter" - -#~ msgid "Version:" -#~ msgstr "Version:" - -#~ msgid "Session timeout, please re-login." -#~ msgstr "Session expir��e, veuillez vous reconnecter." diff --git a/plugins/kimchi/po/gen-pot.in b/plugins/kimchi/po/gen-pot.in deleted file mode 100644 index 0e3cd10..0000000 --- a/plugins/kimchi/po/gen-pot.in +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -for src in $@; do - if [ ${src: -3} == ".py" ]; then - cat $src - else - cat $src | @CHEETAH@ compile - - fi -done | xgettext --no-location -o kimchi.pot -L Python - diff --git a/plugins/kimchi/po/it_IT.po b/plugins/kimchi/po/it_IT.po deleted file mode 100644 index 257c306..0000000 --- a/plugins/kimchi/po/it_IT.po +++ /dev/null @@ -1,2274 +0,0 @@ -# English translations for kimchi package. -# Copyright (C) 2013 ORGANIZATION -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2013-07-11 17:32-0400\n" -"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" -"Language-Team: English\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: it_IT\n" -"Generated-By: pygettext.py 1.5\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "" - -msgid "Unknown \"_cap\" specified" -msgstr "" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "" -"Errore durante il richiamo dei dispositivi del blocco. Dettagli: %(err)s" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "" -"Errore durante il richiamo delle informazioni sul dispositivo del blocco per " -"%(device)s." - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "Impossibile trovare il file distro: %(filename)s" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "" -"Impossibile analizzare il file distro: %(filename)s. Verificare che sia un " -"file JSON." - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "" -"Impossibile accedere a %(portal)s di destinazione host iSCSI. Dettagli: %" -"(err)s" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "Impossibile accedere alla destinazione %(target)s host %(host)s iSCSI" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "Il file ISO %(filename)s non �� avviabile" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "Il file ISO %(filename)s non ha un record di avvio El Torito valido" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "Voce di convalida El Torito non valida in ISO %(filename)s" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "Indicatore di avvio El Torito non valido in ISO %(filename)s" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "Tipo di volume imprevisto per il volume primario in ISO %(filename)s" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "" -"Formato non corretto durante la lettura del descrittore volume in ISO %" -"(filename)s" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" -"L'hypervisor non dispone dell'autorizzazione per utilizzare questo ISO %" -"(filename)s. Spostarlo in /var/lib/libvirt o impostare l'autorizzazione di " -"ricerca per gli elenchi di controllo accesso ai file per l'utente '%(user)" -"s', se possibile, o aggiungere '%(user)s' al gruppo percorso ISO o (non " -"consigliato) 'chmod -R o+x 'path_to_iso'. Dettagli: %(err)s" - -msgid "An error occurred when probing image OS information." -msgstr "" - -msgid "No OS information found in given image." -msgstr "" - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "Macchina virtuale %(name)s gi�� esistente" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "La macchina virtuale %(name)s non esiste" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "" -"Impossibile richiamare l'immagine per la macchina virtuale arrestata %(name)s" - -msgid "Remote ISO image is not supported by this server." -msgstr "L'immagine ISO remota non �� supportata da questo server." - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "Impossibile creare la macchina virtuale %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "Impossibile creare la macchina virtuale %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Impossibile richiamare la macchina virtuale %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "" - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "" -"L'indirizzo dei grafici su cui rimanere in ascolto deve essere IPv4 o IPv6" - -msgid "Specify a template to create a virtual machine from" -msgstr "Specificare un modello da cui creare una macchina virtuale" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "Impossibile avviare la macchina virtuale %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "Impossibile arrestare la macchina virtuale %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "Impossibile eliminare la macchina virtuale %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "" -"Impossibile ridenominare la macchina virtuale %(name)s. Dettagli: %(err)s" - -msgid "User name list must be an array" -msgstr "" - -msgid "User name must be a string" -msgstr "Il nome della rete deve essere una stringa" - -msgid "Group name list must be an array" -msgstr "" - -msgid "Group name must be a string" -msgstr "Il nome della rete deve essere una stringa" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "L'utente '%(users)s' non esiste." - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "L'utente '%(groups)s' non esiste." - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "Impossibile arrestare la macchina virtuale %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "Impossibile avviare la macchina virtuale %(name)s. Dettagli: %(err)s" - -msgid "The guest console password must be a string." -msgstr "" - -msgid "The life time for the guest console password must be a number." -msgstr "" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" - -msgid "\"name\" should be a device name string" -msgstr "" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "L'interfaccia %(iface)s non esiste nella macchina virtuale %(name)s" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "" -"La rete %(network)s specificata per la macchina virtuale %(name)s non esiste" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "" -"Il tipo supportato per le interfacce della macchina virtuale �� solo rete" - -msgid "Network name for virtual machine interface must be a string" -msgstr "" -"Il nome di rete per l'interfaccia della macchina virtuale deve essere una " -"stringa" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "" -"Scheda modello di rete non valida per l'interfaccia della macchina virtuale" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "" -"Specificare il tipo e la rete per aggiungere una nuova interfaccia della " -"macchina virtuale" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "Modello %(name)s gi�� esistente" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "" -"La rete '%(network)s' specificata per il modello %(template)s non esiste" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "" -"Il pool di memoria %(pool)s specificato per il modello %(template)s non " -"esiste" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "" -"Il pool di memoria %(pool)s specificato per il modello %(template)s non �� " -"attivo" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "Parametro non valido %(param)s' specificato per CDROM." - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "" -"La rete %(network)s specificata per il modello %(template)s non �� attiva" - -msgid "Template name must be a string" -msgstr "Il nome del modello deve essere una stringa" - -msgid "Template icon must be a path to the image" -msgstr "L'icona del modello deve essere un percorso all'immagine" - -msgid "Template distribution must be a string" -msgstr "La distribuzione del modello deve essere una stringa" - -msgid "Template distribution version must be a string" -msgstr "La versione della distribuzione del modello deve essere una stringa" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "Il numero di CPU deve essere un numero intero" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "" -"La quantit�� di memoria (MB) deve essere un numero intero maggiore di 512" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "Il CDROM del modello deve essere un file ISO locale o remoto" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "URI pool di memoria non valido: %(value)s specificato per il modello" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "Specificare un'immagine ISO come CDROM per creare un modello" - -msgid "All networks for the template must be specified in a list." -msgstr "Tutte le reti per il modello devono essere specificate in un elenco." - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "Impossibile creare il modello a causa dell'errore: %(err)s" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "Impossibile eliminare il modello a causa dell'errore: %(err)s" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "" - -msgid "Template base image must be a valid local image file" -msgstr "Il CDROM del modello deve essere un file ISO locale o remoto" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "Pool di memoria %(name)s gi�� esistente" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "Il pool di memoria %(name)s non esiste" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "Specificare %(item)s per poter creare il pool di memoria %(name)s" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "Impossibile eliminare il pool di memoria attivo %(name)s" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "Impossibile elencare i pool di memoria. Dettagli: %(err)s" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "Impossibile creare il pool di memoria %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "" -"Impossibile ottenere il numero di volumi di memoria nel pool di memoria %" -"(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "Impossibile attivare il pool di memoria %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "Impossibile disattivare il pool di memoria %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "Impossibile eliminare il pool di memoria %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "" -"Impossibile creare il pool NFS poich�� il percorso di esportazione %(path)s " -"potrebbe bloccarsi durante il montaggio" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "" -"Impossibile creare il pool NFS poich�� il montaggio del percorso di " -"esportazione %(path)s ha avuto esito negativo" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "Tipo di pool di memoria non supportato: %(type)s" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" - -msgid "Storage pool path must be a string" -msgstr "Il percorso del pool di memoria deve essere una stringa" - -msgid "Storage pool host must be a IP or hostname" -msgstr "L'host del pool di memoria deve essere un nome host o IP" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" - -msgid "Storage pool devices parameter must be a list" -msgstr "Il parametro dispositivi pool di memoria deve essere un elenco" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "L'IQN di destinazione di un pool iSCSI deve essere una stringa" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "" -"La porta di un server di memoria remoto deve essere un numero intero tra 1 e " -"65535" - -msgid "iSCSI target username must be a string" -msgstr "" - -msgid "iSCSI target password must be a string" -msgstr "" - -msgid "Specify name and type to create a storage pool" -msgstr "Specificare nome e tipo per creare un pool di memoria" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "" -"%(disk)s non �� un disco/partizione valido. Impossibile aggiungerlo al pool %" -"(pool)s." - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "" -"Solo il parametro dischi pu�� essere aggiornato per il pool di memoria logico." - -msgid "The SCSI host adapter name must be a string." -msgstr "Il nome adattatore host SCSI deve essere una stringa." - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "Il pool di memoria kimchi_isos �� riservato per uso interno" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"Impossibile attivare il pool di memoria NFS %(name)s. Il server NFS %(server)" -"s �� irraggiungibile." - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"Impossibile disattivare il pool di memoria NFS %(name)s. Il server NFS %" -"(server)s �� irraggiungibile." - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "" -"Impossibile disattivare il pool %(name)s poich�� �� associato ad alcuni modelli" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "" -"Impossibile eliminare il pool %(name)s poich�� �� associato ad alcuni modelli" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "" -"Un gruppo di volumi denominato '%(name)s' esiste gi��. Scegliere un altro " -"nome per creare il pool logico." - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "" -"Impossibile aggiornare il database con informazioni approfondite sulla " -"scansione a causa dell'errore: %(err)s" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "Volume di memoria %(name)s gi�� esistente" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "Il volume di memoria %(name)s non esiste nel pool di memoria %(pool)s" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "Specificare %(item)s per poter creare il volume di memoria %(volume)s" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "" -"Impossibile elencare i volumi di memoria poich�� il pool di memoria %(pool)s " -"non �� attivo" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "" -"Impossibile creare il volume di memoria %(name)s nel pool di memoria %(pool)" -"s. Dettagli: %(err)s" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "" -"Impossibile elencare i volumi di memoria nel pool di memoria %(pool)s. " -"Dettagli: %(err)s" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "Impossibile ripulire i volumi di memoria %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "Impossibile eliminare il volume di memoria %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "" -"Impossibile ridimensionare il volume di memoria %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "" -"Il tipo di memoria %(type)s non supporta la creazione ed eliminazione del " -"volume" - -msgid "Storage volume name must be a string" -msgstr "Il nome del volume di memoria deve essere una stringa" - -msgid "Storage volume allocation must be an integer number" -msgstr "L'assegnazione del volume di memoria deve essere un numero intero" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" - -msgid "Storage volume requires a volume name" -msgstr "Il volume di memoria richiede un nome volume" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "" -"Impossibile aggiornare il database con informazioni sul volume di memoria a " -"causa dell'errore: %(err)s" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "" - -msgid "Storage volume capacity must be an integer number." -msgstr "" - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "" - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "L'interfaccia %(name)s non esiste" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "Rete %(name)s gi�� esistente" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "La rete %(name)s non esiste" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "" -"La sottorete %(subnet)s specificata per la rete %(network)s non �� valida ." - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "" -"Specificare un'interfaccia di rete per creare la rete con bridge %(name)s" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "Impossibile eliminare la rete attiva %(name)s" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "" -"L'interfaccia %(iface)s specificata per la rete %(network)s �� gi�� in uso" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "" -"L'interfaccia deve essere un dispositivo bridge o di collegamento NIC bare-" -"metal." - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "Impossibile creare la rete %(name)s. Dettagli: %(err)s" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "Impossibile trovare un indirizzo IP libero per la rete '%(name)s'" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "L'interfaccia %(iface)s gi�� esistente." - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "I tipi di rete supportati sono isolata, NAT e bridge" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "" -"La sottorete della rete deve essere una stringa con indirizzo IP e prefisso " -"o maschera di rete" - -msgid "Network interface must be a string" -msgstr "L'interfaccia di rete deve essere una stringa" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "L'ID VLAN di rete deve essere un numero intero tra 1 e 4094" - -msgid "Specify name and type to create a Network" -msgstr "Specificare nome e tipo per creare una rete" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" -"Impossibile eliminare la rete %(name)s. Ci sono alcune macchine virtuali %" -"(vms)s e/o modelli collegati a tale rete." - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" -"Impossibile disattivare la rete %(name)s. Ci sono alcune macchine virtualie %" -"(vms)s e/o modelli collegati a tale rete." - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "" -"Il dispositivo bridge %(name)s non pu�� essere il dispositivo trunk di una " -"VLAN." - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "Impossibile attivare l'interfaccia %(iface)s: %(err)s." - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "" -"Impossibile attivare l'interfaccia %(iface)s. Controllare lo stato del link " -"fisico." - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "Il report di debug %(name)s non esiste" - -msgid "Debug report tool not found in system" -msgstr "Strumento report di debug non trovato nel sistema" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "Impossibile creare il report di debug %(name)s. Dettagli: %(err)s." - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "Impossibile generare il report di debug %(name)s. Dettagli: %(err)s" - -msgid "You should give a name for the debug report file." -msgstr "" - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "" -"Un gruppo di volumi denominato '%(name)s' esiste gi��. Scegliere un altro " -"nome per creare il pool logico." - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "Il server di memoria %(server)s non �� stato utilizzato da Kimchi" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "Distro '%(name)s' non esistente" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "La partizione %(name)s non esiste nell'host" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "" -"Impossibile arrestare la macchina host poich�� sono presenti macchine " -"virtuali in esecuzione" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "" -"Impossibile riavviare la macchina host poich�� sono presenti macchine " -"virtuali in esecuzione" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "Dispositivo nodo '%(name)s' non trovato" - -msgid "Conflicting flag filters specified." -msgstr "" - -msgid "No packages marked for update" -msgstr "Nessun pacchetto contrassegnato per l'aggiornamento" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "Il pacchetto %(name)s non �� contrassegnato per l'aggiornamento." - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "" -"Errore durante il richiamo dei pacchetti contrassegnati per l'aggiornamento. " -"Dettagli: %(err)s" - -msgid "There is no compatible package manager for this system." -msgstr "Non �� presente un gestore pacchetti compatibile per questo sistema." - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "URI %(uri)s non valido" - -msgid "Unable to choose a virtual machine name" -msgstr "" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "Tipo di memoria non valido. I tipi supportati sono: 'cdrom'" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" - -msgid "Only CDROM path can be update." -msgstr "" - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "" -"Errore durante la creazione del nuovo dispositivo di memoria: %(error)s" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "Errore durante l'aggiornamento del dispositivo di memoria: %(error)s" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "Errore durante la rimozione del dispositivo di memoria: %(error)s" - -msgid "Do not support IDE device hot plug" -msgstr "" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "" -"Specificare tipo e percorso per aggiungere un nuovo disco della macchina " -"virtuale" - -msgid "Specify path to update virtual machine disk" -msgstr "" -"Specificare il percorso per aggiornare il disco della macchina virtuale" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" - -msgid "Volume already in use by other virtual machine." -msgstr "" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "" -"Specificare tipo e percorso per aggiungere un nuovo disco della macchina " -"virtuale" - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" - -msgid "YUM Repository ID must be one word only string." -msgstr "L'ID repository YUM deve essere una stringa di una sola parola." - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "L'URL del repository deve essere http://, ftp:// o file:// URL." - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "" -"La configurazione del repository �� un dizionario con valori specifici in " -"base al tipo di repository." - -msgid "Distribution to DEB repository must be a string" -msgstr "La distribuzione al repository DEB deve essere una stringa" - -msgid "Components to DEB repository must be listed in a array" -msgstr "I componenti per il repository DEB devono essere elencati in un array" - -msgid "Components to DEB repository must be a string" -msgstr "I componenti per il repository DEB devono essere una stringa" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "Il nome del repository YUM deve essere una stringa." - -msgid "GPG check must be a boolean value." -msgstr "Il controllo GPG deve essere un valore booleano." - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "La chiave GPG deve essere un URL che punta al file blindato ASCII." - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "Impossibile aggiornare il repository %(repo_id)s." - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "Il repository %(repo_id)s non esiste." - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "" -"Lo strumento di gestione del repository non �� stato riconosciuto per il " -"sistema." - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "Il repository %(repo_id)s �� gi�� abilitato." - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "Il repository %(repo_id)s �� gi�� disabilitato." - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "Impossibile rimuovere il repository %(repo_id)s." - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "" -"Impossibile scrivere il file di configurazione del repository %(repo_file)s" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "" -"Specificare la distribuzione del repository per poter creare un repository " -"DEB." - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "Impossibile abilitare il repository %(repo_id)s." - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "Impossibile disabilitare il repository %(repo_id)s." - -msgid "YUM Repository ID already exists" -msgstr "ID repository YUM gi�� esistente" - -msgid "YUM Repository name must be a string" -msgstr "Il nome del repository YUM deve essere una stringa" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "Impossibile elencare i repository. Dettagli: '%(err)s'" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "" -"Impossibile richiamare le informazioni sul repository. Dettagli: '%(err)s'" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "Impossibile aggiungere il repository. Dettagli: '%(err)s'" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "Impossibile rimuovere il repository. Dettagli: '%(err)s'" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" - -msgid "The number of vCPUs is too large for this system." -msgstr "" - -msgid "Invalid vCPU/topology combination." -msgstr "" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "" - -msgid "ERROR CODE" -msgstr "CODICE DI ERRORE" - -msgid "REASON" -msgstr "CAUSA" - -msgid "STACK" -msgstr "STACK" - -msgid "Go to Homepage" -msgstr "Vai alla home page" - -msgid "Create a New Virtual Machine" -msgstr "Crea una nuova macchina virtuale" - -msgid "Virtual Machine Name" -msgstr "Nome macchina virtuale" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "" -"Il nome utilizzato per identificare la macchina virtuale. Se il nome viene " -"omesso ne verr�� scelto uno in base al modello utilizzato." - -msgid "Template" -msgstr "Modello" - -msgid "Please create a template first." -msgstr "Creare prima un modello." - -msgid "Create a Template" -msgstr "Crea un modello" - -msgid "Please choose a template." -msgstr "Scegliere un modello." - -msgid "OS" -msgstr "SO" - -msgid "OS Version" -msgstr "Versione SO" - -msgid "CPUS" -msgstr "CPUS" - -msgid "Memory" -msgstr "Memoria" - -msgid "Create" -msgstr "Crea" - -msgid "Creating..." -msgstr "" - -msgid "Cancel" -msgstr "Annulla" - -msgid "Edit Guest" -msgstr "Modifica guest" - -msgid "General" -msgstr "Generale" - -msgid "Storage" -msgstr "Memoria" - -msgid "Interface" -msgstr "Interfaccia" - -msgid "Permission" -msgstr "Versione" - -msgid "Host PCI Device" -msgstr "" - -msgid "Snapshot" -msgstr "" - -msgid "Name" -msgstr "Nome" - -msgid "CPUs" -msgstr "CPU" - -msgid "Memory (MB)" -msgstr "Memoria" - -msgid "Icon" -msgstr "Icona" - -msgid "Device" -msgstr "Nome dispositivo" - -msgid "Path" -msgstr "Percorso NFS" - -msgid "Network" -msgstr "Rete" - -msgid "Type" -msgstr "Tipo" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "" - -msgid "Selected system users and groups" -msgstr "" - -msgid "User" -msgstr "" - -msgid "All" -msgstr "Tutti" - -msgid "To Add" -msgstr "" - -msgid "Added" -msgstr "" - -msgid "filter" -msgstr "" - -msgid "Product" -msgstr "" - -msgid "Vendor" -msgstr "Fornitore" - -msgid "Created" -msgstr "" - -msgid "Save" -msgstr "Salva" - -msgid "Replace" -msgstr "Sostituisci" - -msgid "Detach" -msgstr "Scollega" - -msgid "revert" -msgstr "" - -msgid "Start" -msgstr "Avvia" - -msgid "Reset" -msgstr "Reimposta" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "" - -msgid "Actions" -msgstr "Azioni" - -msgid "Connect" -msgstr "Connetti" - -msgid "Clone" -msgstr "" - -msgid "Edit" -msgstr "Modifica" - -msgid "Shut Down" -msgstr "Arresta" - -msgid "Delete" -msgstr "Elimina" - -msgid "CPU" -msgstr "CPU" - -msgid "Disk I/O" -msgstr "I/O disco" - -msgid "Network I/O" -msgstr "I/O di rete" - -msgid "Livetile" -msgstr "Riquadro animato" - -msgid "No guests found." -msgstr "Nessuna macchina guest trovata." - -msgid "Add a Storage Device to VM" -msgstr "Aggiungi un dispositivo di memoria alla VM" - -msgid "Device Type" -msgstr "Tipo dispositivo" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "Il tipo di dispositivo. Attualmente, �� supportato solo \"cdrom\"." - -msgid "Storage Pool" -msgstr "Pool di memoria" - -msgid "Storage pool which volume located in" -msgstr "Il percorso del pool di memoria deve essere una stringa" - -msgid "Storage Volume" -msgstr "Nome pool di memoria" - -msgid "Storage volume to be attached" -msgstr "Il nome del volume di memoria deve essere una stringa" - -msgid "File Path" -msgstr "Percorso file" - -msgid "The ISO file path in the server for CDROM." -msgstr "Il percorso file ISO nel server per CDROM." - -msgid "Attach" -msgstr "Allega" - -msgid "Shut down" -msgstr "Arresta" - -msgid "Restart" -msgstr "Riavvia" - -msgid "Basic Information" -msgstr "Informazioni di base" - -msgid "OS Distro" -msgstr "Distro SO" - -msgid "OS Code Name" -msgstr "Nome codice SO" - -msgid "Processor" -msgstr "Processore" - -msgid "CPU(s)" -msgstr "" - -msgid "System Statistics" -msgstr "Statistiche di sistema" - -msgid "Software Updates" -msgstr "Aggiornamenti del software" - -msgid "Update Progress" -msgstr "Avanzamento aggiornamento" - -msgid "Repositories" -msgstr "Repository" - -msgid "Debug Reports" -msgstr "Report di debug" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "" -"Il nome utente o la password immessi non sono corretti. Ripetere " -"l'operazione." - -msgid "This field is required." -msgstr "Questo campo �� obbligatorio." - -msgid "Log in" -msgstr "Accedi" - -msgid "Logging in..." -msgstr "Accesso in corso..." - -msgid "Host" -msgstr "Host" - -msgid "Guests" -msgstr "Guest" - -msgid "Templates" -msgstr "Modelli" - -msgid "Failed to get application configuration" -msgstr "Richiamo della configurazione dell'applicazione non riuscito" - -msgid "This is not a valid Linux path" -msgstr "Non �� un percorso Linux valido" - -msgid "This is not a valid URL." -msgstr "Non �� un URL valido." - -msgid "No such data available." -msgstr "Dati indicati non disponibili." - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" -"Impossibile contattare il sistema host. Verificare che il sistema host sia " -"attivo e che si disponga della connettivit�� di rete per tale sistema. " -"Risposta alla richiesta HTTP %1. " - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "Conferma eliminazione" - -msgid "OK" -msgstr "OK" - -msgid "Confirm" -msgstr "Conferma" - -msgid "Warning" -msgstr "Avvertenza" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "Caricamento in corso..." - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "Riprova" - -msgid "Detailed message:" -msgstr "Messaggio dettagliato:" - -msgid "No ISO found" -msgstr "" - -msgid "This is not a valid ISO file." -msgstr "Non �� un file ISO valido." - -msgid "This may take a long time. Do you want to continue?" -msgstr "Richieder�� molto tempo. Continuare?" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "L'azione eliminer�� permanentemente il modello. Continuare?" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "" -"Impossibile arrestare il sistema poich�� sono in esecuzione alcune macchine " -"virtuali." - -msgid "Max:" -msgstr "Massimo:" - -msgid "Utilization" -msgstr "Utilizzo" - -msgid "Available" -msgstr "Disponibile" - -msgid "Read Rate" -msgstr "Velocit�� di lettura" - -msgid "Write Rate" -msgstr "Velocit�� di scrittura" - -msgid "Received" -msgstr "Ricevuti" - -msgid "Sent" -msgstr "Inviati" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"L'arresto o il riavvio dell'host provocher�� la perdita del lavoro non " -"salvato. Continuare con l'arresto o il riavvio?" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"Il repository verr�� rimosso permanentemente e non potr�� essere ripristinato. " -"Si desidera continuare?" - -msgid "ID" -msgstr "ID" - -msgid "Base URL" -msgstr "URL di base" - -msgid "Is Mirror" -msgstr "�� speculare" - -msgid "URL Args" -msgstr "Argomenti URL" - -msgid "Enabled" -msgstr "Abilitato" - -msgid "GPG Check" -msgstr "Controllo GPG" - -msgid "GPG Key" -msgstr "Chiave GPG" - -msgid "Add" -msgstr "Aggiungi" - -msgid "Remove" -msgstr "Rimuovi" - -msgid "Enable" -msgstr "Abilita" - -msgid "Disable" -msgstr "Disabilita" - -msgid "Package Name" -msgstr "Nome pacchetto" - -msgid "Version" -msgstr "Versione" - -msgid "Architecture" -msgstr "Architettura" - -msgid "Repository" -msgstr "Repository" - -msgid "Update All" -msgstr "Aggiorna tutto" - -msgid "Updating..." -msgstr "Aggiornamento in corso..." - -msgid "Failed to retrieve packages update information." -msgstr "" - -msgid "Failed to update package(s)." -msgstr "Aggiornamento dei pacchetti non riuscito." - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"Il report del debug verr�� rimosso permanentemente e non potr�� essere " -"ripristinato. Si desidera continuare?" - -msgid "Generated Time" -msgstr "Ora di creazione" - -msgid "Generate" -msgstr "Crea" - -msgid "Generating..." -msgstr "Creazione in corso..." - -msgid "Rename" -msgstr "Ridenomina" - -msgid "Download" -msgstr "Scarica" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "" -"Il nome del report pu�� contenere solo lettere, cifre e/o trattini ('-')." - -msgid "Pending..." -msgstr "Caricamento in corso..." - -msgid "Report name is the same as the original one." -msgstr "" - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "" -"L'operazione eliminer�� la macchina virtuale e i relativi dischi virtuali e " -"non �� reversibile. Continuare?" - -msgid "Power off Confirmation" -msgstr "Conferma eliminazione" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" - -msgid "Reset Confirmation" -msgstr "Conferma eliminazione" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" - -msgid "Shut Down Confirmation" -msgstr "Conferma eliminazione" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "L'azione eliminer�� permanentemente il modello. Continuare?" - -msgid "Virtual Machine delete Confirmation" -msgstr "" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" -"Il CDROM verr�� scollegato permanentemente e non sar�� possibile ricollegarlo. " -"Continuare con lo scollegamento?" - -msgid "Attaching..." -msgstr "Collegamento in corso..." - -msgid "Replacing..." -msgstr "Sostituzione in corso..." - -msgid "Successfully attached!" -msgstr "Collegamento riuscito." - -msgid "Successfully replaced!" -msgstr "Sostituzione riuscita." - -msgid "Successfully detached!" -msgstr "Scollegamento riuscito." - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" - -msgid "interface:" -msgstr "" - -msgid "address:" -msgstr "" - -msgid "link_type:" -msgstr "" - -msgid "block:" -msgstr "" - -msgid "drive_type:" -msgstr "" - -msgid "model:" -msgstr "" - -msgid "Affected devices:" -msgstr "" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "L'ID VLAN deve essere compreso tra 1 e 4094." - -msgid "unavailable" -msgstr "non disponibile" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" -"L'azione interromper�� la connettivit�� di rete per qualsiasi macchina " -"virtuale che dipende da questa rete." - -msgid "Create a network" -msgstr "Crea una rete" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"Il pool di memoria non �� permanente. Invece di disattivarlo, l'azione lo " -"eliminer�� permanentemente. Continuare?" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "L'azione eliminer�� permanentemente il pool di memoria. Continuare?" - -msgid "This storage pool is empty." -msgstr "Il pool di memoria �� vuoto." - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" -"Il disco verr�� formattato e tutti i dati su di esso andranno persi, sicuri " -"di voler continuare? " - -msgid "SCSI Fibre Channel" -msgstr "Canale a fibre ottiche SCSI" - -msgid "No SCSI adapters found." -msgstr "Nessun adattatore SCSI trovato." - -msgid "Loading iSCSI targets..." -msgstr "" - -msgid "No iSCSI found. Please input one." -msgstr "" - -msgid "Failed to load iSCSI targets." -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "Il campo per il nome del pool di memoria non pu�� essere vuoto." - -msgid "The storage pool path can not be blank." -msgstr "Il campo per il percorso del pool di memoria non pu�� essere vuoto." - -msgid "NFS server mount path can not be blank." -msgstr "" -"Il campo per il percorso di montaggio del server NFS non pu�� essere vuoto." - -msgid "Invalid NFS mount path." -msgstr "Percorso di montaggio NFS non valido." - -msgid "No logical device selected." -msgstr "Nessun dispositivo logico selezionato." - -msgid "The iSCSI target can not be blank." -msgstr "Il campo per la destinazione iSCSI non pu�� essere vuoto." - -msgid "Server name can not be blank." -msgstr "Il campo per il nome del server non pu�� essere vuoto." - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "" - -msgid "Looking for available partitions ..." -msgstr "Ricerca di partizioni disponibili in corso..." - -msgid "No available partitions found." -msgstr "Nessuna partizione disponibile trovata." - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"Il pool di memoria non �� permanente. Invece di disattivarlo, l'azione lo " -"eliminer�� permanentemente. Continuare?" - -msgid "Unable to retrieve partitions information." -msgstr "" -"Impossibile richiamare le informazioni sul repository. Dettagli: '%(err)s'" - -msgid "In progress..." -msgstr "" - -msgid "Failed!" -msgstr "" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" - -msgid "Disk pool or volume cannot be blank." -msgstr "Il campo per il nome del pool di memoria non pu�� essere vuoto." - -msgid "Filter" -msgstr "" - -msgid "Network Name" -msgstr "Nome rete" - -msgid "State" -msgstr "Stato" - -msgid "Network Type" -msgstr "Tipo di Rete" - -msgid "Address Space" -msgstr "Spazio indirizzo" - -msgid "Name should not contain '/' and '\"'." -msgstr "Nome pool di memoria non valido. Non deve contenere '/'." - -msgid "Isolated: no external network connection" -msgstr "Isolata: nessuna connessione di rete fisica" - -msgid "NAT: outbound physical network connection only" -msgstr "NAT: solo connessione di rete fisica in uscita" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "" -"Con bridge: le macchine virtuali sono connesse direttamente alla rete fisica" - -msgid "(No interfaces found)" -msgstr "" - -msgid "Destination" -msgstr "Destinazione:" - -msgid "Enable VLAN" -msgstr "Abilita VLAN:" - -msgid "VLAN ID" -msgstr "ID VLAN:" - -msgid "Stop" -msgstr "Arresta" - -msgid "Generate a New Debug Report" -msgstr "Crea un nuovo report di debug" - -msgid "Report Name" -msgstr "Nome report" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" -"Il nome utilizzato per identificare il report. Se il nome viene omesso, ne " -"viene scelto uno in base all'ora corrente. Il nome pu�� contenere lettere, " -"cifre e trattini (\"-\")." - -msgid "Rename a Debug Report" -msgstr "Crea un nuovo report di debug" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" -"Il nome utilizzato per identificare il report. Se il nome viene omesso, ne " -"viene scelto uno in base all'ora corrente. Il nome pu�� contenere lettere, " -"cifre e trattini (\"-\")." - -msgid "Submit" -msgstr "" - -msgid "Add a Repository" -msgstr "Aggiungi un repository" - -msgid "Identifier" -msgstr "Identificativo" - -msgid "Single word, unique identifier for the repository." -msgstr "Identificativo univoco di una sola parola per il repository." - -msgid "Textual name for the repository." -msgstr "Nome in formato testo per il repository." - -msgid "URL" -msgstr "URL" - -msgid "Required Field" -msgstr "Campo obbligatorio" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "URL al repository. I protocolli supportati sono http, ftp e file." - -msgid "Repository is a mirror" -msgstr "Il repository �� un elemento speculare." - -msgid "Distribution" -msgstr "Distribuzione" - -msgid "Distribution of the DEB repository." -msgstr "Distribuzione del repository DEB." - -msgid "Components" -msgstr "Componenti" - -msgid "List of components in DEB repository." -msgstr "Elenco di componenti nel repository DEB." - -msgid "Edit Repository" -msgstr "Modifica repository" - -msgid "Mirror List URL" -msgstr "URL elenco elementi speculari" - -msgid "Yes" -msgstr "S��" - -msgid "No" -msgstr "No" - -msgid "Capacity" -msgstr "Capacit��" - -msgid "Allocated" -msgstr "Assegnato" - -msgid "Location" -msgstr "Ubicazione" - -msgid "Device path" -msgstr "Percorso dispositivo" - -msgid "active" -msgstr "attivo" - -msgid "inactive" -msgstr "non attivo" - -msgid "Deactivate" -msgstr "Disattiva" - -msgid "Activate" -msgstr "Attiva" - -msgid "Add Volume" -msgstr "" - -msgid "Extend" -msgstr "" - -msgid "Undefine" -msgstr "Rimuovi definizione" - -msgid "Format" -msgstr "Formato:" - -msgid "Allocation" -msgstr "Allocazione:" - -msgid "Define a New Storage Pool" -msgstr "Definisci un nuovo pool di memoria" - -msgid "Storage Pool Name" -msgstr "Nome pool di memoria" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "" -"Il nome utilizzato per identificare i pool di memoria; il campo non deve " -"essere vuoto." - -msgid "Storage Pool Type" -msgstr "Tipo di pool di memoria" - -msgid "Storage Path" -msgstr "Percorso di memoria" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "" -"Il percorso del pool di memoria. Ogni pool di memoria deve avere un percorso " -"univoco." - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "" -"Kimchi tenter�� di creare la directory nel caso non esista ancora sul sistema." - -msgid "NFS Server IP" -msgstr "IP server NFS" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "" -"Il nome host o l'indirizzo IP del server NFS. �� possibile immetterlo o " -"sceglierlo dalla cronologia." - -msgid "NFS Path" -msgstr "Percorso NFS" - -msgid "The NFS exported path on NFS server." -msgstr "Il percorso esportato NFS sul server NFS." - -msgid "iSCSI Server" -msgstr "Server iSCSI" - -msgid "Server" -msgstr "Server" - -msgid "Port" -msgstr "Porta" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "" -"Il nome host o l'indirizzo IP del server iSCSI. Il campo non deve essere " -"vuoto." - -msgid "Target" -msgstr "Destinazione" - -msgid "The iSCSI target on iSCSI server" -msgstr "La destinazione iSCSI sul server iSCSI" - -msgid "Add iSCSI Authentication" -msgstr "Aggiungi autenticazione iSCSI" - -msgid "iSCSI Authentication" -msgstr "Autenticazione iSCSI" - -msgid "User Name" -msgstr "Nome utente" - -msgid "Password" -msgstr "Password" - -msgid "SCSI Adapter" -msgstr "Adattatore SCSI" - -msgid "Please, wait..." -msgstr "Attendere..." - -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - -msgid "Add Template" -msgstr "Aggiungi modello" - -msgid "Where is the source media for this template? " -msgstr "Dov'�� il supporto di origine per questo modello?" - -msgid "Local ISO Image" -msgstr "Immagine ISO locale" - -msgid "Local Image File" -msgstr "" - -msgid "Remote ISO Image" -msgstr "Immagine ISO remota" - -msgid "Search ISOs" -msgstr "Ricerca ISO" - -msgid "The following ISOs are available:" -msgstr "Sono disponibili i seguenti file ISO:" - -msgid "OS: " -msgstr "SO: " - -msgid "Version: " -msgstr "Versione: " - -msgid "Size: " -msgstr "Dimensione: " - -msgid "Search more ISOs" -msgstr "Ricerca pi�� ISO" - -msgid "Create Templates from Selected ISO" -msgstr "Crea modelli da ISO selezionato" - -msgid "I want to use a specific ISO file" -msgstr "Utilizzare un file ISO specifico" - -msgid "Loading default remote ISOs ..." -msgstr "Caricamento di ISO remoti predefiniti in corso..." - -msgid "Arch: " -msgstr "Arch: " - -msgid "I want to use a custom URL" -msgstr "Utilizzare un URL personalizzato" - -msgid "Edit Template" -msgstr "Modifica modello" - -msgid "CDROM" -msgstr "CDROM" - -msgid "Image File" -msgstr "" - -msgid "Graphics" -msgstr "Grafici" - -msgid "Disk(GB)" -msgstr "" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "Numero CPU" - -msgid "Manually set CPU topology" -msgstr "" - -msgid "Cores" -msgstr "" - -msgid "Threads" -msgstr "" - -msgid "No templates found." -msgstr "Nessun modello trovato." - -#~ msgid "Delete is not allowed for %(resource)s" -#~ msgstr "Eliminazione non consentita per %(resource)s" - -#~ msgid "%(resource)s does not implement update method" -#~ msgstr "%(resource)s non implementa il metodo di aggiornamento" - -#~ msgid "Create is not allowed for %(resource)s" -#~ msgstr "Creazione non consentita per %(resource)s" - -#~ msgid "Unable to parse JSON request" -#~ msgstr "Impossibile analizzare la richiesta JSON" - -#~ msgid "This API only supports JSON" -#~ msgstr "L'API supporta solo JSON" - -#~ msgid "Datastore is not initiated in the model object." -#~ msgstr "Archivio dati non inizializzato nell'oggetto modello." - -#~ msgid "Unable to start task due error: %(err)s" -#~ msgstr "Impossibile avviare l'attivit�� a causa dell'errore: %(err)s" - -#~ msgid "" -#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" -#~ msgstr "" -#~ "Autenticazione non riuscita per l'utente '%(username)s'. [Codice di " -#~ "errore: %(code)s]" - -#~ msgid "You are not authorized to access Kimchi" -#~ msgstr "Non si dispone dell'autorizzazione ad accedere a Kimchi" - -#~ msgid "Specify %(item)s to login into Kimchi" -#~ msgstr "Specificare %(item)s per accedere a Kimchi" - -#~ msgid "Unable to find %(item)s in datastore" -#~ msgstr "Impossibile trovare %(item)s nell'archivio dati" - -#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" -#~ msgstr "" -#~ "�� stato raggiunto il timeout durante l'esecuzione del comando '%(cmd)s' " -#~ "dopo %(seconds)s secondi" - -#~ msgid "Help" -#~ msgstr "Guida" - -#~ msgid "About" -#~ msgstr "Info su" - -#~ msgid "Log out" -#~ msgstr "Disconnetti" - -#~ msgid "Version:" -#~ msgstr "Versione:" diff --git a/plugins/kimchi/po/ja_JP.po b/plugins/kimchi/po/ja_JP.po deleted file mode 100644 index a3d3be3..0000000 --- a/plugins/kimchi/po/ja_JP.po +++ /dev/null @@ -1,2269 +0,0 @@ -# English translations for kimchi package. -# Copyright (C) 2013 ORGANIZATION -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2013-07-11 17:32-0400\n" -"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" -"Language-Team: English\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ja_JP\n" -"Generated-By: pygettext.py 1.5\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "" - -msgid "Unknown \"_cap\" specified" -msgstr "" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "" -"������������������������������������������������������������������������������������������������: %(err)s" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "" -"%(device)s ���������������������������������������������������������������������������������������������������" - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "������������������������������������������������ %(filename)s ������������������������" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "" -"������������������������������������������������ %(filename)s ���������������������������JSON ������������" -"���������������������������������������������" - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "" -"iSCSI ��������������������������� %(portal)s ���������������������������������������: %(err)s" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "iSCSI ��������� %(host)s ��������������� %(target)s ������������������������������" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "ISO ������������ %(filename)s ������������������������������������������" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "" -"ISO ������������ %(filename)s ������������������ El Torito ������������������������������������������" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "��������� El Torito ������������������������ ISO %(filename)s ���������������" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "��������� El Torito ������������������������������������ ISO %(filename)s ���������������" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "" -"1 ������������������������������������������������������������������ ISO %(filename)s ���������������" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "" -"��������������������������������������������� ISO %(filename)s ���������������������������������������" -"������������������������������������" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" -"��������������������������������� ISO %(filename)s ������������������������������������������/var/lib/" -"libvirt ���������������������������������������������������������������%(user)s���������������������������" -"���������������������������������������������������������%(user)s������ISO ���������������������������������" -"���������������������chmod -R o+x path_to_iso������������ (���������������������) ���������������" -"������������: %(err)s" - -msgid "An error occurred when probing image OS information." -msgstr "" - -msgid "No OS information found in given image." -msgstr "" - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "��������������� %(name)s ������������������������" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "��������������� %(name)s ���������������������" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "��������������������������������� %(name)s ���������������������������������������������������������" - -msgid "Remote ISO image is not supported by this server." -msgstr "������������ ISO ������������������������������������������������������������������������������" - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "��������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "��������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "��������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "" - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "" -"listen ���������������������������������������������������IPv4 ��������� IPv6 ���������������������������" -"���" - -msgid "Specify a template to create a virtual machine from" -msgstr "���������������������������������������������������������������������������������" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "��������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "��������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "��������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "��������������� %(name)s ���������������������������������������: %(err)s" - -msgid "User name list must be an array" -msgstr "" - -msgid "User name must be a string" -msgstr "���������������������������������������������������������������������" - -msgid "Group name list must be an array" -msgstr "" - -msgid "Group name must be a string" -msgstr "���������������������������������������������������������������������" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "���������������%(users)s���������������������������" - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "���������������%(groups)s���������������������������" - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "��������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "��������������� %(name)s ���������������������������������: %(err)s" - -msgid "The guest console password must be a string." -msgstr "" - -msgid "The life time for the guest console password must be a number." -msgstr "" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" - -msgid "\"name\" should be a device name string" -msgstr "" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "������������������������ %(iface)s ������������������ %(name)s ������������������������" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "" -"��������������� %(name)s ��������������������������������������������� %(network)s ���������������������" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"���" - -msgid "Network name for virtual machine interface must be a string" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"���������" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "������������������ %(name)s ������������������������" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "" -"������������������ %(template)s ������������������������������������������������%(network)s������������" -"������������" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "" -"������������������ %(template)s ������������������������������������������������������ %(pool)s ������" -"���������������" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "" -"������������������ %(template)s ������������������������������������������������������ %(pool)s ������" -"���������������������������������" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "CDROM ���������������������������������������������%(param)s���������������������" - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "" -"������������������ %(template)s ��������������������������������������������� %(network)s ���������" -"������������������������������" - -msgid "Template name must be a string" -msgstr "���������������������������������������������������������������������" - -msgid "Template icon must be a path to the image" -msgstr "���������������������������������������������������������������������������������������" - -msgid "Template distribution must be a string" -msgstr "������������������������������������������������������������������������������������������������������" - -msgid "Template distribution version must be a string" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "CPU ������������������������������������������" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "������������������ (MB ������) ������512 ���������������������������������������������������" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "" -"������������������ CDROM ��������������������������������������� ISO ���������������������������������������" -"���" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "" -"������������������������������������ URI %(value)s ������������������������������������������������" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "" -"CDROM ������������������������������������������������������ ISO ���������������������������������������" - -msgid "All networks for the template must be specified in a list." -msgstr "������������������������������������������������������������������������������������������������������" - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "���������������������������������������������������������������������: %(err)s" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "���������������������������������������������������������������������: %(err)s" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "" - -msgid "Template base image must be a valid local image file" -msgstr "" -"������������������ CDROM ��������������������������������������� ISO ���������������������������������������" -"���" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "��������������������������� %(name)s ������������������������" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "��������������������������� %(name)s ���������������������" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "" -"��������������������������� %(name)s ������������������������������%(item)s ���������������������������" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "��������������������������������������������� %(name)s ������������������������" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "���������������������������������������������������������������: %(err)s" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "��������������������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "" -"��������������������������� %(name)s ������������������������������������������������������������������������" -"���:%(err)s" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "��������������������������� %(name)s ���������������������������������������������: %(err)s" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "��������������������������� %(name)s ������������������������������������������������: %(err)s" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "��������������������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "" -"��������������������������������������������� %(path)s ���������������������������������������������������" -"������NFS ���������������������������������" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "" -"��������������������������� %(path)s ���������������������������������������NFS ���������������������������" -"������" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "���������������������������������������������������������������������: %(type)s" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" - -msgid "Storage pool path must be a string" -msgstr "������������������������������������������������������������������������������������" - -msgid "Storage pool host must be a IP or hostname" -msgstr "���������������������������������������������IP ���������������������������������������������������" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" - -msgid "Storage pool devices parameter must be a list" -msgstr "���������������������������������������������������������������������������������������������������������" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "iSCSI ��������������������������� IQN ������������������������������������������������" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "" -"���������������������������������������������������������������1 ������ 65535 ���������������������������������" -"������������" - -msgid "iSCSI target username must be a string" -msgstr "" - -msgid "iSCSI target password must be a string" -msgstr "" - -msgid "Specify name and type to create a storage pool" -msgstr "������������������������������������������������������������������������������������������������" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "" -"%(disk)s ���������������������������/��������������������������������������������������� %(pool)s ������" -"������������������������������" - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "" -"���������������������������������������������������������������������������������������������������������������" -"������" - -msgid "The SCSI host adapter name must be a string." -msgstr "SCSI ���������������������������������������������������������������������������������" - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "��������������������������� kimchi_isos ������������������������������������������������������" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"NFS ��������������������������� %(name)s ���������������������������������������NFS ������������ %" -"(server)s ���������������������������" - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"NFS ��������������������������� %(name)s ������������������������������������������NFS ������������ %" -"(server)s ���������������������������" - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "" -"��������� %(name)s ������������������������������������������������������������������������������������������" -"���������������������" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "" -"��������� %(name)s ������������������������������������������������������������������������������������������" -"������" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "" -"���������%(name)s���������������������������������������������������������������������������������������������" -"���������������������������������������������������" - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "" -"���������������������������������������������������������������������������������������������������������: %" -"(err)s" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "��������������������������������� %(name)s ������������������������" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "" -"��������������������������������� %(name)s ��������������������������������� %(pool)s ������������������" -"���" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "" -"��������������������������������� %(volume)s ������������������������������%(item)s ���������������������" -"������" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "" -"��������������������������� %(pool)s ������������������������������������������������������������������������" -"���������������������������" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "" -"��������������������������������� %(name)s ������������������������������ %(pool)s ���������������������" -"������������: %(err)s" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "" -"��������������������������� %(pool)s ���������������������������������������������������������������������" -"���: %(err)s" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "��������������������������� %(name)s ������������������������������������: %(err)s" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "��������������������������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "��������������������������������� %(name)s ������������������������������������������: %(err)s" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "" -"��������������������������� %(type)s ������������������������������������������������������������������������" -"���������" - -msgid "Storage volume name must be a string" -msgstr "������������������������������������������������������������������������������������" - -msgid "Storage volume allocation must be an integer number" -msgstr "������������������������������������������������������������������������������������" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" - -msgid "Storage volume requires a volume name" -msgstr "������������������������������������������������������������������������" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "" -"���������������������������������������������������������������������������������������������������������������: %" -"(err)s" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "" - -msgid "Storage volume capacity must be an integer number." -msgstr "" - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "" - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "������������������������ %(name)s ���������������������" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "������������������ %(name)s ������������������������" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "������������������ %(name)s ���������������������" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "" -"������������������ %(network)s ������������������������������������������ %(subnet)s ������������������" - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "" -"������������������������������������ %(name)s ���������������������������������������������������������" -"���������������������������������������" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "������������������������������������ %(name)s ������������������������" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "" -"������������������ %(network)s ��������������������������������������������������� %(iface)s ���������" -"���������������������������" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "" -"��������������������������������� NIC���������������������������������������������������������������������������" -"������" - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "������������������ %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "���������������������%(name)s��������������� IP ���������������������������������������" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "���������������������������������������������������������������������NAT������������������������������" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "" -"������������������������������������������IP ������������������������������������������������������������������" -"������������������������������������������������������" - -msgid "Network interface must be a string" -msgstr "���������������������������������������������������������������������������������������������" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "������������������ VLAN ID ������1 ������ 4094 ���������������������������������������������" - -msgid "Specify name and type to create a Network" -msgstr "���������������������������������������������������������������������������������������" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "" -"��������������������������� %(name)s ������VLAN ������������������������������������������������������������" -"������" - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "������������������������ %(iface)s ���������������������������������: %(err)s���" - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "" -"������������������������ %(iface)s ���������������������������������������������������������������������������" -"������������" - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "��������������������������� %(name)s ������������������������" - -msgid "Debug report tool not found in system" -msgstr "������������������������������������������������������������������������������" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "��������������������������� %(name)s ���������������������������������: %(err)s" - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "��������������������������� %(name)s ���������������������������������: %(err)s" - -msgid "You should give a name for the debug report file." -msgstr "" - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "" -"���������%(name)s���������������������������������������������������������������������������������������������" -"���������������������������������������������������" - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "" -"������������������������������ %(server)s ������Kimchi ������������������������������������������������" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "������������������������������������%(name)s������������������������" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "��������������������� %(name)s ������������������������������������" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "���������������������������������������������������������������������������������������������������������" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "������������������������������������������������������������������������������������������������" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "���������������������������%(name)s���������������������������" - -msgid "Conflicting flag filters specified." -msgstr "" - -msgid "No packages marked for update" -msgstr "���������������������������������������������������������������������������������" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "��������������� %(name)s ���������������������������������������������������������������" - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������������: %(err)s" - -msgid "There is no compatible package manager for this system." -msgstr "���������������������������������������������������������������������������������������" - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "��������� URI %(uri)s" - -msgid "Unable to choose a virtual machine name" -msgstr "" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "" -"���������������������������������������������������������������������������������������cdrom������������" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" - -msgid "Only CDROM path can be update." -msgstr "" - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "" -"���������������������������������������������������������������������������������������������������: %(error)s" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "" -"������������������������������������������������������������������������������������������: %(error)s" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "" -"������������������������������������������������������������������������������������������: %(error)s" - -msgid "Do not support IDE device hot plug" -msgstr "" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "������������������������������������������������������������������������������������������������" - -msgid "Specify path to update virtual machine disk" -msgstr "���������������������������������������������������������������������������������������" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" - -msgid "Volume already in use by other virtual machine." -msgstr "" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "������������������������������������������������������������������������������������������������" - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" - -msgid "YUM Repository ID must be one word only string." -msgstr "YUM ������������������ ID ������1 ���������������������������������������������������������������" - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "" -"������������������ URL ��� http://���ftp://������������ file:// URL ���������������������������" -"������" - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������������������" - -msgid "Distribution to DEB repository must be a string" -msgstr "" -"DEB ������������������������������������������������������������������������������������������������������������" - -msgid "Components to DEB repository must be listed in a array" -msgstr "" -"DEB ������������������������������������������������������������������������������������������������������������" -"������" - -msgid "Components to DEB repository must be a string" -msgstr "DEB ������������������������������������������������������������������������������������������������" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "YUM ������������������������������������������������������������������������" - -msgid "GPG check must be a boolean value." -msgstr "GPG ������������������������������������������������������������" - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "GPG ���������ASCII ��������������������������������������� URL ���������������������������������" - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "������������������ %(repo_id)s ������������������������������������" - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "������������������ %(repo_id)s ������������������������" - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "���������������������������������������������������������������������������������������" - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "������������������ %(repo_id)s ���������������������������������������" - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "������������������ %(repo_id)s ���������������������������������������" - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "������������������ %(repo_id)s ������������������������������������" - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "" -"������������������������������������ %(repo_file)s ������������������������������������������������" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "" -"DEB ������������������������������������������������������������������������������������������������������������" -"������������������������" - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "������������������ %(repo_id)s ���������������������������������������" - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "������������������ %(repo_id)s ���������������������������������������" - -msgid "YUM Repository ID already exists" -msgstr "YUM ������������������ ID ������������������������" - -msgid "YUM Repository name must be a string" -msgstr "YUM ���������������������������������������������������������������������" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "������������������������������������������������������: ���%(err)s���" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "���������������������������������������������������������: ���%(err)s���" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "���������������������������������������������������: ���%(err)s���" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "���������������������������������������������������: ���%(err)s���" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" - -msgid "The number of vCPUs is too large for this system." -msgstr "" - -msgid "Invalid vCPU/topology combination." -msgstr "" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "" - -msgid "ERROR CODE" -msgstr "���������������������" - -msgid "REASON" -msgstr "������" - -msgid "STACK" -msgstr "������������" - -msgid "Go to Homepage" -msgstr "������������������������������������" - -msgid "Create a New Virtual Machine" -msgstr "������������������������������" - -msgid "Virtual Machine Name" -msgstr "������������������" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������������������������������������������������" - -msgid "Template" -msgstr "������������������" - -msgid "Please create a template first." -msgstr "������������������������������������������������������" - -msgid "Create a Template" -msgstr "���������������������������" - -msgid "Please choose a template." -msgstr "������������������������������������������������" - -msgid "OS" -msgstr "OS" - -msgid "OS Version" -msgstr "OS ���������������" - -msgid "CPUS" -msgstr "CPU" - -msgid "Memory" -msgstr "������������" - -msgid "Create" -msgstr "������" - -msgid "Creating..." -msgstr "" - -msgid "Cancel" -msgstr "������" - -msgid "Edit Guest" -msgstr "������������������" - -msgid "General" -msgstr "������" - -msgid "Storage" -msgstr "���������������" - -msgid "Interface" -msgstr "������������������������" - -msgid "Permission" -msgstr "���������������" - -msgid "Host PCI Device" -msgstr "" - -msgid "Snapshot" -msgstr "" - -msgid "Name" -msgstr "������" - -msgid "CPUs" -msgstr "CPU" - -msgid "Memory (MB)" -msgstr "������������" - -msgid "Icon" -msgstr "������������" - -msgid "Device" -msgstr "���������������" - -msgid "Path" -msgstr "NFS ������" - -msgid "Network" -msgstr " ������������������" - -msgid "Type" -msgstr "���������" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "" - -msgid "Selected system users and groups" -msgstr "" - -msgid "User" -msgstr "" - -msgid "All" -msgstr "���������" - -msgid "To Add" -msgstr "" - -msgid "Added" -msgstr "" - -msgid "filter" -msgstr "" - -msgid "Product" -msgstr "" - -msgid "Vendor" -msgstr "������������" - -msgid "Created" -msgstr "" - -msgid "Save" -msgstr "������" - -msgid "Replace" -msgstr "������" - -msgid "Detach" -msgstr "������������" - -msgid "revert" -msgstr "" - -msgid "Start" -msgstr "������" - -msgid "Reset" -msgstr "������������" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "" - -msgid "Actions" -msgstr "���������������" - -msgid "Connect" -msgstr "������" - -msgid "Clone" -msgstr "" - -msgid "Edit" -msgstr "������" - -msgid "Shut Down" -msgstr "���������������������" - -msgid "Delete" -msgstr "������" - -msgid "CPU" -msgstr "CPU" - -msgid "Disk I/O" -msgstr "���������������������" - -msgid "Network I/O" -msgstr "���������������������������" - -msgid "Livetile" -msgstr "������������������" - -msgid "No guests found." -msgstr "������������������������������������" - -msgid "Add a Storage Device to VM" -msgstr "VM ������������������������������������������" - -msgid "Device Type" -msgstr "������������������������" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "������������������������������������������������������������������ \"cdrom\" ���������������" - -msgid "Storage Pool" -msgstr "���������������������������" - -msgid "Storage pool which volume located in" -msgstr "������������������������������������������������������������������������������������" - -msgid "Storage Volume" -msgstr "������������������������������" - -msgid "Storage volume to be attached" -msgstr "������������������������������������������������������������������������������������" - -msgid "File Path" -msgstr "���������������������" - -msgid "The ISO file path in the server for CDROM." -msgstr "��������������������� CDROM ��� ISO ������������������������" - -msgid "Attach" -msgstr "������" - -msgid "Shut down" -msgstr "���������������������" - -msgid "Restart" -msgstr "���������" - -msgid "Basic Information" -msgstr "������������" - -msgid "OS Distro" -msgstr "OS ���������������������������������" - -msgid "OS Code Name" -msgstr "OS ������������" - -msgid "Processor" -msgstr "������������������" - -msgid "CPU(s)" -msgstr "" - -msgid "System Statistics" -msgstr "������������������������" - -msgid "Software Updates" -msgstr "������������������������" - -msgid "Update Progress" -msgstr "���������������������" - -msgid "Repositories" -msgstr "������������������" - -msgid "Debug Reports" -msgstr "���������������������������" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "���������������������������������������������������������������������������������������������������������" - -msgid "This field is required." -msgstr "���������������������������������������" - -msgid "Log in" -msgstr "������������" - -msgid "Logging in..." -msgstr "���������������������������..." - -msgid "Host" -msgstr "���������" - -msgid "Guests" -msgstr "���������" - -msgid "Templates" -msgstr "������������������" - -msgid "Failed to get application configuration" -msgstr "���������������������������������������������������������������" - -msgid "This is not a valid Linux path" -msgstr "��������� Linux ���������������������������" - -msgid "This is not a valid URL." -msgstr "��������� URL ������������������������" - -msgid "No such data available." -msgstr "���������������������������������������������" - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������������������������������������������������������������������HTTP ������������ %1" - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "���������������" - -msgid "OK" -msgstr "OK" - -msgid "Confirm" -msgstr "������" - -msgid "Warning" -msgstr "������" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "������������������������..." - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "���������" - -msgid "Detailed message:" -msgstr "���������������������:" - -msgid "No ISO found" -msgstr "" - -msgid "This is not a valid ISO file." -msgstr "��������� ISO ������������������������������������" - -msgid "This may take a long time. Do you want to continue?" -msgstr "������������������������������������������������������������������������?" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "���������������������������������������������������������������������?" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "" -"������������������������������������������������������������������������������������������������������������������!" - -msgid "Max:" -msgstr "������:" - -msgid "Utilization" -msgstr "���������" - -msgid "Available" -msgstr "������������" - -msgid "Read Rate" -msgstr "������������������" - -msgid "Write Rate" -msgstr "������������������" - -msgid "Received" -msgstr "������������" - -msgid "Sent" -msgstr "������������" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"���������������������/������������������������������?" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"���������������������������������������������������������������������������������������������������������?" - -msgid "ID" -msgstr "ID" - -msgid "Base URL" -msgstr "��������� URL" - -msgid "Is Mirror" -msgstr "���������" - -msgid "URL Args" -msgstr "URL ������" - -msgid "Enabled" -msgstr "������������" - -msgid "GPG Check" -msgstr "GPG ������������" - -msgid "GPG Key" -msgstr "GPG ���" - -msgid "Add" -msgstr "������" - -msgid "Remove" -msgstr "������" - -msgid "Enable" -msgstr "������������" - -msgid "Disable" -msgstr "������������" - -msgid "Package Name" -msgstr "������������������" - -msgid "Version" -msgstr "���������������" - -msgid "Architecture" -msgstr "������������������������" - -msgid "Repository" -msgstr "������������������" - -msgid "Update All" -msgstr "���������������" - -msgid "Updating..." -msgstr "���������������������..." - -msgid "Failed to retrieve packages update information." -msgstr "" - -msgid "Failed to update package(s)." -msgstr "���������������������������������������������������" - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"������������������������������������������������������������������������������������������������������������������?" - -msgid "Generated Time" -msgstr "������������" - -msgid "Generate" -msgstr "������" - -msgid "Generating..." -msgstr "���������������������..." - -msgid "Rename" -msgstr "������������" - -msgid "Download" -msgstr "������������������" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "��������������������������������������������������������������������������������� (-) ���������������" - -msgid "Pending..." -msgstr "������������������������..." - -msgid "Report name is the same as the original one." -msgstr "" - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������������������������?" - -msgid "Power off Confirmation" -msgstr "���������������" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" - -msgid "Reset Confirmation" -msgstr "���������������" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" - -msgid "Shut Down Confirmation" -msgstr "���������������" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "���������������������������������������������������������������������?" - -msgid "Virtual Machine delete Confirmation" -msgstr "" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" -"������ CDROM ������������������������������������������������������������������������������������������������?" - -msgid "Attaching..." -msgstr "���������������������..." - -msgid "Replacing..." -msgstr "���������������������..." - -msgid "Successfully attached!" -msgstr "���������������������������!" - -msgid "Successfully replaced!" -msgstr "���������������������������!" - -msgid "Successfully detached!" -msgstr "������������������������������!" - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" - -msgid "interface:" -msgstr "" - -msgid "address:" -msgstr "" - -msgid "link_type:" -msgstr "" - -msgid "block:" -msgstr "" - -msgid "drive_type:" -msgstr "" - -msgid "model:" -msgstr "" - -msgid "Affected devices:" -msgstr "" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "VLAN ID ������1 ������ 4094 ���������������������������������������" - -msgid "unavailable" -msgstr "������������" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������������������" - -msgid "Create a network" -msgstr "���������������������������" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"���������������������������������������������������������������������������������?" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "������������������������������������������������������������������������������?" - -msgid "This storage pool is empty." -msgstr "������������������������������������������������" - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" -"���������������������������������������������������������������������������������������������������������������?" - -msgid "SCSI Fibre Channel" -msgstr "SCSI ������������������������������" - -msgid "No SCSI adapters found." -msgstr "SCSI ������������������������������������������" - -msgid "Loading iSCSI targets..." -msgstr "" - -msgid "No iSCSI found. Please input one." -msgstr "" - -msgid "Failed to load iSCSI targets." -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "���������������������������������������������������������������������������������" - -msgid "The storage pool path can not be blank." -msgstr "���������������������������������������������������������������������������������������" - -msgid "NFS server mount path can not be blank." -msgstr "NFS ���������������������������������������������������������������������������������������" - -msgid "Invalid NFS mount path." -msgstr "NFS ���������������������������������������" - -msgid "No logical device selected." -msgstr "���������������������������������������������������" - -msgid "The iSCSI target can not be blank." -msgstr "iSCSI ������������������������������������������������������������������" - -msgid "Server name can not be blank." -msgstr "������������������������������������������������������������������" - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "" - -msgid "Looking for available partitions ..." -msgstr "���������������������������������������������������������..." - -msgid "No available partitions found." -msgstr "���������������������������������������������������������������" - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"���������������������������������������������������������������������������������?" - -msgid "Unable to retrieve partitions information." -msgstr "���������������������������������������������������������: ���%(err)s���" - -msgid "In progress..." -msgstr "" - -msgid "Failed!" -msgstr "" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" - -msgid "Disk pool or volume cannot be blank." -msgstr "���������������������������������������������������������������������������������" - -msgid "Filter" -msgstr "" - -msgid "Network Name" -msgstr "���������������������" - -msgid "State" -msgstr "������" - -msgid "Network Type" -msgstr "������������������������������" - -msgid "Address Space" -msgstr "���������������������������" - -msgid "Name should not contain '/' and '\"'." -msgstr "" - -msgid "Isolated: no external network connection" -msgstr "������: ������������������������������������" - -msgid "NAT: outbound physical network connection only" -msgstr "NAT: ���������������������������������������������������������" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "������������: ������������������������������������������������������������������" - -msgid "(No interfaces found)" -msgstr "" - -msgid "Destination" -msgstr "������:" - -msgid "Enable VLAN" -msgstr "VLAN ������������������������:" - -msgid "VLAN ID" -msgstr "VLAN ID:" - -msgid "Stop" -msgstr "������" - -msgid "Generate a New Debug Report" -msgstr "������������������������������������������" - -msgid "Report Name" -msgstr "���������������" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"��������������������������������������������������������������������� (-) ������������������������" - -msgid "Rename a Debug Report" -msgstr "������������������������������������������" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"��������������������������������������������������������������������� (-) ������������������������" - -msgid "Submit" -msgstr "" - -msgid "Add a Repository" -msgstr "���������������������������" - -msgid "Identifier" -msgstr "ID" - -msgid "Single word, unique identifier for the repository." -msgstr "��������������������������� ID ������������������������������" - -msgid "Textual name for the repository." -msgstr "���������������������������������������" - -msgid "URL" -msgstr "URL" - -msgid "Required Field" -msgstr "���������������������" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "" -"��������������������� URL ��������������������������������������������������� http���ftp������������ file " -"���������" - -msgid "Repository is a mirror" -msgstr "���������������������������������������" - -msgid "Distribution" -msgstr "���������������������������������" - -msgid "Distribution of the DEB repository." -msgstr "DEB ���������������������������������������������������������" - -msgid "Components" -msgstr "���������������������" - -msgid "List of components in DEB repository." -msgstr "DEB ������������������������������������������������������������" - -msgid "Edit Repository" -msgstr "���������������������������" - -msgid "Mirror List URL" -msgstr "��������������������� URL" - -msgid "Yes" -msgstr " ������" - -msgid "No" -msgstr " ���������" - -msgid "Capacity" -msgstr "������" - -msgid "Allocated" -msgstr "������������������" - -msgid "Location" -msgstr "������������������" - -msgid "Device path" -msgstr "���������������������" - -msgid "active" -msgstr "���������������" - -msgid "inactive" -msgstr "������������������" - -msgid "Deactivate" -msgstr "���������������������������" - -msgid "Activate" -msgstr "������������������������" - -msgid "Add Volume" -msgstr "" - -msgid "Extend" -msgstr "" - -msgid "Undefine" -msgstr "���������������������" - -msgid "Format" -msgstr "������������������:" - -msgid "Allocation" -msgstr "������������:" - -msgid "Define a New Storage Pool" -msgstr "������������������������������������������" - -msgid "Storage Pool Name" -msgstr "������������������������������" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������" - -msgid "Storage Pool Type" -msgstr "���������������������������������������" - -msgid "Storage Path" -msgstr "������������������������" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "" -"���������������������������������������������������������������������������������������������������������������" -"������" - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "" -"���������������������������������������������������������������Kimchi ���������������������������������" - -msgid "NFS Server IP" -msgstr "NFS ������������ IP" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "" -"NFS ������������ IP ������������������������������������������������������������������������������������������" -"���������������" - -msgid "NFS Path" -msgstr "NFS ������" - -msgid "The NFS exported path on NFS server." -msgstr "NFS ������������ NFS ������������������������������������������������" - -msgid "iSCSI Server" -msgstr "iSCSI ������������" - -msgid "Server" -msgstr "������������" - -msgid "Port" -msgstr "���������" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "iSCSI ������������ IP ���������������������������������������������������������������" - -msgid "Target" -msgstr "���������������" - -msgid "The iSCSI target on iSCSI server" -msgstr "iSCSI ������������������ iSCSI ���������������" - -msgid "Add iSCSI Authentication" -msgstr "iSCSI ���������������" - -msgid "iSCSI Authentication" -msgstr "iSCSI ������" - -msgid "User Name" -msgstr "���������������" - -msgid "Password" -msgstr "���������������" - -msgid "SCSI Adapter" -msgstr "SCSI ���������������" - -msgid "Please, wait..." -msgstr "���������������������..." - -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - -msgid "Add Template" -msgstr "���������������������������" - -msgid "Where is the source media for this template? " -msgstr "������������������������������������������������������������������������������?" - -msgid "Local ISO Image" -msgstr "������������ ISO ������������" - -msgid "Local Image File" -msgstr "" - -msgid "Remote ISO Image" -msgstr "������������ ISO ������������" - -msgid "Search ISOs" -msgstr "ISO ���������" - -msgid "The following ISOs are available:" -msgstr "������ ISO ���������������������:" - -msgid "OS: " -msgstr "OS: " - -msgid "Version: " -msgstr "���������������: " - -msgid "Size: " -msgstr "���������: " - -msgid "Search more ISOs" -msgstr "ISO ������������������" - -msgid "Create Templates from Selected ISO" -msgstr "������������ ISO ���������������������������������" - -msgid "I want to use a specific ISO file" -msgstr "��������� ISO ���������������������������" - -msgid "Loading default remote ISOs ..." -msgstr "������������������������������ ISO ���������������������������..." - -msgid "Arch: " -msgstr "������������������������: " - -msgid "I want to use a custom URL" -msgstr "������������ URL ���������������" - -msgid "Edit Template" -msgstr "���������������������������" - -msgid "CDROM" -msgstr "CDROM" - -msgid "Image File" -msgstr "" - -msgid "Graphics" -msgstr "���������������������" - -msgid "Disk(GB)" -msgstr "" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "CPU ���" - -msgid "Manually set CPU topology" -msgstr "" - -msgid "Cores" -msgstr "" - -msgid "Threads" -msgstr "" - -msgid "No templates found." -msgstr "���������������������������������������������" - -#~ msgid "Delete is not allowed for %(resource)s" -#~ msgstr "%(resource)s ���������������������������������" - -#~ msgid "%(resource)s does not implement update method" -#~ msgstr "%(resource)s ������������������������������������������������" - -#~ msgid "Create is not allowed for %(resource)s" -#~ msgstr "%(resource)s ���������������������������������" - -#~ msgid "Unable to parse JSON request" -#~ msgstr "JSON ������������������������������" - -#~ msgid "This API only supports JSON" -#~ msgstr "������ API ��� JSON ���������������������������" - -#~ msgid "Datastore is not initiated in the model object." -#~ msgstr "������������������������������������������������������������������������������������������" - -#~ msgid "Unable to start task due error: %(err)s" -#~ msgstr "������������������������������������������������������������: %(err)s" - -#~ msgid "" -#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" -#~ msgstr "" -#~ "���������������%(username)s������������������������������������[���������������������: %(code)s]" - -#~ msgid "You are not authorized to access Kimchi" -#~ msgstr "Kimchi ������������������������������������������������" - -#~ msgid "Specify %(item)s to login into Kimchi" -#~ msgstr "Kimchi ������������������������������%(item)s ������������������" - -#~ msgid "Unable to find %(item)s in datastore" -#~ msgstr "%(item)s ������������������������������������������������" - -#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" -#~ msgstr "" -#~ "���������������%(cmd)s������������������������������������%(seconds)s ������������������������������" -#~ "������������������������" - -#~ msgid "Help" -#~ msgstr "���������" - -#~ msgid "About" -#~ msgstr "������������" - -#~ msgid "Log out" -#~ msgstr "���������������" - -#~ msgid "Version:" -#~ msgstr "���������������: " diff --git a/plugins/kimchi/po/kimchi.pot b/plugins/kimchi/po/kimchi.pot deleted file mode 100755 index d4605c7..0000000 --- a/plugins/kimchi/po/kimchi.pot +++ /dev/null @@ -1,2074 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" -"Language-Team: LANGUAGE <LL@li.org>\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "" - -msgid "Unknown \"_cap\" specified" -msgstr "" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "" - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "" - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" - -msgid "An error occurred when probing image OS information." -msgstr "" - -msgid "No OS information found in given image." -msgstr "" - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "" - -msgid "Remote ISO image is not supported by this server." -msgstr "" - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "" - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "" - -msgid "Specify a template to create a virtual machine from" -msgstr "" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "" - -msgid "User name list must be an array" -msgstr "" - -msgid "User name must be a string" -msgstr "" - -msgid "Group name list must be an array" -msgstr "" - -msgid "Group name must be a string" -msgstr "" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "" - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "" - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "" - -msgid "The guest console password must be a string." -msgstr "" - -msgid "The life time for the guest console password must be a number." -msgstr "" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" - -msgid "\"name\" should be a device name string" -msgstr "" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "" - -msgid "Network name for virtual machine interface must be a string" -msgstr "" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "" - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "" - -msgid "Template name must be a string" -msgstr "" - -msgid "Template icon must be a path to the image" -msgstr "" - -msgid "Template distribution must be a string" -msgstr "" - -msgid "Template distribution version must be a string" -msgstr "" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "" - -msgid "All networks for the template must be specified in a list." -msgstr "" - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "" - -msgid "Template base image must be a valid local image file" -msgstr "" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" - -msgid "Storage pool path must be a string" -msgstr "" - -msgid "Storage pool host must be a IP or hostname" -msgstr "" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" - -msgid "Storage pool devices parameter must be a list" -msgstr "" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "" - -msgid "iSCSI target username must be a string" -msgstr "" - -msgid "iSCSI target password must be a string" -msgstr "" - -msgid "Specify name and type to create a storage pool" -msgstr "" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "" - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "" - -msgid "The SCSI host adapter name must be a string." -msgstr "" - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "" - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "" - -msgid "Storage volume name must be a string" -msgstr "" - -msgid "Storage volume allocation must be an integer number" -msgstr "" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" - -msgid "Storage volume requires a volume name" -msgstr "" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "" - -msgid "Storage volume capacity must be an integer number." -msgstr "" - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "" - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "" - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "" - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "" - -msgid "Network interface must be a string" -msgstr "" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "" - -msgid "Specify name and type to create a Network" -msgstr "" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "" - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "" - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "" - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "" - -msgid "Debug report tool not found in system" -msgstr "" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "" - -msgid "You should give a name for the debug report file." -msgstr "" - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "" - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "" - -msgid "Conflicting flag filters specified." -msgstr "" - -msgid "No packages marked for update" -msgstr "" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "" - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "" - -msgid "There is no compatible package manager for this system." -msgstr "" - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "" - -msgid "Unable to choose a virtual machine name" -msgstr "" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" - -msgid "Only CDROM path can be update." -msgstr "" - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "" - -msgid "Do not support IDE device hot plug" -msgstr "" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "" - -msgid "Specify path to update virtual machine disk" -msgstr "" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" - -msgid "Volume already in use by other virtual machine." -msgstr "" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "" - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" - -msgid "YUM Repository ID must be one word only string." -msgstr "" - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "" - -msgid "Distribution to DEB repository must be a string" -msgstr "" - -msgid "Components to DEB repository must be listed in a array" -msgstr "" - -msgid "Components to DEB repository must be a string" -msgstr "" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "" - -msgid "GPG check must be a boolean value." -msgstr "" - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "" - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "" - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "" - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "" - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "" - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "" - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "" - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "" - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "" - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "" - -msgid "YUM Repository ID already exists" -msgstr "" - -msgid "YUM Repository name must be a string" -msgstr "" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" - -msgid "The number of vCPUs is too large for this system." -msgstr "" - -msgid "Invalid vCPU/topology combination." -msgstr "" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "" - -msgid "ERROR CODE" -msgstr "" - -msgid "REASON" -msgstr "" - -msgid "STACK" -msgstr "" - -msgid "Go to Homepage" -msgstr "" - -msgid "Create a New Virtual Machine" -msgstr "" - -msgid "Virtual Machine Name" -msgstr "" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "" - -msgid "Template" -msgstr "" - -msgid "Please create a template first." -msgstr "" - -msgid "Create a Template" -msgstr "" - -msgid "Please choose a template." -msgstr "" - -msgid "OS" -msgstr "" - -msgid "OS Version" -msgstr "" - -msgid "CPUS" -msgstr "" - -msgid "Memory" -msgstr "" - -msgid "Create" -msgstr "" - -msgid "Creating..." -msgstr "" - -msgid "Cancel" -msgstr "" - -msgid "Edit Guest" -msgstr "" - -msgid "General" -msgstr "" - -msgid "Storage" -msgstr "" - -msgid "Interface" -msgstr "" - -msgid "Permission" -msgstr "" - -msgid "Host PCI Device" -msgstr "" - -msgid "Snapshot" -msgstr "" - -msgid "Name" -msgstr "" - -msgid "CPUs" -msgstr "" - -msgid "Memory (MB)" -msgstr "" - -msgid "Icon" -msgstr "" - -msgid "Device" -msgstr "" - -msgid "Path" -msgstr "" - -msgid "Network" -msgstr "" - -msgid "Type" -msgstr "" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "" - -msgid "Selected system users and groups" -msgstr "" - -msgid "User" -msgstr "" - -msgid "All" -msgstr "" - -msgid "To Add" -msgstr "" - -msgid "Added" -msgstr "" - -msgid "filter" -msgstr "" - -msgid "Product" -msgstr "" - -msgid "Vendor" -msgstr "" - -msgid "Created" -msgstr "" - -msgid "Save" -msgstr "" - -msgid "Replace" -msgstr "" - -msgid "Detach" -msgstr "" - -msgid "revert" -msgstr "" - -msgid "Start" -msgstr "" - -msgid "Reset" -msgstr "" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "" - -msgid "Actions" -msgstr "" - -msgid "Connect" -msgstr "" - -msgid "Clone" -msgstr "" - -msgid "Edit" -msgstr "" - -msgid "Shut Down" -msgstr "" - -msgid "Delete" -msgstr "" - -msgid "CPU" -msgstr "" - -msgid "Disk I/O" -msgstr "" - -msgid "Network I/O" -msgstr "" - -msgid "Livetile" -msgstr "" - -msgid "No guests found." -msgstr "" - -msgid "Add a Storage Device to VM" -msgstr "" - -msgid "Device Type" -msgstr "" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "" - -msgid "Storage Pool" -msgstr "" - -msgid "Storage pool which volume located in" -msgstr "" - -msgid "Storage Volume" -msgstr "" - -msgid "Storage volume to be attached" -msgstr "" - -msgid "File Path" -msgstr "" - -msgid "The ISO file path in the server for CDROM." -msgstr "" - -msgid "Attach" -msgstr "" - -msgid "Shut down" -msgstr "" - -msgid "Restart" -msgstr "" - -msgid "Basic Information" -msgstr "" - -msgid "OS Distro" -msgstr "" - -msgid "OS Code Name" -msgstr "" - -msgid "Processor" -msgstr "" - -msgid "CPU(s)" -msgstr "" - -msgid "System Statistics" -msgstr "" - -msgid "Software Updates" -msgstr "" - -msgid "Update Progress" -msgstr "" - -msgid "Repositories" -msgstr "" - -msgid "Debug Reports" -msgstr "" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "" - -msgid "This field is required." -msgstr "" - -msgid "Log in" -msgstr "" - -msgid "Logging in..." -msgstr "" - -msgid "Host" -msgstr "" - -msgid "Guests" -msgstr "" - -msgid "Templates" -msgstr "" - -msgid "Failed to get application configuration" -msgstr "" - -msgid "This is not a valid Linux path" -msgstr "" - -msgid "This is not a valid URL." -msgstr "" - -msgid "No such data available." -msgstr "" - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "" - -msgid "OK" -msgstr "" - -msgid "Confirm" -msgstr "" - -msgid "Warning" -msgstr "" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "" - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "" - -msgid "Detailed message:" -msgstr "" - -msgid "No ISO found" -msgstr "" - -msgid "This is not a valid ISO file." -msgstr "" - -msgid "This may take a long time. Do you want to continue?" -msgstr "" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "" - -msgid "Max:" -msgstr "" - -msgid "Utilization" -msgstr "" - -msgid "Available" -msgstr "" - -msgid "Read Rate" -msgstr "" - -msgid "Write Rate" -msgstr "" - -msgid "Received" -msgstr "" - -msgid "Sent" -msgstr "" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" - -msgid "ID" -msgstr "" - -msgid "Base URL" -msgstr "" - -msgid "Is Mirror" -msgstr "" - -msgid "URL Args" -msgstr "" - -msgid "Enabled" -msgstr "" - -msgid "GPG Check" -msgstr "" - -msgid "GPG Key" -msgstr "" - -msgid "Add" -msgstr "" - -msgid "Remove" -msgstr "" - -msgid "Enable" -msgstr "" - -msgid "Disable" -msgstr "" - -msgid "Package Name" -msgstr "" - -msgid "Version" -msgstr "" - -msgid "Architecture" -msgstr "" - -msgid "Repository" -msgstr "" - -msgid "Update All" -msgstr "" - -msgid "Updating..." -msgstr "" - -msgid "Failed to retrieve packages update information." -msgstr "" - -msgid "Failed to update package(s)." -msgstr "" - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" - -msgid "Generated Time" -msgstr "" - -msgid "Generate" -msgstr "" - -msgid "Generating..." -msgstr "" - -msgid "Rename" -msgstr "" - -msgid "Download" -msgstr "" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "" - -msgid "Pending..." -msgstr "" - -msgid "Report name is the same as the original one." -msgstr "" - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "" - -msgid "Power off Confirmation" -msgstr "" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" - -msgid "Reset Confirmation" -msgstr "" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" - -msgid "Shut Down Confirmation" -msgstr "" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "" - -msgid "Virtual Machine delete Confirmation" -msgstr "" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" - -msgid "Attaching..." -msgstr "" - -msgid "Replacing..." -msgstr "" - -msgid "Successfully attached!" -msgstr "" - -msgid "Successfully replaced!" -msgstr "" - -msgid "Successfully detached!" -msgstr "" - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" - -msgid "interface:" -msgstr "" - -msgid "address:" -msgstr "" - -msgid "link_type:" -msgstr "" - -msgid "block:" -msgstr "" - -msgid "drive_type:" -msgstr "" - -msgid "model:" -msgstr "" - -msgid "Affected devices:" -msgstr "" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "" - -msgid "unavailable" -msgstr "" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" - -msgid "Create a network" -msgstr "" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "" - -msgid "This storage pool is empty." -msgstr "" - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" - -msgid "SCSI Fibre Channel" -msgstr "" - -msgid "No SCSI adapters found." -msgstr "" - -msgid "Loading iSCSI targets..." -msgstr "" - -msgid "No iSCSI found. Please input one." -msgstr "" - -msgid "Failed to load iSCSI targets." -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "" - -msgid "The storage pool path can not be blank." -msgstr "" - -msgid "NFS server mount path can not be blank." -msgstr "" - -msgid "Invalid NFS mount path." -msgstr "" - -msgid "No logical device selected." -msgstr "" - -msgid "The iSCSI target can not be blank." -msgstr "" - -msgid "Server name can not be blank." -msgstr "" - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "" - -msgid "Looking for available partitions ..." -msgstr "" - -msgid "No available partitions found." -msgstr "" - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" - -msgid "Unable to retrieve partitions information." -msgstr "" - -msgid "In progress..." -msgstr "" - -msgid "Failed!" -msgstr "" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" - -msgid "Disk pool or volume cannot be blank." -msgstr "" - -msgid "Filter" -msgstr "" - -msgid "Network Name" -msgstr "" - -msgid "State" -msgstr "" - -msgid "Network Type" -msgstr "" - -msgid "Address Space" -msgstr "" - -msgid "Name should not contain '/' and '\"'." -msgstr "" - -msgid "Isolated: no external network connection" -msgstr "" - -msgid "NAT: outbound physical network connection only" -msgstr "" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "" - -msgid "(No interfaces found)" -msgstr "" - -msgid "Destination" -msgstr "" - -msgid "Enable VLAN" -msgstr "" - -msgid "VLAN ID" -msgstr "" - -msgid "Stop" -msgstr "" - -msgid "Generate a New Debug Report" -msgstr "" - -msgid "Report Name" -msgstr "" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" - -msgid "Rename a Debug Report" -msgstr "" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" - -msgid "Submit" -msgstr "" - -msgid "Add a Repository" -msgstr "" - -msgid "Identifier" -msgstr "" - -msgid "Single word, unique identifier for the repository." -msgstr "" - -msgid "Textual name for the repository." -msgstr "" - -msgid "URL" -msgstr "" - -msgid "Required Field" -msgstr "" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "" - -msgid "Repository is a mirror" -msgstr "" - -msgid "Distribution" -msgstr "" - -msgid "Distribution of the DEB repository." -msgstr "" - -msgid "Components" -msgstr "" - -msgid "List of components in DEB repository." -msgstr "" - -msgid "Edit Repository" -msgstr "" - -msgid "Mirror List URL" -msgstr "" - -msgid "Yes" -msgstr "" - -msgid "No" -msgstr "" - -msgid "Capacity" -msgstr "" - -msgid "Allocated" -msgstr "" - -msgid "Location" -msgstr "" - -msgid "Device path" -msgstr "" - -msgid "active" -msgstr "" - -msgid "inactive" -msgstr "" - -msgid "Deactivate" -msgstr "" - -msgid "Activate" -msgstr "" - -msgid "Add Volume" -msgstr "" - -msgid "Extend" -msgstr "" - -msgid "Undefine" -msgstr "" - -msgid "Format" -msgstr "" - -msgid "Allocation" -msgstr "" - -msgid "Define a New Storage Pool" -msgstr "" - -msgid "Storage Pool Name" -msgstr "" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "" - -msgid "Storage Pool Type" -msgstr "" - -msgid "Storage Path" -msgstr "" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "" - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "" - -msgid "NFS Server IP" -msgstr "" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "" - -msgid "NFS Path" -msgstr "" - -msgid "The NFS exported path on NFS server." -msgstr "" - -msgid "iSCSI Server" -msgstr "" - -msgid "Server" -msgstr "" - -msgid "Port" -msgstr "" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "" - -msgid "Target" -msgstr "" - -msgid "The iSCSI target on iSCSI server" -msgstr "" - -msgid "Add iSCSI Authentication" -msgstr "" - -msgid "iSCSI Authentication" -msgstr "" - -msgid "User Name" -msgstr "" - -msgid "Password" -msgstr "" - -msgid "SCSI Adapter" -msgstr "" - -msgid "Please, wait..." -msgstr "" - -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - -msgid "Add Template" -msgstr "" - -msgid "Where is the source media for this template? " -msgstr "" - -msgid "Local ISO Image" -msgstr "" - -msgid "Local Image File" -msgstr "" - -msgid "Remote ISO Image" -msgstr "" - -msgid "Search ISOs" -msgstr "" - -msgid "The following ISOs are available:" -msgstr "" - -msgid "OS: " -msgstr "" - -msgid "Version: " -msgstr "" - -msgid "Size: " -msgstr "" - -msgid "Search more ISOs" -msgstr "" - -msgid "Create Templates from Selected ISO" -msgstr "" - -msgid "I want to use a specific ISO file" -msgstr "" - -msgid "Loading default remote ISOs ..." -msgstr "" - -msgid "Arch: " -msgstr "" - -msgid "I want to use a custom URL" -msgstr "" - -msgid "Edit Template" -msgstr "" - -msgid "CDROM" -msgstr "" - -msgid "Image File" -msgstr "" - -msgid "Graphics" -msgstr "" - -msgid "Disk(GB)" -msgstr "" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "" - -msgid "Manually set CPU topology" -msgstr "" - -msgid "Cores" -msgstr "" - -msgid "Threads" -msgstr "" - -msgid "No templates found." -msgstr "" diff --git a/plugins/kimchi/po/ko_KR.po b/plugins/kimchi/po/ko_KR.po deleted file mode 100644 index 08bf222..0000000 --- a/plugins/kimchi/po/ko_KR.po +++ /dev/null @@ -1,2197 +0,0 @@ -# English translations for kimchi package. -# Copyright (C) 2013 ORGANIZATION -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2013-07-11 17:32-0400\n" -"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" -"Language-Team: English\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ko_KR\n" -"Generated-By: pygettext.py 1.5\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "" - -msgid "Unknown \"_cap\" specified" -msgstr "" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "������ ��������� ������������ ������ ��������� ������������������. ������������: %(err)s" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "%(device)s��� ������ ������ ������ ��������� ������������ ������ ��������� ������������������." - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "distro ��������� ������ ��� ������: %(filename)s" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "" -"distro ������(%(filename)s)��� ������ ��������� ��� ������������. JSON ������������ ���������������" -"���." - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "iSCSI ��������� ������ %(portal)s��� ������������ ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "iSCSI host %(host)s ������ %(target)s��� ������������ ��� ������������." - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "ISO ������ %(filename)s���(���) ������ ������������ ������������." - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "ISO ������ %(filename)s��� ��������� El Torito ������ ������������ ������������." - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "" -"ISO %(filename)s��� ������������ ������ El Torito ��������� ������ ��������� ������������." - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "ISO %(filename)s��� ������������ ������ El Torito ������ ������������ ������������." - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "ISO %(filename)s������ ������ ��������� ��������� ������ ������ ���������������." - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "" -"ISO %(filename)s������ ������ ������������������ ������ ������ ��������� ��������� ������������������" -"���." - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" -"��������������������� ��� ISO %(filename)s���(���) ��������� ��������� ������������. ������ /var/" -"lib/libvirt ��������� ������������������, (��������� ������) ������ ��������� '%(user)s' ���������" -"��� ������ ��������� ������ ��������� ���������������, '%(user)s'���(���) ISO ������ ��������� ������" -"���������, 'chmod -R o+x 'path_to_iso'(������������ ������)��� ������������������. ������������: " -"%(err)s" - -msgid "An error occurred when probing image OS information." -msgstr "" - -msgid "No OS information found in given image." -msgstr "" - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "������ ������ %(name)s���(���) ������ ���������������." - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "������ ������ %(name)s���(���) ������������." - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "��������� ������ ������ %(name)s��� ������ ��������������� ��������� ��� ������������." - -msgid "Remote ISO image is not supported by this server." -msgstr "������ ISO ������������ ��� ������������ ������������ ������������." - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "" - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "������ ������ ��������� ��������� IPv4 ������ IPv6������ ���������." - -msgid "Specify a template to create a virtual machine from" -msgstr "������ ��������� ������������ ������ ��������������� ������������������." - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "������ ������ %(name)s��� ��������� ������ ��� ������������. ������������: %(err)s" - -msgid "User name list must be an array" -msgstr "" - -msgid "User name must be a string" -msgstr "������������ ��������� ������������������ ���������." - -msgid "Group name list must be an array" -msgstr "" - -msgid "Group name must be a string" -msgstr "������������ ��������� ������������������ ���������." - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "'%(users)s' ������������ ������������." - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "'%(groups)s' ������������ ������������." - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -msgid "The guest console password must be a string." -msgstr "" - -msgid "The life time for the guest console password must be a number." -msgstr "" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" - -msgid "\"name\" should be a device name string" -msgstr "" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "������ ������ %(name)s��� %(iface)s ������������������ ������������." - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "������ ������ %(name)s��� ������ ��������� %(network)s ��������������� ������������." - -msgid "Supported virtual machine interfaces type is only network" -msgstr "������������ ������ ������ ��������������� ��������� ������������������������." - -msgid "Network name for virtual machine interface must be a string" -msgstr "������ ������ ������������������ ������������ ��������� ������������������ ���������." - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "" -"������ ������ ������������������ ������ ������������ ������ ������������ ������ ��������� ������������������" -"���." - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "��� ������ ������ ������������������ ��������� ������ ��� ��������������� ������������������." - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "������������ %(name)s���(���) ������ ���������������." - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "������������ %(template)s��� ������ ��������� '%(network)s' ��������������� ������������." - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "" -"������������ %(template)s��� ������ ��������� ������������ ��� %(pool)s���(���) ������������." - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "" -"������������ %(template)s��� ������ ��������� ������������ ��� %(pool)s���(���) ��������� ���������" -"���." - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "CDROM��� ������ ������������ ������ ������������ '%(param)s'���(���) ���������������������." - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "" -"������������ %(template)s��� ������ ��������� %(network)s ��������������� ��������� ������������." - -msgid "Template name must be a string" -msgstr "������������ ��������� ������������������ ���������." - -msgid "Template icon must be a path to the image" -msgstr "������������ ������������ ������������ ������������ ���������." - -msgid "Template distribution must be a string" -msgstr "������������ ��������� ������������������ ���������." - -msgid "Template distribution version must be a string" -msgstr "������������ ������ ��������� ������������������ ���������." - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "CPU ������ ������������ ���������." - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "��������� ������(MB)��� 512������ ��� ������������ ���������." - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "������������ CDROM��� ������ ������ ������ ISO ��������������� ���������." - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "" -"��������������� ������ ������������ ������ ������������ ��� URI %(value)s���(���) ���������������������." - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "��������������� ��������������� ISO ������������ CDROM������ ������������������." - -msgid "All networks for the template must be specified in a list." -msgstr "��������������� ������ ��������������� ��������� ��������������� ���������." - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "������ ��������� ��������������� ��������� ��� ������: %(err)s" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "������ ��������� ��������������� ��������� ��� ������: %(err)s" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "" - -msgid "Template base image must be a valid local image file" -msgstr "������������ CDROM��� ������ ������ ������ ISO ��������������� ���������." - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "������������ ��� %(name)s���(���) ������ ���������������." - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "������������ ��� %(name)s���(���) ������������." - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "������������ ��� %(name)s���(���) ��������������� %(item)s���(���) ������������������." - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "������ ������������ ��� %(name)s���(���) ��������� ��� ������������." - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "������������ ������ ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "������������ ��� %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "" -"������������ ��� %(name)s��� ������ ������������ ��������� ������ ��������� ��� ������������. ���������" -"���: %(err)s" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "������������ ��� %(name)s���(���) ������������ ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "������������ ��� %(name)s���(���) ��������������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "������������ ��� %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "" -"������������ ������ %(path)s���(���) ��������� ������ ��������� ��� ������������ NFS ������ ��������� " -"��� ������������." - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "" -"������������ ������ %(path)s ������������ ������������������ NFS ������ ��������� ��� ������������." - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "������������ ������ ������������ ��� ������: %(type)s" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" - -msgid "Storage pool path must be a string" -msgstr "������������ ��� ��������� ������������������ ���������." - -msgid "Storage pool host must be a IP or hostname" -msgstr "������������ ��� ������������ IP ������ ��������� ��������������� ���������." - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" - -msgid "Storage pool devices parameter must be a list" -msgstr "������������ ��� ��������� ��������������� ���������." - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "iSCSI ������ ������ IQN��� ������������������ ���������." - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "������ ������������ ��������� ��������� 1��� 65535 ��������� ������������ ���������." - -msgid "iSCSI target username must be a string" -msgstr "" - -msgid "iSCSI target password must be a string" -msgstr "" - -msgid "Specify name and type to create a storage pool" -msgstr "������������ ������ ��������������� ������ ��� ��������� ������������������." - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "" -"%(disk)s���(���) ��������� ���������/������������ ������������. ������ %(pool)s ������ ��������� ��� " -"������������." - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "������ ������������ ������ ������������ ������������ ��������������� ��� ������������." - -msgid "The SCSI host adapter name must be a string." -msgstr "SCSI ��������� ��������� ��������� ������������������ ���������." - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "������������ ��� kimchi_isos��� ������ ��������� ���������������������." - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"NFS ������������ ��� %(name)s���(���) ������������ ��� ������������. NFS ������ %(server)s��� ���" -"������ ��� ������������." - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"NFS ������������ ��� %(name)s���(���) ��������������� ��� ������������. NFS ������ %(server)s��� " -"��������� ��� ������������." - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "" -"������ ��������������� ������������ ������������ %(name)s ������ ��������������� ��� ������������." - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "������ ��������������� ������������ ������������ %(name)s ������ ��������� ��� ������������." - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "" -"��������� '%(name)s'��� ������ ��������� ������ ���������������. ������ ������ ��������������� ������ ���" -"������ ������������������." - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "" -"������ ��������� ��������� ������ ��������� ��������������������� ��������������� ��� ������: %(err)s" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "������������ ������ %(name)s���(���) ������ ���������������." - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "������������ ������ %(name)s���(���) ������������ ��� %(pool)s��� ������������." - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "������������ ������ %(volume)s���(���) ��������������� %(item)s���(���) ������������������." - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "" -"������������ ��� %(pool)s���(���) ��������� ������������ ������������ ��������� ��������� ��� ���������" -"���." - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "" -"������������ ������ %(name)s���(���) ������������ ��� %(pool)s��� ��������� ��� ������������. ������" -"������: %(err)s" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "" -"������������ ��� %(pool)s��� ������������ ��������� ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "������������ ��� %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "������������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "������������ ������ %(name)s��� ��������� ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "������������ ������ %(type)s���(���) ������ ������ ��� ��������� ������������ ������������." - -msgid "Storage volume name must be a string" -msgstr "������������ ������ ��������� ������������������ ���������." - -msgid "Storage volume allocation must be an integer number" -msgstr "������������ ������ ��������� ������������ ���������." - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" - -msgid "Storage volume requires a volume name" -msgstr "������������ ��������� ������ ��������� ���������������." - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "" -"������ ��������� ������������ ������ ��������� ��������������������� ��������������� ��� ������: %(err)s" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "" - -msgid "Storage volume capacity must be an integer number." -msgstr "" - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "" - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "��������������� %(name)s���(���) ������������." - -#, python-format -msgid "Network %(name)s already exists" -msgstr "������������ %(name)s���(���) ������ ���������������." - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "������������ %(name)s���(���) ������������." - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "" -"������������ %(network)s��� ������ ��������� ��������� %(subnet)s���(���) ������������ ������������." - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "" -"������������ ������������ %(name)s���(���) ��������� ������������ ������������������ ������������������." - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "������ ������������ %(name)s���(���) ��������� ��� ������������." - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "" -"������������ %(network)s��� ������ ��������� ��������������� %(iface)s���(���) ������ ������ ������" -"������." - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "������������������ ������ NIC, ������ ������ ��������� ������������ ���������." - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "������������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "������������ '%(name)s'��� ������ ������ IP ��������� ������ ��� ������������." - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "������������ ������������ ��������� ������, NAT ��� ������������������." - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "" -"������������ ������������ IP ������ ��� ��������� ������ ��������������� ������ ������������������ ���������." - -msgid "Network interface must be a string" -msgstr "������������ ������������������ ������������������ ���������." - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "������������ VLAN ID��� 1��� 4094 ��������� ������������ ���������." - -msgid "Specify name and type to create a Network" -msgstr "��������������� ��������������� ������ ��� ��������� ������������������." - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "��������� ������ %(name)s���(���) VLAN��� ��������� ��������� ��� ��� ������������." - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "%(iface)s ������������������ ��������������� ������: %(err)s." - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "" -"%(iface)s ������������������ ��������������� ���������������. ��������� ������ ��������� ���������������" -"���." - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "��������� ��������� %(name)s���(���) ������������." - -msgid "Debug report tool not found in system" -msgstr "��������� ��������� ��������� ������������ ������������." - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "��������� ��������� %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "��������� ��������� %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" - -msgid "You should give a name for the debug report file." -msgstr "" - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "" -"��������� '%(name)s'��� ������ ��������� ������ ���������������. ������ ������ ��������������� ������ ���" -"������ ������������������." - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "������������ ������ %(server)s���(���) Kimchi������ ������������ ���������������." - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "Distro '%(name)s'���(���) ������������." - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "��������� %(name)s���(���) ������������ ������������." - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "������ ��������� ������ ������ ��������� ��������� ��������� ��� ������������." - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "������ ��������� ������ ������ ��������� ��������� ������ ��������� ��� ������������." - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "������ ������ '%(name)s'���(���) ������������." - -msgid "Conflicting flag filters specified." -msgstr "" - -msgid "No packages marked for update" -msgstr "������������ ��������� ������������ ������������." - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "��������� %(name)s���(���) ��������������������� ������������ ���������������." - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "" -"��������������������� ��������� ������������ ������������ ������ ��������� ������������������. ������������: %" -"(err)s" - -msgid "There is no compatible package manager for this system." -msgstr "��� ������������ ������ ������ ��������� ��������� ������������ ������������." - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "������������ ������ URI %(uri)s" - -msgid "Unable to choose a virtual machine name" -msgstr "" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "������������ ������ ������������ ���������������. ������������ ������: 'cdrom'" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" - -msgid "Only CDROM path can be update." -msgstr "" - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "��� ������������ ��������� ������������ ������ ������ ������: %(error)s" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "������������ ��������� ������������������ ������ ������ ������: %(error)s" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "������������ ��������� ������������ ������ ������ ������: %(error)s" - -msgid "Do not support IDE device hot plug" -msgstr "" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "��� ������ ������ ������������ ��������� ������ ��� ��������� ������������������." - -msgid "Specify path to update virtual machine disk" -msgstr "������ ������ ������������ ��������������� ��������� ������������������." - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" - -msgid "Volume already in use by other virtual machine." -msgstr "" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "��� ������ ������ ������������ ��������� ������ ��� ��������� ������������������." - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" - -msgid "YUM Repository ID must be one word only string." -msgstr "YUM ��������� ID��� ������ ��������� ������������������ ���������." - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "��������� URL��� http://, ftp:// ������ file:// URL��������� ���������." - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "��������� ��������� ��������� ��������� ������ ������ ������ ������ ���������������." - -msgid "Distribution to DEB repository must be a string" -msgstr "DEB ������������ ������ ��������� ������������������ ���������." - -msgid "Components to DEB repository must be listed in a array" -msgstr "DEB ������������ ������ ��������������� ��������� ��������������� ���������." - -msgid "Components to DEB repository must be a string" -msgstr "DEB ������������ ������ ��������������� ������������������ ���������." - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "YUM ��������� ��������� ������������������ ���������." - -msgid "GPG check must be a boolean value." -msgstr "GPG ��������� ������ ������������ ���������." - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "GPG ������ ASCII ������ ��������� ������������ URL��������� ���������." - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "%(repo_id)s ������������ ��������������� ��� ������������." - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "%(repo_id)s ������������ ������������." - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "������ ������������ ������ ��������� ������ ��������� ������������ ���������������." - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "%(repo_id)s ������������ ������ ������������ ������������ ������������." - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "%(repo_id)s ������������ ������ ������ ������������ ������������ ������������." - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "%(repo_id)s ������������ ��������� ��� ������������." - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "��������� ������ ������ %(repo_file)s���(���) ��������� ��� ������������." - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "DEB ������������ ��������������� ��������� ��������� ������������������." - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "%(repo_id)s ������������ ������������ ��������� ��� ������������." - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "%(repo_id)s ������������ ������ ������������ ��������� ��� ������������." - -msgid "YUM Repository ID already exists" -msgstr "YUM ��������� ID��� ������ ���������������." - -msgid "YUM Repository name must be a string" -msgstr "YUM ��������� ��������� ������������������ ���������." - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "������������ ��������� ��� ������������. ������������: '%(err)s'" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "��������� ��������� ��������� ��� ������������. ������������: '%(err)s'" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "������������ ��������� ��� ������������. ������������: '%(err)s'" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "������������ ��������� ��� ������������. ������������: '%(err)s'" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" - -msgid "The number of vCPUs is too large for this system." -msgstr "" - -msgid "Invalid vCPU/topology combination." -msgstr "" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "" - -msgid "ERROR CODE" -msgstr "������ ������" - -msgid "REASON" -msgstr "������" - -msgid "STACK" -msgstr "������" - -msgid "Go to Homepage" -msgstr "��� ������������ ������" - -msgid "Create a New Virtual Machine" -msgstr "��� ������ ������ ������" - -msgid "Virtual Machine Name" -msgstr "������ ������ ������" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "" -"������ ��������� ������������ ��� ������������ ���������������. ������������ ��������� ��������� ������������" -"��� ������������ ���������������." - -msgid "Template" -msgstr "������������" - -msgid "Please create a template first." -msgstr "��������������� ������ ������������������." - -msgid "Create a Template" -msgstr "������������ ������" - -msgid "Please choose a template." -msgstr "��������������� ������������������." - -msgid "OS" -msgstr "OS" - -msgid "OS Version" -msgstr "OS ������" - -msgid "CPUS" -msgstr "CPUS" - -msgid "Memory" -msgstr "���������" - -msgid "Create" -msgstr "������" - -msgid "Creating..." -msgstr "" - -msgid "Cancel" -msgstr "������" - -msgid "Edit Guest" -msgstr "��������� ������" - -msgid "General" -msgstr "������" - -msgid "Storage" -msgstr "������������" - -msgid "Interface" -msgstr "���������������" - -msgid "Permission" -msgstr "������" - -msgid "Host PCI Device" -msgstr "" - -msgid "Snapshot" -msgstr "" - -msgid "Name" -msgstr "������" - -msgid "CPUs" -msgstr "CPU" - -msgid "Memory (MB)" -msgstr "���������" - -msgid "Icon" -msgstr "���������" - -msgid "Device" -msgstr "������ ������" - -msgid "Path" -msgstr "NFS ������" - -msgid "Network" -msgstr "������������" - -msgid "Type" -msgstr "������" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "" - -msgid "Selected system users and groups" -msgstr "" - -msgid "User" -msgstr "" - -msgid "All" -msgstr "������" - -msgid "To Add" -msgstr "" - -msgid "Added" -msgstr "" - -msgid "filter" -msgstr "" - -msgid "Product" -msgstr "" - -msgid "Vendor" -msgstr "������������" - -msgid "Created" -msgstr "" - -msgid "Save" -msgstr "������" - -msgid "Replace" -msgstr "������" - -msgid "Detach" -msgstr "������" - -msgid "revert" -msgstr "" - -msgid "Start" -msgstr "������" - -msgid "Reset" -msgstr "������ ������" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "" - -msgid "Actions" -msgstr "������" - -msgid "Connect" -msgstr "������" - -msgid "Clone" -msgstr "" - -msgid "Edit" -msgstr "������" - -msgid "Shut Down" -msgstr "��������� ������" - -msgid "Delete" -msgstr "������" - -msgid "CPU" -msgstr "CPU" - -msgid "Disk I/O" -msgstr "��������� I/O" - -msgid "Network I/O" -msgstr "������������ I/O" - -msgid "Livetile" -msgstr "���������������" - -msgid "No guests found." -msgstr "������������ ������������." - -msgid "Add a Storage Device to VM" -msgstr "������������ ��������� VM��� ������" - -msgid "Device Type" -msgstr "������ ������" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "������ ���������������. ������ \"cdrom\"��� ���������������." - -msgid "Storage Pool" -msgstr "������������ ���" - -msgid "Storage pool which volume located in" -msgstr "������������ ��� ��������� ������������������ ���������." - -msgid "Storage Volume" -msgstr "������������ ��� ������" - -msgid "Storage volume to be attached" -msgstr "������������ ������ ��������� ������������������ ���������." - -msgid "File Path" -msgstr "������ ������" - -msgid "The ISO file path in the server for CDROM." -msgstr "CDROM��� ������ ��������� ISO ������ ���������������." - -msgid "Attach" -msgstr "������" - -msgid "Shut down" -msgstr "��������� ������" - -msgid "Restart" -msgstr "������ ������" - -msgid "Basic Information" -msgstr "������ ������" - -msgid "OS Distro" -msgstr "OS Distro" - -msgid "OS Code Name" -msgstr "OS ������ ������" - -msgid "Processor" -msgstr "������������" - -msgid "CPU(s)" -msgstr "" - -msgid "System Statistics" -msgstr "��������� ������" - -msgid "Software Updates" -msgstr "��������������� ������������" - -msgid "Update Progress" -msgstr "������������ ������������" - -msgid "Repositories" -msgstr "���������" - -msgid "Debug Reports" -msgstr "��������� ���������" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "" -"��������� ��������� ������ ������ ��������������� ������������ ������������. ������ ������������������." - -msgid "This field is required." -msgstr "��� ��������� ���������������." - -msgid "Log in" -msgstr "���������" - -msgid "Logging in..." -msgstr "��������� ���..." - -msgid "Host" -msgstr "���������" - -msgid "Guests" -msgstr "���������" - -msgid "Templates" -msgstr "������������" - -msgid "Failed to get application configuration" -msgstr "������������������ ��������� ������������ ���������������." - -msgid "This is not a valid Linux path" -msgstr "��������� Linux ��������� ������������." - -msgid "This is not a valid URL." -msgstr "��������� URL��� ������������." - -msgid "No such data available." -msgstr "������ ������������ ������������." - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" -"��������� ������������ ��������� ��� ������������. ��������� ������������ ��������������� ������ ������ ������" -"������ ��������� ��������� ������������������. HTTP ������ ������ %1. " - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "������ ������" - -msgid "OK" -msgstr "������" - -msgid "Confirm" -msgstr "������" - -msgid "Warning" -msgstr "������" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "������ ���..." - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "���������" - -msgid "Detailed message:" -msgstr "������ ���������:" - -msgid "No ISO found" -msgstr "" - -msgid "This is not a valid ISO file." -msgstr "��������� ISO ��������� ������������." - -msgid "This may take a long time. Do you want to continue?" -msgstr "��������� ������ ������������. ������������������������?" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "��������������� ��������������� ���������������. ������������������������?" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "������ ������ ��������� ������ ������������ ������������ ��������� ��� ������������." - -msgid "Max:" -msgstr "������:" - -msgid "Utilization" -msgstr "���������" - -msgid "Available" -msgstr "������ ������" - -msgid "Read Rate" -msgstr "������ ������" - -msgid "Write Rate" -msgstr "������ ������" - -msgid "Received" -msgstr "������" - -msgid "Sent" -msgstr "������" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"������������ ��������������� ������ ������������ ������������ ������ ��������� ���������������. ��������� ���" -"���/������ ��������� ������������������������?" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "������������ ��������������� ������������ ��������� ��� ������������. ������������������������?" - -msgid "ID" -msgstr "ID" - -msgid "Base URL" -msgstr "������ URL" - -msgid "Is Mirror" -msgstr "���������" - -msgid "URL Args" -msgstr "URL ������" - -msgid "Enabled" -msgstr "���������" - -msgid "GPG Check" -msgstr "GPG ������" - -msgid "GPG Key" -msgstr "GPG ���" - -msgid "Add" -msgstr "������" - -msgid "Remove" -msgstr "������" - -msgid "Enable" -msgstr "������" - -msgid "Disable" -msgstr "������ ������" - -msgid "Package Name" -msgstr "��������� ������" - -msgid "Version" -msgstr "������" - -msgid "Architecture" -msgstr "������������" - -msgid "Repository" -msgstr "���������" - -msgid "Update All" -msgstr "������ ������������" - -msgid "Updating..." -msgstr "������������ ���..." - -msgid "Failed to retrieve packages update information." -msgstr "" - -msgid "Failed to update package(s)." -msgstr "������������ ������������������ ���������������." - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"��������� ������������ ��������������� ������������ ��������� ��� ������������. ������������������������?" - -msgid "Generated Time" -msgstr "������ ������" - -msgid "Generate" -msgstr "������" - -msgid "Generating..." -msgstr "������ ���..." - -msgid "Rename" -msgstr "������ ���������" - -msgid "Download" -msgstr "������������" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "��������� ������������ ������, ������ ���/������ ���������('-')��� ��������������� ���������." - -msgid "Pending..." -msgstr "������ ���..." - -msgid "Report name is the same as the original one." -msgstr "" - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "" -"������ ������ ��� ������ ������ ������������ ���������������. ��� ��������� ������ ��������� ��� ���������" -"���. ������������������������?" - -msgid "Power off Confirmation" -msgstr "������ ������" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" - -msgid "Reset Confirmation" -msgstr "������ ������" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" - -msgid "Shut Down Confirmation" -msgstr "������ ������" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "��������������� ��������������� ���������������. ������������������������?" - -msgid "Virtual Machine delete Confirmation" -msgstr "" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" -"��� CDROM��� ��������������� ������������ ������ ��������� ��� ������������. ��������� ���������������������" -"���?" - -msgid "Attaching..." -msgstr "������ ���..." - -msgid "Replacing..." -msgstr "������ ���..." - -msgid "Successfully attached!" -msgstr "���������������������." - -msgid "Successfully replaced!" -msgstr "���������������������." - -msgid "Successfully detached!" -msgstr "���������������������." - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" - -msgid "interface:" -msgstr "" - -msgid "address:" -msgstr "" - -msgid "link_type:" -msgstr "" - -msgid "block:" -msgstr "" - -msgid "drive_type:" -msgstr "" - -msgid "model:" -msgstr "" - -msgid "Affected devices:" -msgstr "" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "VLAN ID��� 1��� 4094 ������������ ���������." - -msgid "unavailable" -msgstr "������ ���������" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" -"��� ��������� ��� ��������������� ������������ ������ ��������� ������������ ��������� ���������������������." - -msgid "Create a network" -msgstr "������������ ������" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"��� ������������ ������ ��������������� ������������. ��� ��������� ������ ������������������ ������ ���������" -"������ ���������������. ������������������������?" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "������������ ������ ��������������� ���������������. ������������������������?" - -msgid "This storage pool is empty." -msgstr "��� ������������ ������ ������ ������������." - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "������������ ������������ ������������ ���������������. ������������������������? " - -msgid "SCSI Fibre Channel" -msgstr "SCSI ��������� ������" - -msgid "No SCSI adapters found." -msgstr "SCSI ������������ ������������." - -msgid "Loading iSCSI targets..." -msgstr "" - -msgid "No iSCSI found. Please input one." -msgstr "" - -msgid "Failed to load iSCSI targets." -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "������������ ��� ��������� ��������� ��� ������������." - -msgid "The storage pool path can not be blank." -msgstr "������������ ��� ��������� ��������� ��� ������������." - -msgid "NFS server mount path can not be blank." -msgstr "NFS ������ ��������� ��������� ��������� ��� ������������." - -msgid "Invalid NFS mount path." -msgstr "������������ ������ NFS ��������� ���������������." - -msgid "No logical device selected." -msgstr "������ ��������� ������������ ���������������." - -msgid "The iSCSI target can not be blank." -msgstr "iSCSI ��������� ��������� ��� ������������." - -msgid "Server name can not be blank." -msgstr "������ ��������� ��������� ��� ������������." - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "" - -msgid "Looking for available partitions ..." -msgstr "������ ��������� ������������ ������ ���..." - -msgid "No available partitions found." -msgstr "������ ��������� ������������ ������������." - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"��� ������������ ������ ��������������� ������������. ��� ��������� ������ ������������������ ������ ���������" -"������ ���������������. ������������������������?" - -msgid "Unable to retrieve partitions information." -msgstr "��������� ��������� ��������� ��� ������������. ������������: '%(err)s'" - -msgid "In progress..." -msgstr "" - -msgid "Failed!" -msgstr "" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" - -msgid "Disk pool or volume cannot be blank." -msgstr "������������ ��� ��������� ��������� ��� ������������." - -msgid "Filter" -msgstr "" - -msgid "Network Name" -msgstr "������������ ������" - -msgid "State" -msgstr "������" - -msgid "Network Type" -msgstr "������������ ������" - -msgid "Address Space" -msgstr "������ ������" - -msgid "Name should not contain '/' and '\"'." -msgstr "������������ ������ ������������ ��� ���������������. '/'��� ������������ ��������� ���������." - -msgid "Isolated: no external network connection" -msgstr "���������: ��������� ������������ ������ ������" - -msgid "NAT: outbound physical network connection only" -msgstr "NAT: ��������������� ��������� ������������ ���������" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "������������: ������ ��������� ��������� ��������������� ������ ���������" - -msgid "(No interfaces found)" -msgstr "" - -msgid "Destination" -msgstr "������:" - -msgid "Enable VLAN" -msgstr "VLAN ������:" - -msgid "VLAN ID" -msgstr "VLAN ID:" - -msgid "Stop" -msgstr "������" - -msgid "Generate a New Debug Report" -msgstr "��� ��������� ��������� ������" - -msgid "Report Name" -msgstr "��������� ������" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" -"������������ ������������ ��� ������������ ���������������. ������������ ��������� ������ ��������� ���������" -"��� ���������������. ��������� ������, ������ ��� ���������(\"-\")��� ��������� ��� ������������." - -msgid "Rename a Debug Report" -msgstr "��� ��������� ��������� ������" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" -"������������ ������������ ��� ������������ ���������������. ������������ ��������� ������ ��������� ���������" -"��� ���������������. ��������� ������, ������ ��� ���������(\"-\")��� ��������� ��� ������������." - -msgid "Submit" -msgstr "" - -msgid "Add a Repository" -msgstr "��������� ������" - -msgid "Identifier" -msgstr "ID" - -msgid "Single word, unique identifier for the repository." -msgstr "������������ ������ ������ ��������� ������ ID���������." - -msgid "Textual name for the repository." -msgstr "������������ ������ ��������� ���������������." - -msgid "URL" -msgstr "URL" - -msgid "Required Field" -msgstr "������ ������" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "������������ ������ URL���������. ������������ ��������������� http, ftp ��� file���������." - -msgid "Repository is a mirror" -msgstr "������������ ���������������." - -msgid "Distribution" -msgstr "������" - -msgid "Distribution of the DEB repository." -msgstr "DEB ������������ ���������������." - -msgid "Components" -msgstr "������������" - -msgid "List of components in DEB repository." -msgstr "DEB ������������ ������������ ���������������." - -msgid "Edit Repository" -msgstr "��������� ������" - -msgid "Mirror List URL" -msgstr "������ ������ URL" - -msgid "Yes" -msgstr "���" - -msgid "No" -msgstr "���������" - -msgid "Capacity" -msgstr "������" - -msgid "Allocated" -msgstr "���������" - -msgid "Location" -msgstr "������" - -msgid "Device path" -msgstr "������ ������" - -msgid "active" -msgstr "������" - -msgid "inactive" -msgstr "���������" - -msgid "Deactivate" -msgstr "������������" - -msgid "Activate" -msgstr "���������" - -msgid "Add Volume" -msgstr "" - -msgid "Extend" -msgstr "" - -msgid "Undefine" -msgstr "������ ������" - -msgid "Format" -msgstr "������:" - -msgid "Allocation" -msgstr "������:" - -msgid "Define a New Storage Pool" -msgstr "��� ������������ ��� ������" - -msgid "Storage Pool Name" -msgstr "������������ ��� ������" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "������������ ������ ������������ ��� ������������ ������������ ������ ������ ��������� ���������." - -msgid "Storage Pool Type" -msgstr "������������ ��� ������" - -msgid "Storage Path" -msgstr "������������ ������" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "������������ ������ ���������������. ��� ������������ ������ ������ ��������� ��������� ���������." - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "" -"��������������� ������������ ������ ������������ ��������� Kimchi��� ������������ ��������� ���������������." - -msgid "NFS Server IP" -msgstr "NFS ������ IP" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "" -"NFS ������ IP ������ ��������� ���������������. ��������� ��������������� ������������������ ��������� ��� " -"������������." - -msgid "NFS Path" -msgstr "NFS ������" - -msgid "The NFS exported path on NFS server." -msgstr "NFS ������������ NFS��� ��������� ���������������." - -msgid "iSCSI Server" -msgstr "iSCSI ������" - -msgid "Server" -msgstr "������" - -msgid "Port" -msgstr "������" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "iSCSI ������ IP ������ ��������� ���������������. ������ ������ ��������� ���������." - -msgid "Target" -msgstr "������" - -msgid "The iSCSI target on iSCSI server" -msgstr "iSCSI ��������� iSCSI ������" - -msgid "Add iSCSI Authentication" -msgstr "iSCSI ������ ������" - -msgid "iSCSI Authentication" -msgstr "iSCSI ������" - -msgid "User Name" -msgstr "��������� ������" - -msgid "Password" -msgstr "������������" - -msgid "SCSI Adapter" -msgstr "SCSI ���������" - -msgid "Please, wait..." -msgstr "������ ��������� ������������." - -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - -msgid "Add Template" -msgstr "������������ ������" - -msgid "Where is the source media for this template? " -msgstr "��� ��������������� ������ ��������� ��������� ������������?" - -msgid "Local ISO Image" -msgstr "������ ISO ���������" - -msgid "Local Image File" -msgstr "" - -msgid "Remote ISO Image" -msgstr "������ ISO ���������" - -msgid "Search ISOs" -msgstr "ISO ������" - -msgid "The following ISOs are available:" -msgstr "������ ISO��� ������ ���������������." - -msgid "OS: " -msgstr "OS: " - -msgid "Version: " -msgstr "������: " - -msgid "Size: " -msgstr "������: " - -msgid "Search more ISOs" -msgstr "������ ISO ������" - -msgid "Create Templates from Selected ISO" -msgstr "��������� ISO��������� ������������ ������" - -msgid "I want to use a specific ISO file" -msgstr "������ ISO ��������� ��������������� ���������." - -msgid "Loading default remote ISOs ..." -msgstr "������ ������ ISO ������ ���..." - -msgid "Arch: " -msgstr "Arch: " - -msgid "I want to use a custom URL" -msgstr "��������� ������ URL��� ��������������� ���������." - -msgid "Edit Template" -msgstr "������������ ������" - -msgid "CDROM" -msgstr "CDROM" - -msgid "Image File" -msgstr "" - -msgid "Graphics" -msgstr "���������" - -msgid "Disk(GB)" -msgstr "" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "CPU ������" - -msgid "Manually set CPU topology" -msgstr "" - -msgid "Cores" -msgstr "" - -msgid "Threads" -msgstr "" - -msgid "No templates found." -msgstr "��������������� ������������." - -#~ msgid "Delete is not allowed for %(resource)s" -#~ msgstr "%(resource)s��� ��������� ������������ ������" - -#~ msgid "%(resource)s does not implement update method" -#~ msgstr "%(resource)s��������� ������������ ������������ ������������ ������" - -#~ msgid "Create is not allowed for %(resource)s" -#~ msgstr "%(resource)s��� ��������� ������������ ������" - -#~ msgid "Unable to parse JSON request" -#~ msgstr "JSON ��������� ������ ��������� ��� ������������." - -#~ msgid "This API only supports JSON" -#~ msgstr "��� API��� JSON��� ���������������." - -#~ msgid "Datastore is not initiated in the model object." -#~ msgstr "��������� ������������ ������ ������������������ ������������ ���������������." - -#~ msgid "Unable to start task due error: %(err)s" -#~ msgstr "������ ��������� ��������� ��������� ��� ������: %(err)s" - -#~ msgid "" -#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" -#~ msgstr "��������� '%(username)s'��� ��������� ������������������. [������ ������: %(code)s]" - -#~ msgid "You are not authorized to access Kimchi" -#~ msgstr "Kimchi��� ������������ ��������� ������������." - -#~ msgid "Specify %(item)s to login into Kimchi" -#~ msgstr "Kimchi��� ������������������ %(item)s���(���) ������������������." - -#~ msgid "Unable to find %(item)s in datastore" -#~ msgstr "��������� ��������������� %(item)s���(���) ������ ��� ������������." - -#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" -#~ msgstr "" -#~ "%(seconds)s��� ������ '%(cmd)s' ������ ������ ��� ��������������� ���������������������." - -#~ msgid "Help" -#~ msgstr "���������" - -#~ msgid "About" -#~ msgstr "������" - -#~ msgid "Log out" -#~ msgstr "������������" - -#~ msgid "Version:" -#~ msgstr "������: " diff --git a/plugins/kimchi/po/pt_BR.po b/plugins/kimchi/po/pt_BR.po deleted file mode 100644 index c2cb4e9..0000000 --- a/plugins/kimchi/po/pt_BR.po +++ /dev/null @@ -1,2369 +0,0 @@ -# i18n portable object for kimchi. -# Copyright (C) IBM, Corp. 2013-2014 -# ShaoHe Feng <shaohef@linux.vnet.ibm.com>, 2013-04-18. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 1.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2015-03-23 12:57+0000\n" -"Last-Translator: Cr��stian Deives dos Santos Viana <cristiandeives@gmail." -"com>\n" -"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/" -"kimchi/language/pt_BR/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: pt_BR\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "Par��metro desconhecido: %(value)s" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" -"Limite de tempo de %(seconds)s segundos expirado ao executar a tarefa '%" -"(task)s'." - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "Usu��rio %(user_id)s n��o encontrado com as configura����es LDAP dadas." - -msgid "Unknown \"_cap\" specified" -msgstr "\"_cap\" desconhecido especificado" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "\"_passthrough\" deve ser \"true\" ou \"false\"" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "\"_passthrough_affected_by\" deve ser um texto do nome do dispositivo" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "Erro ao consultar block devices. Detalhes %(err)s" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "Erro ao consultar informa����es de block devices para %(device)s." - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "N��o foi poss��vel encontrar o arquivo da distribui����o: %(filename)s" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "" -"N��o foi poss��vel ler o arquivo da distribui����o: %(filename)s. Confirme se �� " -"um arquivo JSON." - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "" -"N��o foi poss��vel logar na m��quina alvo do iSCSI %(portal)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "N��o foi poss��vel logar na m��quina %(host)s alvo %(target)s do iSCSI" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "N��o foi poss��vel encontrar a ISO %(filename)s" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "A ISO %(filename)s n��o �� boot��vel" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "A ISO %(filename)s n��o possui uma grava����o v��lida de boot El Torito" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "Valida����o El Torito inv��lida na ISO %(filename)s" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "Indicador de boot El Torito inv��lido na ISO %(filename)s" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "" -"Tipo de volume n��o esperado para um volume prim��rio na ISO %(filename)s" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "Formato errado na leitura do descritor de volume na ISO %(filename)s" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" -"O servidor n��o tem permiss��o para acessar a ISO %(filename)s. Considere mud��-" -"la para o diret��rio /var/lib/libvirt, ou mude as permiss��es para que o " -"usu��rio '%(user)s' tenha acesso, ou, adicione o usu��rio '%(user)s' no grupo " -"do caminho da ISO, ou (n��o recomendado) 'chmod -R o+x 'caminho_para_iso'. " -"Detalhes: %(err)s" - -msgid "An error occurred when probing image OS information." -msgstr "Ocorreu um erro ao identificar o sistema operacional da imagem." - -msgid "No OS information found in given image." -msgstr "" -"Nenhuma informa����o de sistema operacional encontrada na imagem fornecida." - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "N��o foi poss��vel ler o arquivo de imagem %(filename)s." - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" -"Arquivo de imagem deve ser um arquivo existente no sistema. %(filename)s n��o " -"�� uma entrada v��lida." - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "M��quina virtual %(name)s j�� existe" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "M��quina virtual %(name)s n��o existe" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" -"N��o foi poss��vel renomear a m��quina virtual %(name)s. O nome %(new_name)s j�� " -"est�� em uso ou a m��quina virtual n��o est�� ligada." - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "" -"N��o foi poss��vel tirar uma foto da tela para a m��quina virtual %(name)s que " -"est�� desligada" - -msgid "Remote ISO image is not supported by this server." -msgstr "Imagem de ISO remota n��o �� suportada por esse servidor." - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "Foto da tela n��o �� suportado na m��quina virtual %(name)s" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "N��o foi poss��vel criar a m��quina virtual %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "" -"N��o foi poss��vel atualizar a m��quina virtual %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "" -"N��o foi poss��vel encontrar a m��quina virtual %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "N��o foi poss��vel conectar �� m��quina virtual desligada %(name)s." - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "URI do Modelo inv��lida %(value)s especificada para m��quina virtual" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" -"URI do Storage pool URI inv��lida %(value)s especificada para m��quina virtual" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "Gr��ficos suportados para a m��quina virtual s��o Spice ou VNC" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "Endere��o para receber eventos gr��ficos deve ser IPv4 ou IPv6" - -msgid "Specify a template to create a virtual machine from" -msgstr "Especifique um modelo para ser base da cria����o da m��quina virtual" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "N��o foi poss��vel iniciar a m��quina virtual %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "" -"N��o foi poss��vel for��ar o desligamento da m��quina virtual %(name)s. " -"Detalhes: %(err)s" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "N��o foi poss��vel remover a m��quina virtual %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "" -"N��o foi poss��vel reiniciar a m��quina virtual %(name)s. Detalhes: %(err)s" - -msgid "User name list must be an array" -msgstr "Lista de nomes de usu��rio deve ser um array" - -msgid "User name must be a string" -msgstr "Nome de usu��rio deve ser um texto" - -msgid "Group name list must be an array" -msgstr "Lista de nomes de grupo deve ser um array" - -msgid "Group name must be a string" -msgstr "Nome de grupo deve ser um texto" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "Usu��rio(s) '%(users)s' n��o existe(m)" - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "Grupo(s) '%(groups)s' n��o existe(m)" - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "" -"N��o foi poss��vel desligar a m��quina virtual %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "" -"N��o foi poss��vel acessar os metadados da m��quina virtual %(name)s. Detalhes: " -"%(err)s" - -msgid "The guest console password must be a string." -msgstr "A senha para o console do guest deve ser um texto." - -msgid "The life time for the guest console password must be a number." -msgstr "O tempo de vida da senha do console do guest deve ser um n��mero." - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "A m��quina virtual '%(name)s' deve estar parada antes de clon��-la." - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "Espa��o em disco insuficiente para clonar a m��quina virtual '%(name)s'" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "N��o foi poss��vel clonar a VM '%(name)s'. Detalhes: %(err)s" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "Opera����o inv��lida para m��quina virtual n��o-persistente %(name)s" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" -"A VM %(vmid)s n��o cont��m o dispositivo de host atribu��do diretamente %" -"(dev_name)s." - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" -"N��o �� permitido atribuir diretamente o dispositivo de host %(dev_name)s." - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" -"Nenhum grupo IOMMU encontrado. Passthrough de host PCI necessita do grupo " -"IOMMU para funcionar corretamente. Por favor, habilite o suporte ao Intel VT-" -"d ou AMD IOMMU. Para uma CPU Intel, adicione \"intel_iommu=on\" nos seus " -"par��metros de kernel em \"/boot/grub2/grub.conf\". Para uma CPU AMD, " -"adicione \"iommu=pt iommu=1\"." - -msgid "\"name\" should be a device name string" -msgstr "\"nome\" deve ser um texto do nome do dispositivo." - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "Interface %(iface)s n��o existe na m��quina virtual %(name)s" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "" -"Rede %(network)s especificada para a m��quina virtual %(name)s n��o existe" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "Tipo de interface suportado das m��quinas virtuais �� somente rede" - -msgid "Network name for virtual machine interface must be a string" -msgstr "Nome da rede para a interface da m��quina virtual deve ser texto" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "Modelo de placa de rede inv��lido para a interface da m��quina virtual" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "" -"Especifique o tipo e a rede para adicionar uma nova interface da m��quina " -"virtual" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "Modelo %(name)s j�� existe" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "Rede '%(network)s' especificada para o modelo %(template)s n��o existe" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "" -"Storage pool %(pool)s especificado para o modelo %(template)s n��o existe" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "" -"Storage pool %(pool)s especificado para o modelo %(template)s n��o est�� ativo" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "Par��metro inv��lido '%(param)s' especificado para CDROM" - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "Rede %(network)s especificada para modelo %(template)s n��o est�� ativa" - -msgid "Template name must be a string" -msgstr "Nome do modelo deve ser um texto" - -msgid "Template icon must be a path to the image" -msgstr "��cone do modelo deve ser um caminho para uma imagem" - -msgid "Template distribution must be a string" -msgstr "Distribui����o do modelo deve ser um texto" - -msgid "Template distribution version must be a string" -msgstr "Vers��o da distribui����o do modelo deve ser um texto" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "O n��mero de CPUs deve ser um inteiro maior do que 0" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "Quantidade de mem��ria (MB) deve ser um inteiro maior que 512" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "Modelo do CDROM deve ser um arquivo ISO local ou remoto" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "URI de storage pool inv��lido %(value)s especificado para modelo" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "" -"Especifique uma imagem ISO como CD-ROM ou uma imagem base para criar um " -"modelo" - -msgid "All networks for the template must be specified in a list." -msgstr "Todas redes para o modelo devem ser especificadas em uma lista" - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" -"Especifique um volume para o template quando o storage pool for iSCSI or SCSI" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "O volume %(volume)s n��o est�� no storage pool %(pool)s" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "N��o foi poss��vel criar o modelo devido a um erro: %(err)s" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "N��o foi poss��vel remover o modelo devido a um erro: %(err)s" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "O tamanho do disco deve ser um n��mero inteiro maior que 1GB." - -msgid "Template base image must be a valid local image file" -msgstr "Imagem base do modelo deve ser um arquivo de imagem local v��lido" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "N��o foi poss��vel identificar o formato da imagem base %(path)s" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" -"Ao especificar a topologia de CPU, VCPUs deve ser um produto de sockets, " -"cores e threads." - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" -"Ao especificar a topologia de CPU, cada elemento deve ser um n��mero inteiro " -"maior do que zero." - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" -"Formato de imagem de disco inv��lido. Formatos v��lidos: bochs, cloop, cow, " -"dmg, qcow, qcow2, qed, raw, vmdk, vpc." - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "Storage pool %(name)s j�� existe" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "Storage pool %(name)s n��o existe" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "Especifique %(item)s para criar o storage pool %(name)s" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "N��o foi poss��vel remover o storage pool ativo %(name)s" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "N��o foi poss��vel listar os storage pools. Detalhes: %(err)s" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "N��o foi poss��vel criar o storage pool %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "" -"N��o foi poss��vel saber o n��mero de volumes no storage pool %(name)s. " -"Detalhes: %(err)s" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "N��o foi possivel ativar o storage pool %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "N��o foi possivel desativar o storage pool %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "N��o foi possivel remover o storage pool %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "" -"N��o foi poss��vel criar Pool NFS uma vez que o caminho de exporta����o %(path)s " -"pode bloquear durante a montagem" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "" -"N��o foi poss��vel criar NFS Pool uma vez que a montagem do caminho de " -"exporta����o %(path)s falhou" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "Tipo de storage pool n��o suportado: %(type)s" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "Erro durante a leitura do XML do storage pool %(pool)s" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" -"Tipos de storage pool supportados s��o dir, netfs, logical, iscsi, scsi e " -"kimchi-iso" - -msgid "Storage pool path must be a string" -msgstr "Caminho para storage pool deve ser um texto" - -msgid "Storage pool host must be a IP or hostname" -msgstr "Host do storage pool deve ser um IP ou um hostname" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" -"Dispositivo do storage pool deve ser o caminho absoluto para o block device" - -msgid "Storage pool devices parameter must be a list" -msgstr "Par��metro dos dispositivos do storage pool devem ser uma lista" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "Alvo IQN de um pool iSCSI deve ser um texto" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "" -"Porta de um servidor remoto de storage deve ser um inteiro entre 1 e 65535" - -msgid "iSCSI target username must be a string" -msgstr "Usu��rio do iSCSI target deve ser um texto" - -msgid "iSCSI target password must be a string" -msgstr "Senha do iSCSI target deve ser um texto" - -msgid "Specify name and type to create a storage pool" -msgstr "Especifique o nome e o tipo para criar um storage pool" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "" -"%(disk)s n��o �� um disco/parti����o v��lido. N��o foi poss��vel adicion��-lo ao " -"pool %(pool)s." - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "N��o foi poss��vel extender o pool l��gico %(pool)s. Detalhes: %(err)s" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "" -"O par��metro discos somente pode ser atualizado para storage pool l��gicos." - -msgid "The SCSI host adapter name must be a string." -msgstr "O nome do adaptador SCSI host deve ser um texto" - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "O storage pool kimchi_isos �� reservado para uso interno" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"N��o foi poss��vel ativar o storage pool NFS %(name)s. Servidor NFS %(server)s " -"est�� inacess��vel." - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"N��o foi poss��vel desativar o storage pool NFS %(name)s. Servidor NFS %" -"(server)s est�� inacess��vel." - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "" -"N��o foi poss��vel desativar o pool %(name)s uma vez que ele est�� associado " -"com algum dos modelos" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "" -"N��o foi poss��vel remover o pool %(name)s uma vez que ele est�� associado com " -"algum dos modelos" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "" -"Um grupo de volume chamado '%(name)s' j�� existe. Por favor, escolha outro " -"nome para criar o pool l��gico." - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "" -"N��o foi poss��vel atualizar a base de dados com informa����es de mais ISOs " -"devido a um erro: %(err)s" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "Volume de storage %(name)s j�� existe" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "Volume de storage %(name)s n��o existe no storage pool %(pool)s" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" -"N��o foi poss��vel criar o storaget volume %(volume)s pois o storage pool %" -"(pool)s n��o est�� ativo" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "Especifique %(item)s para poder criar o volume %(volume)s" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "" -"N��o foi poss��vel listar volumes pois o storage pool %(pool)s n��o est�� ativo" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "" -"N��o foi poss��vel criar o volume %(name)s no storage pool %(pool)s. Detalhes: " -"%(err)s" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "" -"N��o foi poss��vel listar os volumes do storage pool %(pool)s. Detalhes: %(err)" -"s" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "N��o foi poss��vel limpar o volume %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "N��o foi poss��vel remover o volume %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "N��o foi poss��vel redimensionar o volume %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "Storage do tipo %(type)s n��o suporta cria����o ou remo����o de volume" - -msgid "Storage volume name must be a string" -msgstr "Nome do volume deve ser um texto" - -msgid "Storage volume allocation must be an integer number" -msgstr "Aloca����o do volume de storage deve ser um n��mero inteiro" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" -"Formato de volume de storage inv��lido. Formatos v��lidos: bochs, cloop, cow, " -"dmg, qcow, qcow2, qed, raw, vmdk, vpc." - -msgid "Storage volume requires a volume name" -msgstr "Volume de storage requer um nome" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "" -"N��o foi poss��vel atualizar a base de dados com informa����es de volume de " -"storage devido a um erro: %(err)s" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "Somente um par��metro %(param)s pode ser especificado" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "Criar um volume a partir de %(param)s n��o �� suportado" - -msgid "Storage volume capacity must be an integer number." -msgstr "A capacidade do storage volume deve ser um n��mero inteiro." - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" -"URL para o storage volume deve ser http://, https://, ftp:// ou ftps://." - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "Erro ao acessar arquivo %(url)s. Por favor, verifique isso." - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" -"N��o foi poss��vel clonar o volume de storage '%(name)s' no pool '%(pool)s'. " -"Detalhes: %(err)s" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "Interface %(name)s n��o existe" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "Rede %(name)s j�� existe" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "Rede %(name)s n��o existe" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "" -"A subrede %(subnet)s especificada para a rede %(network)s n��o �� v��lida." - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "Especifique uma interface de rede para criar a rede de bridge %(name)s" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "N��o foi poss��vel remover a rede ativa %(name)s" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "" -"A interface %(iface)s especificada para a rede %(network)s j�� est�� em uso" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "Interface deve ser 'bare NIC', 'bonding' ou 'dispositivo de bridge'." - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "N��o foi poss��vel criar a rede %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "N��o foi poss��vel encontrar um endere��o IP livre para a rede '%(name)s'" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "A interface %(iface)s j�� existe" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "Tipos de rede suportados s��o isolada, NAT e bridge" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "" -"Subrede deve ser um texto com endere��o IP e prefixo, ou m��scara de rede" - -msgid "Network interface must be a string" -msgstr "Interface de rede deve ser um texto" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "ID da rede VLAN deve ser um inteiro entre 1 e 4094" - -msgid "Specify name and type to create a Network" -msgstr "Especifique o nome e o tipo para criar uma rede" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" -"N��o foi poss��vel desativar a rede %(name)s. H�� alguma m��quina virtual %(vms)" -"s e/ou modelo associados a esta rede." - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" -"N��o foi poss��vel desativar a rede %(name)s. H�� alguma m��quina virtual %(vms)" -"s e/ou modelo associados a esta rede." - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "" -"Dispositivo da bridge %(name)s n��o pode ser um dispositivo vinculado a uma " -"VLAN." - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "N��o foi poss��vel ativar a interface %(iface)s: %(err)s." - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "" -"N��o foi poss��vel ativar a interface %(iface)s. Por favor, verifique o status " -"da conex��o f��sica." - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "N��o foi poss��vel iniciar a rede %(name)s. Detalhes: %(err)s" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "Relat��rio de debug %(name)s n��o existe" - -msgid "Debug report tool not found in system" -msgstr "Ferramenta de relat��rio de debug n��o encontrada no sistema" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "" -"N��o foi poss��vel criar o relat��rio de debug %(name)s. Detalhes: %(err)s." - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "N��o foi poss��vel encontrar nenhum relat��rio com o nome %(name)s" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "" -"N��o foi poss��vel gerar o relat��rio de debug %(name)s. Detalhes: %(err)s" - -msgid "You should give a name for the debug report file." -msgstr "Voc�� deve dar um nome para o arquivo do relat��rio de debug." - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" -"Nome do relat��rio deve ser um texto. Somente letras, digitos, underscore " -"('_') e h��fem ('-') s��o permitidos." - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "" -"O relat��rio de debug com o nome especificado \"%(name)s\" j�� existe. Por " -"favor, use outro nome." - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "Servidor de storage %(server)s n��o foi usado pelo Kimchi" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "Distribui����o '%(name)s' n��o existe" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "Parti����o %(name)s n��o existe no host" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "" -"N��o foi poss��vel desligar o host uma vez que h�� m��quinas virtuais ligadas" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "" -"N��o foi poss��vel resetar o host uma vez que h�� m��quinas virtuais ligadas" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "Dispositivo de n�� '%(name)s' n��o encontrado" - -msgid "Conflicting flag filters specified." -msgstr "Foram especificados filtros de flag com conflito." - -msgid "No packages marked for update" -msgstr "Nenhum pacote marcado para atualiza����o" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "Pacote %(name)s n��o est�� marcado para atualiza����o." - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "Erro ao buscar pacotes marcados para atualiza����o. Detalhes: %(err)s" - -msgid "There is no compatible package manager for this system." -msgstr "N��o h�� gerenciador de pacotes compat��vel para este sistema." - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "URI %(uri)s inv��lida" - -msgid "Unable to choose a virtual machine name" -msgstr "N��o foi poss��vel escolher um nome para a m��quina virtual" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "Tipo de storage inv��lido. Tipos suportados: 'cdrom', 'disco'" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" -"O caminho '%(value)s' n��o �� um caminho local/remoto v��lido para este " -"dispositivo" - -msgid "Only CDROM path can be update." -msgstr "Apenas o caminho do CD-ROM pode ser atualizado." - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "O disco %(dev_name)s n��o existe na m��quina virtual %(vm_name)s" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "Erro ao criar novo dispositivo de storage: %(error)s" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "Erro ao atualizar dispositivo de storage: %(error)s" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "Erro ao remover dispositivo de storage: %(error)s" - -msgid "Do not support IDE device hot plug" -msgstr "Dispositivo IDE hot plug n��o �� suportado" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "" -"Especifique o tipo e o caminho, ou o tipo e o pool/volume, para adicionar um " -"novo disco da m��quina virtual" - -msgid "Specify path to update virtual machine disk" -msgstr "Especifique o caminho para atualizar o disco da m��quina virtual" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" -"Limita����o do tipo do controlador %(type)s de %(limit)s dispositivos foi " -"alcan��ada" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" -"N��o foi poss��vel buscar informa����es do caminho do disco para o pool/volume " -"dado: %(error)s" - -msgid "Volume already in use by other virtual machine." -msgstr "Volume j�� em uso por outra m��quina virtual." - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "" -"Somente um caminho ou pool/volume pode ser especificado para adicionar um " -"novo disco da m��quina virtual." - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" -"Volume escolhido com formato %(format)s n��o se enquadra no tipo de storage %" -"(type)s" - -msgid "YUM Repository ID must be one word only string." -msgstr "ID do reposit��rio YUM deve ser apenas uma palavra." - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "URL do reposit��rio deve ser uma URL http://, ftp:// ou file://." - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "" -"Configura����o do reposit��rio �� um dicion��rio com valores espec��ficos de " -"acordo com o tipo do reposit��rio." - -msgid "Distribution to DEB repository must be a string" -msgstr "Distribui����o para o reposit��rio DEB deve ser um texto" - -msgid "Components to DEB repository must be listed in a array" -msgstr "Componentes para o reposit��rio DEB deve ser um array" - -msgid "Components to DEB repository must be a string" -msgstr "Componentes para o reposit��rio DEB deve ser um texto" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "Nome do reposit��rio YUM deve ser um texto." - -msgid "GPG check must be a boolean value." -msgstr "Verifica����o de GPG deve ser um valor booleano." - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "" -"Chave GPG deve ser uma URL apontando para o arquivo no formato ASCII-armor." - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "N��o foi poss��vel atualizar o reposit��rio %(repo_id)s." - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "Reposit��rio %(repo_id)s n��o existe." - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "" -"Ferramenta de gerenciamento de reposit��rio n��o foi reconhecida no seu " -"sistema." - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "Reposit��rio %(repo_id)s j�� est�� habilitado." - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "Reposit��rio %(repo_id)s j�� est�� desabilitado." - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "N��o foi poss��vel remover o reposit��rio %(repo_id)s." - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "" -"N��o foi poss��vel gravar o arquivo de configura����o do reposit��rio %(repo_file)" -"s" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "" -"Especificar o reposit��rio de distribui����o para poder criar o reposit��rio DEB." - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "N��o foi poss��vel habilitar o reposit��rio %(repo_id)s." - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "N��o foi poss��vel desabilitar o reposit��rio %(repo_id)s." - -msgid "YUM Repository ID already exists" -msgstr "ID do reposit��rio YUM j�� existe" - -msgid "YUM Repository name must be a string" -msgstr "Nome do reposit��rio YUM deve ser um texto" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "N��o �� poss��vel listar os reposit��rios. Detalhes: '%(err)s'" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "" -"N��o foi poss��vel carregar as informa����es do reposit��rio. Detalhes: '%(err)s'" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "N��o foi poss��vel adicionar o reposit��rio. Detalhes: '%(err)s'" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "N��o foi poss��vel remover o reposit��rio. Detalhes: '%(err)s'" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" -"Itens de configura����o '%(items)s' n��o s��o suportados pelo gerenciador de " -"reposit��rios." - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" -"A m��quina virtual '%(vm)s' deve estar parada antes de criar um snapshot dela" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" -"N��o foi poss��vel criar o snapshot '%(name)s' na m��quina virtual '%(vm)s'. " -"Detalhes: %(err)s" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "O snapshot '%(name)s' n��o existe na m��quina virtual '%(vm)s'." - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" -"N��o foi poss��vel recuperar o snapshot '%(name)s' da m��quina virtual '%(vm)" -"s'. Detalhes: %(err)s" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" -"N��o foi poss��vel listar os snapshots da m��quina virtual '%(vm)s'. Detalhes: %" -"(err)s" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" -"N��o foi poss��vel remover o snapshot '%(name)s' da m��quina virtual '%(vm)s'. " -"Detalhes: %(err)s" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" -"N��o foi poss��vel recuperar o snapshot atual da m��quina virtual '%(vm)s'. " -"Detalhes: %(err)s." - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" -"N��o foi poss��vel reverter a m��quina virtual '%(vm)s' para o snapshot '%(name)" -"s'. Detalhes: %(err)s" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" -"N��o foi poss��vel criar o snapshot para a m��quina virtual '%(vm)s' porque ela " -"cont��m discos no formato '%(format)s'; somente 'qcow2' �� suportado." - -msgid "The number of vCPUs is too large for this system." -msgstr "O n��mero de VCPUs �� grande demais para esse sistema." - -msgid "Invalid vCPU/topology combination." -msgstr "Combina����o inv��lida de VCPU/topologia." - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "Este host (ou configura����o atual) n��o permite topologia de CPU." - -msgid "ERROR CODE" -msgstr "C��DIGO DE ERRO" - -msgid "REASON" -msgstr "MOTIVO" - -msgid "STACK" -msgstr "PILHA" - -msgid "Go to Homepage" -msgstr "Ir para a P��gina Inicial" - -msgid "Create a New Virtual Machine" -msgstr "Criar nova M��quina Virtual" - -msgid "Virtual Machine Name" -msgstr "Nome da M��quina Virtual" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "" -"O nome usado para identificar a m��quina virtual. Se ele for omitido, a " -"escolha ser�� baseada no modelo selecionado." - -msgid "Template" -msgstr "Modelo" - -msgid "Please create a template first." -msgstr "Por favor, crie um modelo primeiro." - -msgid "Create a Template" -msgstr "Criar um Modelo" - -msgid "Please choose a template." -msgstr "Por favor, escolha um modelo." - -msgid "OS" -msgstr "Sistema Operacional" - -msgid "OS Version" -msgstr "Vers��o do Sistema Speracional" - -msgid "CPUS" -msgstr "CPUS" - -msgid "Memory" -msgstr "Mem��ria" - -msgid "Create" -msgstr "Criar" - -msgid "Creating..." -msgstr "Criando..." - -msgid "Cancel" -msgstr "Cancelar" - -msgid "Edit Guest" -msgstr "Editar Guest" - -msgid "General" -msgstr "Geral" - -msgid "Storage" -msgstr "Storage" - -msgid "Interface" -msgstr "Interface" - -msgid "Permission" -msgstr "Permiss��o" - -msgid "Host PCI Device" -msgstr "Dispositivo de host PCI" - -msgid "Snapshot" -msgstr "Snapshot" - -msgid "Name" -msgstr "Nome" - -msgid "CPUs" -msgstr "CPUs" - -msgid "Memory (MB)" -msgstr "Mem��ria (MB)" - -msgid "Icon" -msgstr "��cone" - -msgid "Device" -msgstr "Dispositivo" - -msgid "Path" -msgstr "Caminho" - -msgid "Network" -msgstr "Rede" - -msgid "Type" -msgstr "Tipo" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "Usu��rios e grupos de sistema dispon��veis" - -msgid "Selected system users and groups" -msgstr "Usu��rios e grupos de sistema selecionados" - -msgid "User" -msgstr "Usu��rio" - -msgid "All" -msgstr "Todos" - -msgid "To Add" -msgstr "Para adicionar" - -msgid "Added" -msgstr "Adicionado" - -msgid "filter" -msgstr "filtro" - -msgid "Product" -msgstr "Produto" - -msgid "Vendor" -msgstr "Vendor" - -msgid "Created" -msgstr "Criado" - -msgid "Save" -msgstr "Salvar" - -msgid "Replace" -msgstr "Substituir" - -msgid "Detach" -msgstr "Remover" - -msgid "revert" -msgstr "Reverter" - -msgid "Start" -msgstr "Iniciar" - -msgid "Reset" -msgstr "Reiniciar" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "For��ar desligamento" - -msgid "Actions" -msgstr "A����es" - -msgid "Connect" -msgstr "Conectar" - -msgid "Clone" -msgstr "Clonar" - -msgid "Edit" -msgstr "Editar" - -msgid "Shut Down" -msgstr "Desligar" - -msgid "Delete" -msgstr "Remover" - -msgid "CPU" -msgstr "CPU" - -msgid "Disk I/O" -msgstr "Disco E/S" - -msgid "Network I/O" -msgstr "Rede E/S" - -msgid "Livetile" -msgstr "Tela ao vivo" - -msgid "No guests found." -msgstr "Nenhum guest encontrado." - -msgid "Add a Storage Device to VM" -msgstr "Adicionar um dispositivo de storage �� VM" - -msgid "Device Type" -msgstr "Tipo do Dispositivo" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "" -"O tipo do dispositivo. Atualmente, \"cdrom\" e \"disco\" s��o suportados." - -msgid "Storage Pool" -msgstr "Storage Pool" - -msgid "Storage pool which volume located in" -msgstr "Storage pool no qual o volume est�� localizado" - -msgid "Storage Volume" -msgstr "Volume de storage" - -msgid "Storage volume to be attached" -msgstr "Volume de storage a ser adicionado" - -msgid "File Path" -msgstr "Caminho do Arquivo" - -msgid "The ISO file path in the server for CDROM." -msgstr "O caminho do arquivo ISO para o CDROM no servidor." - -msgid "Attach" -msgstr "Adicionar" - -msgid "Shut down" -msgstr "Desligar" - -msgid "Restart" -msgstr "Reiniciar" - -msgid "Basic Information" -msgstr "Informa����es b��sicas" - -msgid "OS Distro" -msgstr "Distribui����o" - -msgid "OS Code Name" -msgstr "Nome-c��digo do sistema operacional" - -msgid "Processor" -msgstr "Processador" - -msgid "CPU(s)" -msgstr "CPU(s)" - -msgid "System Statistics" -msgstr "Estat��sticas do sistema" - -msgid "Software Updates" -msgstr "Atualiza����es de software" - -msgid "Update Progress" -msgstr "Progresso da atualiza����o" - -msgid "Repositories" -msgstr "Reposit��rios" - -msgid "Debug Reports" -msgstr "Relat��rios de Debug" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "" -"O usu��rio ou senha inseridos est��o incorretos. Por favor, tente novamente." - -msgid "This field is required." -msgstr "Esse campo �� obrigat��rio." - -msgid "Log in" -msgstr "Entrar" - -msgid "Logging in..." -msgstr "Entrando..." - -msgid "Host" -msgstr "Host" - -msgid "Guests" -msgstr "Guests" - -msgid "Templates" -msgstr "Modelos" - -msgid "Failed to get application configuration" -msgstr "N��o foi poss��vel carregar as configura����es da aplica����o" - -msgid "This is not a valid Linux path" -msgstr "Este n��o �� um caminho v��lido no Linux" - -msgid "This is not a valid URL." -msgstr "Essa n��o �� uma URL v��lida." - -msgid "No such data available." -msgstr "N��o h�� dados dispon��veis." - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" -"N��o foi poss��vel contactar o sistema host. Verique se o sistema do host est�� " -"ligado e se voc�� possui conectividade de rede com ele. Resposta da " -"requisi����o HTTP %1. " - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "Confirma����o de remo����o" - -msgid "OK" -msgstr "OK" - -msgid "Confirm" -msgstr "Confirmar" - -msgid "Warning" -msgstr "Aviso" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "Carregando..." - -msgid "An error occurred while retrieving system information." -msgstr "Ocorreu um erro ao recuperar informa����es do sistema." - -msgid "Retry" -msgstr "Tentar novamente" - -msgid "Detailed message:" -msgstr "Mensagem detalhada:" - -msgid "No ISO found" -msgstr "Nenhuma ISO encontrada" - -msgid "This is not a valid ISO file." -msgstr "Esse n��o �� um arquivo ISO v��lido." - -msgid "This may take a long time. Do you want to continue?" -msgstr "Isso vai levar um longo tempo. Deseja continuar?" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "O modelo vai ser permanentemente removido. Deseja continuar?" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "" -"N��o foi poss��vel desligar o sistema porque algumas m��quinas virtuais est��o " -"ligadas!" - -msgid "Max:" -msgstr "M��ximo:" - -msgid "Utilization" -msgstr "Utiliza����o" - -msgid "Available" -msgstr "Dispon��vel" - -msgid "Read Rate" -msgstr "Taxa de leitura" - -msgid "Write Rate" -msgstr "Taxa de escrita" - -msgid "Received" -msgstr "Recebido" - -msgid "Sent" -msgstr "Enviado" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"Desligar ou reiniciar o host causar�� perda de trabalho que n��o foi salvo. " -"Continuar o processo de desligar/reiniciar?" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"Reposit��rio ser�� removido permanentemente e n��o poder�� ser recuperado. " -"Deseja continuar?" - -msgid "ID" -msgstr "ID" - -msgid "Base URL" -msgstr "URL Base" - -msgid "Is Mirror" -msgstr "�� mirror" - -msgid "URL Args" -msgstr "Argumentos da URL" - -msgid "Enabled" -msgstr "Ativado" - -msgid "GPG Check" -msgstr "Verifica����o GPG" - -msgid "GPG Key" -msgstr "Chave GPG" - -msgid "Add" -msgstr "Adicionar" - -msgid "Remove" -msgstr "Remover" - -msgid "Enable" -msgstr "Ativar" - -msgid "Disable" -msgstr "Desativar" - -msgid "Package Name" -msgstr "Nome do pacote" - -msgid "Version" -msgstr "Vers��o" - -msgid "Architecture" -msgstr "Arquitetura" - -msgid "Repository" -msgstr "Reposit��rio" - -msgid "Update All" -msgstr "Atualizar todos" - -msgid "Updating..." -msgstr "Atualizando..." - -msgid "Failed to retrieve packages update information." -msgstr "N��o foi poss��vel recuperar as informa����es de atualiza����o de pacoates." - -msgid "Failed to update package(s)." -msgstr "Erro ao atualizar pacote(s)." - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"Relat��rio de debug ser�� permanentemente removido e n��o poder�� ser " -"recuperado. Deseja continuar?" - -msgid "Generated Time" -msgstr "Tempo gerado" - -msgid "Generate" -msgstr "Gerar" - -msgid "Generating..." -msgstr "Gerando..." - -msgid "Rename" -msgstr "Renomear" - -msgid "Download" -msgstr "Baixar" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "" -"Nome do relat��rio deve apenas conter letras, n��meros, underscore ('_') e/ou " -"h��fen ('-')." - -msgid "Pending..." -msgstr "Pendente..." - -msgid "Report name is the same as the original one." -msgstr "Nome do relat��rio �� o mesmo que o original." - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "" -"A m��quina virtual vai ser removida com todos seus discos. Essa opera����o �� " -"irrevers��vel. Deseja continuar?" - -msgid "Power off Confirmation" -msgstr "Confirma����o de desligamento for��ado" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" -"Essa a����o pode produzir resultados n��o desej��veis, como por exemplo cache de " -"disco n��o-atualizado no guest. Deseja continuar?" - -msgid "Reset Confirmation" -msgstr "Confirma����o de reinicializa����o" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" -"Existe um risco de perda de dados causado pela reinicializa����o sem o " -"desligamento do sistema operacional do guest. Deseja continuar?" - -msgid "Shut Down Confirmation" -msgstr "Confirma����o de desligamento" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "" -"O sistema operacional do guest pode ignorar essa requisi����o. Deseja " -"continuar?" - -msgid "Virtual Machine delete Confirmation" -msgstr "Confirma����o de Remo����o da M��quina Virtual" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" -"Essa m��quina virtual n��o �� persistente. O desligamento ir�� remov��-la. Deseja " -"continuar?" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" -"Quando o guest de destino tiver volumes SCSI ou iSCSI, eles ser��o clonados " -"no storage pool padr��o. O mesmo vai acontecer quando o pool de destino n��o " -"tiver espa��o suficiente para clonar os volumes. Voc�� deseja continuar?" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" -"Esse CDROM ser�� desconectado permanentemente e voc�� pode reconect��-lo. " -"Deseja continuar a remo����o? " - -msgid "Attaching..." -msgstr "Adicionando..." - -msgid "Replacing..." -msgstr "Substituindo..." - -msgid "Successfully attached!" -msgstr "Adicionado com sucesso!" - -msgid "Successfully replaced!" -msgstr "Substitu��do com sucesso!" - -msgid "Successfully detached!" -msgstr "Removido com sucesso!" - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" -"Esse disco ser�� desconectado permanentemente e voc�� pode reconect��-lo. " -"Deseja continuar a remo����o? " - -msgid "interface:" -msgstr "interface:" - -msgid "address:" -msgstr "endere��o:" - -msgid "link_type:" -msgstr "tipo do link:" - -msgid "block:" -msgstr "bloco:" - -msgid "drive_type:" -msgstr "tipo do drive:" - -msgid "model:" -msgstr "modelo:" - -msgid "Affected devices:" -msgstr "Dispositivos afetados:" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "ID da VLAN deve ser um n��mero entre 1 e 4094." - -msgid "unavailable" -msgstr "indispon��vel" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" -"Esta a����o ir�� interromper a conectividade da rede para qualquer m��quina " -"virtual que depende dessa rede." - -msgid "Create a network" -msgstr "Criar uma rede" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"Essa rede n��o �� persistente. Ao inv��s de parar, essa a����o ir�� remov��-la " -"permantemente. Deseja continuar?" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "O storage pool vai ser permanentemente removido. Deseja continuar?" - -msgid "This storage pool is empty." -msgstr "Esse storage pool est�� vazio." - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" -"Isso formatar�� seu disco e voc�� perder�� toda informa����o, voc�� tem certeza " -"que quer continuar?" - -msgid "SCSI Fibre Channel" -msgstr "SCSI Fibre Channel" - -msgid "No SCSI adapters found." -msgstr "Nenhum adaptador SCSI encontrado." - -msgid "Loading iSCSI targets..." -msgstr "Carregando iSCSI targets..." - -msgid "No iSCSI found. Please input one." -msgstr "Nenhum iSCSI encontrado. Por favor, forne��a um." - -msgid "Failed to load iSCSI targets." -msgstr "Erro ao carregar iSCSI targets." - -msgid "The storage pool name can not be blank." -msgstr "O nome do storage pool n��o pode ser vazio." - -msgid "The storage pool path can not be blank." -msgstr "O caminho do storage pool n��o pode ser vazio." - -msgid "NFS server mount path can not be blank." -msgstr "Caminho de montagem do servidor de NFS n��o pode ser vazio." - -msgid "Invalid NFS mount path." -msgstr "Caminho de montagem do NFS inv��lido." - -msgid "No logical device selected." -msgstr "Nenhum dispositivo l��gico selecionado." - -msgid "The iSCSI target can not be blank." -msgstr "O alvo iSCSI n��o pode ser vazio." - -msgid "Server name can not be blank." -msgstr "Nome do servidor n��o pode ser vazio." - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "Este n��o �� um nome ou IP de servidor v��lido. Por favor, modifique-o." - -msgid "Looking for available partitions ..." -msgstr "Procurando por parti����es dispon��veis ..." - -msgid "No available partitions found." -msgstr "Nenhuma parti����o dispon��vel encontrada." - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"O storage pool n��o �� persistente. Ao inv��s de desativar, essa a����o vai " -"remov��-lo permanentemente. Deseja continuar?" - -msgid "Unable to retrieve partitions information." -msgstr "N��o foi poss��vel recuperar as informa����es das parti����es." - -msgid "In progress..." -msgstr "Em progresso..." - -msgid "Failed!" -msgstr "Falhou!" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" -"Caminho do CDROM precisa ser um caminho local v��lido e n��o pode ser vazio." - -msgid "Disk pool or volume cannot be blank." -msgstr "Pool ou volume do disco n��o pode ser vazio." - -#, fuzzy -msgid "Filter" -msgstr "filtro" - -msgid "Network Name" -msgstr "Nome da rede" - -msgid "State" -msgstr "Estado" - -msgid "Network Type" -msgstr "Tipo da rede" - -msgid "Address Space" -msgstr "Espa��o de endere��o" - -msgid "Name should not contain '/' and '\"'." -msgstr "O nome n��o deve conter '/' and '\"'." - -msgid "Isolated: no external network connection" -msgstr "Isolada: nenhuma conex��o externa" - -msgid "NAT: outbound physical network connection only" -msgstr "NAT: somente conex��o de rede f��sica de sa��da" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "" -"Bridged: M��quinas virtuais est��o conectadas diretamente com a rede f��sica" - -msgid "(No interfaces found)" -msgstr "(Nenhuma interface encontrada)" - -msgid "Destination" -msgstr "Destino" - -msgid "Enable VLAN" -msgstr "Habilitar VLAN" - -msgid "VLAN ID" -msgstr "ID da VLAN" - -msgid "Stop" -msgstr "Parar" - -msgid "Generate a New Debug Report" -msgstr "Gerar um novo Relat��rio de Debug" - -msgid "Report Name" -msgstr "Nome do Relat��rio" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" -"O nome usado para identificar o relat��rio. Se omitido, um nome ser�� " -"escolhido baseado no hor��rio atual. O nome pode conter: letras, n��meros, " -"underscore ('_') e h��fen ('-')." - -msgid "Rename a Debug Report" -msgstr "Renomear um Relat��rio de Debug" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" -"O nome usado para identificar o relat��rio. O nome pode conter: letras, " -"d��gitos e h��fen (\"-\")." - -msgid "Submit" -msgstr "Enviar" - -msgid "Add a Repository" -msgstr "Adicionar um Reposit��rio" - -msgid "Identifier" -msgstr "Identificador" - -msgid "Single word, unique identifier for the repository." -msgstr "Uma ��nica palavra, identificador ��nico para o reposit��rio." - -msgid "Textual name for the repository." -msgstr "Nome textual para o reposit��rio." - -msgid "URL" -msgstr "URL" - -msgid "Required Field" -msgstr "Campo Obrigat��rio" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "URL para o reposit��rio. Protocolos suportados s��o http, ftp e file." - -msgid "Repository is a mirror" -msgstr "Reposit��rio �� um mirror" - -msgid "Distribution" -msgstr "Distribui����o" - -msgid "Distribution of the DEB repository." -msgstr "Distribui����o para o reposit��rio DEB." - -msgid "Components" -msgstr "Componentes" - -msgid "List of components in DEB repository." -msgstr "Lista de componentes para o reposit��rio DEB." - -msgid "Edit Repository" -msgstr "Editar Reposit��rio" - -msgid "Mirror List URL" -msgstr "URL para a lista de mirror" - -msgid "Yes" -msgstr "Sim" - -msgid "No" -msgstr "N��o" - -msgid "Capacity" -msgstr "Capacidade" - -msgid "Allocated" -msgstr "Alocado" - -msgid "Location" -msgstr "Localiza����o" - -msgid "Device path" -msgstr "Caminho do dispositivo" - -msgid "active" -msgstr "ativo" - -msgid "inactive" -msgstr "inativo" - -msgid "Deactivate" -msgstr "Desativar" - -msgid "Activate" -msgstr "Ativar" - -msgid "Add Volume" -msgstr "Adicionar volume" - -msgid "Extend" -msgstr "Aumentar" - -msgid "Undefine" -msgstr "Indefinir" - -msgid "Format" -msgstr "Formato" - -msgid "Allocation" -msgstr "Aloca����o" - -msgid "Define a New Storage Pool" -msgstr "Definir novo Storage Pool" - -msgid "Storage Pool Name" -msgstr "Nome do Storage Pool" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "O nome usado para identificar o storage pool e n��o deve ser vazio." - -msgid "Storage Pool Type" -msgstr "Tipo do Storage Pool" - -msgid "Storage Path" -msgstr "Caminho do storage" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "" -"O caminho do Storage Pool. Cada Storage Pool deve ter um caminho ��nico." - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "" -"O Kimchi vai tentar criar o diret��rio se ainda n��o existir no seu sistema." - -msgid "NFS Server IP" -msgstr "IP do servidor NFS" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "" -"IP ou hostname do servidor NFS. Pode ser inserido ou escolhido do hist��rico." - -msgid "NFS Path" -msgstr "Caminho do NFS" - -msgid "The NFS exported path on NFS server." -msgstr "O caminho exportado do servidor NFS." - -msgid "iSCSI Server" -msgstr "Servidor iSCSI" - -msgid "Server" -msgstr "Servidor" - -msgid "Port" -msgstr "Porta" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "IP ou hostname do servidor iSCSI. N��o deve ser vazio." - -msgid "Target" -msgstr "Alvo" - -msgid "The iSCSI target on iSCSI server" -msgstr "O alvo iSCSI no servidor iSCSI" - -msgid "Add iSCSI Authentication" -msgstr "Adicionar as credenciais do iSCSI" - -msgid "iSCSI Authentication" -msgstr "Credenciais do iSCSI" - -msgid "User Name" -msgstr "Usu��rio" - -msgid "Password" -msgstr "Senha" - -msgid "SCSI Adapter" -msgstr "Adaptador SCSI" - -msgid "Please, wait..." -msgstr "Por favor, aguarde..." - -msgid "Add a Volume to Storage Pool" -msgstr "Adicionar um volume ao Storage Pool" - -msgid "Fetch from remote URL" -msgstr "Fazer download de uma URL remota" - -msgid "Enter the remote URL here." -msgstr "Digite a URL remota aqui." - -msgid "Upload a file" -msgstr "Fazer upload de um arquivo" - -msgid "Choose the file you want to upload." -msgstr "Escolha o arquivo que voc�� quer fazer upload." - -msgid "Add Template" -msgstr "Adicionar Modelo" - -msgid "Where is the source media for this template? " -msgstr "Onde est�� a m��dia de origem desse modelo? " - -msgid "Local ISO Image" -msgstr "Imagem ISO Local" - -msgid "Local Image File" -msgstr "Arquivo de Imagem Local" - -msgid "Remote ISO Image" -msgstr "Imagem ISO Remota" - -msgid "Search ISOs" -msgstr "Procurar ISOs" - -msgid "The following ISOs are available:" -msgstr "As seguintes ISOs est��o dispon��veis:" - -msgid "OS: " -msgstr "Sistema Operacional: " - -msgid "Version: " -msgstr "Vers��o: " - -msgid "Size: " -msgstr "Tamanho: " - -msgid "Search more ISOs" -msgstr "Procurar por mais ISOs" - -msgid "Create Templates from Selected ISO" -msgstr "Criar Modelos a partir das ISOs selecionadas" - -msgid "I want to use a specific ISO file" -msgstr "Eu quero usar um arquivo ISO espec��fico" - -msgid "Loading default remote ISOs ..." -msgstr "Carregando ISOs remotas ..." - -msgid "Arch: " -msgstr "Arquitetura: " - -msgid "I want to use a custom URL" -msgstr "Eu quero usar uma URL personalizada" - -msgid "Edit Template" -msgstr "Editar Modelo" - -msgid "CDROM" -msgstr "CD-ROM" - -msgid "Image File" -msgstr "Arquivo de imagem" - -msgid "Graphics" -msgstr "Gr��ficos" - -msgid "Disk(GB)" -msgstr "Disco (GB)" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "Quantidade de CPUs" - -msgid "Manually set CPU topology" -msgstr "Configurar manualmente a topologia de CPU" - -msgid "Cores" -msgstr "Cores" - -msgid "Threads" -msgstr "Threads" - -msgid "No templates found." -msgstr "Nenhum modelo encontrado." - -#~ msgid "Delete is not allowed for %(resource)s" -#~ msgstr "M��todo de remo����o n��o �� permitido em %(resource)s" - -#~ msgid "%(resource)s does not implement update method" -#~ msgstr "%(resource)s n��o implementa m��todo de atualiza����o" - -#~ msgid "Create is not allowed for %(resource)s" -#~ msgstr "M��todo de cria����o n��o �� permitido em %(resource)s" - -#~ msgid "Unable to parse JSON request" -#~ msgstr "N��o �� poss��vel realizar a leitura da requisi����o do JSON" - -#~ msgid "This API only supports JSON" -#~ msgstr "Essa API suporta apenas JSON" - -#~ msgid "Parameters does not match requirement in schema: %(err)s" -#~ msgstr "Par��metros n��o correspondem �� especifica����o do esquema: %(err)s" - -#~ msgid "You don't have permission to perform this operation." -#~ msgstr "Voc�� n��o tem permiss��o para executar esta opera����o." - -#~ msgid "Datastore is not initiated in the model object." -#~ msgstr "Datastore n��o est�� inicializado no objeto modelo." - -#~ msgid "Unable to start task due error: %(err)s" -#~ msgstr "N��o foi poss��vel iniciar a tarefa devido a um erro: %(err)s" - -#~ msgid "" -#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" -#~ msgstr "" -#~ "Autentica����o falhou para o usu��rio '%(username)s'. [C��digo de erro: %" -#~ "(code)s]" - -#~ msgid "You are not authorized to access Kimchi" -#~ msgstr "Voc�� n��o est�� autorizado para acessar o Kimchi" - -#~ msgid "Specify %(item)s to login into Kimchi" -#~ msgstr "Especifique %(item)s para autenticar no Kimchi" - -#~ msgid "Invalid LDAP configuration: %(item)s : %(value)s" -#~ msgstr "Configura����es LDAP inv��lidas: %(item)s : %(value)s" - -#~ msgid "Unable to find %(item)s in datastore" -#~ msgstr "N��o foi poss��vel encontrar %(item)s no datastore" - -#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" -#~ msgstr "" -#~ "Fim do limite de tempo ao rodar comando '%(cmd)s' ap��s %(seconds)s " -#~ "segundos" - -#~ msgid "Invalid data value '%(value)s'" -#~ msgstr "Valor inv��lido '%(value)s'" - -#~ msgid "Invalid data unit '%(unit)s'" -#~ msgstr "Unidade inv��lida '%(unit)s'" - -#~ msgid "Peers" -#~ msgstr "Peers" - -#~ msgid "Searching" -#~ msgstr "Procurando" - -#~ msgid "No peers found." -#~ msgstr "Nenhum peer encontrado." - -#~ msgid "Help" -#~ msgstr "Ajuda" - -#~ msgid "About" -#~ msgstr "Sobre" - -#~ msgid "Log out" -#~ msgstr "Sair" - -#~ msgid "Version:" -#~ msgstr "Vers��o:" - -#~ msgid "Session timeout, please re-login." -#~ msgstr "" -#~ "Fim do limite do tempo da sess��o, por favor se autentique novamente." diff --git a/plugins/kimchi/po/ru_RU.po b/plugins/kimchi/po/ru_RU.po deleted file mode 100644 index a5dec2e..0000000 --- a/plugins/kimchi/po/ru_RU.po +++ /dev/null @@ -1,2198 +0,0 @@ -# English translations for kimchi package. -# Copyright (C) 2013 ORGANIZATION -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2014-08-28 17:32+0000\n" -"Last-Translator: Aline Manera <aline.manera@gmail.com>\n" -"Language-Team: Russian (http://www.transifex.com/projects/p/kimchi/language/" -"ru/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ru_RU\n" -"Generated-By: pygettext.py 1.5\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "" - -msgid "Unknown \"_cap\" specified" -msgstr "" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "������������ ������������������ �������������� ������������������. ����������������: %(err)s" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "������������ ������������������ �������������������� �� �������������� ���������������������� ������ %(device)s." - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "���� ������������ �������� ���������������� ����: %(filename)s" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "" -"������������ �������������� ���������� ���������������� ���� %(filename)s. ������������������, ������ ������ �������� JSON." - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "���� �������������� ���������� �� �������������� %(portal)s ���������� iSCSI. ����������������: %(err)s" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "���� �������������� ���������� �� �������������� %(target)s ���������� iSCSI %(host)s" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "�������� ISO %(filename)s ���� ����������������������" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "" -"�������� ISO %(filename)s ���� ���������������� �������������������� ���������������������� ������������ El Torito" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "������������������������ ������������ ���������������� El Torito �� ������������ ISO %(filename)s" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "������������������������ ������������������ ���������������� El Torito �� ������������ ISO %(filename)s" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "���������������������� ������ �������� ������ ���������������� �������� �� ������������ ISO %(filename)s" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "���������������� ������������ ���������������������� �������� �� ������������ ISO %(filename)s" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" -"�� ���������������������� ������ �������� �������������� ������ �������������������������� ���������� ������������ ISO %(filename)" -"s. ���������������������� ������ �� �������������� /var/lib/libvirt, ���������������� �������������������� ���� ���������� " -"�� ������������ ���������������� �������������� ������ ������������������������ %(user)s, �������� ������ ����������������, " -"���������������� %(user)s �� ������������ �������� �� ������������ ISO ������ (���� ��������������������������) " -"������������������ �������������� 'chmod -R o+x 'path_to_iso'. ����������������: %(err)s" - -msgid "An error occurred when probing image OS information." -msgstr "" - -msgid "No OS information found in given image." -msgstr "" - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "���������������������� ������������ %(name)s ������ ��������������������" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "���������������������� ������������ %(name)s ���� ��������������������" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "" -"���� �������������� ���������������� ������������ ������������ ������ �������������������������� ���������������������� ������������ %" -"(name)s" - -msgid "Remote ISO image is not supported by this server." -msgstr "������������������ ���������� ISO ���� ���������������������������� �������� ����������������." - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "���� �������������� ���������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "" - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "" -"���������� ������������ ���������������� ������ ���������������������� �������������������� ������������ �������� IPv4 ������ IPv6" - -msgid "Specify a template to create a virtual machine from" -msgstr "�������������� ������������ ������ ���������������� ���������������������� ������������" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "���� �������������� ������������������ ���������������������� ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "" -"���� �������������� �������������������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" - -msgid "User name list must be an array" -msgstr "" - -msgid "User name must be a string" -msgstr "������ �������� ������������ �������� ��������������" - -msgid "Group name list must be an array" -msgstr "" - -msgid "Group name must be a string" -msgstr "������ �������� ������������ �������� ��������������" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "������������������������ %(users)s ���� ��������������������." - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "������������������������ %(groups)s ���� ��������������������." - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "���� �������������� ������������������ ���������������������� ������������ %(name)s. ����������������: %(err)s" - -msgid "The guest console password must be a string." -msgstr "" - -msgid "The life time for the guest console password must be a number." -msgstr "" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" - -msgid "\"name\" should be a device name string" -msgstr "" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "������������������ %(iface)s ���� �������������������� �� ���������������������� ������������ %(name)s" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "" -"�������� %(network)s, ������������������ ������ ���������������������� ������������ %(name)s, ���� ��������������������" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "���������������������������� ������������ �������� ������ ���������������������� ���������������������� ������������ - ��������" - -msgid "Network name for virtual machine interface must be a string" -msgstr "������ �������� ������ �������������������� ���������������������� ������������ ������������ �������� ��������������" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "" -"�������������� ������������������������ ���������� ������������ �������� ������ �������������������� ���������������������� ������������" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "�������������� ������ �� �������� ������ �������������������� ������������ �������������������� ���������������������� ������������" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "������������ %(name)s ������ ��������������������" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "�������� %(network)s, ������������������ ������ �������������� %(template)s, ���� ��������������������" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "������ ������������ %(pool)s, ������������������ ������ �������������� %(template)s, ���� ��������������������" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "������ ������������ %(pool)s, ������������������ ������ �������������� %(template)s, ���� ��������������" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "������������ ������������������������ ���������������� %(param)s ������ CDROM." - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "�������� %(network)s, ������������������ ������ �������������� %(template)s, ���� ��������������" - -msgid "Template name must be a string" -msgstr "������ �������������� ������������ �������� ��������������" - -msgid "Template icon must be a path to the image" -msgstr "������������ �������������� ������������ �������� ���������� �� ������������" - -msgid "Template distribution must be a string" -msgstr "�������������� �������������� ������������ �������� ��������������" - -msgid "Template distribution version must be a string" -msgstr "������������ ���������������� �������������� ������������ �������� ��������������" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "���������� ���������������������� ������������ �������� ���������� ������������" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "���������� ������������ (����) ������������ �������� ���������� ������������ ������������ 512" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "CDROM �������������� ������������ �������� ������������������ ������ ������������������ ������������ ISO" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "������ �������������� ������������ ������������������������ URI �������� ������������ %(value)s" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "�������������� ���������� ISO �� ���������������� CDROM ������ ���������������� ��������������" - -msgid "All networks for the template must be specified in a list." -msgstr "������ �������� ������ �������������� ������������ �������� �������������� �� ������������." - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "���� �������������� �������������� ������������ ����-���� ������������ %(err)s" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "���� �������������� �������������� ������������ ����-���� ������������ %(err)s" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "" - -msgid "Template base image must be a valid local image file" -msgstr "CDROM �������������� ������������ �������� ������������������ ������ ������������������ ������������ ISO" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "������ ������������ %(name)s ������ ��������������������" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "������ ������������ %(name)s ���� ��������������������" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "�������������� %(item)s ������ ���������������� �������� ������������ %(name)s" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "���� �������������� �������������� ���������������� ������ ������������ %(name)s" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "���� �������������� �������������� ������������ ���������� ������������. ����������������: %(err)s" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������� ������ ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "" -"���� �������������� ���������������� ���������� ���������� �� �������� ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "���� �������������� ������������������������ ������ ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "���� �������������� ���������������������������� ������ ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������� ������ ������������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "" -"���� �������������� �������������� ������ NFS: �������������������������������� �������� %(path)s ������ �������� " -"������������������������ ���� ���������� ������������������������" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "" -"���� �������������� �������������� ������ NFS: ���� �������������� ������������������������ �������������������������������� �������� %" -"(path)s" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "�������������������������������� ������ �������� ������������: %(type)s" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" - -msgid "Storage pool path must be a string" -msgstr "�������� �� �������� ������������ ������������ �������� ��������������" - -msgid "Storage pool host must be a IP or hostname" -msgstr "�������� �������� ������������ ������������ �������� IP-�������������� ������ ������������ ����������" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" - -msgid "Storage pool devices parameter must be a list" -msgstr "���������������� ������������������ �������� ������������ ������������ �������� ��������������" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "�������������� IQN �������� iSCSI ������������ �������� ��������������" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "�������� �������������������� �������������� ������������ ������������ �������� ���������� ������������ ���� 1 ���� 65535" - -msgid "iSCSI target username must be a string" -msgstr "" - -msgid "iSCSI target password must be a string" -msgstr "" - -msgid "Specify name and type to create a storage pool" -msgstr "�������������� ������ �� ������ ������ ���������������� �������� ������������" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "" -"%(disk)s ���� ���������������� �������������������� ������������/����������������. ���� �������������� ���������������� ������ �� " -"������ %(pool)s." - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "���������� �������������������� ���������� ������������������ ������������ ������ ���������������������� �������� ������������." - -msgid "The SCSI host adapter name must be a string." -msgstr "������ ���������������� ���������� SCSI ������������ �������� ��������������." - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "kimchi_isos �������� ������������ ���������������������������� ������ ���������������������� ��������������������������" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"���� �������������� ������������������������ ������ ������������ NFS %(name)s. ������������ NFS %(server)s " -"��������������������." - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "" -"���� �������������� ���������������������������� ������ ������������ NFS %(name)s. ������������ NFS %(server)s " -"��������������������." - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "" -"���� �������������� ���������������������������� ������ %(name)s: ������ ������������ �� �������������������� ������������������" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "���� �������������� �������������� ������ %(name)s: ������ ������������ �� �������������������� ������������������" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "" -"������������ ���������� �� ������������ %(name)s ������ ��������������������. ���������������� ������������ ������ ������ " -"���������������� ���������������������� ��������." - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "" -"���� �������������� ���������������� �������� ������������ �� ���������������������� ������������������ ������������������������ ����-���� " -"������������ %(err)s" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "������ %(name)s ������ ��������������������" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "������ %(name)s ���� �������������������� �� �������� ������������ %(pool)s" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "�������������� %(item)s ������ ���������������� �������� %(volume)s" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "���� �������������� �������������� ������������ ����������: ������ ������������ %(pool)s ���� ��������������" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "" -"���� �������������� �������������� ������ %(name)s �� �������� ������������ %(pool)s. ����������������: %(err)s" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "" -"���� �������������� �������������� ������������ ���������� �� �������� ������������ %(pool)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������� �������� %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������� ������ %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "���� �������������� ���������������� ������������ �������� %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "������ ������������ %(type)s ���� ������������������������ ���������������� �� ���������������� ����������" - -msgid "Storage volume name must be a string" -msgstr "������ �������� ������������ �������� ��������������" - -msgid "Storage volume allocation must be an integer number" -msgstr "������������������ �������� ������������ �������� ���������� ������������" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" - -msgid "Storage volume requires a volume name" -msgstr "�������� ������������������ ������" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "" -"���� �������������� ���������������� �������� ������������ �� ���������������������� �� ���������� ����-���� ������������ %(err)s" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "" - -msgid "Storage volume capacity must be an integer number." -msgstr "" - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "" - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "������������������ %(name)s ���� ��������������������" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "�������� %(name)s ������ ��������������������" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "�������� %(name)s ���� ��������������������" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "�������������� %(subnet)s, ������������������ ������ �������� %(network)s, ����������������������." - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "" -"�������������� �������������� ������������������ ������ ���������������� �������� %(name)s �� ���������������� ���������� ��������" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "���� �������������� �������������� ���������������� �������� %(name)s" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "������������������ %(iface)s, ������������������ ������ �������� %(network)s, ������ ������������������������" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "" -"������������������ ������������ �������� �������������� ������������, ���������������������� ���������� ������ ������������������ " -"����������������������." - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������� �������� %(name)s. ����������������: %(err)s" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "���� ������������ ������������������ IP-���������� ������ �������� %(name)s" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "���������������������������� �������� ����������: isolated, NAT �� bridge" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "" -"�������������� �������� ������������ �������� ��������������, �������������������� IP-����������, �������������� ������ ���������� ��������" - -msgid "Network interface must be a string" -msgstr "�������������� ������������������ ������������ �������� ��������������" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "�������������� ���� VLAN ������������ �������� ���������� ������������ ���� 1 ���� 4094" - -msgid "Specify name and type to create a Network" -msgstr "�������������� ������ �� ������ ������ ���������������� ��������" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "" -"�������������������� ���������� %(name)s ���� ���������� �������� �������������������������� ���������������������� VLAN." - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "���� �������������� ������������������������ ������������������ %(iface)s: %(err)s." - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "" -"���� ������������ ������������������������ ������������������ %(iface)s. ������������������ ������������������ �������������������� " -"���������� ����������. " - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "�������������������� ���������� %(name)s ���� ��������������������" - -msgid "Debug report tool not found in system" -msgstr "�������������������� ���������������������� ������������ ���� ������������ �� ��������������" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "���� �������������� �������������� �������������������� ���������� %(name)s. ����������������: %(err)s." - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "���� �������������� �������������� �������������������� ���������� %(name)s. ����������������: %(err)s" - -msgid "You should give a name for the debug report file." -msgstr "" - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "" -"������������ ���������� �� ������������ %(name)s ������ ��������������������. ���������������� ������������ ������ ������ " -"���������������� ���������������������� ��������." - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "������������ ������������ %(server)s ���� �������������������������� Kimchi" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "�������������� ���� %(name)s ���� ��������������������" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "������������ %(name)s ���� �������������������� ���� ����������" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "" -"���� �������������� ������������������ ������������ �������������� ����������: ���������������������� ���������������������� ������������" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "���� �������������� �������������������������� �������������� ����������: ���������������������� ���������������������� ������������" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "�������������������� %(name)s �������� ���� ��������������" - -msgid "Conflicting flag filters specified." -msgstr "" - -msgid "No packages marked for update" -msgstr "������ ��������������, �������������������� ������ ��������������������" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "���������� %(name)s ���� �������������� ������ ��������������������." - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "������������ ������������������ ��������������, �������������������� ������ ��������������������. ����������������: %(err)s" - -msgid "There is no compatible package manager for this system." -msgstr "������ ������������������������ ���������������������������� �������������� ������ �������� ��������������." - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "������������������������ URI %(uri)s" - -msgid "Unable to choose a virtual machine name" -msgstr "" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "������������������������ ������ ������������. ���������������������������� ��������: cdrom" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" - -msgid "Only CDROM path can be update." -msgstr "" - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "������������ ���������������� �������������������� ����������������: %(error)s" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "������������ �������������������� �������������������� ����������������: %(error)s" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "������������ ���������������� �������������������� ����������������: %(error)s" - -msgid "Do not support IDE device hot plug" -msgstr "" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "�������������� ������ �� �������� ������ �������������������� ������������ ���������� ���������������������� ������������" - -msgid "Specify path to update virtual machine disk" -msgstr "�������������� �������� ������ �������������������� ���������� ���������������������� ������������" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" - -msgid "Volume already in use by other virtual machine." -msgstr "" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "�������������� ������ �� �������� ������ �������������������� ������������ ���������� ���������������������� ������������" - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" - -msgid "YUM Repository ID must be one word only string." -msgstr "" -"���� ������������������ YUM ������������ �������� ��������������, ������������������ ������������ ���� ������������ ����������." - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "URL ������������������ ������������ �������� http://, ftp:// ������ file:// ." - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "" -"������������������������ ������������������ ������������������������ ���������� �������������� ����������������, ������������������������ " -"���������� ������������������." - -msgid "Distribution to DEB repository must be a string" -msgstr "�������������� ������ ������������������ DEB ������������ �������� ��������������" - -msgid "Components to DEB repository must be listed in a array" -msgstr "�������������������� ������ ������������������ DEB ������������ �������� ���������������������� �� ��������������" - -msgid "Components to DEB repository must be a string" -msgstr "�������������������� ������ ������������������ DEB ������������ �������� ��������������" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "������ ������������������ YUM ������������ �������� ��������������." - -msgid "GPG check must be a boolean value." -msgstr "���������������� GPG ������������ �������� ������������������ ������������������." - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "" -"�������� GPG ������������ �������� URL, ���������������������� ���� �������������������� �������� �� ������������������������ " -"ASCII." - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "���� �������������� ���������������� ������������������ %(repo_id)s." - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "������������������ %(repo_id)s ���� ��������������������." - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "���� ������������������ �������������������� �������������������� �������������������� ������ ��������������." - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "������������������ %(repo_id)s ������ ����������������." - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "������������������ %(repo_id)s ������ ������������������." - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "���� �������������� �������������� ������������������ %(repo_id)s." - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "���� �������������� ���������������� �� �������� ������������������������ ������������������ %(repo_file)s" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "�������������� �������������� ������������������ ������ ���������������� ������������������ DEB." - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "���� �������������� ���������������� ������������������ %(repo_id)s." - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "���� �������������� ������������������ ������������������ %(repo_id)s." - -msgid "YUM Repository ID already exists" -msgstr "���� ������������������ YUM ������ ��������������������" - -msgid "YUM Repository name must be a string" -msgstr "������ ������������������ YUM ������������ �������� ��������������" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "���� �������������� �������������� ������������ ����������������. ����������������: %(err)s" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "���� �������������� ���������������� �������������������� �� ������������������. ����������������: %(err)s" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "���� �������������� ���������������� ������������������. ����������������: %(err)s" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "���� �������������� �������������� ������������������. ����������������: %(err)s" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" - -msgid "The number of vCPUs is too large for this system." -msgstr "" - -msgid "Invalid vCPU/topology combination." -msgstr "" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "" - -msgid "ERROR CODE" -msgstr "������ ������������" - -msgid "REASON" -msgstr "��������������" - -msgid "STACK" -msgstr "��������" - -msgid "Go to Homepage" -msgstr "�������������� ���� �������������� ����������������" - -msgid "Create a New Virtual Machine" -msgstr "�������������� ���������� ���������������������� ������������" - -msgid "Virtual Machine Name" -msgstr "������ ���������������������� ������������" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "" -"������ ������ �������������������������� ���������������������� ������������. �������� ���� ��������������, ������ ���������� �������������� " -"�� ���������������������� ���� �������������������������� ��������������." - -msgid "Template" -msgstr "������������" - -msgid "Please create a template first." -msgstr "��������������������, ���������������� ������������ �� ������������ ��������������." - -msgid "Create a Template" -msgstr "�������������� ������������" - -msgid "Please choose a template." -msgstr "��������������������, ���������������� ������������." - -msgid "OS" -msgstr "����" - -msgid "OS Version" -msgstr "������������ ����" - -msgid "CPUS" -msgstr "��������������������" - -msgid "Memory" -msgstr "������������" - -msgid "Create" -msgstr "��������������" - -msgid "Creating..." -msgstr "" - -msgid "Cancel" -msgstr "������������" - -msgid "Edit Guest" -msgstr "���������������� ���������������� ��������������" - -msgid "General" -msgstr "����������" - -msgid "Storage" -msgstr "������������������" - -msgid "Interface" -msgstr "������������������" - -msgid "Permission" -msgstr "������������" - -msgid "Host PCI Device" -msgstr "" - -msgid "Snapshot" -msgstr "" - -msgid "Name" -msgstr "������" - -msgid "CPUs" -msgstr "��������������������" - -msgid "Memory (MB)" -msgstr "������������ (����)" - -msgid "Icon" -msgstr "������������" - -msgid "Device" -msgstr "������ ��������������������" - -msgid "Path" -msgstr "�������� NFS" - -msgid "Network" -msgstr "��������" - -msgid "Type" -msgstr "������" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "" - -msgid "Selected system users and groups" -msgstr "" - -msgid "User" -msgstr "" - -msgid "All" -msgstr "������" - -msgid "To Add" -msgstr "" - -msgid "Added" -msgstr "" - -msgid "filter" -msgstr "" - -msgid "Product" -msgstr "" - -msgid "Vendor" -msgstr "������������" - -msgid "Created" -msgstr "" - -msgid "Save" -msgstr "������������������" - -msgid "Replace" -msgstr "����������������" - -msgid "Detach" -msgstr "������������������" - -msgid "revert" -msgstr "" - -msgid "Start" -msgstr "������������������" - -msgid "Reset" -msgstr "����������������" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "������������������" - -msgid "Actions" -msgstr "����������������" - -msgid "Connect" -msgstr "��������������������" - -msgid "Clone" -msgstr "����������������������" - -msgid "Edit" -msgstr "��������������������������" - -msgid "Shut Down" -msgstr "������������������ ������������" - -msgid "Delete" -msgstr "��������������" - -msgid "CPU" -msgstr "������������������" - -msgid "Disk I/O" -msgstr "���������������� ��������-����������" - -msgid "Network I/O" -msgstr "�������������� ��������-����������" - -msgid "Livetile" -msgstr "Livetile" - -msgid "No guests found." -msgstr "���� �������������� ���������������� ��������������." - -msgid "Add a Storage Device to VM" -msgstr "���������������� �������������������� ���������������� �� VM" - -msgid "Device Type" -msgstr "������ ��������������������" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "������ ��������������������. �� ������������ ������������ ���������������������������� ������������ \"cdrom\"." - -msgid "Storage Pool" -msgstr "������ ������������" - -msgid "Storage pool which volume located in" -msgstr "�������� �� �������� ������������ ������������ �������� ��������������" - -msgid "Storage Volume" -msgstr "������ �������� ������������" - -msgid "Storage volume to be attached" -msgstr "������ �������� ������������ �������� ��������������" - -msgid "File Path" -msgstr "�������� �� ����������" - -msgid "The ISO file path in the server for CDROM." -msgstr "�������� �� ���������� ISO ������ CDROM ���� ��������������." - -msgid "Attach" -msgstr "��������������������" - -msgid "Shut down" -msgstr "����������������" - -msgid "Restart" -msgstr "��������������������" - -msgid "Basic Information" -msgstr "�������������� ��������������������" - -msgid "OS Distro" -msgstr "�������������� ����" - -msgid "OS Code Name" -msgstr "�������������� ������ ����" - -msgid "Processor" -msgstr "������������������" - -msgid "CPU(s)" -msgstr "" - -msgid "System Statistics" -msgstr "������������������ ��������������������" - -msgid "Software Updates" -msgstr "�������������������� ������������������������ ����������������������" - -msgid "Update Progress" -msgstr "������ ��������������������" - -msgid "Repositories" -msgstr "������������������" - -msgid "Debug Reports" -msgstr "�������������������� ������������" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "�������������� ���������������� ������ ������������������������ ������ ������������. �������������� ������ ������." - -msgid "This field is required." -msgstr "������ ������������������������ ��������." - -msgid "Log in" -msgstr "����������" - -msgid "Logging in..." -msgstr "��������..." - -msgid "Host" -msgstr "��������" - -msgid "Guests" -msgstr "���������������� ��������������" - -msgid "Templates" -msgstr "��������������" - -msgid "Failed to get application configuration" -msgstr "���� �������������� ���������������� ������������������������ ��������������������" - -msgid "This is not a valid Linux path" -msgstr "�������� ������������������������ �������� �� Linux" - -msgid "This is not a valid URL." -msgstr "������ ������������������������ URL." - -msgid "No such data available." -msgstr "������ ���������� ������������." - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" -"������ ���������� �� ���������������� ����������. ������������������, ������ �������������� ���������� ���������������� �� ���������������� " -"������ ����������������������. ���������� ���� ������������ HTTP: %1. " - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "�������������������������� ����������������" - -msgid "OK" -msgstr "OK" - -msgid "Confirm" -msgstr "����������������������" - -msgid "Warning" -msgstr "����������������������������" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "����������������������..." - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "������������������" - -msgid "Detailed message:" -msgstr "������������������ ������������������:" - -msgid "No ISO found" -msgstr "" - -msgid "This is not a valid ISO file." -msgstr "�������� �������� ���� ���������������� �������������������� �������������� ISO." - -msgid "This may take a long time. Do you want to continue?" -msgstr "������ ������������ ���������� ��������������. ��������������������?" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "������������ ���������� ������������������������ ������������. ��������������������?" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "" -"�������������������� ������������������ ������������ ��������������, ������������������ �� ������ ���������������� ���������������������� " -"������������!" - -msgid "Max:" -msgstr "��������.:" - -msgid "Utilization" -msgstr "��������������������������" - -msgid "Available" -msgstr "����������������" - -msgid "Read Rate" -msgstr "���������������� ������������" - -msgid "Write Rate" -msgstr "���������������� ������������" - -msgid "Received" -msgstr "����������������" - -msgid "Sent" -msgstr "��������������������" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"�������������������� ������������ �� �������������������� ���������� ���������������� �� ������������ �������������������������� ������������. " -"�������������������� �������������������� ������������/��������������������?" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "������������������ ���������� �������������� ������ ���������������������� ����������������������������. ��������������������?" - -msgid "ID" -msgstr "����" - -msgid "Base URL" -msgstr "�������������� URL" - -msgid "Is Mirror" -msgstr "�������������������� ����������" - -msgid "URL Args" -msgstr "������������������ URL" - -msgid "Enabled" -msgstr "����������������" - -msgid "GPG Check" -msgstr "���������������� GPG" - -msgid "GPG Key" -msgstr "�������� GPG" - -msgid "Add" -msgstr "����������������" - -msgid "Remove" -msgstr "��������������" - -msgid "Enable" -msgstr "����������������" - -msgid "Disable" -msgstr "������������������" - -msgid "Package Name" -msgstr "������ ������������" - -msgid "Version" -msgstr "������������" - -msgid "Architecture" -msgstr "����������������������" - -msgid "Repository" -msgstr "������������������" - -msgid "Update All" -msgstr "���������������� ������" - -msgid "Updating..." -msgstr "��������������������..." - -msgid "Failed to retrieve packages update information." -msgstr "" - -msgid "Failed to update package(s)." -msgstr "���� �������������� ���������������� ������������." - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "" -"�������������������� ���������� ���������� ������������ ������ ���������������������� ����������������������������. ��������������������?" - -msgid "Generated Time" -msgstr "���������� ����������������" - -msgid "Generate" -msgstr "��������������" - -msgid "Generating..." -msgstr "����������������..." - -msgid "Rename" -msgstr "��������������������������" - -msgid "Download" -msgstr "������������������" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "������ ������������ ������������ ������������������ ������������ ����������, ���������� �� ������������ ('-')." - -msgid "Pending..." -msgstr "����������������������..." - -msgid "Report name is the same as the original one." -msgstr "" - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "" -"���������� �������������� ���������������������� ������������ ������������ ���� ������������ ������������������������ ��������������. ������ " -"���������������������� ����������������. ��������������������?" - -msgid "Power off Confirmation" -msgstr "�������������������������� ����������������" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" - -msgid "Reset Confirmation" -msgstr "�������������������������� ����������������" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" - -msgid "Shut Down Confirmation" -msgstr "�������������������������� ����������������" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "������������ ���������� ������������������������ ������������. ��������������������?" - -msgid "Virtual Machine delete Confirmation" -msgstr "" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" -"�������� CDROM ���������� ����������������. ������ ���������� ���������� ���������� ��������������������. ������������������?" - -msgid "Attaching..." -msgstr "����������������������..." - -msgid "Replacing..." -msgstr "������������..." - -msgid "Successfully attached!" -msgstr "�������������� ������������������!" - -msgid "Successfully replaced!" -msgstr "�������������� ��������������!" - -msgid "Successfully detached!" -msgstr "�������������� ����������������!" - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" - -msgid "interface:" -msgstr "" - -msgid "address:" -msgstr "" - -msgid "link_type:" -msgstr "" - -msgid "block:" -msgstr "" - -msgid "drive_type:" -msgstr "" - -msgid "model:" -msgstr "" - -msgid "Affected devices:" -msgstr "" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "���� VLAN ������������ �������� ���� 1 ���� 4094." - -msgid "unavailable" -msgstr "��������������������" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" -"������ ���������������� �������������� �������������� �������������������� �� �������� ���������������������� ����������, �������������� " -"�������������� ���� �������� ��������." - -msgid "Create a network" -msgstr "�������������� ��������" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"�������� ������ ������������ ���� ��������������������. ������������ ����������������������, ������ ���������������� ������������������������ " -"������ ������������. ��������������������?" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "������ ������������ ���������� ������������������������ ������������. ��������������������?" - -msgid "This storage pool is empty." -msgstr "�������� ������ ������������ ������������." - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" -"�������� ���������� ����������������������������, �� ������ ������������ ���� ������ ���������� ����������������. ���� " -"�������������������������� ������������ ��������������������? " - -msgid "SCSI Fibre Channel" -msgstr "SCSI Fibre Channel" - -msgid "No SCSI adapters found." -msgstr "���� �������������� ���������������� SCSI." - -msgid "Loading iSCSI targets..." -msgstr "" - -msgid "No iSCSI found. Please input one." -msgstr "" - -msgid "Failed to load iSCSI targets." -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "���� �������������� ������ �������� ������������." - -msgid "The storage pool path can not be blank." -msgstr "���� ������������ �������� �� �������� ������������." - -msgid "NFS server mount path can not be blank." -msgstr "���� ������������ �������� ������������������������ �������������� NFS." - -msgid "Invalid NFS mount path." -msgstr "������������������������ �������� ������������������������ NFS." - -msgid "No logical device selected." -msgstr "���� �������������� �������������������� ��������������������." - -msgid "The iSCSI target can not be blank." -msgstr "���� ������������ �������������� ������������ iSCSI." - -msgid "Server name can not be blank." -msgstr "���� �������������� ������ ��������������." - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "" - -msgid "Looking for available partitions ..." -msgstr "���������� ������������������ ����������������..." - -msgid "No available partitions found." -msgstr "���� �������������� ������������������ ��������������." - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"�������� ������ ������������ ���� ��������������������. ������������ ����������������������, ������ ���������������� ������������������������ " -"������ ������������. ��������������������?" - -msgid "Unable to retrieve partitions information." -msgstr "���� �������������� ���������������� �������������������� �� ������������������. ����������������: %(err)s" - -msgid "In progress..." -msgstr "" - -msgid "Failed!" -msgstr "" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" - -msgid "Disk pool or volume cannot be blank." -msgstr "���� �������������� ������ �������� ������������." - -msgid "Filter" -msgstr "" - -msgid "Network Name" -msgstr "������ ��������" - -msgid "State" -msgstr "������������������" - -msgid "Network Type" -msgstr "������ ��������" - -msgid "Address Space" -msgstr "���������������� ������������������������" - -msgid "Name should not contain '/' and '\"'." -msgstr "������������������������ ������ �������� ������������. �� ���������� ���� ������������ �������� ���������������� '/'." - -msgid "Isolated: no external network connection" -msgstr "�������������������������� (������ �������������������� �������������� ��������������������)" - -msgid "NAT: outbound physical network connection only" -msgstr "NAT (������������ ������������������ �������������������� �������������� ��������������������)" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "���������� �������� (������������ ���������������������� ���������������������� ���������� �� �������������������� ��������)" - -msgid "(No interfaces found)" -msgstr "" - -msgid "Destination" -msgstr "�������������� ������������������������:" - -msgid "Enable VLAN" -msgstr "���������������� VLAN:" - -msgid "VLAN ID" -msgstr "" - -msgid "Stop" -msgstr "������������������" - -msgid "Generate a New Debug Report" -msgstr "�������������� ���������� �������������������� ����������" - -msgid "Report Name" -msgstr "������ ������������" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" -"������ ������ �������������������������� ������������. �������� ���� ��������������, ������ ���������� ������������������������ ���� " -"������������ ���������������� ��������������. ������ ���������� ������������������: ����������, ���������� �� ������������ (\"-\")." - -msgid "Rename a Debug Report" -msgstr "�������������� ���������� �������������������� ����������" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" -"������ ������ �������������������������� ������������. �������� ���� ��������������, ������ ���������� ������������������������ ���� " -"������������ ���������������� ��������������. ������ ���������� ������������������: ����������, ���������� �� ������������ (\"-\")." - -msgid "Submit" -msgstr "����������������������" - -msgid "Add a Repository" -msgstr "���������������� ������������������" - -msgid "Identifier" -msgstr "��������������������������" - -msgid "Single word, unique identifier for the repository." -msgstr "������������������ ���������� - �������������������� �������������������������� ������������������." - -msgid "Textual name for the repository." -msgstr "������������������ ������ ������������������." - -msgid "URL" -msgstr "URL" - -msgid "Required Field" -msgstr "������������������������ ��������" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "URL ������������������. ���������������������������� ������������������: http, ftp, file." - -msgid "Repository is a mirror" -msgstr "������������������ ���������������� �������������������� ������������." - -msgid "Distribution" -msgstr "��������������" - -msgid "Distribution of the DEB repository." -msgstr "�������������� ������������������ DEB." - -msgid "Components" -msgstr "��������������������" - -msgid "List of components in DEB repository." -msgstr "������������ ���������������������� �� ������������������ DEB." - -msgid "Edit Repository" -msgstr "���������������� ������������������" - -msgid "Mirror List URL" -msgstr "URL ������������ �������������������� ����������" - -msgid "Yes" -msgstr "����" - -msgid "No" -msgstr "������" - -msgid "Capacity" -msgstr "��������������" - -msgid "Allocated" -msgstr "����������������" - -msgid "Location" -msgstr "������������������������" - -msgid "Device path" -msgstr "�������� �� ��������������������" - -msgid "active" -msgstr "��������������" - -msgid "inactive" -msgstr "������������������" - -msgid "Deactivate" -msgstr "������������������" - -msgid "Activate" -msgstr "������������������������" - -msgid "Add Volume" -msgstr "" - -msgid "Extend" -msgstr "" - -msgid "Undefine" -msgstr "��������������" - -msgid "Format" -msgstr "������������:" - -msgid "Allocation" -msgstr "������������������ ����������������:" - -msgid "Define a New Storage Pool" -msgstr "�������������� ������ ������������" - -msgid "Storage Pool Name" -msgstr "������ �������� ������������" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "������ ������ �������������������������� ���������� ������������. ���� ���������� �������� ������������." - -msgid "Storage Pool Type" -msgstr "������ �������� ������������" - -msgid "Storage Path" -msgstr "�������� �� ����������" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "�������� �� �������� ������������. ������������ ������ ������������ ������������ ���������� �������������������� ��������." - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "Kimchi �������������������� �������������� ��������������, �������� ���� ���� �������������������� �� ��������������." - -msgid "NFS Server IP" -msgstr "IP-���������� �������������� NFS" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "" -"IP-���������� ������ ������ ���������� �������������� NFS. ������ ���������� ������������ ������ �������������� �� " -"��������������������." - -msgid "NFS Path" -msgstr "�������� NFS" - -msgid "The NFS exported path on NFS server." -msgstr "�������������������������������� �������� NFS ���� �������������� NFS." - -msgid "iSCSI Server" -msgstr "������������ iSCSI" - -msgid "Server" -msgstr "������������" - -msgid "Port" -msgstr "��������" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "IP-���������� ������ ������ ���������� �������������� iSCSI. ���� ���������� �������� ������������." - -msgid "Target" -msgstr "�������������� ������������" - -msgid "The iSCSI target on iSCSI server" -msgstr "�������������� ������������ iSCSI ���� �������������� iSCSI" - -msgid "Add iSCSI Authentication" -msgstr "���������������� �������������������������� iSCSI" - -msgid "iSCSI Authentication" -msgstr "�������������������������� iSCSI" - -msgid "User Name" -msgstr "������ ������������������������" - -msgid "Password" -msgstr "������������" - -msgid "SCSI Adapter" -msgstr "�������������� SCSI" - -msgid "Please, wait..." -msgstr "������������������..." - -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - -msgid "Add Template" -msgstr "���������������� ������������" - -msgid "Where is the source media for this template? " -msgstr "������ ������������������ ���������������� ���������������� ������ ���������� ��������������?" - -msgid "Local ISO Image" -msgstr "������������������ ���������� ISO" - -msgid "Local Image File" -msgstr "" - -msgid "Remote ISO Image" -msgstr "������������������ ���������� ISO" - -msgid "Search ISOs" -msgstr "���������� �������������� ISO" - -msgid "The following ISOs are available:" -msgstr "������������������ ������������ ISO:" - -msgid "OS: " -msgstr "����: " - -msgid "Version: " -msgstr "������������: " - -msgid "Size: " -msgstr "������������: " - -msgid "Search more ISOs" -msgstr "���������� ���������������������������� �������������� ISO" - -msgid "Create Templates from Selected ISO" -msgstr "�������������� �������������� ���� ������������������ �������������� ISO" - -msgid "I want to use a specific ISO file" -msgstr "������������������������ �������������������� �������� ISO" - -msgid "Loading default remote ISOs ..." -msgstr "���������������� ������������������ ISO ���� ������������������..." - -msgid "Arch: " -msgstr "����������������������: " - -msgid "I want to use a custom URL" -msgstr "������������������������ ������������ URL" - -msgid "Edit Template" -msgstr "���������������� ������������" - -msgid "CDROM" -msgstr "CDROM" - -msgid "Image File" -msgstr "" - -msgid "Graphics" -msgstr "��������������" - -msgid "Disk(GB)" -msgstr "" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "�������������������� ����������������������" - -msgid "Manually set CPU topology" -msgstr "" - -msgid "Cores" -msgstr "" - -msgid "Threads" -msgstr "" - -msgid "No templates found." -msgstr "���� �������������� ��������������." - -#~ msgid "Delete is not allowed for %(resource)s" -#~ msgstr "���������������� ������������������ ������ %(resource)s" - -#~ msgid "%(resource)s does not implement update method" -#~ msgstr "%(resource)s ���� ������������������ ���������� ��������������������" - -#~ msgid "Create is not allowed for %(resource)s" -#~ msgstr "���������������� ������������������ ������ %(resource)s" - -#~ msgid "Unable to parse JSON request" -#~ msgstr "������������ �������������� �������������� JSON" - -#~ msgid "This API only supports JSON" -#~ msgstr "������ �������������� API ������������������������ ������������ JSON" - -#~ msgid "Datastore is not initiated in the model object." -#~ msgstr "������������������ ������������ �� �������������� ������������ ���� ��������������������������������." - -#~ msgid "Unable to start task due error: %(err)s" -#~ msgstr "���� �������������� ������������������ ������������ ����-���� ������������ %(err)s" - -#~ msgid "" -#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" -#~ msgstr "" -#~ "�������� �������������������������� ������������������������ %(username)s. [������ ������������: %(code)s]" - -#~ msgid "You are not authorized to access Kimchi" -#~ msgstr "������ �������� �������������� �� Kimchi" - -#~ msgid "Specify %(item)s to login into Kimchi" -#~ msgstr "�������������� %(item)s ������ ���������� �� Kimchi" - -#~ msgid "Unable to find %(item)s in datastore" -#~ msgstr "���� ������������ %(item)s �� ������������������ ������������" - -#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" -#~ msgstr "���������� ��������-������ �������������������� �������������� %(cmd)s (%(seconds)s ��)" - -#~ msgid "Help" -#~ msgstr "������������" - -#~ msgid "About" -#~ msgstr "�� ������������������" - -#~ msgid "Log out" -#~ msgstr "����������" - -#~ msgid "Version:" -#~ msgstr "������������:" diff --git a/plugins/kimchi/po/zh_CN.po b/plugins/kimchi/po/zh_CN.po deleted file mode 100644 index fc6dd84..0000000 --- a/plugins/kimchi/po/zh_CN.po +++ /dev/null @@ -1,2186 +0,0 @@ -# i18n portable object for kimchi. -# Copyright (C) IBM, Corp. 2013-2014 -# ShaoHe Feng <shaohef@linux.vnet.ibm.com>, 2013-04-18. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2013-06-27 10:48+0000\n" -"Last-Translator: ShaoHe Feng <shaohef@linux.vnet.ibm.com>\n" -"Language-Team: ShaoHe Feng <shaohef@linux.vnet.ibm.com>\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: zh_CN\n" -"Generated-By: pygettext.py 1.5\n" -"X-Poedit-Country: CHINA\n" -"X-Poedit-Language: Chinese\n" -"X-Poedit-SourceCharset: utf-8\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "������������ %(value)s" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "������'%(task)s������%(seconds)s������" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "���������������LDAP���������������%(user_id)s������" - -msgid "Unknown \"_cap\" specified" -msgstr "������������\"_cap\"" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "\"_passthrough\"���������\"true\"������\"false\"" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "\"_passthrough_affected_by\"���������������������������������" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "������������������������������������%(err)s" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "��������������� %(device)s ������������������" - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "���������������������������%(filename)s" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "������������������������������%(filename)s������������������������JSON������������������" - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "������������ %(portal)s ������iSCSI���������������������������%(err)s" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "������������iSCSI������%(host)s������������%(target)s���" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "������������ISO������ %(filename)s" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "ISO������%(filename)s���������������" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "ISO������%(filename)s���������������El Torito���������������" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "���ISO������%(filename)s������������������El Torito������������������" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "ISO������%(filename)s���El Torito������������������������" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "������������ISO������%(filename)s���������������" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "ISO������%(filename)s���������������������������" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" -"hypervisor������������ISO������%(filename)s���������������������ISO������/var/lib/libvirt���" -"���������������'%(user)s'���������������������������������'%(user)s'���������������ISO������������������" -"������������������������������������������ 'chmod -R o+x '���������������������������%(err)s" - -msgid "An error occurred when probing image OS information." -msgstr "������������������������������������������������" - -msgid "No OS information found in given image." -msgstr "���������������������������������������������������������" - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "������������������������ %(filename)s" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "���������������������������������������%(filename)s���������������������" - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "���������%(name)s������������" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "���������%(name)s���������" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" -"��������������������� %(name)s ������������������ %(new_name)s ������������������������������������" -"������" - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "������������������������������������%(name)s���������" - -msgid "Remote ISO image is not supported by this server." -msgstr "���������������������������ISO���������" - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "��������� %(name)s ���������������" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������%(err)s" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������%(err)s" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������%(err)s" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "���������%(name)s���������������������������" - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "������������������������URI %(value)s" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "���������������������������URI %(value)s" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "������������������������������Spice������VNC" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "������������������������������������������IPv4���IPv6���������" - -msgid "Specify a template to create a virtual machine from" -msgstr "������������������������������������" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "��������������������� %(name)s. ���������%(err)s" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������%(err)s" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "��������������������� %(name)s������������%(err)s" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������%(err)s" - -msgid "User name list must be an array" -msgstr "������������������������������������" - -msgid "User name must be a string" -msgstr "���������������������������������" - -msgid "Group name list must be an array" -msgstr "������������������������������������" - -msgid "Group name must be a string" -msgstr "���������������������������������������" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "������'%(users)s'���������" - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "���������'%(groups)s'���������" - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������%(err)s" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "��������������������� %(name)s������������������������%(err)s" - -msgid "The guest console password must be a string." -msgstr "���������������������������������������������������" - -msgid "The life time for the guest console password must be a number." -msgstr "������������������������������������������������������������" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "���������'%(name)s'���������������������������������" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "���������������'%(name)s'���������������������������������" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "���������������������������'%(name)s'������������������%(err)s" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "���������%(vmid)s���������������������������������%(dev_name)s���" - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "������������%(dev_name)s������������������������������������" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" -"���������IOMMU groups���������PCI pass through������IOMMU group������������������������������" -"BIOS������������Intel VT-d ������ AMD IOMMU ���������������������������������������IOMMU���������" -"Intel CPU������������/boot/grub2/grub.conf���������������������intel_iommu=on���������AMD " -"CPU������������iommu=pt iommu=1���" - -msgid "\"name\" should be a device name string" -msgstr "\"name\"���������������������������������������" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "��������� %(name)s ��������������� %(iface)s" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "������������%(name)s���������������%(network)s���������" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "���������������������������������������" - -msgid "Network name for virtual machine interface must be a string" -msgstr "������������������������������������������������" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "���������������������������������������������" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "���������������������������������������������" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "������ %(name)s ������������" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "��������� %(template)s ��������������� '%(network)s' ���������" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "��������� %(template)s ������������������ '%(pool)s' ���������" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "��������� %(template)s ������������������ '%(pool)s' ������������" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "���CDROM��������������� '%(param)s' ������" - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "��������� %(template)s ��������������� '%(network)s' ������������" - -msgid "Template name must be a string" -msgstr "���������������������������������������" - -msgid "Template icon must be a path to the image" -msgstr "���������������������������������������������������" - -msgid "Template distribution must be a string" -msgstr "������������������������������������������" - -msgid "Template distribution version must be a string" -msgstr "���������������������������������������������������" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "CPU���������������������������0���������" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "���������������MB���������������������������������512���������" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "���������CDROM������������������������������������ISO������" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "������������������������������������URI %(value)s" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "������������ISO���������������������������CDROM������������������" - -msgid "All networks for the template must be specified in a list." -msgstr "������������������������������������������������" - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "���������������������iSCSI������SCSI������������������������������������" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "���%(volume)s���������������%(pool)s���" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "������������������������������%(err)s" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "���������������%(err)s���������������������" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "������������������������1GB���" - -msgid "Template base image must be a valid local image file" -msgstr "������������������������������������������������������������" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "������������������������%(path)s������" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "CPU������������VCPUs������������sockets, cores ������threads���" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "CPU���������������������������������������������������������" - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" -"���������������������������������������������������bochs, cloop, cow, dmg, qcow, qcow2, qed, " -"raw, vmdk, vpc���" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "���������%(name)s������������" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "���������%(name)s���������" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "���������������%(name)s������%(item)s" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "������������������������������ %(name)s" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "������������������������ ��������� %(err)s" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "��������������������� %(name)s������������ %(err)s" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "���������������������%(name)s��������������������������� %(err)s" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������ %(err)s" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������ %(err)s" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������ %(err)s" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "������������NFS������������������������������%(path)s������������������������" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "������������NFS������������������������������%(path)s������" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "������������������������������%(type)s" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "���������������XML���%(pool)s���������������" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "������������������������dir���netfs���logical���iscsi���isci������kimchi-iso" - -msgid "Storage pool path must be a string" -msgstr "���������������������������������" - -msgid "Storage pool host must be a IP or hostname" -msgstr "������������������������������IP���������������" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "������������������������������������������������������" - -msgid "Storage pool devices parameter must be a list" -msgstr "������������������������������������������" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "iSCSI������������������IQN������������������" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "���������������������������������������1���65535���������������" - -msgid "iSCSI target username must be a string" -msgstr "iSCSI���������������������������������������" - -msgid "iSCSI target password must be a string" -msgstr "iSCSI������������������������������������" - -msgid "Specify name and type to create a storage pool" -msgstr "������������������������������������" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "%(disk)s ���������������������/������������������������������������%(pool)s���" - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "���������������������%(pool)s���������������������%(err)s" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "������������������������������������������������" - -msgid "The SCSI host adapter name must be a string." -msgstr "SCSI���������������������������������������" - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "���������kimchi_isos������������������" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "������������NFS���������%(name)s���NFS���������%(server)s���������������" - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "������������NFS���������%(name)s���NFS���������%(server)s���������������" - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "���������������������%(name)s������������������������������������" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "���������������������%(name)s������������������������������������" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "������'%(name)s'������������������������������������������������������������������" - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "������������������������������������������%(err)s���" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "���������%(name)s������������" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "���������%(pool)s������������������%(name)s" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "���������������������%(volume)s������������������%(pool)s ������������" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "���������������%(volume)s������������%(item)s" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "���������������������������������������%(pool)s������������" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "������������������%(pool)s������������������%(name)s������������%(err)s" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "������������������%(pool)s������������������������������%(err)s" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������%(err)s" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s������������%(err)s" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "���������������������%(name)s���������������������%(err)s" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "������������%(type)s������������������������������" - -msgid "Storage volume name must be a string" -msgstr "������������������������������������" - -msgid "Storage volume allocation must be an integer number" -msgstr "���������������������������������" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" -"������������������������������������������������bochs, cloop, cow, dmg, qcow, qcow2, qed, " -"raw, vmdk, vpc���" - -msgid "Storage volume requires a volume name" -msgstr "���������������������" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "���������������������������������������%(err)s" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "���������������%(param)s������������������������" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "������������%(param)s���������������" - -msgid "Storage volume capacity must be an integer number." -msgstr "������������������������������������" - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "���������URL���������http://���https://���ftp://���ftps://" - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "������������������%(url)s������������������������������������" - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "������������������'%(pool)s'���������������'%(name)s'���������������������%(err)s" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "������%(name)s���������" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "������%(name)s������������" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "������%(name)s���������" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "���������%(network)s���������������%(subnet)s������" - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "������������������������������������������������������%(name)s" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "���������������������������%(name)s" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "���������%(network)s���������������%(iface)s������������" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "���������������������������������������������bonding���������������������" - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "������������������%(name)s������������%(err)s" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "���������������'%(name)s'������������������������IP���������������" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "���������������������������������NAT���������" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "���������������������������IP������������������������������������������������" - -msgid "Network interface must be a string" -msgstr "������������������������������������" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "������VLAN������������1���4094���������������" - -msgid "Specify name and type to create a Network" -msgstr "���������������������������������" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "������������������%(name)s������VLAN���trunk���������" - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "������������������������ %(iface)s���%(err)s���" - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "������������%(iface)s���������������������������������������������" - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "������������%(name)s������������������%(err)s" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "������������%(name)s���������" - -msgid "Debug report tool not found in system" -msgstr "���������������������������������" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "������������������������%(name)s������������%(err)s" - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "������������������������%(name)s���������������" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "������������������������%(name)s������������%(err)s" - -msgid "You should give a name for the debug report file." -msgstr "������������������������%(name)s������������%(err)s" - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" -"������������������������������������������������������������������������������������('_')���������������('-')" -"������������������" - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "���������\"'%(name)s\"���������������������������������������������������������" - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "���������������%(server)s������Kimchi������" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "������������'%(name)s'���������" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "������������������������%(name)s" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "������������������������������������������" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "������������������������������������������" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "������������������������'%(name)s'" - -msgid "Conflicting flag filters specified." -msgstr "flag filters���������" - -msgid "No packages marked for update" -msgstr "������������������������������" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "���������%(name)s������������������������" - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "���������������������������������������������������������%(err)s" - -msgid "There is no compatible package manager for this system." -msgstr "������������������������������������������" - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "���������URI %(uri)s" - -msgid "Unable to choose a virtual machine name" -msgstr "���������������������������������" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "������������������������������������������'cdrom'���'disk'" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "������'%(value)s'���������������������������/������������" - -msgid "Only CDROM path can be update." -msgstr "���������CDROM���������������" - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "������������%(dev_name)s������������%(vm_name)s������������" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "������������������������������������%(error)s" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "������������������������������%(error)s" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "������������������������������%(error)s" - -msgid "Do not support IDE device hot plug" -msgstr "���������IDE������������������" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "���������������������������������������������������������������������������/���������" - -msgid "Specify path to update virtual machine disk" -msgstr "������������������������������������" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "������������������%(type)s���������������������%(limit)s" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "���������������������������/������������������������������������������%(error)s" - -msgid "Volume already in use by other virtual machine." -msgstr "���������������������������������������" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "���������������������������������������������������������/���������������������" - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "���������%(format)s���������������������������%(type)s" - -msgid "YUM Repository ID must be one word only string." -msgstr "YUM������������ID������������������������������������������" - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "������������URL���������http://��� ftp:// ��� file://" - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "������������������������������������������������������������������" - -msgid "Distribution to DEB repository must be a string" -msgstr "DEB���������������������������������������������" - -msgid "Components to DEB repository must be listed in a array" -msgstr "DEB������������������������������������������" - -msgid "Components to DEB repository must be a string" -msgstr "DEB���������������������������������������" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "YUM���������������������������������������" - -msgid "GPG check must be a boolean value." -msgstr "GPG������������������������������" - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "GPG������������������������ASCII���������������.asc������������URL" - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "������������������������%(repo_id)s" - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "������������%(repo_id)s������������" - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "������������������������������������������" - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "������������%(repo_id)s���������������" - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "������������%(repo_id)s���������������" - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "������������������������%(repo_id)s" - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "������������������������������������%(repo_file)s" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "���������������������������������������������DEB���������" - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "������������������������%(repo_id)s" - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "������������������������%(repo_id)s" - -msgid "YUM Repository ID already exists" -msgstr "YUM������ID������������" - -msgid "YUM Repository name must be a string" -msgstr "YUM������������������������������������" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "������������������������������������'%(err)s'" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "���������������������������������������������'%(err)s'" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "������������������������������������'%(err)s'" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "������������������������������������'%(err)s'" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "���������������������������������: %(items)s" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "���������'%(vm)s'���������������������������������" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "������������������'%(vm)s'������������'%(name)s'������������%(err)s" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "������'%(name)s'������������������'%(vm)s'������" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "������������������'%(vm)s'������������'%(name)s'������������%(err)s" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "���������������������'%(vm)s'���������������������%(err)s" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "���������������������'%(vm)s'������'%(name)s'������������%(err)s" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "���������������������'%(vm)s'������������������������%(err)s" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "���������������������'%(vm)s'���������'%(name)s'������������%(err)s" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" -"������������������'%(vm)s'���������������������������������������'%(format)s'������������������������" -"���'qcow2'���������" - -msgid "The number of vCPUs is too large for this system." -msgstr "vCPUs������������������������������������" - -msgid "Invalid vCPU/topology combination." -msgstr "���������vCPU/topology���������" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "������������������������������������������CPU���������" - -msgid "ERROR CODE" -msgstr "���������" - -msgid "REASON" -msgstr "������" - -msgid "STACK" -msgstr "���������" - -msgid "Go to Homepage" -msgstr "������������" - -msgid "Create a New Virtual Machine" -msgstr "���������������������������" - -msgid "Virtual Machine Name" -msgstr "���������������" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "���������������������������������������������������������������������������������������������" - -msgid "Template" -msgstr "������" - -msgid "Please create a template first." -msgstr "������������������������" - -msgid "Create a Template" -msgstr "������������������" - -msgid "Please choose a template." -msgstr "������������������" - -msgid "OS" -msgstr "������������" - -msgid "OS Version" -msgstr "������������������" - -msgid "CPUS" -msgstr "���������������" - -msgid "Memory" -msgstr "������" - -msgid "Create" -msgstr "������" - -msgid "Creating..." -msgstr "������������..." - -msgid "Cancel" -msgstr "������" - -msgid "Edit Guest" -msgstr "���������������" - -msgid "General" -msgstr "������" - -msgid "Storage" -msgstr "������" - -msgid "Interface" -msgstr "������������" - -msgid "Permission" -msgstr "������" - -msgid "Host PCI Device" -msgstr "������PCI������" - -msgid "Snapshot" -msgstr "������" - -msgid "Name" -msgstr "������" - -msgid "CPUs" -msgstr "���������������" - -msgid "Memory (MB)" -msgstr "������(MB)" - -msgid "Icon" -msgstr "������" - -msgid "Device" -msgstr "������������" - -msgid "Path" -msgstr "������" - -msgid "Network" -msgstr "������" - -msgid "Type" -msgstr "������" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "���������������������������������" - -msgid "Selected system users and groups" -msgstr "���������������������������������" - -msgid "User" -msgstr "������" - -msgid "All" -msgstr "������" - -msgid "To Add" -msgstr "���������" - -msgid "Added" -msgstr "���������" - -msgid "filter" -msgstr "���������" - -msgid "Product" -msgstr "������" - -msgid "Vendor" -msgstr "������" - -msgid "Created" -msgstr "���������" - -msgid "Save" -msgstr "������" - -msgid "Replace" -msgstr "������" - -msgid "Detach" -msgstr "������" - -msgid "revert" -msgstr "������" - -msgid "Start" -msgstr "������" - -msgid "Reset" -msgstr "������" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "������������" - -msgid "Actions" -msgstr "������" - -msgid "Connect" -msgstr "���������" - -msgid "Clone" -msgstr "������������" - -msgid "Edit" -msgstr "������" - -msgid "Shut Down" -msgstr "������" - -msgid "Delete" -msgstr "������" - -msgid "CPU" -msgstr "���������" - -msgid "Disk I/O" -msgstr "������I/O" - -msgid "Network I/O" -msgstr "������I/O" - -msgid "Livetile" -msgstr "������" - -msgid "No guests found." -msgstr "���������������������" - -msgid "Add a Storage Device to VM" -msgstr "������������������������������������" - -msgid "Device Type" -msgstr "������������" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "������������������������������������������\"cdrom\"���\"disk\"��� " - -msgid "Storage Pool" -msgstr "���������" - -msgid "Storage pool which volume located in" -msgstr "���������������������������" - -msgid "Storage Volume" -msgstr "���������" - -msgid "Storage volume to be attached" -msgstr "���������������������" - -msgid "File Path" -msgstr "������������" - -msgid "The ISO file path in the server for CDROM." -msgstr "������������CDROM������������ISO������������" - -msgid "Attach" -msgstr "������" - -msgid "Shut down" -msgstr "������" - -msgid "Restart" -msgstr "������" - -msgid "Basic Information" -msgstr "������������" - -msgid "OS Distro" -msgstr "���������������������" - -msgid "OS Code Name" -msgstr "������������������" - -msgid "Processor" -msgstr "���������" - -msgid "CPU(s)" -msgstr "CPU(s)" - -msgid "System Statistics" -msgstr "������������������" - -msgid "Software Updates" -msgstr "������������" - -msgid "Update Progress" -msgstr "������������" - -msgid "Repositories" -msgstr "������������" - -msgid "Debug Reports" -msgstr "������������������" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "���������������������������������������������" - -msgid "This field is required." -msgstr "������������������" - -msgid "Log in" -msgstr "������" - -msgid "Logging in..." -msgstr "���������..." - -msgid "Host" -msgstr "������" - -msgid "Guests" -msgstr "���������" - -msgid "Templates" -msgstr "������" - -msgid "Failed to get application configuration" -msgstr "������������������������" - -msgid "This is not a valid Linux path" -msgstr "������������������������Linux������" - -msgid "This is not a valid URL." -msgstr "������������������������URL" - -msgid "No such data available." -msgstr "���������������������" - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" -"������������������������������������������������������������������������������������������HTTP���������������%1" - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "������������" - -msgid "OK" -msgstr "������" - -msgid "Confirm" -msgstr "������" - -msgid "Warning" -msgstr "������" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "������������..." - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "������" - -msgid "Detailed message:" -msgstr "���������������" - -msgid "No ISO found" -msgstr "������������ISO������" - -msgid "This is not a valid ISO file." -msgstr "������������������������ISO������" - -msgid "This may take a long time. Do you want to continue?" -msgstr "���������������������������������������" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "������������������������������������������" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "���������������������������������������������" - -msgid "Max:" -msgstr "���������" - -msgid "Utilization" -msgstr "���������" - -msgid "Available" -msgstr "������������" - -msgid "Read Rate" -msgstr "���������" - -msgid "Write Rate" -msgstr "���������" - -msgid "Received" -msgstr "������" - -msgid "Sent" -msgstr "������" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "���������������������������������������������������������������������������/���������" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "���������������������������������������������������������������" - -msgid "ID" -msgstr "���������" - -msgid "Base URL" -msgstr "������URL" - -msgid "Is Mirror" -msgstr "���������������" - -msgid "URL Args" -msgstr "URL������" - -msgid "Enabled" -msgstr "���������" - -msgid "GPG Check" -msgstr "GPG������" - -msgid "GPG Key" -msgstr "GPG���" - -msgid "Add" -msgstr "������" - -msgid "Remove" -msgstr "������" - -msgid "Enable" -msgstr "������" - -msgid "Disable" -msgstr "������" - -msgid "Package Name" -msgstr "���������������" - -msgid "Version" -msgstr "������" - -msgid "Architecture" -msgstr "������������" - -msgid "Repository" -msgstr "������������" - -msgid "Update All" -msgstr "������������" - -msgid "Updating..." -msgstr "������������..." - -msgid "Failed to retrieve packages update information." -msgstr "������������������������������������" - -msgid "Failed to update package(s)." -msgstr "���������������������" - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "���������������������������������������������������������������������" - -msgid "Generated Time" -msgstr "������������" - -msgid "Generate" -msgstr "������" - -msgid "Generating..." -msgstr "������������..." - -msgid "Rename" -msgstr "���������" - -msgid "Download" -msgstr "������" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "������������������������������������������������������('_')������������('-')" - -msgid "Pending..." -msgstr "������������..." - -msgid "Report name is the same as the original one." -msgstr "������������������������������������" - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "���������������������������������������������������������������������������������" - -msgid "Power off Confirmation" -msgstr "������������������" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "������������������������������������������������������������������������������������������������" - -msgid "Reset Confirmation" -msgstr "������������" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "������������������������������������������������������������������������������������������������������" - -msgid "Shut Down Confirmation" -msgstr "������������" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "���������������������������������������������������������������������������������" - -msgid "Virtual Machine delete Confirmation" -msgstr "���������������������" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "������������������������������������������������������������������������������������" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" -"������������������������SCSI������iSCSI���������������������������������������������������������������������" -"������������������������������������������������������������������������������������������������������" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "CDROM���������������������������������������������������������������" - -msgid "Attaching..." -msgstr "������������" - -msgid "Replacing..." -msgstr "������������..." - -msgid "Successfully attached!" -msgstr "������������" - -msgid "Successfully replaced!" -msgstr "������������" - -msgid "Successfully detached!" -msgstr "������������" - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "���������������������������������������������������������������������������������������?" - -msgid "interface:" -msgstr "���������" - -msgid "address:" -msgstr "���������" - -msgid "link_type:" -msgstr "���������������" - -msgid "block:" -msgstr "������" - -msgid "drive_type:" -msgstr "���������������" - -msgid "model:" -msgstr "���������" - -msgid "Affected devices:" -msgstr "���������������������" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "VLAN ������������������1���4094������" - -msgid "unavailable" -msgstr "������������" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "������������������������������������������������������������������" - -msgid "Create a network" -msgstr "������������������" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"���������" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "���������������������������������������������" - -msgid "This storage pool is empty." -msgstr "���������������������" - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "������������������������������������������������������������������������������������" - -msgid "SCSI Fibre Channel" -msgstr "SCSI������������" - -msgid "No SCSI adapters found." -msgstr "������������SCSI���������" - -msgid "Loading iSCSI targets..." -msgstr "������iSCSI������..." - -msgid "No iSCSI found. Please input one." -msgstr "������������iSCSI,������������������" - -msgid "Failed to load iSCSI targets." -msgstr "������iSCSI���������������" - -msgid "The storage pool name can not be blank." -msgstr "���������������������������������" - -msgid "The storage pool path can not be blank." -msgstr "���������������������������������" - -msgid "NFS server mount path can not be blank." -msgstr "NFS������������������������������������" - -msgid "Invalid NFS mount path." -msgstr "���������NFS���������������" - -msgid "No logical device selected." -msgstr "���������������������������" - -msgid "The iSCSI target can not be blank." -msgstr "iSCSI���������������������" - -msgid "Server name can not be blank." -msgstr "������������������������" - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "������������������������������������������IP���������������������������������" - -msgid "Looking for available partitions ..." -msgstr "��������������������� ..." - -msgid "No available partitions found." -msgstr "���������������������" - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "���������������������������������������������������������������������������������������������������" - -msgid "Unable to retrieve partitions information." -msgstr "���������������������������" - -msgid "In progress..." -msgstr "������������..." - -msgid "Failed!" -msgstr "���������" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "CDROM���������������������������������/������������������������������" - -msgid "Disk pool or volume cannot be blank." -msgstr "���������������������������" - -#, fuzzy -msgid "Filter" -msgstr "���������" - -msgid "Network Name" -msgstr "������������" - -msgid "State" -msgstr "������" - -msgid "Network Type" -msgstr "������������" - -msgid "Address Space" -msgstr "������������" - -msgid "Name should not contain '/' and '\"'." -msgstr "������������������������/������'\"'���" - -msgid "Isolated: no external network connection" -msgstr "������: ������������������������" - -msgid "NAT: outbound physical network connection only" -msgstr "NAT: ���������������������������������������" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "���������������������������������������������������������" - -msgid "(No interfaces found)" -msgstr "(������������������������)" - -msgid "Destination" -msgstr "������������" - -msgid "Enable VLAN" -msgstr "������VLAN" - -msgid "VLAN ID" -msgstr "VLAN���" - -msgid "Stop" -msgstr "������" - -msgid "Generate a New Debug Report" -msgstr "������������������������������" - -msgid "Report Name" -msgstr "���������������" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������������������������������ ('_') ���������������'-'���" - -msgid "Rename a Debug Report" -msgstr "���������������������������" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "������������������������������������������������������������������������������������(\"-\")���" - -msgid "Submit" -msgstr "������" - -msgid "Add a Repository" -msgstr "������������������������" - -msgid "Identifier" -msgstr "���������" - -msgid "Single word, unique identifier for the repository." -msgstr "���������������������������������������" - -msgid "Textual name for the repository." -msgstr "���������������������������" - -msgid "URL" -msgstr "URL" - -msgid "Required Field" -msgstr "���������������" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "���������������URL���������������������http���ftp������file" - -msgid "Repository is a mirror" -msgstr "���������������������������" - -msgid "Distribution" -msgstr "���������" - -msgid "Distribution of the DEB repository." -msgstr "DEB������������������" - -msgid "Components" -msgstr "������" - -msgid "List of components in DEB repository." -msgstr "DEB������������������������" - -msgid "Edit Repository" -msgstr "������������������" - -msgid "Mirror List URL" -msgstr "������������URL" - -msgid "Yes" -msgstr "���" - -msgid "No" -msgstr "���" - -msgid "Capacity" -msgstr "������" - -msgid "Allocated" -msgstr "���������" - -msgid "Location" -msgstr "������" - -msgid "Device path" -msgstr "������������" - -msgid "active" -msgstr "���������" - -msgid "inactive" -msgstr "���������" - -msgid "Deactivate" -msgstr "������" - -msgid "Activate" -msgstr "������" - -msgid "Add Volume" -msgstr "���������" - -msgid "Extend" -msgstr "������" - -msgid "Undefine" -msgstr "������������" - -msgid "Format" -msgstr "������" - -msgid "Allocation" -msgstr "������" - -msgid "Define a New Storage Pool" -msgstr "���������������������������" - -msgid "Storage Pool Name" -msgstr "���������������" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "���������������������������������������������������������������" - -msgid "Storage Pool Type" -msgstr "���������������" - -msgid "Storage Path" -msgstr "������������" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "������������������.���������������������������������������" - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "������������������������KIMCHI���������������������������������������������" - -msgid "NFS Server IP" -msgstr "NFS���������IP" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "NFS���������IP���������������������������������������������������������������������" - -msgid "NFS Path" -msgstr "NFS ������" - -msgid "The NFS exported path on NFS server." -msgstr "NFS���������������������NFS������" - -msgid "iSCSI Server" -msgstr "iSCSI���������" - -msgid "Server" -msgstr "���������" - -msgid "Port" -msgstr "������" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "iSCSI���������IP������������������ ���������������" - -msgid "Target" -msgstr "������" - -msgid "The iSCSI target on iSCSI server" -msgstr "iSCSI������" - -msgid "Add iSCSI Authentication" -msgstr "������ISCSI������" - -msgid "iSCSI Authentication" -msgstr "iSCSI������" - -msgid "User Name" -msgstr "���������" - -msgid "Password" -msgstr "������" - -msgid "SCSI Adapter" -msgstr "SCSI���������" - -msgid "Please, wait..." -msgstr "���������..." - -msgid "Add a Volume to Storage Pool" -msgstr "���������������������������" - -msgid "Fetch from remote URL" -msgstr "���������URL������" - -msgid "Enter the remote URL here." -msgstr "���������������������URL���" - -msgid "Upload a file" -msgstr "������������������" - -msgid "Choose the file you want to upload." -msgstr "������������������������������" - -msgid "Add Template" -msgstr "������������" - -msgid "Where is the source media for this template? " -msgstr "������������������������������" - -msgid "Local ISO Image" -msgstr "������ISO������" - -msgid "Local Image File" -msgstr "������������������" - -msgid "Remote ISO Image" -msgstr "������ISO������" - -msgid "Search ISOs" -msgstr "������ISO" - -msgid "The following ISOs are available:" -msgstr "������ISO������������" - -msgid "OS: " -msgstr "��������������� " - -msgid "Version: " -msgstr "��������� " - -msgid "Size: " -msgstr "���������" - -msgid "Search more ISOs" -msgstr "������������ISO" - -msgid "Create Templates from Selected ISO" -msgstr "������������ISO���������������" - -msgid "I want to use a specific ISO file" -msgstr "������������ISO������" - -msgid "Loading default remote ISOs ..." -msgstr "���������������������ISOs ..." - -msgid "Arch: " -msgstr "���������������" - -msgid "I want to use a custom URL" -msgstr "���������������������������URL" - -msgid "Edit Template" -msgstr "������������" - -msgid "CDROM" -msgstr "������" - -msgid "Image File" -msgstr "������������" - -msgid "Graphics" -msgstr "������" - -msgid "Disk(GB)" -msgstr "������(GB)" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "CPU������" - -msgid "Manually set CPU topology" -msgstr "������������CPU������" - -msgid "Cores" -msgstr "���������" - -msgid "Threads" -msgstr "������" - -msgid "No templates found." -msgstr "������������������" - -#~ msgid "Delete is not allowed for %(resource)s" -#~ msgstr "���������������%(resource)s" - -#~ msgid "%(resource)s does not implement update method" -#~ msgstr "���������������%(resource)s" - -#~ msgid "Create is not allowed for %(resource)s" -#~ msgstr "���������������%(resource)s" - -#~ msgid "Unable to parse JSON request" -#~ msgstr "������������JSON������" - -#~ msgid "This API only supports JSON" -#~ msgstr "������API���������JSON" - -#~ msgid "Parameters does not match requirement in schema: %(err)s" -#~ msgstr "���������������������������������%(err)s" - -#~ msgid "You don't have permission to perform this operation." -#~ msgstr "������������������������������������" - -#~ msgid "Datastore is not initiated in the model object." -#~ msgstr "���������model������������������������������" - -#~ msgid "Unable to start task due error: %(err)s" -#~ msgstr "������������%(err)s������������������" - -#~ msgid "" -#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" -#~ msgstr "������'%(username)s'������������������.[���������������%(code)s]" - -#~ msgid "You are not authorized to access Kimchi" -#~ msgstr "������������������������Kimchi" - -#~ msgid "Specify %(item)s to login into Kimchi" -#~ msgstr "������������Kimchi���%(item)s" - -#~ msgid "Invalid LDAP configuration: %(item)s : %(value)s" -#~ msgstr "���������LDAP���������%(item)s : %(value)s" - -#~ msgid "Unable to find %(item)s in datastore" -#~ msgstr "���������������������������%(item)s" - -#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" -#~ msgstr "������'%(cmd)s'������%(seconds)s���������������" - -#~ msgid "Peers" -#~ msgstr "���������" - -#~ msgid "Searching" -#~ msgstr "������������" - -#~ msgid "No peers found." -#~ msgstr "������������������������" - -#~ msgid "Help" -#~ msgstr "������" - -#~ msgid "About" -#~ msgstr "������" - -#~ msgid "Log out" -#~ msgstr "������" - -#~ msgid "Version:" -#~ msgstr "���������" - -#~ msgid "Session timeout, please re-login." -#~ msgstr "���������������������������������" diff --git a/plugins/kimchi/po/zh_TW.po b/plugins/kimchi/po/zh_TW.po deleted file mode 100644 index 90045b5..0000000 --- a/plugins/kimchi/po/zh_TW.po +++ /dev/null @@ -1,2138 +0,0 @@ -# English translations for kimchi package. -# Copyright (C) 2013 ORGANIZATION -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-01 16:11-0300\n" -"PO-Revision-Date: 2013-07-11 17:32-0400\n" -"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" -"Language-Team: English\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: zh_TW\n" -"Generated-By: pygettext.py 1.5\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#, python-format -msgid "Unknown parameter %(value)s" -msgstr "" - -#, python-format -msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." -msgstr "" - -#, python-format -msgid "User %(user_id)s not found with given LDAP settings." -msgstr "" - -msgid "Unknown \"_cap\" specified" -msgstr "" - -msgid "\"_passthrough\" should be \"true\" or \"false\"" -msgstr "" - -msgid "\"_passthrough_affected_by\" should be a device name string" -msgstr "" - -#, python-format -msgid "Error while getting block devices. Details: %(err)s" -msgstr "���������������������������������������������������%(err)s" - -#, python-format -msgid "Error while getting block device information for %(device)s." -msgstr "������ %(device)s ���������������������������������������" - -#, python-format -msgid "Unable to find distro file: %(filename)s" -msgstr "��������� distro ���������%(filename)s" - -#, python-format -msgid "" -"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." -msgstr "������������ distro ���������%(filename)s������������������ JSON ���������" - -#, python-format -msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" -msgstr "������������ iSCSI ������������ %(portal)s������������������%(err)s" - -#, python-format -msgid "Unable to login to iSCSI host %(host)s target %(target)s" -msgstr "������������ iSCSI ������ %(host)s ������ %(target)s" - -#, python-format -msgid "Unable to find ISO file %(filename)s" -msgstr "" - -#, python-format -msgid "The ISO file %(filename)s is not bootable" -msgstr "ISO ������ %(filename)s ������������" - -#, python-format -msgid "The ISO file %(filename)s does not have a valid El Torito boot record" -msgstr "ISO ������ %(filename)s ��������������� El Torito ������������" - -#, python-format -msgid "Invalid El Torito validation entry in ISO %(filename)s" -msgstr "ISO %(filename)s ��������������� El Torito ������������" - -#, python-format -msgid "Invalid El Torito boot indicator in ISO %(filename)s" -msgstr "ISO %(filename)s ��������������� El Torito ���������������" - -#, python-format -msgid "Unexpected volume type for primary volume in ISO %(filename)s" -msgstr "ISO %(filename)s ���������������������������������������������" - -#, python-format -msgid "Bad format while reading volume descriptor in ISO %(filename)s" -msgstr "������ ISO %(filename)s ���������������������������������������������" - -#, python-format -msgid "" -"The hypervisor doesn't have permission to use this ISO %(filename)s. " -"Consider moving it under /var/lib/libvirt, or set the search permission to " -"file access control lists for '%(user)s' user if possible, or add the '%" -"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " -"'path_to_iso'.Details: %(err)s" -msgstr "" -"Hypervisor ��������������� ISO %(filename)s ��������������������������������������� /var/lib/" -"libvirt ������������������������������'%(user)s' ���������������������������������������������������������" -"��� '%(user)s' ��������� ISO ������������������������������������������������������ 'chmod -R o+x " -"'path_to_iso'������������������%(err)s" - -msgid "An error occurred when probing image OS information." -msgstr "" - -msgid "No OS information found in given image." -msgstr "" - -#, python-format -msgid "Unable to read image file %(filename)s" -msgstr "" - -#, python-format -msgid "" -"Image file must be an existing file on system. %(filename)s is not a valid " -"input." -msgstr "" - -#, python-format -msgid "Virtual machine %(name)s already exists" -msgstr "������������ %(name)s ���������" - -#, python-format -msgid "Virtual machine %(name)s does not exist" -msgstr "������������ %(name)s ���������" - -#, python-format -msgid "" -"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " -"in use or the virtual machine is not powered off." -msgstr "" - -#, python-format -msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" -msgstr "��������������������������������� %(name)s ���������" - -msgid "Remote ISO image is not supported by this server." -msgstr "��������������������������� ISO ������������" - -#, python-format -msgid "Screenshot is not supported on virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Unable to create virtual machine %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to update virtual machine %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to connect to powered off virtual machine %(name)s." -msgstr "" - -msgid "Virtual machine name must be a string without slashes (/)" -msgstr "" - -#, python-format -msgid "Invalid template URI %(value)s specified for virtual machine" -msgstr "" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for virtual machine" -msgstr "" - -msgid "Supported virtual machine graphics are Spice or VNC" -msgstr "" - -msgid "Graphics address to listen on must be IPv4 or IPv6" -msgstr "������������������������������������ IPv4 ��� IPv6" - -msgid "Specify a template to create a virtual machine from" -msgstr "���������������������������������������" - -#, python-format -msgid "Unable to start virtual machine %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" -msgstr "������������������������������ %(name)s������������������%(err)s" - -msgid "User name list must be an array" -msgstr "" - -msgid "User name must be a string" -msgstr "���������������������������" - -msgid "Group name list must be an array" -msgstr "" - -msgid "Group name must be a string" -msgstr "���������������������������" - -#, python-format -msgid "User(s) '%(users)s' do not exist" -msgstr "��������� '%(users)s' ������������" - -#, python-format -msgid "Group(s) '%(groups)s' do not exist" -msgstr "��������� '%(groups)s' ������������" - -#, python-format -msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -#, python-format -msgid "" -"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -msgid "The guest console password must be a string." -msgstr "" - -msgid "The life time for the guest console password must be a number." -msgstr "" - -#, python-format -msgid "Virtual machine '%(name)s' must be stopped before cloning it." -msgstr "" - -#, python-format -msgid "Insufficient disk space to clone virtual machine '%(name)s'" -msgstr "" - -#, python-format -msgid "Unable to clone VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Invalid operation for non-persistent virtual machine %(name)s" -msgstr "" - -#, python-format -msgid "Cannot suspend VM '%(name)s' because it is not running." -msgstr "" - -#, python-format -msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Cannot resume VM '%(name)s' because it is not paused." -msgstr "" - -#, python-format -msgid "Unable to resume VM '%(name)s'. Details: %(err)s" -msgstr "" - -msgid "Memory assigned is higher then the maximum allowed in the host." -msgstr "" - -#, python-format -msgid "" -"VM '%(name)s' does not support live memory update. Update the memory with " -"the machine offline to enable this feature." -msgstr "" - -msgid "Only increase memory is allowed in active VMs" -msgstr "" - -msgid "" -"For live memory update, new memory value must be equal old memory value plus " -"multiples of 1024 Mib" -msgstr "" - -msgid "There are not enough free slots of 1024 Mib in the guest." -msgstr "" - -msgid "" -"Host's libvirt version does not support memory devices. Libvirt must be >= " -"1.2.14" -msgstr "" - -#, python-format -msgid "Error attaching memory device. Details: %(error)s" -msgstr "" - -#, python-format -msgid "" -"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." -msgstr "" - -#, python-format -msgid "The host device %(dev_name)s is not allowed to directly assign to VM." -msgstr "" - -msgid "" -"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " -"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " -"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " -"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " -"iommu=1." -msgstr "" - -msgid "\"name\" should be a device name string" -msgstr "" - -#, python-format -msgid "" -"The device %(name)s is probably in use by the host. Unable to attach it to " -"the guest." -msgstr "" - -#, python-format -msgid "Interface %(iface)s does not exist in virtual machine %(name)s" -msgstr "������ %(iface)s ������������������������ %(name)s ���" - -#, python-format -msgid "" -"Network %(network)s specified for virtual machine %(name)s does not exist" -msgstr "��������������� %(name)s ��������������� %(network)s ���������" - -msgid "Supported virtual machine interfaces type is only network" -msgstr "���������������������������������������������������" - -msgid "Network name for virtual machine interface must be a string" -msgstr "������������������������������������������������" - -msgid "Invalid network model card specified for virtual machine interface" -msgstr "���������������������������������������������������" - -msgid "Specify type and network to add a new virtual machine interface" -msgstr "������������������������������������������������" - -msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" -msgstr "" - -#, python-format -msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" -msgstr "" - -msgid "Invalid MAC Address" -msgstr "" - -msgid "Cannot change MAC address of a running virtual machine" -msgstr "" - -#, python-format -msgid "Template %(name)s already exists" -msgstr "������ %(name)s ���������" - -#, python-format -msgid "" -"Network '%(network)s' specified for template %(template)s does not exist" -msgstr "��������� %(template)s ��������������� '%(network)s' ���������" - -#, python-format -msgid "" -"Storage pool %(pool)s specified for template %(template)s does not exist" -msgstr "��������� %(template)s ������������������ '%(pool)s' ���������" - -#, python-format -msgid "Storage pool %(pool)s specified for template %(template)s is not active" -msgstr "��������� %(template)s ������������������ '%(pool)s' ������������������������" - -#, python-format -msgid "Invalid parameter '%(param)s' specified for CDROM." -msgstr "��� CDROM ��������������� '%(param)s' ���������" - -#, python-format -msgid "Network %(network)s specified for template %(template)s is not active" -msgstr "��������� %(template)s ��������������� %(network)s ������������������������" - -msgid "Template name must be a string" -msgstr "���������������������������" - -msgid "Template icon must be a path to the image" -msgstr "������������������������������������" - -msgid "Template distribution must be a string" -msgstr "���������������������������������" - -msgid "Template distribution version must be a string" -msgstr "���������������������������������" - -msgid "The number of CPUs must be an integer greater than 0" -msgstr "CPU ���������������������" - -msgid "Amount of memory (MB) must be an integer greater than 512" -msgstr "��������������� (MB) ��������������� 512 ���������" - -msgid "Template CDROM must be a local or remote ISO file" -msgstr "������ CDROM ������������������������ ISO ������" - -#, python-format -msgid "Invalid storage pool URI %(value)s specified for template" -msgstr "��������������������������� URI %(value)s ������" - -msgid "Specify an ISO image as CDROM or a base image to create a template" -msgstr "������ ISO ��������������� CDROM ���������������" - -msgid "All networks for the template must be specified in a list." -msgstr "���������������������������������������������������" - -msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" -msgstr "" - -#, python-format -msgid "The volume %(volume)s is not in storage pool %(pool)s" -msgstr "" - -#, python-format -msgid "Unable to create template due error: %(err)s" -msgstr "������������������������������������������%(err)s" - -#, python-format -msgid "Unable to delete template due error: %(err)s" -msgstr "������������������������������������������%(err)s" - -msgid "Disk size must be an integer greater than 1GB." -msgstr "" - -msgid "Template base image must be a valid local image file" -msgstr "������ CDROM ������������������������ ISO ������" - -#, python-format -msgid "Cannot identify base image %(path)s format" -msgstr "" - -msgid "" -"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " -"threads." -msgstr "" - -msgid "" -"When specifying CPU topology, each element must be an integer greater than " -"zero." -msgstr "" - -msgid "" -"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " -"qcow2, qed, raw, vmdk, vpc." -msgstr "" - -#, python-format -msgid "Storage pool %(name)s already exists" -msgstr "��������� %(name)s ���������" - -#, python-format -msgid "Storage pool %(name)s does not exist" -msgstr "��������� %(name)s ���������" - -#, python-format -msgid "Specify %(item)s in order to create the storage pool %(name)s" -msgstr "������ %(item)s ������������������ %(name)s" - -#, python-format -msgid "Unable to delete active storage pool %(name)s" -msgstr "��������������������������������� %(name)s" - -#, python-format -msgid "Unable to list storage pools. Details: %(err)s" -msgstr "���������������������������������������%(err)s" - -#, python-format -msgid "Unable to create storage pool %(name)s. Details: %(err)s" -msgstr "��������������������� %(name)s������������������%(err)s" - -#, python-format -msgid "" -"Unable to get number of storage volumes in storage pool %(name)s. Details: %" -"(err)s" -msgstr "��������������������� %(name)s ������������������������������������������%(err)s" - -#, python-format -msgid "Unable to activate storage pool %(name)s. Details: %(err)s" -msgstr "��������������������� %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" -msgstr "��������������������������� %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to delete storage pool %(name)s. Details: %(err)s" -msgstr "��������������������� %(name)s������������������%(err)s" - -#, python-format -msgid "" -"Unable to create NFS Pool as export path %(path)s may block during mount" -msgstr "������������ NFS ������������������������������������������������ %(path)s ���������������" - -#, python-format -msgid "Unable to create NFS Pool as export path %(path)s mount failed" -msgstr "������������ NFS ������������������������������ %(path)s ������������" - -#, python-format -msgid "Unsupported storage pool type: %(type)s" -msgstr "���������������������������������%(type)s" - -#, python-format -msgid "Error while retrieving storage pool XML to %(pool)s" -msgstr "" - -msgid "Storage pool name must be a string without slashes (/)" -msgstr "" - -msgid "" -"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" -"iso" -msgstr "" - -msgid "Storage pool path must be a string" -msgstr "������������������������������" - -msgid "Storage pool host must be a IP or hostname" -msgstr "������������������������ IP ���������������" - -msgid "Storage pool device must be the absolute path to the block device" -msgstr "" - -msgid "Storage pool devices parameter must be a list" -msgstr "������������������������������������" - -msgid "Target IQN of an iSCSI pool must be a string" -msgstr "iSCSI ������������������ IQN ���������������" - -msgid "Port of a remote storage server must be an integer between 1 and 65535" -msgstr "��������������������������������������������� 1 ��� 65535 ���������������" - -msgid "iSCSI target username must be a string" -msgstr "" - -msgid "iSCSI target password must be a string" -msgstr "" - -msgid "Specify name and type to create a storage pool" -msgstr "���������������������������������������" - -#, python-format -msgid "" -"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" -"s." -msgstr "%(disk)s ���������������������/������������������������������������������%(pool)s���" - -#, python-format -msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" -msgstr "" - -msgid "The parameter disks only can be updated for logical storage pool." -msgstr "������������������������������������������������������������" - -msgid "The SCSI host adapter name must be a string." -msgstr "SCSI ���������������������������������������" - -msgid "The storage pool kimchi_isos is reserved for internal use" -msgstr "��������� kimchi_isos ���������������������" - -#, python-format -msgid "" -"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "������������ NFS ��������� %(name)s���NFS ��������� %(server)s���������������" - -#, python-format -msgid "" -"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " -"unreachable." -msgstr "������������������ NFS ��������� %(name)s���NFS ��������� %(server)s���������������" - -#, python-format -msgid "" -"Unable to deactivate pool %(name)s as it is associated with some templates" -msgstr "��������������������������� %(name)s������������������������������������" - -#, python-format -msgid "Unable to delete pool %(name)s as it is associated with some templates" -msgstr "��������������������� %(name)s������������������������������������" - -#, python-format -msgid "" -"A volume group named '%(name)s' already exists. Please, choose another name " -"to create the logical pool." -msgstr "������ '%(name)s' ������������������������������������������������������������������������������" - -#, python-format -msgid "Unable to update database with deep scan information due error: %(err)s" -msgstr "������������������������������������������������������������������������%(err)s" - -#, python-format -msgid "Storage volume %(name)s already exists" -msgstr "������������ %(name)s ���������" - -#, python-format -msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" -msgstr "������������ %(name)s ��������������������� %(pool)s ���" - -#, python-format -msgid "" -"Unable to create storage volume %(volume)s because storage pool %(pool)s is " -"not active" -msgstr "" - -#, python-format -msgid "Specify %(item)s in order to create storage volume %(volume)s" -msgstr "������ %(item)s ��������������������� %(volume)s" - -#, python-format -msgid "" -"Unable to list storage volumes because storage pool %(pool)s is not active" -msgstr "������������������������������������������ %(pool)s ������������������������" - -#, python-format -msgid "" -"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" -"(err)s" -msgstr "������������������ %(pool)s ��������������������� %(name)s������������������%(err)s" - -#, python-format -msgid "" -"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" -msgstr "��������������������� %(pool)s ������������������������������������%(err)s" - -#, python-format -msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to delete storage volume %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to resize storage volume %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s ���������������������������%(err)s" - -#, python-format -msgid "Storage type %(type)s does not support volume create and delete" -msgstr "��������������� %(type)s ������������������������������" - -msgid "Storage volume name must be a string" -msgstr "���������������������������������" - -msgid "Storage volume allocation must be an integer number" -msgstr "���������������������������������" - -msgid "" -"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " -"qcow, qcow2, qed, raw, vmdk, vpc." -msgstr "" - -msgid "Storage volume requires a volume name" -msgstr "������������������������������" - -#, python-format -msgid "" -"Unable to update database with storage volume information due error: %(err)s" -msgstr "������������������������������������������������������������������������%(err)s" - -#, python-format -msgid "Only one of parameter %(param)s can be specified" -msgstr "" - -#, python-format -msgid "Create volume from %(param)s is not supported" -msgstr "" - -msgid "Storage volume capacity must be an integer number." -msgstr "" - -msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." -msgstr "" - -#, python-format -msgid "Unable to access file %(url)s. Please, check it." -msgstr "" - -#, python-format -msgid "" -"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" -"s" -msgstr "" - -msgid "Specify chunk data and its size to upload a file." -msgstr "" - -msgid "In order to upload a storage volume, specify the 'upload' parameter." -msgstr "" - -msgid "" -"Unable to upload chunk data as it does not match with requested chunk size." -msgstr "" - -#, python-format -msgid "The storage volume %(vol)s is not under an upload process." -msgstr "" - -msgid "The upload chunk data will exceed the storage volume size." -msgstr "" - -#, python-format -msgid "Unable to upload chunk data to storage volume. Details: %(err)s." -msgstr "" - -#, python-format -msgid "Interface %(name)s does not exist" -msgstr "������ %(name)s ���������" - -#, python-format -msgid "Network %(name)s already exists" -msgstr "������ %(name)s ���������" - -#, python-format -msgid "Network %(name)s does not exist" -msgstr "������ %(name)s ���������" - -#, python-format -msgid "Subnet %(subnet)s specified for network %(network)s is not valid." -msgstr "��������� %(network)s ������������������ %(subnet)s ���������" - -#, python-format -msgid "Specify a network interface to create bridged network %(name)s" -msgstr "������������������������������������������ %(name)s" - -#, python-format -msgid "Unable to delete active network %(name)s" -msgstr "������������������������������ %(name)s" - -#, python-format -msgid "Interface %(iface)s specified for network %(network)s is already in use" -msgstr "��������� %(network)s ��������������� %(iface)s ���������������" - -msgid "Interface should be bare NIC, bonding or bridge device." -msgstr "��������������������� NIC������������������������������������" - -#, python-format -msgid "Unable to create network %(name)s. Details: %(err)s" -msgstr "������������������ %(name)s������������������%(err)s" - -#, python-format -msgid "Unable to find a free IP address for network '%(name)s'" -msgstr "��������������� '%(name)s' ��������� IP ������" - -#, python-format -msgid "The interface %(iface)s already exists." -msgstr "" - -msgid "Network name must be a string without slashes (/) or quotes (\")" -msgstr "" - -msgid "Supported network types are isolated, NAT and bridge" -msgstr "���������������������������������������NAT ������������" - -msgid "Network subnet must be a string with IP address and prefix or netmask" -msgstr "��������������������������������� IP ���������������������������������������" - -msgid "Network interface must be a string" -msgstr "���������������������������" - -msgid "Network VLAN ID must be an integer between 1 and 4094" -msgstr "������ VLAN ID ��������������� 1 ��� 4094 ���������������" - -msgid "Specify name and type to create a Network" -msgstr "������������������������������������" - -#, python-format -msgid "" -"Unable to delete network %(name)s. There are some virtual machines %(vms)s " -"and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "" -"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" -"s and/or templates linked to this network." -msgstr "" - -#, python-format -msgid "Bridge device %(name)s can not be the trunk device of a VLAN." -msgstr "��������������� %(name)s ��������� VLAN ������������������" - -#, python-format -msgid "Failed to activate interface %(iface)s: %(err)s." -msgstr "������������������ %(iface)s���%(err)s���" - -#, python-format -msgid "" -"Failed to activate interface %(iface)s. Please check the physical link " -"status." -msgstr "������������������ %(iface)s���������������������������������" - -#, python-format -msgid "Failed to start network %(name)s. Details: %(err)s" -msgstr "" - -#, python-format -msgid "Debug report %(name)s does not exist" -msgstr "������������ %(name)s ���������" - -msgid "Debug report tool not found in system" -msgstr "���������������������������������������" - -#, python-format -msgid "Unable to create debug report %(name)s. Details: %(err)s." -msgstr "������������������������ %(name)s������������������%(err)s���" - -#, python-format -msgid "Can not find any debug report with the given name %(name)s" -msgstr "" - -#, python-format -msgid "Unable to generate debug report %(name)s. Details: %(err)s" -msgstr "������������������������ %(name)s������������������%(err)s" - -msgid "You should give a name for the debug report file." -msgstr "" - -msgid "" -"Debug report name must be a string. Only letters, digits, underscore ('_') " -"and hyphen ('-') are allowed." -msgstr "" - -#, python-format -msgid "" -"The debug report with specified name \"%(name)s\" already exists. Please use " -"another one." -msgstr "������ '%(name)s' ������������������������������������������������������������������������������" - -#, python-format -msgid "Storage server %(server)s was not used by Kimchi" -msgstr "Kimchi ��������������������������� %(server)s" - -#, python-format -msgid "Distro '%(name)s' does not exist" -msgstr "Distro '%(name)s' ���������" - -#, python-format -msgid "Partition %(name)s does not exist in the host" -msgstr "��������� %(name)s ���������������������" - -msgid "Unable to shutdown host machine as there are running virtual machines" -msgstr "���������������������������������������������������������������" - -msgid "Unable to reboot host machine as there are running virtual machines" -msgstr "������������������������������������������������������������������������" - -#, python-format -msgid "Node device '%(name)s' not found" -msgstr "��������������������� '%(name)s'" - -msgid "Conflicting flag filters specified." -msgstr "" - -msgid "No packages marked for update" -msgstr "������������������������������������" - -#, python-format -msgid "Package %(name)s is not marked to be updated." -msgstr "������ %(name)s ������������������������������" - -#, python-format -msgid "Error while getting packages marked to be updated. Details: %(err)s" -msgstr "������������������������������������������������������������������������%(err)s" - -msgid "There is no compatible package manager for this system." -msgstr "���������������������������������������������" - -#, python-format -msgid "Invalid URI %(uri)s" -msgstr "URI %(uri)s ������" - -msgid "Unable to choose a virtual machine name" -msgstr "" - -msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" -msgstr "���������������������������������������������'cdrom'" - -#, python-format -msgid "The path '%(value)s' is not a valid local/remote path for the device" -msgstr "" - -msgid "Only CDROM path can be update." -msgstr "" - -#, python-format -msgid "" -"The storage device %(dev_name)s does not exist in the virtual machine %" -"(vm_name)s" -msgstr "" - -#, python-format -msgid "Error while creating new storage device: %(error)s" -msgstr "������������������������������������������%(error)s" - -#, python-format -msgid "Error while updating storage device: %(error)s" -msgstr "������������������������������������%(error)s" - -#, python-format -msgid "Error while removing storage device: %(error)s" -msgstr "������������������������������������%(error)s" - -msgid "Do not support IDE device hot plug" -msgstr "" - -msgid "" -"Specify type and path or type and pool/volume to add a new virtual machine " -"disk" -msgstr "������������������������������������������������" - -msgid "Specify path to update virtual machine disk" -msgstr "���������������������������������������" - -#, python-format -msgid "Controller type %(type)s limitation of %(limit)s devices reached" -msgstr "" - -#, python-format -msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" -msgstr "" - -msgid "Volume already in use by other virtual machine." -msgstr "" - -msgid "" -"Only one of path or pool/volume can be specified to add a new virtual " -"machine disk" -msgstr "������������������������������������������������" - -#, python-format -msgid "" -"Volume chosen with format %(format)s does not fit in the storage type %(type)" -"s" -msgstr "" - -msgid "YUM Repository ID must be one word only string." -msgstr "YUM ��������� ID ���������������������������������������" - -msgid "Repository URL must be an http://, ftp:// or file:// URL." -msgstr "��������� URL ��������� http://���ftp:// ��� file:// URL���" - -msgid "" -"Repository configuration is a dictionary with specific values according to " -"repository type." -msgstr "������������������������������������������������������������������������������" - -msgid "Distribution to DEB repository must be a string" -msgstr "DEB ���������������������������������������" - -msgid "Components to DEB repository must be listed in a array" -msgstr "DEB ������������������������������������������������" - -msgid "Components to DEB repository must be a string" -msgstr "DEB ���������������������������������" - -msgid "Mirror list to repository must be a string" -msgstr "" - -msgid "YUM Repository name must be string." -msgstr "YUM ���������������������������������" - -msgid "GPG check must be a boolean value." -msgstr "GPG ���������������������������" - -msgid "GPG key must be a URL pointing to the ASCII-armored file." -msgstr "GPG ��������������������� ASCII ��������������� URL���" - -#, python-format -msgid "Could not update repository %(repo_id)s." -msgstr "��������������������� %(repo_id)s���" - -#, python-format -msgid "Repository %(repo_id)s does not exist." -msgstr "��������� %(repo_id)s ������������" - -msgid "" -"Specify repository base URL, mirror list or metalink in order to create or " -"update a YUM repository." -msgstr "" - -msgid "Repository management tool was not recognized for your system." -msgstr "���������������������������������������������" - -#, python-format -msgid "Repository %(repo_id)s is already enabled." -msgstr "������������������ %(repo_id)s���" - -#, python-format -msgid "Repository %(repo_id)s is already disabled." -msgstr "������������������ %(repo_id)s���" - -#, python-format -msgid "Could not remove repository %(repo_id)s." -msgstr "��������������������� %(repo_id)s���" - -#, python-format -msgid "Could not write repository configuration file %(repo_file)s" -msgstr "������������������������������ %(repo_file)s" - -msgid "Specify repository distribution in order to create a DEB repository." -msgstr "������������������������������������ DEB ������������" - -#, python-format -msgid "Could not enable repository %(repo_id)s." -msgstr "��������������������� %(repo_id)s���" - -#, python-format -msgid "Could not disable repository %(repo_id)s." -msgstr "��������������������� %(repo_id)s���" - -msgid "YUM Repository ID already exists" -msgstr "YUM ��������� ID ���������" - -msgid "YUM Repository name must be a string" -msgstr "YUM ������������������������������" - -#, python-format -msgid "Unable to list repositories. Details: '%(err)s'" -msgstr "���������������������������������������'%(err)s'" - -#, python-format -msgid "Unable to retrieve repository information. Details: '%(err)s'" -msgstr "���������������������������������������������'%(err)s'" - -#, python-format -msgid "Unable to add repository. Details: '%(err)s'" -msgstr "���������������������������������������'%(err)s'" - -#, python-format -msgid "Unable to remove repository. Details: '%(err)s'" -msgstr "���������������������������������������'%(err)s'" - -#, python-format -msgid "" -"Configuration items: '%(items)s' are not supported by repository manager" -msgstr "" - -msgid "Repository metalink must be an http://, ftp:// or file:// URL." -msgstr "" - -msgid "Cannot specify mirrorlist and metalink at the same time." -msgstr "" - -#, python-format -msgid "" -"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " -"%(err)s" -msgstr "" - -#, python-format -msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" -"(err)s" -msgstr "" - -#, python-format -msgid "" -"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " -"disk with format '%(format)s'; only 'qcow2' is supported." -msgstr "" - -msgid "The number of vCPUs is too large for this system." -msgstr "" - -msgid "Invalid vCPU/topology combination." -msgstr "" - -msgid "This host (or current configuration) does not allow CPU topology." -msgstr "" - -msgid "ERROR CODE" -msgstr "���������" - -msgid "REASON" -msgstr "������" - -msgid "STACK" -msgstr "������" - -msgid "Go to Homepage" -msgstr "������������" - -msgid "Create a New Virtual Machine" -msgstr "������������������������" - -msgid "Virtual Machine Name" -msgstr "������������������" - -msgid "" -"The name used to identify the virtual machine. If omitted, a name will be " -"chosen based on the template used." -msgstr "���������������������������������������������������������������������������������������������" - -msgid "Template" -msgstr "������" - -msgid "Please create a template first." -msgstr "���������������������" - -msgid "Create a Template" -msgstr "������������" - -msgid "Please choose a template." -msgstr "������������������" - -msgid "OS" -msgstr "OS" - -msgid "OS Version" -msgstr "OS ������" - -msgid "CPUS" -msgstr "CPUS" - -msgid "Memory" -msgstr "���������" - -msgid "Create" -msgstr "������" - -msgid "Creating..." -msgstr "" - -msgid "Cancel" -msgstr "������ " - -msgid "Edit Guest" -msgstr "������������" - -msgid "General" -msgstr "������" - -msgid "Storage" -msgstr "���������" - -msgid "Interface" -msgstr "������" - -msgid "Permission" -msgstr "������" - -msgid "Host PCI Device" -msgstr "" - -msgid "Snapshot" -msgstr "" - -msgid "Name" -msgstr "������" - -msgid "CPUs" -msgstr "CPU" - -msgid "Memory (MB)" -msgstr "���������" - -msgid "Icon" -msgstr "������" - -msgid "Device" -msgstr "������������" - -msgid "Path" -msgstr "NFS ������" - -msgid "Network" -msgstr "������" - -msgid "Type" -msgstr "������" - -msgid "MAC Address" -msgstr "" - -msgid "Available system users and groups" -msgstr "" - -msgid "Selected system users and groups" -msgstr "" - -msgid "User" -msgstr "" - -msgid "All" -msgstr "������" - -msgid "To Add" -msgstr "" - -msgid "Added" -msgstr "" - -msgid "filter" -msgstr "" - -msgid "Product" -msgstr "" - -msgid "Vendor" -msgstr "���������" - -msgid "Created" -msgstr "" - -msgid "Save" -msgstr "������" - -msgid "Replace" -msgstr "������" - -msgid "Detach" -msgstr "������" - -msgid "revert" -msgstr "" - -msgid "Start" -msgstr "������" - -msgid "Reset" -msgstr "������" - -msgid "Pause" -msgstr "" - -msgid "Resume" -msgstr "" - -msgid "Power Off" -msgstr "" - -msgid "Actions" -msgstr "������" - -msgid "Connect" -msgstr "������" - -msgid "Clone" -msgstr "" - -msgid "Edit" -msgstr "������" - -msgid "Shut Down" -msgstr "������" - -msgid "Delete" -msgstr "������" - -msgid "CPU" -msgstr "CPU" - -msgid "Disk I/O" -msgstr "������ I/O" - -msgid "Network I/O" -msgstr "������ I/O" - -msgid "Livetile" -msgstr "Livetile" - -msgid "No guests found." -msgstr "������������������" - -msgid "Add a Storage Device to VM" -msgstr "������������������������ VM" - -msgid "Device Type" -msgstr "������������" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "������������������������������ \"cdrom\"���" - -msgid "Storage Pool" -msgstr "���������" - -msgid "Storage pool which volume located in" -msgstr "������������������������������" - -msgid "Storage Volume" -msgstr "���������������" - -msgid "Storage volume to be attached" -msgstr "���������������������������������" - -msgid "File Path" -msgstr "������������" - -msgid "The ISO file path in the server for CDROM." -msgstr "CDROM ��� ISO ������������������������������" - -msgid "Attach" -msgstr "������" - -msgid "Shut down" -msgstr "������" - -msgid "Restart" -msgstr "������������" - -msgid "Basic Information" -msgstr "������������" - -msgid "OS Distro" -msgstr "OS Distro" - -msgid "OS Code Name" -msgstr "OS ���������������" - -msgid "Processor" -msgstr "���������" - -msgid "CPU(s)" -msgstr "" - -msgid "System Statistics" -msgstr "������������������" - -msgid "Software Updates" -msgstr "������������" - -msgid "Update Progress" -msgstr "������������" - -msgid "Repositories" -msgstr "���������" - -msgid "Debug Reports" -msgstr "������������" - -msgid "The username or password you entered is incorrect. Please try again." -msgstr "������������������������������������������������������������" - -msgid "This field is required." -msgstr "������������������������" - -msgid "Log in" -msgstr "������" - -msgid "Logging in..." -msgstr "������������..." - -msgid "Host" -msgstr "������" - -msgid "Guests" -msgstr "������" - -msgid "Templates" -msgstr "������" - -msgid "Failed to get application configuration" -msgstr "������������������������������" - -msgid "This is not a valid Linux path" -msgstr "��������������� Linux ������" - -msgid "This is not a valid URL." -msgstr "��������������� URL���" - -msgid "No such data available." -msgstr "���������������������������" - -msgid "" -"Can not contact the host system. Verify the host system is up and that you " -"have network connectivity to it. HTTP request response %1. " -msgstr "" -"������������������������������������������������������������������������������������������������������������HTTP " -"��������������� %1���" - -msgid "Unable to read file." -msgstr "" - -msgid "Error while uploading file." -msgstr "" - -msgid "Delete Confirmation" -msgstr "������������" - -msgid "OK" -msgstr "������" - -msgid "Confirm" -msgstr "������" - -msgid "Warning" -msgstr "������" - -msgid "Cloning..." -msgstr "" - -msgid "Loading..." -msgstr "������������..." - -msgid "An error occurred while retrieving system information." -msgstr "" - -msgid "Retry" -msgstr "������" - -msgid "Detailed message:" -msgstr "������������������" - -msgid "No ISO found" -msgstr "" - -msgid "This is not a valid ISO file." -msgstr "��������������� ISO ���������" - -msgid "This may take a long time. Do you want to continue?" -msgstr "������������������������������������������" - -msgid "This will permanently delete the template. Would you like to continue?" -msgstr "���������������������������������������������������" - -msgid "Unable to shut down system as there are some virtual machines running!" -msgstr "������������������������������������������������������������������" - -msgid "Max:" -msgstr "���������" - -msgid "Utilization" -msgstr "���������" - -msgid "Available" -msgstr "������" - -msgid "Read Rate" -msgstr "������������" - -msgid "Write Rate" -msgstr "������������" - -msgid "Received" -msgstr "���������" - -msgid "Sent" -msgstr "���������" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "������������������������������������������������������������������������������/������������������" - -msgid "" -"Repository will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "������������������������������������������������������������������" - -msgid "ID" -msgstr "ID" - -msgid "Base URL" -msgstr "������ URL" - -msgid "Is Mirror" -msgstr "���������" - -msgid "URL Args" -msgstr "URL ������" - -msgid "Enabled" -msgstr "���������" - -msgid "GPG Check" -msgstr "GPG ������" - -msgid "GPG Key" -msgstr "GPG ������" - -msgid "Add" -msgstr "������" - -msgid "Remove" -msgstr "������" - -msgid "Enable" -msgstr "������" - -msgid "Disable" -msgstr "������" - -msgid "Package Name" -msgstr "������������" - -msgid "Version" -msgstr "������" - -msgid "Architecture" -msgstr "������" - -msgid "Repository" -msgstr "���������" - -msgid "Update All" -msgstr "������������" - -msgid "Updating..." -msgstr "������������..." - -msgid "Failed to retrieve packages update information." -msgstr "" - -msgid "Failed to update package(s)." -msgstr "���������������������" - -msgid "" -"Debug report will be removed permanently and can't be recovered. Do you want " -"to continue?" -msgstr "���������������������������������������������������������������������" - -msgid "Generated Time" -msgstr "������������" - -msgid "Generate" -msgstr "������" - -msgid "Generating..." -msgstr "������������..." - -msgid "Rename" -msgstr "������������" - -msgid "Download" -msgstr "������" - -msgid "" -"Report name should contain only letters, digits, underscore ('_') and/or " -"hyphen ('-')." -msgstr "���������������������������������������������/������������ ('-')���" - -msgid "Pending..." -msgstr "������������..." - -msgid "Report name is the same as the original one." -msgstr "" - -msgid "" -"This will delete the virtual machine and its virtual disks. This operation " -"cannot be undone. Would you like to continue?" -msgstr "���������������������������������������������������������������������������������������������" - -msgid "Power off Confirmation" -msgstr "������������" - -msgid "" -"This action may produce undesirable results, for example unflushed disk " -"cache in the guest. Would you like to continue?" -msgstr "" - -msgid "Reset Confirmation" -msgstr "������������" - -msgid "" -"There is a risk of data loss caused by reset without the guest OS shutdown. " -"Would you like to continue?" -msgstr "" - -msgid "Shut Down Confirmation" -msgstr "������������" - -msgid "Note the guest OS may ignore this request. Would you like to continue?" -msgstr "���������������������������������������������������" - -msgid "Virtual Machine delete Confirmation" -msgstr "" - -msgid "" -"This virtual machine is not persistent. Power Off will delete it. Continue?" -msgstr "" - -msgid "" -"When the target guest has SCSI or iSCSI volumes, they will be cloned on " -"default storage pool. The same will happen when the target pool does not " -"have enough space to clone the volumes. Do you want to continue?" -msgstr "" - -msgid "" -"This CDROM will be detached permanently and you can re-attach it. Continue " -"to detach it?" -msgstr "" -"������������������������ CDROM��������������������������������������������������������� CDROM ������" - -msgid "Attaching..." -msgstr "������������..." - -msgid "Replacing..." -msgstr "������������..." - -msgid "Successfully attached!" -msgstr "������������������" - -msgid "Successfully replaced!" -msgstr "������������������" - -msgid "Successfully detached!" -msgstr "������������������" - -msgid "" -"This disk will be detached permanently and you can re-attach it. Continue to " -"detach it?" -msgstr "" - -msgid "interface:" -msgstr "" - -msgid "address:" -msgstr "" - -msgid "link_type:" -msgstr "" - -msgid "block:" -msgstr "" - -msgid "drive_type:" -msgstr "" - -msgid "model:" -msgstr "" - -msgid "Affected devices:" -msgstr "" - -msgid "The VLAN id must be between 1 and 4094." -msgstr "VLAN ID ������������ 1 ��� 4094 ���������" - -msgid "unavailable" -msgstr "������������" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "������������������������������������������������������������������������������������" - -msgid "Create a network" -msgstr "������������" - -msgid "" -"This network is not persistent. Instead of stop, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������" - -msgid "" -"The bridged VLAN tag may not work well with NetworkManager enabled. You " -"should consider disabling it." -msgstr "" - -msgid "" -"This will permanently delete the storage pool. Would you like to continue?" -msgstr "������������������������������������������������������" - -msgid "This storage pool is empty." -msgstr "������������������������" - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "������������������������������������������������������������������������������������������������������" - -msgid "SCSI Fibre Channel" -msgstr "SCSI ������������" - -msgid "No SCSI adapters found." -msgstr "��������� SCSI ������������" - -msgid "Loading iSCSI targets..." -msgstr "" - -msgid "No iSCSI found. Please input one." -msgstr "" - -msgid "Failed to load iSCSI targets." -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "������������������������������" - -msgid "The storage pool path can not be blank." -msgstr "������������������������������" - -msgid "NFS server mount path can not be blank." -msgstr "NFS ������������������������������������" - -msgid "Invalid NFS mount path." -msgstr "NFS ���������������������" - -msgid "No logical device selected." -msgstr "������������������������" - -msgid "The iSCSI target can not be blank." -msgstr "iSCSI ���������������������" - -msgid "Server name can not be blank." -msgstr "������������������������������" - -msgid "This is not a valid Server Name or IP. Please, modify it." -msgstr "" - -msgid "Looking for available partitions ..." -msgstr "������������������������������ ..." - -msgid "No available partitions found." -msgstr "������������������������������" - -msgid "" -"This storage pool is not persistent. Instead of deactivate, this action will " -"permanently delete it. Would you like to continue?" -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������" - -msgid "Unable to retrieve partitions information." -msgstr "���������������������������������������������'%(err)s'" - -msgid "In progress..." -msgstr "" - -msgid "Failed!" -msgstr "" - -msgid "CDROM path needs to be a valid local/remote path and cannot be blank." -msgstr "" - -msgid "Disk pool or volume cannot be blank." -msgstr "������������������������������" - -msgid "Filter" -msgstr "" - -msgid "Network Name" -msgstr "������������" - -msgid "State" -msgstr "������" - -msgid "Network Type" -msgstr "������������" - -msgid "Address Space" -msgstr "������������" - -msgid "Name should not contain '/' and '\"'." -msgstr "������������������������������������������ '/'���" - -msgid "Isolated: no external network connection" -msgstr "������������������������������������" - -msgid "NAT: outbound physical network connection only" -msgstr "NAT���������������������������������" - -msgid "Bridged: Virtual machines are connected to physical network directly" -msgstr "������������������������������������������������������" - -msgid "(No interfaces found)" -msgstr "" - -msgid "Destination" -msgstr "������������" - -msgid "Enable VLAN" -msgstr "������ VLAN���" - -msgid "VLAN ID" -msgstr "VLAN ID���" - -msgid "Stop" -msgstr "������" - -msgid "Generate a New Debug Report" -msgstr "������������������������" - -msgid "Report Name" -msgstr "������������" - -msgid "" -"The name used to identify the report. If omitted, a name will be chosen " -"based on current time. Name can contain: letters, digits, underscore (\"_\") " -"and hyphen (\"-\")." -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������������������ (\"-\")���" - -msgid "Rename a Debug Report" -msgstr "������������������������" - -msgid "" -"The name used to identify the report. Name can contain: letters, digits and " -"hyphen (\"-\")." -msgstr "" -"������������������������������������������������������������������������������������������������������������������" -"������������������ (\"-\")���" - -msgid "Submit" -msgstr "" - -msgid "Add a Repository" -msgstr "���������������" - -msgid "Identifier" -msgstr "ID" - -msgid "Single word, unique identifier for the repository." -msgstr "��������������������������� ID���" - -msgid "Textual name for the repository." -msgstr "���������������������������" - -msgid "URL" -msgstr "URL" - -msgid "Required Field" -msgstr "������������" - -msgid "URL to the repository. Supported protocols are http, ftp, and file." -msgstr "������������ URL��������������������������������� http���ftp ��� file���" - -msgid "Repository is a mirror" -msgstr "���������������������" - -msgid "Distribution" -msgstr "������������" - -msgid "Distribution of the DEB repository." -msgstr "DEB ���������������������������" - -msgid "Components" -msgstr "������" - -msgid "List of components in DEB repository." -msgstr "DEB ������������������������������" - -msgid "Edit Repository" -msgstr "���������������" - -msgid "Mirror List URL" -msgstr "������������ URL" - -msgid "Yes" -msgstr "���" - -msgid "No" -msgstr "���" - -msgid "Capacity" -msgstr "������" - -msgid "Allocated" -msgstr "���������" - -msgid "Location" -msgstr "������" - -msgid "Device path" -msgstr "������������" - -msgid "active" -msgstr "���������" - -msgid "inactive" -msgstr "������������" - -msgid "Deactivate" -msgstr "������������" - -msgid "Activate" -msgstr "������" - -msgid "Add Volume" -msgstr "" - -msgid "Extend" -msgstr "" - -msgid "Undefine" -msgstr "������������" - -msgid "Format" -msgstr "���������" - -msgid "Allocation" -msgstr "���������" - -msgid "Define a New Storage Pool" -msgstr "���������������������" - -msgid "Storage Pool Name" -msgstr "���������������" - -msgid "" -"The name used to identify the storage pools, and it should not be empty." -msgstr "������������������������������������������������������" - -msgid "Storage Pool Type" -msgstr "���������������" - -msgid "Storage Path" -msgstr "���������������" - -msgid "" -"The path of the Storage Pool. Each Storage Pool must have a unique path." -msgstr "���������������������������������������������������������������������������" - -msgid "" -"Kimchi will try to create the directory when it does not already exist in " -"your system." -msgstr "Kimchi ������������������������������������������������������������������������" - -msgid "NFS Server IP" -msgstr "NFS ��������� IP" - -msgid "NFS server IP or hostname. It can be input or chosen from history." -msgstr "NFS ��������� IP ���������������������������������������������������������������������" - -msgid "NFS Path" -msgstr "NFS ������" - -msgid "The NFS exported path on NFS server." -msgstr "NFS ������������ NFS ������������������" - -msgid "iSCSI Server" -msgstr "iSCSI ���������" - -msgid "Server" -msgstr "���������" - -msgid "Port" -msgstr "���" - -msgid "iSCSI server IP or hostname. It should not be empty." -msgstr "iSCSI ��������� IP ������������������������������������������" - -msgid "Target" -msgstr "������" - -msgid "The iSCSI target on iSCSI server" -msgstr "iSCSI ��������������� iSCSI ������" - -msgid "Add iSCSI Authentication" -msgstr "������ iSCSI ������" - -msgid "iSCSI Authentication" -msgstr "iSCSI ������" - -msgid "User Name" -msgstr "���������������" - -msgid "Password" -msgstr "������" - -msgid "SCSI Adapter" -msgstr "SCSI ���������" - -msgid "Please, wait..." -msgstr "���������..." - -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - -msgid "Add Template" -msgstr "������������" - -msgid "Where is the source media for this template? " -msgstr "���������������������������������������" - -msgid "Local ISO Image" -msgstr "������ ISO ���������" - -msgid "Local Image File" -msgstr "" - -msgid "Remote ISO Image" -msgstr "������ ISO ���������" - -msgid "Search ISOs" -msgstr "������ ISO" - -msgid "The following ISOs are available:" -msgstr "������ ISO ���������" - -msgid "OS: " -msgstr "OS���" - -msgid "Version: " -msgstr "���������" - -msgid "Size: " -msgstr "���������" - -msgid "Search more ISOs" -msgstr "������������ ISO" - -msgid "Create Templates from Selected ISO" -msgstr "��������� ISO ������������" - -msgid "I want to use a specific ISO file" -msgstr "��������������������� ISO ������" - -msgid "Loading default remote ISOs ..." -msgstr "������������������������ ISO ..." - -msgid "Arch: " -msgstr "���������" - -msgid "I want to use a custom URL" -msgstr "������������������ URL" - -msgid "Edit Template" -msgstr "������������" - -msgid "CDROM" -msgstr "CDROM" - -msgid "Image File" -msgstr "" - -msgid "Graphics" -msgstr "���������" - -msgid "Disk(GB)" -msgstr "" - -msgid "Disk Format" -msgstr "" - -msgid "CPU Number" -msgstr "CPU ������" - -msgid "Manually set CPU topology" -msgstr "" - -msgid "Cores" -msgstr "" - -msgid "Threads" -msgstr "" - -msgid "No templates found." -msgstr "������������������" - -#~ msgid "Delete is not allowed for %(resource)s" -#~ msgstr "��������������� %(resource)s ������������" - -#~ msgid "%(resource)s does not implement update method" -#~ msgstr "%(resource)s ���������������������" - -#~ msgid "Create is not allowed for %(resource)s" -#~ msgstr "��������������� %(resource)s ������������" - -#~ msgid "Unable to parse JSON request" -#~ msgstr "������������ JSON ������" - -#~ msgid "This API only supports JSON" -#~ msgstr "��� API ��������� JSON" - -#~ msgid "Datastore is not initiated in the model object." -#~ msgstr "���������������������������������������������" - -#~ msgid "Unable to start task due error: %(err)s" -#~ msgstr "������������������������������������������%(err)s" - -#~ msgid "" -#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" -#~ msgstr "��������� '%(username)s' ������������������[������������%(code)s]" - -#~ msgid "You are not authorized to access Kimchi" -#~ msgstr "������������������������ Kimchi" - -#~ msgid "Specify %(item)s to login into Kimchi" -#~ msgstr "������ %(item)s ��������� Kimchi" - -#~ msgid "Unable to find %(item)s in datastore" -#~ msgstr "������������������������������ %(item)s" - -#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" -#~ msgstr "������������ '%(cmd)s' %(seconds)s ���������������" - -#~ msgid "Help" -#~ msgstr "������" - -#~ msgid "About" -#~ msgstr "������" - -#~ msgid "Log out" -#~ msgstr "������" - -#~ msgid "Version:" -#~ msgstr "���������" diff --git a/plugins/kimchi/repositories.py b/plugins/kimchi/repositories.py deleted file mode 100644 index 9caabc4..0000000 --- a/plugins/kimchi/repositories.py +++ /dev/null @@ -1,529 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import copy -import os -import time -import urlparse -from ConfigParser import ConfigParser - -from wok.basemodel import Singleton -from wok.exception import InvalidOperation, InvalidParameter -from wok.exception import OperationFailed, NotFoundError, MissingParameter -from wok.utils import validate_repo_url - -from config import kimchiLock -from yumparser import get_yum_repositories, write_repo_to_file - - -class Repositories(object): - __metaclass__ = Singleton - - """ - Class to represent and operate with repositories information. - """ - def __init__(self): - try: - __import__('yum') - self._pkg_mnger = YumRepo() - except ImportError: - try: - __import__('apt_pkg') - self._pkg_mnger = AptRepo() - except ImportError: - raise InvalidOperation('KCHREPOS0014E') - - def addRepository(self, params): - """ - Add and enable a new repository - """ - config = params.get('config', {}) - extra_keys = list( - set(config.keys()).difference(set(self._pkg_mnger.CONFIG_ENTRY))) - if len(extra_keys) > 0: - raise InvalidParameter("KCHREPOS0028E", - {'items': ",".join(extra_keys)}) - - return self._pkg_mnger.addRepo(params) - - def getRepositories(self): - """ - Return a dictionary with all Kimchi's repositories. Each element uses - the format {<repo_id>: {repo}}, where repo is a dictionary in the - repositories.Repositories() format. - """ - return self._pkg_mnger.getRepositoriesList() - - def getRepository(self, repo_id): - """ - Return a dictionary with all info from a given repository ID. - """ - info = self._pkg_mnger.getRepo(repo_id) - info['repo_id'] = repo_id - return info - - def enableRepository(self, repo_id): - """ - Enable a repository. - """ - return self._pkg_mnger.toggleRepo(repo_id, True) - - def disableRepository(self, repo_id): - """ - Disable a given repository. - """ - return self._pkg_mnger.toggleRepo(repo_id, False) - - def updateRepository(self, repo_id, params): - """ - Update the information of a given repository. - The input is the repo_id of the repository to be updated and a dict - with the information to be updated. - """ - return self._pkg_mnger.updateRepo(repo_id, params) - - def removeRepository(self, repo_id): - """ - Remove a given repository - """ - return self._pkg_mnger.removeRepo(repo_id) - - -class YumRepo(object): - """ - Class to represent and operate with YUM repositories. - It's loaded only on those systems listed at YUM_DISTROS and loads necessary - modules in runtime. - """ - TYPE = 'yum' - DEFAULT_CONF_DIR = "/etc/yum.repos.d" - CONFIG_ENTRY = ('repo_name', 'mirrorlist', 'metalink') - - def __init__(self): - self._confdir = self.DEFAULT_CONF_DIR - - def _get_repos(self, errcode): - try: - kimchiLock.acquire() - repos = get_yum_repositories() - except Exception, e: - kimchiLock.release() - raise OperationFailed(errcode, {'err': str(e)}) - finally: - kimchiLock.release() - - return repos - - def getRepositoriesList(self): - """ - Return a list of repositories IDs - """ - repos = self._get_repos('KCHREPOS0024E') - return repos.keys() - - def getRepo(self, repo_id): - """ - Return a dictionary in the repositories.Repositories() of the given - repository ID format with the information of a YumRepository object. - """ - repos = self._get_repos('KCHREPOS0025E') - - if repo_id not in repos.keys(): - raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) - - entry = repos.get(repo_id) - - info = {} - info['enabled'] = entry.enabled - info['baseurl'] = entry.baseurl or '' - info['config'] = {} - info['config']['repo_name'] = entry.name or '' - info['config']['gpgcheck'] = entry.gpgcheck - info['config']['gpgkey'] = entry.gpgkey or '' - info['config']['mirrorlist'] = entry.mirrorlist or '' - info['config']['metalink'] = entry.metalink or '' - return info - - def addRepo(self, params): - """ - Add a given repository to YumBase - """ - # At least one base url, or one mirror, must be given. - baseurl = params.get('baseurl', '') - - config = params.get('config', {}) - mirrorlist = config.get('mirrorlist', '') - metalink = config.get('metalink', '') - if not baseurl and not mirrorlist and not metalink: - raise MissingParameter("KCHREPOS0013E") - - if baseurl: - validate_repo_url(baseurl) - - if mirrorlist: - validate_repo_url(mirrorlist) - - if metalink: - validate_repo_url(metalink) - - if mirrorlist and metalink: - raise InvalidOperation('KCHREPOS0030E') - - repo_id = params.get('repo_id', None) - if repo_id is None: - repo_id = "kimchi_repo_%s" % str(int(time.time() * 1000)) - - repos = self._get_repos('KCHREPOS0026E') - if repo_id in repos.keys(): - raise InvalidOperation("KCHREPOS0022E", {'repo_id': repo_id}) - - repo_name = config.get('repo_name', repo_id) - repo = {'baseurl': baseurl, 'mirrorlist': mirrorlist, - 'name': repo_name, 'gpgcheck': 1, - 'gpgkey': [], 'enabled': 1, 'metalink': metalink} - - # write a repo file in the system with repo{} information. - parser = ConfigParser() - parser.add_section(repo_id) - - for key, value in repo.iteritems(): - if value: - parser.set(repo_id, key, value) - - repofile = os.path.join(self._confdir, repo_id + '.repo') - try: - with open(repofile, 'w') as fd: - parser.write(fd) - except: - raise OperationFailed("KCHREPOS0018E", - {'repo_file': repofile}) - - return repo_id - - def toggleRepo(self, repo_id, enable): - repos = self._get_repos('KCHREPOS0011E') - if repo_id not in repos.keys(): - raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) - - entry = repos.get(repo_id) - if enable and entry.enabled: - raise InvalidOperation("KCHREPOS0015E", {'repo_id': repo_id}) - - if not enable and not entry.enabled: - raise InvalidOperation("KCHREPOS0016E", {'repo_id': repo_id}) - - kimchiLock.acquire() - try: - if enable: - entry.enable() - else: - entry.disable() - - write_repo_to_file(entry) - except: - if enable: - raise OperationFailed("KCHREPOS0020E", {'repo_id': repo_id}) - - raise OperationFailed("KCHREPOS0021E", {'repo_id': repo_id}) - finally: - kimchiLock.release() - - return repo_id - - def updateRepo(self, repo_id, params): - """ - Update a given repository in repositories.Repositories() format - """ - repos = self._get_repos('KCHREPOS0011E') - if repo_id not in repos.keys(): - raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) - - entry = repos.get(repo_id) - - baseurl = params.get('baseurl', None) - config = params.get('config', {}) - mirrorlist = config.get('mirrorlist', None) - metalink = config.get('metalink', None) - - if baseurl is not None and len(baseurl.strip()) == 0: - baseurl = None - - if mirrorlist is not None and len(mirrorlist.strip()) == 0: - mirrorlist = None - - if metalink is not None and len(metalink.strip()) == 0: - metalink = None - - if baseurl is None and mirrorlist is None and metalink is None: - raise MissingParameter("KCHREPOS0013E") - - if baseurl is not None: - validate_repo_url(baseurl) - entry.baseurl = baseurl - - if mirrorlist is not None: - validate_repo_url(mirrorlist) - entry.mirrorlist = mirrorlist - - if metalink is not None: - validate_repo_url(metalink) - entry.metalink = metalink - - if mirrorlist and metalink: - raise InvalidOperation('KCHREPOS0030E') - - entry.id = params.get('repo_id', repo_id) - entry.name = config.get('repo_name', entry.name) - entry.gpgcheck = config.get('gpgcheck', entry.gpgcheck) - entry.gpgkey = config.get('gpgkey', entry.gpgkey) - kimchiLock.acquire() - write_repo_to_file(entry) - kimchiLock.release() - return repo_id - - def removeRepo(self, repo_id): - """ - Remove a given repository - """ - repos = self._get_repos('KCHREPOS0027E') - if repo_id not in repos.keys(): - raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) - - entry = repos.get(repo_id) - parser = ConfigParser() - with open(entry.repofile) as fd: - parser.readfp(fd) - - if len(parser.sections()) == 1: - os.remove(entry.repofile) - return - - parser.remove_section(repo_id) - with open(entry.repofile, "w") as fd: - parser.write(fd) - - -class AptRepo(object): - """ - Class to represent and operate with YUM repositories. - It's loaded only on those systems listed at YUM_DISTROS and loads necessary - modules in runtime. - """ - TYPE = 'deb' - KIMCHI_LIST = "kimchi-source.list" - CONFIG_ENTRY = ('dist', 'comps') - - def __init__(self): - getattr(__import__('apt_pkg'), 'init_config')() - getattr(__import__('apt_pkg'), 'init_system')() - config = getattr(__import__('apt_pkg'), 'config') - self.pkg_lock = getattr(__import__('apt_pkg'), 'SystemLock') - module = __import__('aptsources.sourceslist', globals(), locals(), - ['SourcesList'], -1) - - self._sourceparts_path = '/%s%s' % ( - config.get('Dir::Etc'), config.get('Dir::Etc::sourceparts')) - self._sourceslist = getattr(module, 'SourcesList') - self.filename = os.path.join(self._sourceparts_path, self.KIMCHI_LIST) - if not os.path.exists(self.filename): - with open(self.filename, 'w') as fd: - fd.write("# This file is managed by Kimchi and it must not " - "be modified manually\n") - - def _get_repos(self): - try: - with self.pkg_lock(): - repos = self._sourceslist() - repos.refresh() - except Exception, e: - kimchiLock.release() - raise OperationFailed('KCHREPOS0025E', {'err': e.message}) - - return repos - - def _get_repo_id(self, repo): - data = urlparse.urlparse(repo.uri) - name = data.hostname or data.path - return '%s-%s-%s' % (name, repo.dist, "-".join(repo.comps)) - - def _get_source_entry(self, repo_id): - kimchiLock.acquire() - repos = self._get_repos() - kimchiLock.release() - - for r in repos: - # Ignore deb-src repositories - if r.type != 'deb': - continue - - if self._get_repo_id(r) != repo_id: - continue - - return r - - return None - - def getRepositoriesList(self): - """ - Return a list of repositories IDs - - APT repositories there aren't the concept about repository ID, so for - internal control, the repository ID will be built as described in - _get_repo_id() - """ - kimchiLock.acquire() - repos = self._get_repos() - kimchiLock.release() - - res = [] - for r in repos: - # Ignore deb-src repositories - if r.type != 'deb': - continue - - res.append(self._get_repo_id(r)) - - return res - - def getRepo(self, repo_id): - """ - Return a dictionary in the repositories.Repositories() format of the - given repository ID with the information of a SourceEntry object. - """ - r = self._get_source_entry(repo_id) - if r is None: - raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) - - info = {'enabled': not r.disabled, - 'baseurl': r.uri, - 'config': {'dist': r.dist, - 'comps': r.comps}} - return info - - def addRepo(self, params): - """ - Add a new APT repository based on <params> - """ - # To create a APT repository the dist is a required parameter - # (in addition to baseurl, verified on controller through API.json) - config = params.get('config', None) - if config is None: - raise MissingParameter("KCHREPOS0019E") - - if 'dist' not in config.keys(): - raise MissingParameter("KCHREPOS0019E") - - uri = params['baseurl'] - dist = config['dist'] - comps = config.get('comps', []) - - validate_repo_url(uri) - - kimchiLock.acquire() - try: - repos = self._get_repos() - source_entry = repos.add('deb', uri, dist, comps, - file=self.filename) - with self.pkg_lock(): - repos.save() - except Exception as e: - kimchiLock.release() - raise OperationFailed("KCHREPOS0026E", {'err': e.message}) - kimchiLock.release() - return self._get_repo_id(source_entry) - - def toggleRepo(self, repo_id, enable): - """ - Enable a given repository - """ - r = self._get_source_entry(repo_id) - if r is None: - raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) - - if enable and not r.disabled: - raise InvalidOperation("KCHREPOS0015E", {'repo_id': repo_id}) - - if not enable and r.disabled: - raise InvalidOperation("KCHREPOS0016E", {'repo_id': repo_id}) - - if enable: - line = 'deb' - else: - line = '#deb' - - kimchiLock.acquire() - try: - repos = self._get_repos() - with self.pkg_lock(): - repos.remove(r) - repos.add(line, r.uri, r.dist, r.comps, file=self.filename) - repos.save() - except: - kimchiLock.release() - if enable: - raise OperationFailed("KCHREPOS0020E", {'repo_id': repo_id}) - - raise OperationFailed("KCHREPOS0021E", {'repo_id': repo_id}) - finally: - kimchiLock.release() - - return repo_id - - def updateRepo(self, repo_id, params): - """ - Update a given repository in repositories.Repositories() format - """ - old_info = self.getRepo(repo_id) - updated_info = copy.deepcopy(old_info) - updated_info['baseurl'] = params.get( - 'baseurl', updated_info['baseurl']) - - if 'config' in params.keys(): - config = params['config'] - updated_info['config']['dist'] = config.get( - 'dist', old_info['config']['dist']) - updated_info['config']['comps'] = config.get( - 'comps', old_info['config']['comps']) - - self.removeRepo(repo_id) - try: - return self.addRepo(updated_info) - except: - self.addRepo(old_info) - raise - - def removeRepo(self, repo_id): - """ - Remove a given repository - """ - r = self._get_source_entry(repo_id) - if r is None: - raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) - - kimchiLock.acquire() - try: - repos = self._get_repos() - with self.pkg_lock(): - repos.remove(r) - repos.save() - except: - kimchiLock.release() - raise OperationFailed("KCHREPOS0017E", {'repo_id': repo_id}) - finally: - kimchiLock.release() diff --git a/plugins/kimchi/root.py b/plugins/kimchi/root.py deleted file mode 100644 index 1e2bfc7..0000000 --- a/plugins/kimchi/root.py +++ /dev/null @@ -1,69 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import cherrypy - -from wok.i18n import messages -from wok.root import WokRoot - -import config -import mockmodel -import vnc -from control import sub_nodes -from model import model as kimchiModel - - -class KimchiRoot(WokRoot): - def __init__(self, wok_options): - if hasattr(wok_options, "model"): - self.model = wok_options.model - elif wok_options.test: - self.model = mockmodel.MockModel() - else: - self.model = kimchiModel.Model() - - dev_env = wok_options.environment != 'production' - super(KimchiRoot, self).__init__(self.model, dev_env) - - for ident, node in sub_nodes.items(): - setattr(self, ident, node(self.model)) - - if isinstance(self.model, kimchiModel.Model): - vnc_ws_proxy = vnc.new_ws_proxy() - cherrypy.engine.subscribe('exit', vnc_ws_proxy.terminate) - - self.api_schema = json.load(open(os.path.join(os.path.dirname( - os.path.abspath(__file__)), 'API.json'))) - self.paths = config.kimchiPaths - self.domain = 'kimchi' - self.messages = messages - - make_dirs = [ - os.path.abspath(config.get_distros_store()), - os.path.abspath(config.get_debugreports_path()), - os.path.abspath(config.get_screenshot_path()) - ] - for directory in make_dirs: - if not os.path.isdir(directory): - os.makedirs(directory) - - def get_custom_conf(self): - return config.KimchiConfig() diff --git a/plugins/kimchi/scan.py b/plugins/kimchi/scan.py deleted file mode 100644 index b475c46..0000000 --- a/plugins/kimchi/scan.py +++ /dev/null @@ -1,89 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -import glob -import hashlib -import os.path -import shutil -import tempfile -import time - -from wok.utils import wok_log - -from isoinfo import IsoImage, probe_iso - - -SCAN_IGNORE = ['/tmp/kimchi-scan-*'] - - -class Scanner(object): - SCAN_TTL = 300 - - def __init__(self, record_clean_cb): - self.clean_cb = record_clean_cb - - def delete(self): - self.clean_stale(-1) - - def clean_stale(self, window=SCAN_TTL): - """ - Clear scan pools generated before time window, - Clear all scan pools if window is -1. - """ - try: - now = time.time() - clean_list = glob.glob("/tmp/kimchi-scan-*") - for d in clean_list: - transient_pool = \ - os.path.basename(d).replace('kimchi-scan-', '')[0: -6] - if now - os.path.getmtime(d) > window: - shutil.rmtree(d) - self.clean_cb(transient_pool) - except OSError as e: - msg = "Exception %s occured when cleaning stale pool, ignore" - wok_log.debug(msg % e.message) - - def scan_dir_prepare(self, name): - # clean stale scan storage pools - self.clean_stale() - return tempfile.mkdtemp(prefix='kimchi-scan-' + name, dir='/tmp') - - def start_scan(self, cb, params): - def updater(iso_info): - iso_name = os.path.basename(iso_info['path'])[:-3] - - duplicates = "%s/%s*" % (params['pool_path'], iso_name) - for f in glob.glob(duplicates): - iso_img = IsoImage(f) - if (iso_info['distro'], iso_info['version']) == \ - iso_img.probe(): - return - - iso_path = iso_name + hashlib.md5(iso_info['path']).hexdigest() + \ - '.iso' - link_name = os.path.join(params['pool_path'], - os.path.basename(iso_path)) - os.symlink(iso_info['path'], link_name) - - ignore_paths = params.get('ignore_list', []) - scan_params = dict(path=params['scan_path'], updater=updater, - ignore_list=ignore_paths + SCAN_IGNORE) - probe_iso(None, scan_params) - cb('', True) diff --git a/plugins/kimchi/screenshot.py b/plugins/kimchi/screenshot.py deleted file mode 100644 index ffe5a1a..0000000 --- a/plugins/kimchi/screenshot.py +++ /dev/null @@ -1,184 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -import glob -import os -import signal -import tempfile -import time -import uuid - -try: - from PIL import Image -except ImportError: - import Image - - -from wok.utils import wok_log - -import config - - -(fd, pipe) = tempfile.mkstemp() -stream_test_result = None - - -class VMScreenshot(object): - OUTDATED_SECS = 5 - THUMBNAIL_SIZE = (256, 256) - LIVE_WINDOW = 60 - MAX_STREAM_ATTEMPTS = 10 - - def __init__(self, args): - self.vm_uuid = args['uuid'] - args.setdefault('thumbnail', - os.path.join(config.get_screenshot_path(), - '%s-%s.png' % - (self.vm_uuid, str(uuid.uuid4())))) - self.info = args - - @staticmethod - def get_stream_test_result(): - return stream_test_result - - def lookup(self): - now = time.time() - try: - last_update = os.path.getmtime(self.info['thumbnail']) - except OSError: - last_update = 0 - - if now - last_update > self.OUTDATED_SECS: - self._clean_extra(self.LIVE_WINDOW) - self._generate_thumbnail() - return 'plugins/kimchi/data/screenshots/%s' %\ - os.path.basename(self.info['thumbnail']) - - def _clean_extra(self, window=-1): - """ - Clear screenshots before time specified by window, - Clear all screenshots if window is -1. - """ - try: - now = time.time() - clear_list = glob.glob("%s/%s-*.png" % - (config.get_screenshot_path(), - self.vm_uuid)) - for f in clear_list: - if now - os.path.getmtime(f) > window: - os.unlink(f) - except OSError: - pass - - def delete(self): - return self._clean_extra() - - def _generate_scratch(self, thumbnail): - """ - Generate screenshot of given vm. - Override me in child class. - """ - pass - - def _create_black_image(self, thumbnail): - image = Image.new("RGB", self.THUMBNAIL_SIZE, 'black') - image.save(thumbnail) - - def _watch_stream_creation(self, thumbnail): - """ - This is a verification test for libvirt stream functionality. - - It is necessary to avoid the server hangs while creating the screenshot - image using libvirt stream API. - - This problem was found in libvirt 0.9.6 for SLES11 SP2. - - This test consists in running the screeshot creation with a timeout. - If timeout occurs, the libvirt is taking too much time to create the - screenshot image and the stream must be disabled it if happens - successively (to avoid blocking server requests). - """ - pid = os.fork() - if pid == 0: - try: - self._generate_scratch(thumbnail) - os._exit(0) - except: - os._exit(1) - else: - counter = 0 - ret = os.waitpid(pid, os.WNOHANG) - while ret == (0, 0) and counter < 3: - counter += 1 - time.sleep(1) - ret = os.waitpid(pid, os.WNOHANG) - - fd = open(pipe, "a") - if ret != (pid, 0): - fd.write("-") - if ret[0] != pid: - os.kill(int(pid), signal.SIGKILL) - os.waitpid(pid, 0) - else: - fd.write("+") - fd.close() - - def _get_test_result(self): - if not os.path.exists(pipe): - return - - fd = open(pipe, "r") - data = fd.read() - fd.close() - - if len(data) >= self.MAX_STREAM_ATTEMPTS or bool('+' in data): - global stream_test_result - stream_test_result = bool('+' in data) - os.remove(pipe) - - def _generate_thumbnail(self): - thumbnail = os.path.join(config.get_screenshot_path(), '%s-%s.png' % - (self.vm_uuid, str(uuid.uuid4()))) - - self._get_test_result() - if stream_test_result is None: - self._watch_stream_creation(thumbnail) - elif stream_test_result: - try: - self._generate_scratch(thumbnail) - except: - wok_log.error("screenshot_creation: Unable to create " - "screenshot image %s." % thumbnail) - else: - self._create_black_image(thumbnail) - - if os.path.getsize(thumbnail) == 0: - self._create_black_image(thumbnail) - else: - im = Image.open(thumbnail) - try: - # Prevent Image lib from lazy load, - # work around pic truncate validation in thumbnail generation - im.thumbnail(self.THUMBNAIL_SIZE) - except Exception as e: - wok_log.warning("Image load with warning: %s." % e) - im.save(thumbnail, "PNG") - - self.info['thumbnail'] = thumbnail diff --git a/plugins/kimchi/swupdate.py b/plugins/kimchi/swupdate.py deleted file mode 100644 index 84b927f..0000000 --- a/plugins/kimchi/swupdate.py +++ /dev/null @@ -1,263 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import subprocess -import time - -from wok.basemodel import Singleton -from wok.exception import NotFoundError, OperationFailed -from wok.utils import run_command, wok_log - -from config import kimchiLock -from yumparser import get_yum_packages_list_update - - -class SoftwareUpdate(object): - __metaclass__ = Singleton - - """ - Class to represent and operate with OS software update. - """ - def __init__(self): - # This stores all packages to be updated for Kimchi perspective. It's a - # dictionary of dictionaries, in the format {'package_name': package}, - # where: - # package = {'package_name': <string>, 'version': <string>, - # 'arch': <string>, 'repository': <string> - # } - self._packages = {} - - # This stores the number of packages to update - self._num2update = 0 - - # Get the distro of host machine and creates an object related to - # correct package management system - try: - __import__('yum') - wok_log.info("Loading YumUpdate features.") - self._pkg_mnger = YumUpdate() - except ImportError: - try: - __import__('apt') - wok_log.info("Loading AptUpdate features.") - self._pkg_mnger = AptUpdate() - except ImportError: - zypper_help = ["zypper", "--help"] - (stdout, stderr, returncode) = run_command(zypper_help) - if returncode == 0: - wok_log.info("Loading ZypperUpdate features.") - self._pkg_mnger = ZypperUpdate() - else: - raise Exception("There is no compatible package manager " - "for this system.") - - def _scanUpdates(self): - """ - Update self._packages with packages to be updated. - """ - self._packages = {} - self._num2update = 0 - - # Call system pkg_mnger to get the packages as list of dictionaries. - for pkg in self._pkg_mnger.getPackagesList(): - - # Check if already exist a package in self._packages - pkg_id = pkg.get('package_name') - if pkg_id in self._packages.keys(): - # package already listed to update. do nothing - continue - - # Update the self._packages and self._num2update - self._packages[pkg_id] = pkg - self._num2update = self._num2update + 1 - - def getUpdates(self): - """ - Return the self._packages. - """ - self._scanUpdates() - return self._packages - - def getUpdate(self, name): - """ - Return a dictionary with all info from a given package name. - """ - if name not in self._packages.keys(): - raise NotFoundError('KCHPKGUPD0002E', {'name': name}) - - return self._packages[name] - - def getNumOfUpdates(self): - """ - Return the number of packages to be updated. - """ - self._scanUpdates() - return self._num2update - - def doUpdate(self, cb, params): - """ - Execute the update - """ - # reset messages - cb('') - - cmd = self._pkg_mnger.update_cmd - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - msgs = [] - while proc.poll() is None: - msgs.append(proc.stdout.readline()) - cb(''.join(msgs)) - time.sleep(0.5) - - # read the final output lines - msgs.extend(proc.stdout.readlines()) - - retcode = proc.poll() - if retcode == 0: - return cb(''.join(msgs), True) - - msgs.extend(proc.stderr.readlines()) - return cb(''.join(msgs), False) - - -class YumUpdate(object): - """ - Class to represent and operate with YUM software update system. - It's loaded only on those systems listed at YUM_DISTROS and loads necessary - modules in runtime. - """ - def __init__(self): - self._pkgs = {} - self.update_cmd = ["yum", "-y", "update"] - - def _refreshUpdateList(self): - """ - Update the list of packages to be updated in the system. - """ - try: - kimchiLock.acquire() - self._pkgs = get_yum_packages_list_update() - except Exception, e: - raise OperationFailed('KCHPKGUPD0003E', {'err': str(e)}) - finally: - kimchiLock.release() - - def getPackagesList(self): - """ - Return a list of package's dictionaries. Each dictionary contains the - information about a package, in the format: - package = {'package_name': <string>, 'version': <string>, - 'arch': <string>, 'repository': <string>} - """ - self._refreshUpdateList() - pkg_list = [] - for pkg in self._pkgs: - package = {'package_name': pkg.name, 'version': pkg.version, - 'arch': pkg.arch, 'repository': pkg.ui_from_repo} - pkg_list.append(package) - return pkg_list - - -class AptUpdate(object): - """ - Class to represent and operate with APT software update system. - It's loaded only on those systems listed at APT_DISTROS and loads necessary - modules in runtime. - """ - def __init__(self): - self._pkgs = {} - self.pkg_lock = getattr(__import__('apt_pkg'), 'SystemLock') - self.update_cmd = ['apt-get', 'upgrade', '-y'] - - def _refreshUpdateList(self): - """ - Update the list of packages to be updated in the system. - """ - apt_cache = getattr(__import__('apt'), 'Cache')() - try: - with self.pkg_lock(): - apt_cache.update() - apt_cache.upgrade() - self._pkgs = apt_cache.get_changes() - except Exception, e: - kimchiLock.release() - raise OperationFailed('KCHPKGUPD0003E', {'err': e.message}) - - def getPackagesList(self): - """ - Return a list of package's dictionaries. Each dictionary contains the - information about a package, in the format - package = {'package_name': <string>, 'version': <string>, - 'arch': <string>, 'repository': <string>} - """ - kimchiLock.acquire() - self._refreshUpdateList() - kimchiLock.release() - pkg_list = [] - for pkg in self._pkgs: - package = {'package_name': pkg.shortname, - 'version': pkg.candidate.version, - 'arch': pkg._pkg.architecture, - 'repository': pkg.candidate.origins[0].label} - pkg_list.append(package) - - return pkg_list - - -class ZypperUpdate(object): - """ - Class to represent and operate with Zypper software update system. - It's loaded only on those systems listed at ZYPPER_DISTROS and loads - necessary modules in runtime. - """ - def __init__(self): - self._pkgs = {} - self.update_cmd = ["zypper", "--non-interactive", "update", - "--auto-agree-with-licenses"] - - def _refreshUpdateList(self): - """ - Update the list of packages to be updated in the system. - """ - self._pkgs = [] - cmd = ["zypper", "list-updates"] - (stdout, stderr, returncode) = run_command(cmd) - - if len(stderr) > 0: - raise OperationFailed('KCHPKGUPD0003E', {'err': stderr}) - - for line in stdout.split('\n'): - if line.find('v |') >= 0: - info = line.split(' | ') - package = {'package_name': info[2], 'version': info[4], - 'arch': info[5], 'repository': info[1]} - self._pkgs.append(package) - - def getPackagesList(self): - """ - Return a list of package's dictionaries. Each dictionary contains the - information about a package, in the format - package = {'package_name': <string>, 'version': <string>, - 'arch': <string>, 'repository': <string>} - """ - kimchiLock.acquire() - self._refreshUpdateList() - kimchiLock.release() - return self._pkgs diff --git a/plugins/kimchi/template.conf b/plugins/kimchi/template.conf deleted file mode 100644 index f3615e6..0000000 --- a/plugins/kimchi/template.conf +++ /dev/null @@ -1,47 +0,0 @@ -# -# Configuration file for Kimchi Templates -# - -[main] -# Memory in MB -#memory = 1024 - -# List of networks separated by comma -# Represents the virtual network interfaces to be assigned to guest -#networks = default, - -[storage] -# Storage pool used to handle the guest disk -#pool = default - -# Specify multiple [[disk.X]] sub-sections to add multiples disks to guest -# All the disk files will be created in the same storage pool as set above -[[disk.0]] -# Disk size in GB -#size = 10 - -# Disk format -#format = qcow2 - -[graphics] -# Graphics type -# Valid options: vnc | spice -#type = vnc - -# The network which the vnc/spice server listens on -#listen = 127.0.0.1 - -[processor] -# Number of vcpus -# When specifying CPU topology, make sure cpus value is equal to the product -# of sockets, cores, and threads. -#cpus = 1 - -# Number of sockets (not set by default) -#sockets = - -# Number of cores per socket (not set by default) -#cores = - -# Number of threads per core (not set by default) -#threads = diff --git a/plugins/kimchi/tests/Makefile.am b/plugins/kimchi/tests/Makefile.am deleted file mode 100644 index c1f6784..0000000 --- a/plugins/kimchi/tests/Makefile.am +++ /dev/null @@ -1,50 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -EXTRA_DIST = \ - Makefile.am \ - run_tests.sh.in \ - test_config.py.in \ - $(filter-out test_config.py, $(wildcard *.py)) \ - $(NULL) - -noinst_SCRIPTS = run_tests.sh - -do_substitution = \ - sed -e 's,[@]HAVE_PYMOD_UNITTEST[@],$(HAVE_PYMOD_UNITTEST),g' \ - -e 's,[@]prefix[@],$(prefix),g' \ - -e 's,[@]datadir[@],$(datadir),g' \ - -e 's,[@]PYTHON_VERSION[@],$(PYTHON_VERSION),g' \ - -e 's,[@]wokdir[@],$(pythondir)/wok,g' \ - -e 's,[@]pkgdatadir[@],$(pkgdatadir),g' - - -run_tests.sh: run_tests.sh.in Makefile - $(do_substitution) < $(srcdir)/run_tests.sh.in > run_tests.sh - chmod +x run_tests.sh - -test_config.py: test_config.py.in Makefile - $(do_substitution) < $(srcdir)/test_config.py.in > test_config.py - -check-local: - $(MKDIR_P) $(top_srcdir)/data/screenshots - ./run_tests.sh - -BUILT_SOURCES = test_config.py -CLEANFILES = run_tests.sh test_config.py diff --git a/plugins/kimchi/tests/iso_gen.py b/plugins/kimchi/tests/iso_gen.py deleted file mode 100644 index 736c660..0000000 --- a/plugins/kimchi/tests/iso_gen.py +++ /dev/null @@ -1,212 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import platform -import struct - -from wok.plugins.kimchi.isoinfo import IsoImage - - -iso_des = [ - ('openbsd', lambda v: True, - lambda v: 'OpenBSD/i386 %s Install CD' % v), - ('centos', lambda v: True, lambda v: 'CentOS_%s_Final' % v), - ('windows', '2000', 'W2AFPP'), - ('windows', 'xp', 'WXPFPP'), - ('windows', '2003', 'ARMECHK'), - ('windows', '2003r2', 'CRMEFPP'), - ('windows', '2008', 'KRTMSVOL'), - ('windows', '2008r2', 'GRMSXVOL'), - ('windows', 'vista', 'FB1EVOL'), - ('windows', '7', 'GRMCULFRER'), - ('windows', '8', 'HB1_CCPA_X86FRE'), - ('sles', '10', 'SLES10'), - ('sles', '11', 'SUSE_SLES-11-0-0'), - ('opensuse', '11.1', 'SU1110.001'), - ('opensuse', '11.3', 'openSUSE-DVD-x86_64.0702..001'), - ('opensuse', '11.4', 'openSUSE-DVD-x86_640024'), - ('opensuse', '12.1', 'openSUSE-DVD-x86_640039'), - ('opensuse', '12.2', 'openSUSE-DVD-x86_640167'), - ('opensuse', lambda v: True, lambda v: 'openSUSE-%s' % v), - ('rhel', '4.8', 'RHEL/4-U8'), - ('rhel', lambda v: v.startswith('6.'), lambda v: 'RHEL_%s' % v), - ('debian', lambda v: True, lambda v: 'Debian %s' % v), - ('ubuntu', - lambda v: v in ('7.10', '8.04', '8.10', '9.04', '9.10', '10.04', '10.10', - '11.04', '11.10', '12.04', '12.10', '13.04', '13.10', - '14.04'), - lambda v: 'Ubuntu %s' % v), - ('fedora', - lambda v: v in ('16', '17', '18', '19'), - lambda v: 'Fedora %s' % v) -] - - -class FakeIsoImage(object): - def _build_iso(self, fd, iso_volid, bootable): - if platform.machine().startswith('ppc'): - self._build_powerpc_bootable_iso(fd, iso_volid) - return - self._build_intel_iso(fd, iso_volid, bootable) - - def _build_powerpc_bootable_iso(self, fd, iso_volid): - self._build_prim_vol(fd, iso_volid) - self._build_bootable_ppc_path_table(fd) - - def _build_intel_iso(self, fd, iso_volid, bootable): - # Do not change the order of the method calls - self._build_el_boot(fd, bootable) - self._build_prim_vol(fd, iso_volid) - self._build_el_torito(fd) - - def _build_prim_vol(self, fd, iso_volid): - fd.seek(16 * IsoImage.SECTOR_SIZE) - fmt = IsoImage.VOL_DESC - vd_type = 1 - vd_ident = 'CD001' - vd_ver = 1 - pad0 = 1 - sys_id = 'fake os' - vol_id = iso_volid - data = (vd_type, vd_ident, vd_ver, pad0, sys_id, vol_id) - s = fmt.pack(*data) - fd.write(s) - self._add_sector_padding(fd, s) - - def _add_sector_padding(self, fd, s): - padding_len = IsoImage.SECTOR_SIZE - len(s) - fmt = struct.Struct('=%ss' % padding_len) - s = fmt.pack('a' * padding_len) - fd.write(s) - - def _build_el_torito(self, fd): - fmt = IsoImage.EL_TORITO_BOOT_RECORD - vd_type = 0 - vd_ident = 'CD001' - vd_ver = 1 - et_ident = "EL TORITO SPECIFICATION:" - pad0 = 'a' * 32 - boot_cat = 0 - data = (vd_type, vd_ident, vd_ver, et_ident, pad0, boot_cat) - s = fmt.pack(*data) - fd.write(s) - self._add_sector_padding(fd, s) - - def _build_el_boot(self, fd, bootable): - fmt = IsoImage.EL_TORITO_VALIDATION_ENTRY - hdr_id = 0 - platform_id = 0 - pad0 = 1 - ident = 'c' * 24 - csum = 1 - key55 = 0x55 - keyAA = 0xaa - data = (hdr_id, platform_id, pad0, ident, csum, key55, keyAA) - s = fmt.pack(*data) - fd.write(s) - - fmt = IsoImage.EL_TORITO_BOOT_ENTRY - if bootable: - boot = 0x88 - else: - boot = 0 - media_type = 1 - load_seg = 1 - sys_type = 1 - pad0 = 1 - sectors = 1 - load_rba = 1 - data = (boot, media_type, load_seg, sys_type, pad0, sectors, load_rba) - s = fmt.pack(*data) - fd.write(s) - - s = 'a' * IsoImage.SECTOR_SIZE - fd.write(s) - - def _build_bootable_ppc_path_table(self, fd): - # write path table locator - PATH_TABLE_LOC_OFFSET = 16 * IsoImage.SECTOR_SIZE + 132 - PATH_TABLE_SIZE_LOC = struct.Struct("<I 4s I") - path_table_size = 64 - path_table_loc = 18 - fd.seek(PATH_TABLE_LOC_OFFSET) - fmt = PATH_TABLE_SIZE_LOC - data = (path_table_size, 4*'0', path_table_loc) - s = fmt.pack(*data) - fd.write(s) - # write path table entry - fd.seek(path_table_loc * IsoImage.SECTOR_SIZE) - DIR_NAMELEN_LOCATION_PARENT = struct.Struct("<B B I H 3s") - dir_namelen = 3 - dir_loc = 19 - dir_parent = 1 - dir_name = 'ppc' - data = (dir_namelen, 0, dir_loc, dir_parent, dir_name) - fmt = DIR_NAMELEN_LOCATION_PARENT - s = fmt.pack(*data) - fd.write(s) - # write 'ppc' dir record - ppc_dir_offset = dir_loc * IsoImage.SECTOR_SIZE - fd.seek(ppc_dir_offset) - STATIC_DIR_RECORD_FMT = struct.Struct("<B 9s I 11s B 6s B 12s") - dir_rec_len = 1 - unused1 = 9 * '0' - dir_size = 100 - unused2 = 11 * '0' - file_flags = 0 - unused3 = 6 * '0' - file_name_len = 12 - boot_file_name = "bootinfo.txt" - data = (dir_rec_len, unused1, dir_size, unused2, file_flags, - unused3, file_name_len, boot_file_name) - fmt = STATIC_DIR_RECORD_FMT - s = fmt.pack(*data) - fd.write(s) - - -def construct_fake_iso(path, bootable, version, distro): - iso = FakeIsoImage() - - for d, v, gen_id in iso_des: - if d != distro: - continue - if hasattr(v, '__call__'): - supported = v(version) - else: - supported = version == v - - if not supported: - continue - - if hasattr(gen_id, '__call__'): - vol_id = gen_id(version) - else: - vol_id = gen_id - with open(path, 'w') as fd: - return iso._build_iso(fd, vol_id, bootable) - - raise Exception("%s: %s not supported generation" % (distro, version)) - - -if __name__ == '__main__': - construct_fake_iso('centos.iso', True, '6.1', 'centos') - construct_fake_iso('ubuntu12.04.iso', True, '12.04', 'ubuntu') - construct_fake_iso('fedora17.iso', True, '17', 'fedora') - construct_fake_iso('sles10.iso', True, '10', 'sles') - construct_fake_iso('openbsd.iso', True, '5.0', 'openbsd') diff --git a/plugins/kimchi/tests/run_tests.sh.in b/plugins/kimchi/tests/run_tests.sh.in deleted file mode 100644 index beef75e..0000000 --- a/plugins/kimchi/tests/run_tests.sh.in +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -HAVE_UNITTEST=@HAVE_PYMOD_UNITTEST@ -PYTHON_VER=@PYTHON_VERSION@ - -if [ "$1" = "-v" ]; then - OPTS="-v" - shift -else - OPTS="" -fi - -if [ $# -ne 0 ]; then - ARGS="$@" -else - ARGS=`find -name "test_*.py" | xargs -I @ basename @ .py` -fi - -if [ "$HAVE_UNITTEST" != "yes" -o "$PYTHON_VER" == "2.6" ]; then - CMD="unit2" -else - CMD="python -m unittest" -fi - -LIST=($ARGS) -MODEL_LIST=() -MOCK_LIST=() -for ((i=0;i<${#LIST[@]};i++)); do - - if [[ ${LIST[$i]} == test_model* ]]; then - MODEL_LIST+=(${LIST[$i]}) - else - MOCK_LIST+=(${LIST[$i]}) - fi -done - -PYTHONPATH=../plugins:../src:../ $CMD $OPTS ${MODEL_LIST[@]} ${MOCK_LIST[@]} diff --git a/plugins/kimchi/tests/test_authorization.py b/plugins/kimchi/tests/test_authorization.py deleted file mode 100644 index 87d68ab..0000000 --- a/plugins/kimchi/tests/test_authorization.py +++ /dev/null @@ -1,178 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import unittest -from functools import partial - -from wok.plugins.kimchi import mockmodel - -from iso_gen import construct_fake_iso -from utils import get_free_port, patch_auth, request -from utils import run_server, wait_task - - -test_server = None -model = None -host = None -port = None -ssl_port = None -fake_iso = '/tmp/fake.iso' - - -def setUpModule(): - global test_server, model, host, port, ssl_port - - patch_auth(sudo=False) - model = mockmodel.MockModel('/tmp/obj-store-test') - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - test_server = run_server(host, port, ssl_port, test_mode=True, model=model) - - # Create fake ISO to do the tests - construct_fake_iso(fake_iso, True, '12.04', 'ubuntu') - - -def tearDownModule(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - os.unlink(fake_iso) - - -class AuthorizationTests(unittest.TestCase): - def setUp(self): - self.request = partial(request, host, ssl_port) - model.reset() - - def test_nonroot_access(self): - # Non-root users can access static host information - resp = self.request('/plugins/kimchi/host', '{}', 'GET') - self.assertEquals(403, resp.status) - - # Non-root users can access host stats - resp = self.request('/plugins/kimchi/host/stats', '{}', 'GET') - self.assertEquals(403, resp.status) - - # Non-root users can not reboot/shutdown host system - resp = self.request('/plugins/kimchi/host/reboot', '{}', 'POST') - self.assertEquals(403, resp.status) - resp = self.request('/plugins/kimchi/host/shutdown', '{}', 'POST') - self.assertEquals(403, resp.status) - - # Non-root users can not get or debug reports - resp = self.request('/plugins/kimchi/debugreports', '{}', 'GET') - self.assertEquals(403, resp.status) - resp = self.request('/plugins/kimchi/debugreports', '{}', 'POST') - self.assertEquals(403, resp.status) - - # Non-root users can not create or delete network (only get) - resp = self.request('/plugins/kimchi/networks', '{}', 'GET') - self.assertEquals(200, resp.status) - resp = self.request('/plugins/kimchi/networks', '{}', 'POST') - self.assertEquals(403, resp.status) - resp = self.request('/plugins/kimchi/networks/default/activate', '{}', - 'POST') - self.assertEquals(403, resp.status) - resp = self.request('/plugins/kimchi/networks/default', '{}', 'DELETE') - self.assertEquals(403, resp.status) - - # Non-root users can not create or delete storage pool (only get) - resp = self.request('/plugins/kimchi/storagepools', '{}', 'GET') - self.assertEquals(200, resp.status) - resp = self.request('/plugins/kimchi/storagepools', '{}', 'POST') - self.assertEquals(403, resp.status) - resp = self.request('/plugins/kimchi/storagepools/default/activate', - '{}', 'POST') - self.assertEquals(403, resp.status) - resp = self.request('/plugins/kimchi/storagepools/default', '{}', - 'DELETE') - self.assertEquals(403, resp.status) - - # Non-root users can not update or delete a template - # but he can get and create a new one - resp = self.request('/plugins/kimchi/templates', '{}', 'GET') - self.assertEquals(403, resp.status) - req = json.dumps({'name': 'test', 'cdrom': fake_iso}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(403, resp.status) - resp = self.request('/plugins/kimchi/templates/test', '{}', 'PUT') - self.assertEquals(403, resp.status) - resp = self.request('/plugins/kimchi/templates/test', '{}', 'DELETE') - self.assertEquals(403, resp.status) - - # Non-root users can only get vms authorized to them - model.templates_create({'name': u'test', 'cdrom': fake_iso}) - - task_info = model.vms_create({ - 'name': u'test-me', - 'template': '/plugins/kimchi/templates/test' - }) - wait_task(model.task_lookup, task_info['id']) - - model.vm_update(u'test-me', - {'users': [mockmodel.fake_user.keys()[0]], - 'groups': []}) - - task_info = model.vms_create({ - 'name': u'test-usera', - 'template': '/plugins/kimchi/templates/test' - }) - wait_task(model.task_lookup, task_info['id']) - - non_root = list(set(model.users_get_list()) - set(['root']))[0] - model.vm_update(u'test-usera', {'users': [non_root], 'groups': []}) - - task_info = model.vms_create({ - 'name': u'test-groupa', - 'template': '/plugins/kimchi/templates/test' - }) - wait_task(model.task_lookup, task_info['id']) - a_group = model.groups_get_list()[0] - model.vm_update(u'test-groupa', {'groups': [a_group]}) - - resp = self.request('/plugins/kimchi/vms', '{}', 'GET') - self.assertEquals(200, resp.status) - vms_data = json.loads(resp.read()) - self.assertEquals([u'test-groupa', u'test-me'], - sorted([v['name'] for v in vms_data])) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(403, resp.status) - - # Create a vm using mockmodel directly to test Resource access - task_info = model.vms_create({ - 'name': 'kimchi-test', - 'template': '/plugins/kimchi/templates/test' - }) - wait_task(model.task_lookup, task_info['id']) - resp = self.request('/plugins/kimchi/vms/kimchi-test', '{}', 'PUT') - self.assertEquals(403, resp.status) - resp = self.request('/plugins/kimchi/vms/kimchi-test', '{}', 'DELETE') - self.assertEquals(403, resp.status) - - # Non-root users can only update VMs authorized by them - resp = self.request('/plugins/kimchi/vms/test-me/start', '{}', 'POST') - self.assertEquals(200, resp.status) - resp = self.request('/plugins/kimchi/vms/test-usera/start', '{}', - 'POST') - self.assertEquals(403, resp.status) - - model.template_delete('test') - model.vm_delete('test-me') diff --git a/plugins/kimchi/tests/test_config.py.in b/plugins/kimchi/tests/test_config.py.in deleted file mode 100644 index 4604eb1..0000000 --- a/plugins/kimchi/tests/test_config.py.in +++ /dev/null @@ -1,267 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import unittest -from cherrypy.lib.reprconf import Parser - -from wok.config import Paths, PluginPaths, WokConfig - -from wok.plugins.kimchi.config import get_debugreports_path -from wok.plugins.kimchi.config import get_screenshot_path -from wok.plugins.kimchi.config import KimchiConfig, KimchiPaths - - -get_prefix = None - - -def setUpModule(): - global get_prefix - get_prefix = Paths.get_prefix - - -def tearDownModule(): - Paths.get_prefix = KimchiPaths.get_prefix = get_prefix - - -class ConfigTests(unittest.TestCase): - def assertInstalledPath(self, actual, expected): - if '@pkgdatadir@' != '/usr/share/kimchi': - usr_local = '/usr/local' - if not expected.startswith('/usr'): - expected = usr_local + expected - self.assertEquals(actual, expected) - - def test_installed_paths(self): - Paths.get_prefix = lambda self: '@datadir@/wok' - paths = Paths() - self.assertInstalledPath(paths.state_dir, '/var/lib/wok') - self.assertInstalledPath(paths.log_dir, '/var/log/wok') - self.assertInstalledPath(paths.conf_dir, '/etc/wok') - self.assertInstalledPath(paths.src_dir, '@wokdir@') - self.assertInstalledPath(paths.plugins_dir, '@wokdir@/plugins') - self.assertInstalledPath(paths.ui_dir, '@datadir@/wok/ui') - self.assertInstalledPath(paths.mo_dir, '@prefix@/share/locale') - - def test_uninstalled_paths(self): - Paths.get_prefix = lambda self: '/home/user/wok' - paths = Paths() - self.assertEquals(paths.state_dir, '/home/user/wok/data') - self.assertEquals(paths.log_dir, '/home/user/wok/log') - self.assertEquals(paths.conf_dir, '/home/user/wok/src') - self.assertEquals(paths.src_dir, '/home/user/wok/src/wok') - self.assertEquals(paths.plugins_dir, '/home/user/wok/plugins') - self.assertEquals(paths.ui_dir, '/home/user/wok/ui') - self.assertEquals(paths.mo_dir, '/home/user/wok/mo') - - def test_installed_plugin_paths(self): - KimchiPaths.get_prefix = lambda self: '@datadir@/wok' - paths = KimchiPaths() - self.assertInstalledPath(paths.conf_dir, '/etc/wok/plugins.d') - self.assertInstalledPath(paths.conf_file, - '/etc/wok/plugins.d/kimchi.conf') - self.assertInstalledPath(paths.src_dir, '@wokdir@/plugins/kimchi') - self.assertInstalledPath(paths.ui_dir, - '@datadir@/wok/plugins/kimchi/ui') - self.assertInstalledPath(paths.mo_dir, '@prefix@/share/locale') - - def test_uninstalled_plugin_paths(self): - KimchiPaths.get_prefix = lambda self: '/home/user/wok' - paths = KimchiPaths() - self.assertEquals(paths.conf_dir, '/home/user/wok/plugins/kimchi') - self.assertEquals( - paths.conf_file, '/home/user/wok/plugins/kimchi/kimchi.conf') - self.assertEquals(paths.src_dir, '/home/user/wok/plugins/kimchi') - self.assertEquals(paths.ui_dir, '/home/user/wok/plugins/kimchi/ui') - self.assertEquals(paths.mo_dir, '/home/user/wok/plugins/kimchi/mo') - - def test_wok_config(self): - Paths.get_prefix = PluginPaths.get_prefix = get_prefix - paths = Paths() - CACHEEXPIRES = 31536000 - SESSIONSTIMEOUT = 10 - configObj = { - '/': { - 'tools.trailing_slash.on': False, - 'request.methods_with_bodies': ('POST', 'PUT'), - 'tools.nocache.on': True, - 'tools.proxy.on': True, - 'tools.sessions.on': True, - 'tools.sessions.name': 'wok', - 'tools.sessions.secure': True, - 'tools.sessions.httponly': True, - 'tools.sessions.locking': 'explicit', - 'tools.sessions.storage_type': 'ram', - 'tools.sessions.timeout': SESSIONSTIMEOUT, - 'tools.wokauth.on': False - }, - '/wok-ui.html': { - 'tools.wokauth.on': True - }, - '/css': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '%s/ui/css' % paths.prefix, - 'tools.expires.on': True, - 'tools.expires.secs': CACHEEXPIRES, - 'tools.nocache.on': False, - 'tools.wokauth.on': False - }, - '/js': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '%s/ui/js' % paths.prefix, - 'tools.expires.on': True, - 'tools.expires.secs': CACHEEXPIRES, - 'tools.nocache.on': False, - 'tools.wokauth.on': False - }, - '/libs': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '%s/ui/libs' % paths.prefix, - 'tools.expires.on': True, - 'tools.expires.secs': CACHEEXPIRES, - 'tools.nocache.on': False, - 'tools.wokauth.on': False - }, - '/images': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '%s/ui/images' % paths.prefix, - 'tools.nocache.on': False, - 'tools.wokauth.on': False - }, - '/favicon.ico': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': - '%s/images/logo.ico' % paths.ui_dir - }, - '/robots.txt': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': '%s/robots.txt' % paths.ui_dir - }, - } - - wok_config = WokConfig() - self.assertEquals(wok_config, configObj) - - - def test_kimchi_config(self): - KimchiPaths.get_prefix = PluginPaths.get_prefix = get_prefix - paths = KimchiPaths() - pluginPrefix = paths.add_prefix(paths.plugin_dir) - CACHEEXPIRES = 31536000 - SESSIONSTIMEOUT = 10 - configObj = { - 'wok': { - 'enable': True, - 'plugin_class': "KimchiRoot", - 'uri': '/%s' % paths.plugin_dir, - 'extra_auth_api_class': "control.sub_nodes" - }, - '/': { - 'tools.trailing_slash.on': False, - 'request.methods_with_bodies': ('POST', 'PUT'), - 'tools.nocache.on': True, - 'tools.proxy.on': True, - 'tools.sessions.on': True, - 'tools.sessions.name': 'wok', - 'tools.sessions.secure': True, - 'tools.sessions.httponly': True, - 'tools.sessions.locking': 'explicit', - 'tools.sessions.storage_type': 'ram', - 'tools.sessions.timeout': SESSIONSTIMEOUT, - 'tools.wokauth.on': True - }, - '/novnc': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': paths.novnc_dir, - 'tools.nocache.on': True, - 'tools.wokauth.on': True - }, - '/spice_auto.html': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': paths.spice_file, - 'tools.nocache.on': True, - 'tools.wokauth.on': True - }, - '/spice-html5': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': paths.spice_dir, - 'tools.nocache.on': True - }, - '/spice-html5/spice.css': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': paths.spice_css_file, - 'tools.nocache.on': True, - }, - '/ui/config/tab-ext.xml': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': '%s/ui/config/tab-ext.xml' % - pluginPrefix, - 'tools.nocache.on': True - }, - '/css': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '%s/ui/css' % pluginPrefix, - 'tools.expires.on': True, - 'tools.expires.secs': CACHEEXPIRES, - 'tools.nocache.on': False, - 'tools.wokauth.on': False - }, - '/js': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '%s/ui/js' % pluginPrefix, - 'tools.expires.on': True, - 'tools.expires.secs': CACHEEXPIRES, - 'tools.nocache.on': False, - 'tools.wokauth.on': False - }, - '/libs': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '%s/ui/libs' % pluginPrefix, - 'tools.expires.on': True, - 'tools.expires.secs': CACHEEXPIRES, - 'tools.nocache.on': False, - 'tools.wokauth.on': False, - }, - '/images': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '%s/ui/images' % pluginPrefix, - 'tools.nocache.on': False, - 'tools.wokauth.on': False - }, - '/data/screenshots': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': get_screenshot_path(), - 'tools.nocache.on': False - }, - '/data/debugreports': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': get_debugreports_path(), - 'tools.nocache.on': False, - 'tools.wokauth.on': True, - 'tools.staticdir.content_types': {'xz': 'application/x-xz'} - }, - '/help': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '%s/ui/pages/help' % pluginPrefix, - 'tools.nocache.on': True - } - } - - kimchi_config = Parser().dict_from_file(KimchiPaths().conf_file) - kimchi_config.update(KimchiConfig()) - self.assertEquals(kimchi_config, configObj) diff --git a/plugins/kimchi/tests/test_exception.py b/plugins/kimchi/tests/test_exception.py deleted file mode 100644 index 4459aa6..0000000 --- a/plugins/kimchi/tests/test_exception.py +++ /dev/null @@ -1,123 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import unittest - -from wok.plugins.kimchi import mockmodel - -from utils import get_free_port, patch_auth, request, run_server - - -test_server = None -model = None -host = None -port = None -ssl_port = None - - -def setup_server(environment='development'): - global test_server, model, host, port, ssl_port - - patch_auth() - model = mockmodel.MockModel('/tmp/obj-store-test') - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - test_server = run_server(host, port, ssl_port, test_mode=True, model=model, - environment=environment) - - -class ExceptionTests(unittest.TestCase): - def tearDown(self): - test_server.stop() - os.unlink('/tmp/obj-store-test') - - def test_production_env(self): - """ - Test reasons sanitized in production env - """ - setup_server('production') - # test 404 - resp = json.loads( - request(host, ssl_port, '/plugins/kimchi/vms/blah').read() - ) - self.assertEquals('404 Not Found', resp.get('code')) - - # test 405 wrong method - resp = json.loads(request(host, ssl_port, '/', None, 'DELETE').read()) - msg = u'WOKAPI0002E: Delete is not allowed for wokroot' - self.assertEquals('405 Method Not Allowed', resp.get('code')) - self.assertEquals(msg, resp.get('reason')) - - # test 400 parse error - resp = json.loads( - request(host, ssl_port, '/plugins/kimchi/vms', '{', 'POST').read() - ) - msg = u'WOKAPI0006E: Unable to parse JSON request' - self.assertEquals('400 Bad Request', resp.get('code')) - self.assertEquals(msg, resp.get('reason')) - self.assertNotIn('call_stack', resp) - - # test 400 missing required parameter - req = json.dumps({}) - resp = json.loads( - request(host, ssl_port, '/plugins/kimchi/vms', req, 'POST').read() - ) - self.assertEquals('400 Bad Request', resp.get('code')) - m = u"KCHVM0016E: Specify a template to create a virtual machine from" - self.assertEquals(m, resp.get('reason')) - self.assertNotIn('call_stack', resp) - - def test_development_env(self): - """ - Test traceback thrown in development env - """ - setup_server() - # test 404 - resp = json.loads( - request(host, ssl_port, '/plugins/kimchi/vms/blah').read() - ) - self.assertEquals('404 Not Found', resp.get('code')) - - # test 405 wrong method - resp = json.loads(request(host, ssl_port, '/', None, 'DELETE').read()) - msg = u'WOKAPI0002E: Delete is not allowed for wokroot' - self.assertEquals('405 Method Not Allowed', resp.get('code')) - self.assertEquals(msg, resp.get('reason')) - - # test 400 parse error - resp = json.loads( - request(host, ssl_port, '/plugins/kimchi/vms', '{', 'POST').read() - ) - msg = u'WOKAPI0006E: Unable to parse JSON request' - self.assertEquals('400 Bad Request', resp.get('code')) - self.assertEquals(msg, resp.get('reason')) - self.assertIn('call_stack', resp) - - # test 400 missing required parameter - req = json.dumps({}) - resp = json.loads( - request(host, ssl_port, '/plugins/kimchi/vms', req, 'POST').read() - ) - m = u"KCHVM0016E: Specify a template to create a virtual machine from" - self.assertEquals('400 Bad Request', resp.get('code')) - self.assertEquals(m, resp.get('reason')) - self.assertIn('call_stack', resp) diff --git a/plugins/kimchi/tests/test_host.py b/plugins/kimchi/tests/test_host.py deleted file mode 100644 index 6cd0833..0000000 --- a/plugins/kimchi/tests/test_host.py +++ /dev/null @@ -1,206 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import platform -import psutil -import tempfile -import time -import unittest -from functools import partial - -from wok.plugins.kimchi.mockmodel import MockModel - -from utils import get_free_port, patch_auth, request, run_server, wait_task - - -test_server = None -model = None -host = None -ssl_port = None -tmpfile = None - - -def setUpModule(): - global test_server, model, host, ssl_port, tmpfile - - patch_auth() - tmpfile = tempfile.mktemp() - model = MockModel(tmpfile) - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - cherrypy_port = get_free_port('cherrypy_port') - test_server = run_server(host, port, ssl_port, test_mode=True, - cherrypy_port=cherrypy_port, model=model) - - -def tearDownModule(): - test_server.stop() - os.unlink(tmpfile) - - -class HostTests(unittest.TestCase): - def setUp(self): - self.request = partial(request, host, ssl_port) - - def test_hostinfo(self): - resp = self.request('/plugins/kimchi/host').read() - info = json.loads(resp) - keys = ['os_distro', 'os_version', 'os_codename', 'cpu_model', - 'memory', 'cpus'] - self.assertEquals(sorted(keys), sorted(info.keys())) - - distro, version, codename = platform.linux_distribution() - self.assertEquals(distro, info['os_distro']) - self.assertEquals(version, info['os_version']) - self.assertEquals(unicode(codename, "utf-8"), info['os_codename']) - self.assertEquals(psutil.TOTAL_PHYMEM, info['memory']) - - def test_hoststats(self): - time.sleep(1) - stats_keys = ['cpu_utilization', 'memory', 'disk_read_rate', - 'disk_write_rate', 'net_recv_rate', 'net_sent_rate'] - resp = self.request('/plugins/kimchi/host/stats').read() - stats = json.loads(resp) - self.assertEquals(sorted(stats_keys), sorted(stats.keys())) - - cpu_utilization = stats['cpu_utilization'] - self.assertIsInstance(cpu_utilization, float) - self.assertGreaterEqual(cpu_utilization, 0.0) - self.assertTrue(cpu_utilization <= 100.0) - - memory_stats = stats['memory'] - self.assertIn('total', memory_stats) - self.assertIn('free', memory_stats) - self.assertIn('cached', memory_stats) - self.assertIn('buffers', memory_stats) - self.assertIn('avail', memory_stats) - - resp = self.request('/plugins/kimchi/host/stats/history').read() - history = json.loads(resp) - self.assertEquals(sorted(stats_keys), sorted(history.keys())) - - def test_host_actions(self): - def _task_lookup(taskid): - return json.loads( - self.request('/plugins/kimchi/tasks/%s' % taskid).read() - ) - - resp = self.request('/plugins/kimchi/host/shutdown', '{}', 'POST') - self.assertEquals(200, resp.status) - resp = self.request('/plugins/kimchi/host/reboot', '{}', 'POST') - self.assertEquals(200, resp.status) - - # Test system update - resp = self.request('/plugins/kimchi/host/packagesupdate', None, 'GET') - pkgs = json.loads(resp.read()) - self.assertEquals(3, len(pkgs)) - - pkg_keys = ['package_name', 'repository', 'arch', 'version'] - for p in pkgs: - name = p['package_name'] - resp = self.request('/plugins/kimchi/host/packagesupdate/' + name, - None, 'GET') - info = json.loads(resp.read()) - self.assertEquals(sorted(pkg_keys), sorted(info.keys())) - - resp = self.request('/plugins/kimchi/host/swupdate', '{}', 'POST') - task = json.loads(resp.read()) - task_params = [u'id', u'message', u'status', u'target_uri'] - self.assertEquals(sorted(task_params), sorted(task.keys())) - - resp = self.request('/tasks/' + task[u'id'], None, - 'GET') - task_info = json.loads(resp.read()) - self.assertEquals(task_info['status'], 'running') - wait_task(_task_lookup, task_info['id']) - resp = self.request('/tasks/' + task[u'id'], None, - 'GET') - task_info = json.loads(resp.read()) - self.assertEquals(task_info['status'], 'finished') - self.assertIn(u'All packages updated', task_info['message']) - pkgs = model.packagesupdate_get_list() - self.assertEquals(0, len(pkgs)) - - def test_host_partitions(self): - resp = self.request('/plugins/kimchi/host/partitions') - self.assertEquals(200, resp.status) - partitions = json.loads(resp.read()) - - keys = ['name', 'path', 'type', 'fstype', 'size', 'mountpoint', - 'available'] - for item in partitions: - resp = self.request('/plugins/kimchi/host/partitions/%s' % - item['name']) - info = json.loads(resp.read()) - self.assertEquals(sorted(info.keys()), sorted(keys)) - - def test_host_devices(self): - def asset_devices_type(devices, dev_type): - for dev in devices: - self.assertEquals(dev['device_type'], dev_type) - - resp = self.request('/plugins/kimchi/host/devices?_cap=scsi_host') - nodedevs = json.loads(resp.read()) - # Mockmodel brings 3 preconfigured scsi fc_host - self.assertEquals(3, len(nodedevs)) - - nodedev = json.loads( - self.request('/plugins/kimchi/host/devices/scsi_host2').read() - ) - # Mockmodel generates random wwpn and wwnn - self.assertEquals('scsi_host2', nodedev['name']) - self.assertEquals('fc_host', nodedev['adapter']['type']) - self.assertEquals(16, len(nodedev['adapter']['wwpn'])) - self.assertEquals(16, len(nodedev['adapter']['wwnn'])) - - devs = json.loads(self.request('/plugins/kimchi/host/devices').read()) - dev_names = [dev['name'] for dev in devs] - for dev_type in ('pci', 'usb_device', 'scsi'): - resp = self.request('/plugins/kimchi/host/devices?_cap=%s' % - dev_type) - devsByType = json.loads(resp.read()) - names = [dev['name'] for dev in devsByType] - self.assertTrue(set(names) <= set(dev_names)) - asset_devices_type(devsByType, dev_type) - - resp = self.request('/plugins/kimchi/host/devices?_passthrough=true') - passthru_devs = [dev['name'] for dev in json.loads(resp.read())] - self.assertTrue(set(passthru_devs) <= set(dev_names)) - - for dev_type in ('pci', 'usb_device', 'scsi'): - resp = self.request( - '/plugins/kimchi/host/devices?_cap=%s&_passthrough=true' % - dev_type - ) - filteredDevs = json.loads(resp.read()) - filteredNames = [dev['name'] for dev in filteredDevs] - self.assertTrue(set(filteredNames) <= set(dev_names)) - asset_devices_type(filteredDevs, dev_type) - - for dev in passthru_devs: - resp = self.request( - '/plugins/kimchi/host/devices?_passthrough_affected_by=%s' % - dev - ) - affected_devs = [dev['name'] for dev in json.loads(resp.read())] - self.assertTrue(set(affected_devs) <= set(dev_names)) diff --git a/plugins/kimchi/tests/test_mock_network.py b/plugins/kimchi/tests/test_mock_network.py deleted file mode 100644 index 4e2a939..0000000 --- a/plugins/kimchi/tests/test_mock_network.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import unittest -from functools import partial - -from wok.plugins.kimchi.mockmodel import MockModel - -from test_model_network import _do_network_test -from utils import get_free_port, patch_auth, request, run_server - - -model = None -test_server = None -host = None -port = None -ssl_port = None -cherrypy_port = None - - -def setUpModule(): - global test_server, model, host, port, ssl_port, cherrypy_port - - patch_auth() - model = MockModel('/tmp/obj-store-test') - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - cherrypy_port = get_free_port('cherrypy_port') - test_server = run_server(host, port, ssl_port, test_mode=True, - cherrypy_port=cherrypy_port, model=model) - - -def tearDownModule(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - - -class MockNetworkTests(unittest.TestCase): - def setUp(self): - self.request = partial(request, host, ssl_port) - model.reset() - - def test_vlan_tag_bridge(self): - # Verify the current system has at least one interface to create a - # bridged network - interfaces = json.loads( - self.request('/plugins/kimchi/interfaces?type=nic').read() - ) - if len(interfaces) > 0: - iface = interfaces[0]['name'] - _do_network_test(self, model, {'name': u'bridge-network', - 'connection': 'bridge', - 'interface': iface, 'vlan_id': 987}) diff --git a/plugins/kimchi/tests/test_mock_storagepool.py b/plugins/kimchi/tests/test_mock_storagepool.py deleted file mode 100644 index 5cf5b3e..0000000 --- a/plugins/kimchi/tests/test_mock_storagepool.py +++ /dev/null @@ -1,147 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import unittest -from functools import partial - -from wok.plugins.kimchi.mockmodel import MockModel - -from utils import get_free_port, patch_auth, request, run_server - - -model = None -test_server = None -host = None -port = None -ssl_port = None -cherrypy_port = None - - -def setUpModule(): - global test_server, model, host, port, ssl_port, cherrypy_port - - patch_auth() - model = MockModel('/tmp/obj-store-test') - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - cherrypy_port = get_free_port('cherrypy_port') - test_server = run_server(host, port, ssl_port, test_mode=True, - cherrypy_port=cherrypy_port, model=model) - - -def tearDownModule(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - - -class MockStoragepoolTests(unittest.TestCase): - def setUp(self): - self.request = partial(request, host, ssl_port) - model.reset() - - def _task_lookup(self, taskid): - return json.loads( - self.request('/tasks/%s' % taskid).read() - ) - - def test_storagepool(self): - # MockModel always returns 2 partitions (vdx, vdz) - partitions = json.loads( - self.request('/plugins/kimchi/host/partitions').read() - ) - devs = [dev['path'] for dev in partitions] - - # MockModel always returns 3 FC devices - fc_devs = json.loads( - self.request('/plugins/kimchi/host/devices?_cap=fc_host').read() - ) - fc_devs = [dev['name'] for dev in fc_devs] - - poolDefs = [ - {'type': 'dir', 'name': u'k������h��UnitTestDirPool', - 'path': '/tmp/kimchi-images'}, - {'type': 'netfs', 'name': u'k������h��UnitTestNSFPool', - 'source': {'host': 'localhost', - 'path': '/var/lib/kimchi/nfs-pool'}}, - {'type': 'scsi', 'name': u'k������h��UnitTestSCSIFCPool', - 'source': {'adapter_name': fc_devs[0]}}, - {'type': 'iscsi', 'name': u'k������h��UnitTestISCSIPool', - 'source': {'host': '127.0.0.1', - 'target': 'iqn.2015-01.localhost.kimchiUnitTest'}}, - {'type': 'logical', 'name': u'k������h��UnitTestLogicalPool', - 'source': {'devices': [devs[0]]}}] - - def _do_test(params): - name = params['name'] - uri = '/plugins/kimchi/storagepools/%s' % name.encode('utf-8') - - req = json.dumps(params) - resp = self.request('/plugins/kimchi/storagepools', req, 'POST') - self.assertEquals(201, resp.status) - - # activate the storage pool - resp = self.request(uri + '/activate', '{}', 'POST') - storagepool = json.loads(self.request(uri).read()) - self.assertEquals('active', storagepool['state']) - - # Set autostart flag of an active storage pool - for autostart in [True, False]: - t = {'autostart': autostart} - req = json.dumps(t) - resp = self.request(uri, req, 'PUT') - storagepool = json.loads(self.request(uri).read()) - self.assertEquals(autostart, storagepool['autostart']) - - # Extend an active logical pool - if params['type'] == 'logical': - t = {'disks': [devs[1]]} - req = json.dumps(t) - resp = self.request(uri, req, 'PUT') - self.assertEquals(200, resp.status) - - # Deactivate the storage pool - resp = self.request(uri + '/deactivate', '{}', 'POST') - storagepool = json.loads(self.request(uri).read()) - self.assertEquals('inactive', storagepool['state']) - - # Set autostart flag of an inactive storage pool - for autostart in [True, False]: - t = {'autostart': autostart} - req = json.dumps(t) - resp = self.request(uri, req, 'PUT') - storagepool = json.loads(self.request(uri).read()) - self.assertEquals(autostart, storagepool['autostart']) - - # Extend an inactive logical pool - if params['type'] == 'logical': - t = {'disks': [devs[1]]} - req = json.dumps(t) - resp = self.request(uri, req, 'PUT') - self.assertEquals(200, resp.status) - - # Delete the storage pool - resp = self.request(uri, '{}', 'DELETE') - self.assertEquals(204, resp.status) - - for pool in poolDefs: - _do_test(pool) diff --git a/plugins/kimchi/tests/test_mock_storagevolume.py b/plugins/kimchi/tests/test_mock_storagevolume.py deleted file mode 100644 index 9d0a5ad..0000000 --- a/plugins/kimchi/tests/test_mock_storagevolume.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import unittest -from functools import partial - -from wok.plugins.kimchi.mockmodel import MockModel - -from test_model_storagevolume import _do_volume_test -from utils import get_free_port, patch_auth, request, run_server - - -model = None -test_server = None -host = None -port = None -ssl_port = None -cherrypy_port = None - - -def setUpModule(): - global test_server, model, host, port, ssl_port, cherrypy_port - - patch_auth() - model = MockModel('/tmp/obj-store-test') - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - cherrypy_port = get_free_port('cherrypy_port') - test_server = run_server(host, port, ssl_port, test_mode=True, - cherrypy_port=cherrypy_port, model=model) - - -def tearDownModule(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - - -class MockStorageVolumeTests(unittest.TestCase): - def setUp(self): - self.request = partial(request, host, ssl_port) - - def test_storagevolume(self): - # MockModel always returns 2 partitions (vdx, vdz) - partitions = json.loads( - self.request('/plugins/kimchi/host/partitions').read() - ) - devs = [dev['path'] for dev in partitions] - - # MockModel always returns 3 FC devices - fc_devs = json.loads( - self.request('/plugins/kimchi/host/devices?_cap=fc_host').read() - ) - fc_devs = [dev['name'] for dev in fc_devs] - - poolDefs = [ - {'type': 'dir', 'name': u'k������h��UnitTestDirPool', - 'path': '/tmp/kimchi-images'}, - {'type': 'netfs', 'name': u'k������h��UnitTestNSFPool', - 'source': {'host': 'localhost', - 'path': '/var/lib/kimchi/nfs-pool'}}, - {'type': 'scsi', 'name': u'k������h��UnitTestSCSIFCPool', - 'source': {'adapter_name': fc_devs[0]}}, - {'type': 'iscsi', 'name': u'k������h��UnitTestISCSIPool', - 'source': {'host': '127.0.0.1', - 'target': 'iqn.2015-01.localhost.kimchiUnitTest'}}, - {'type': 'logical', 'name': u'k������h��UnitTestLogicalPool', - 'source': {'devices': [devs[0]]}}] - - for pool in poolDefs: - pool_name = pool['name'] - uri = '/plugins/kimchi/storagepools/%s' % pool_name.encode('utf-8') - req = json.dumps(pool) - resp = self.request('/plugins/kimchi/storagepools', req, 'POST') - self.assertEquals(201, resp.status) - # activate the storage pool - resp = self.request(uri + '/activate', '{}', 'POST') - self.assertEquals(200, resp.status) - _do_volume_test(self, model, host, ssl_port, pool_name) diff --git a/plugins/kimchi/tests/test_mockmodel.py b/plugins/kimchi/tests/test_mockmodel.py deleted file mode 100644 index ffbf8d5..0000000 --- a/plugins/kimchi/tests/test_mockmodel.py +++ /dev/null @@ -1,141 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import cherrypy -import json -import os -import time -import unittest - -from wok.plugins.kimchi import mockmodel -from wok.plugins.kimchi.osinfo import get_template_default - -from utils import get_free_port, patch_auth, request, run_server, wait_task - - -test_server = None -model = None -host = None -port = None -ssl_port = None -fake_iso = None - - -def setUpModule(): - global host, port, ssl_port, model, test_server, fake_iso - cherrypy.request.headers = {'Accept': 'application/json'} - model = mockmodel.MockModel('/tmp/obj-store-test') - patch_auth() - port = get_free_port('http') - ssl_port = get_free_port('https') - host = '127.0.0.1' - test_server = run_server(host, port, ssl_port, test_mode=True, - model=model) - fake_iso = '/tmp/fake.iso' - open(fake_iso, 'w').close() - - -def tearDown(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - os.unlink(fake_iso) - - -class MockModelTests(unittest.TestCase): - def setUp(self): - model.reset() - - def test_screenshot_refresh(self): - # Create a VM - req = json.dumps({'name': 'test', 'cdrom': fake_iso}) - request(host, ssl_port, '/plugins/kimchi/templates', req, 'POST') - req = json.dumps({'name': 'test-vm', 'template': '/templates/test'}) - resp = request(host, ssl_port, '/plugins/kimchi/vms', req, 'POST') - task = json.loads(resp.read()) - wait_task(model.task_lookup, task['id']) - - # Test screenshot refresh for running vm - request(host, ssl_port, '/plugins/kimchi/vms/test-vm/start', '{}', - 'POST') - resp = request(host, ssl_port, - '/plugins/kimchi/vms/test-vm/screenshot') - self.assertEquals(200, resp.status) - self.assertEquals('image/png', resp.getheader('content-type')) - resp1 = request(host, ssl_port, '/plugins/kimchi/vms/test-vm') - rspBody = resp1.read() - testvm_Data = json.loads(rspBody) - screenshotURL = testvm_Data['screenshot'] - time.sleep(5) - resp2 = request(host, ssl_port, screenshotURL) - self.assertEquals(200, resp2.status) - self.assertEquals(resp2.getheader('content-type'), - resp.getheader('content-type')) - self.assertEquals(resp2.getheader('content-length'), - resp.getheader('content-length')) - self.assertEquals(resp2.getheader('last-modified'), - resp.getheader('last-modified')) - - def test_vm_list_sorted(self): - req = json.dumps({'name': 'test', 'cdrom': fake_iso}) - request(host, ssl_port, '/plugins/kimchi/templates', req, 'POST') - - def add_vm(name): - # Create a VM - req = json.dumps({'name': name, - 'template': '/plugins/kimchi/templates/test'}) - task = json.loads(request(host, ssl_port, '/plugins/kimchi/vms', - req, 'POST').read()) - wait_task(model.task_lookup, task['id']) - - vms = [u'abc', u'bca', u'cab', u'xba'] - for vm in vms: - add_vm(vm) - - vms.append(u'test') - self.assertEqual(model.vms_get_list(), sorted(vms)) - - def test_vm_info(self): - model.templates_create({'name': u'test', - 'cdrom': fake_iso}) - task = model.vms_create({'name': u'test-vm', - 'template': '/plugins/kimchi/templates/test'}) - wait_task(model.task_lookup, task['id']) - vms = model.vms_get_list() - self.assertEquals(2, len(vms)) - self.assertIn(u'test-vm', vms) - - keys = set(('name', 'state', 'stats', 'uuid', 'memory', 'cpus', - 'screenshot', 'icon', 'graphics', 'users', 'groups', - 'access', 'persistent')) - - stats_keys = set(('cpu_utilization', - 'net_throughput', 'net_throughput_peak', - 'io_throughput', 'io_throughput_peak')) - - info = model.vm_lookup(u'test-vm') - self.assertEquals(keys, set(info.keys())) - self.assertEquals('shutoff', info['state']) - self.assertEquals('test-vm', info['name']) - self.assertEquals(get_template_default('old', 'memory'), - info['memory']) - self.assertEquals(1, info['cpus']) - self.assertEquals('images/icon-vm.png', info['icon']) - self.assertEquals(stats_keys, set(info['stats'].keys())) - self.assertEquals('vnc', info['graphics']['type']) - self.assertEquals('127.0.0.1', info['graphics']['listen']) diff --git a/plugins/kimchi/tests/test_model.py b/plugins/kimchi/tests/test_model.py deleted file mode 100644 index 7c89048..0000000 --- a/plugins/kimchi/tests/test_model.py +++ /dev/null @@ -1,1248 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import grp -import os -import pwd -import re -import shutil -import time -import unittest -import uuid - -import wok.objectstore -from wok.basemodel import Singleton -from wok.config import config -from wok.exception import InvalidOperation -from wok.exception import InvalidParameter, NotFoundError, OperationFailed -from wok.rollbackcontext import RollbackContext -from wok.utils import add_task - -from wok.plugins.kimchi import netinfo -from wok.plugins.kimchi.osinfo import get_template_default -from wok.plugins.kimchi.model import model -from wok.plugins.kimchi.model.libvirtconnection import LibvirtConnection - -import iso_gen -import utils - - -invalid_repository_urls = ['www.fedora.org', # missing protocol - '://www.fedora.org', # missing protocol - 'http://www.fedora', # invalid domain name - 'file:///home/foobar'] # invalid path - -TMP_DIR = '/var/lib/kimchi/tests/' -UBUNTU_ISO = TMP_DIR + 'ubuntu14.04.iso' - - -def setUpModule(): - if not os.path.exists(TMP_DIR): - os.makedirs(TMP_DIR) - - iso_gen.construct_fake_iso(UBUNTU_ISO, True, '14.04', 'ubuntu') - - # Some FeatureTests functions depend on server to validate their result. - # As CapabilitiesModel is a Singleton class it will get the first result - # from FeatureTests which may be wrong when using the Model instance - # directly - the case of this test_model.py - # So clean Singleton instances to make sure to get the right result when - # running the following tests. - Singleton._instances = {} - - -def tearDownModule(): - shutil.rmtree(TMP_DIR) - - -class ModelTests(unittest.TestCase): - def setUp(self): - self.tmp_store = '/tmp/kimchi-store-test' - - def tearDown(self): - # FIXME: Tests using 'test:///default' URI should be moved to - # test_rest or test_mockmodel to avoid overriding problems - LibvirtConnection._connections['test:///default'] = {} - - os.unlink(self.tmp_store) - - def test_vm_info(self): - inst = model.Model('test:///default', self.tmp_store) - vms = inst.vms_get_list() - self.assertEquals(1, len(vms)) - self.assertEquals('test', vms[0]) - - keys = set(('name', 'state', 'stats', 'uuid', 'memory', 'cpus', - 'screenshot', 'icon', 'graphics', 'users', 'groups', - 'access', 'persistent')) - - stats_keys = set(('cpu_utilization', - 'net_throughput', 'net_throughput_peak', - 'io_throughput', 'io_throughput_peak')) - info = inst.vm_lookup('test') - self.assertEquals(keys, set(info.keys())) - self.assertEquals('running', info['state']) - self.assertEquals('test', info['name']) - self.assertEquals(2048, info['memory']) - self.assertEquals(2, info['cpus']) - self.assertEquals(None, info['icon']) - self.assertEquals(stats_keys, set(info['stats'].keys())) - self.assertRaises(NotFoundError, inst.vm_lookup, 'nosuchvm') - self.assertEquals([], info['users']) - self.assertEquals([], info['groups']) - self.assertTrue(info['persistent']) - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_vm_lifecycle(self): - inst = model.Model(objstore_loc=self.tmp_store) - - with RollbackContext() as rollback: - vol_params = {'name': u'test-vol', 'capacity': 1024} - task = inst.storagevolumes_create(u'default', vol_params) - rollback.prependDefer(inst.storagevolume_delete, u'default', - vol_params['name']) - inst.task_wait(task['id']) - task = inst.task_lookup(task['id']) - self.assertEquals('finished', task['status']) - vol = inst.storagevolume_lookup(u'default', vol_params['name']) - - params = {'name': 'test', 'disks': [{'base': vol['path'], - 'size': 1}], - 'cdrom': UBUNTU_ISO} - inst.templates_create(params) - rollback.prependDefer(inst.template_delete, 'test') - - params = {'name': 'kimchi-vm', - 'template': '/plugins/kimchi/templates/test'} - task = inst.vms_create(params) - rollback.prependDefer(inst.vm_delete, 'kimchi-vm') - inst.task_wait(task['id'], 10) - task = inst.task_lookup(task['id']) - self.assertEquals('finished', task['status']) - - vms = inst.vms_get_list() - self.assertTrue('kimchi-vm' in vms) - - inst.vm_start('kimchi-vm') - - info = inst.vm_lookup('kimchi-vm') - self.assertEquals('running', info['state']) - - self.assertRaises(InvalidOperation, inst.vmsnapshots_create, - u'kimchi-vm') - - inst.vm_poweroff(u'kimchi-vm') - vm = inst.vm_lookup(u'kimchi-vm') - - empty_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm') - self.assertEquals({}, empty_snap) - - # this snapshot should be deleted when its VM is deleted - params = {'name': u'mysnap'} - task = inst.vmsnapshots_create(u'kimchi-vm', params) - inst.task_wait(task['id']) - task = inst.task_lookup(task['id']) - self.assertEquals('finished', task['status']) - - self.assertRaises(NotFoundError, inst.vmsnapshot_lookup, - u'kimchi-vm', u'foobar') - - snap = inst.vmsnapshot_lookup(u'kimchi-vm', params['name']) - self.assertTrue(int(time.time()) >= int(snap['created'])) - self.assertEquals(vm['state'], snap['state']) - self.assertEquals(params['name'], snap['name']) - self.assertEquals(u'', snap['parent']) - - snaps = inst.vmsnapshots_get_list(u'kimchi-vm') - self.assertEquals([params['name']], snaps) - - current_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm') - self.assertEquals(snap, current_snap) - - task = inst.vmsnapshots_create(u'kimchi-vm') - snap_name = task['target_uri'].split('/')[-1] - rollback.prependDefer(inst.vmsnapshot_delete, - u'kimchi-vm', snap_name) - inst.task_wait(task['id']) - task = inst.task_lookup(task['id']) - self.assertEquals('finished', task['status']) - - snaps = inst.vmsnapshots_get_list(u'kimchi-vm') - self.assertEquals(sorted([params['name'], snap_name], - key=unicode.lower), snaps) - - snap = inst.vmsnapshot_lookup(u'kimchi-vm', snap_name) - current_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm') - self.assertEquals(snap, current_snap) - - # update vm name - inst.vm_update('kimchi-vm', {'name': u'kimchi-vm-new'}) - - # Look up the first created snapshot from the renamed vm - snap = inst.vmsnapshot_lookup(u'kimchi-vm-new', params['name']) - - # snapshot revert to the first created vm - result = inst.vmsnapshot_revert(u'kimchi-vm-new', params['name']) - self.assertEquals(result, [u'kimchi-vm', snap['name']]) - - vm = inst.vm_lookup(u'kimchi-vm') - self.assertEquals(vm['state'], snap['state']) - - current_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm') - self.assertEquals(params['name'], current_snap['name']) - - self.assertRaises(NotFoundError, inst.vmsnapshot_delete, - u'kimchi-vm', u'foobar') - - # suspend and resume the VM - info = inst.vm_lookup(u'kimchi-vm') - self.assertEquals(info['state'], 'shutoff') - self.assertRaises(InvalidOperation, inst.vm_suspend, u'kimchi-vm') - inst.vm_start(u'kimchi-vm') - info = inst.vm_lookup(u'kimchi-vm') - self.assertEquals(info['state'], 'running') - inst.vm_suspend(u'kimchi-vm') - info = inst.vm_lookup(u'kimchi-vm') - self.assertEquals(info['state'], 'paused') - self.assertRaises(InvalidParameter, inst.vm_update, u'kimchi-vm', - {'name': 'foo'}) - inst.vm_resume(u'kimchi-vm') - info = inst.vm_lookup(u'kimchi-vm') - self.assertEquals(info['state'], 'running') - self.assertRaises(InvalidOperation, inst.vm_resume, u'kimchi-vm') - # leave the VM suspended to make sure a paused VM can be - # deleted correctly - inst.vm_suspend(u'kimchi-vm') - - vms = inst.vms_get_list() - self.assertFalse('kimchi-vm' in vms) - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_image_based_template(self): - inst = model.Model(objstore_loc=self.tmp_store) - - with RollbackContext() as rollback: - vol = 'base-vol.img' - params = {'name': vol, - 'capacity': 1073741824, # 1 GiB - 'allocation': 1048576, # 1 MiB - 'format': 'qcow2'} - task_id = inst.storagevolumes_create('default', params)['id'] - rollback.prependDefer(inst.storagevolume_delete, 'default', vol) - inst.task_wait(task_id) - self.assertEquals('finished', inst.task_lookup(task_id)['status']) - vol_path = inst.storagevolume_lookup('default', vol)['path'] - - params = {'name': 'test', 'disks': [{'base': vol_path}]} - self.assertRaises(OperationFailed, inst.templates_create, params) - - # Hack the model objstore to add a new template - # It is needed as the image file must be a bootable image when - # using model - # As it is difficult to create one on test runtime, inject a - # template with an empty image file to the objstore to test the - # feature - tmpl_name = "img-tmpl" - tmpl_info = {"cpus": 1, "cdrom": "", - "graphics": {"type": "vnc", "listen": "127.0.0.1"}, - "networks": ["default"], "memory": 1024, "folder": [], - "icon": "images/icon-vm.png", - "os_distro": "unknown", "os_version": "unknown", - "disks": [{"base": vol_path, "size": 10}], - "storagepool": "/plugins/kimchi/storagepools/default"} - - with inst.objstore as session: - session.store('template', tmpl_name, tmpl_info) - - params = {'name': 'kimchi-vm', - 'template': '/plugins/kimchi/templates/img-tmpl'} - task = inst.vms_create(params) - inst.task_wait(task['id']) - rollback.prependDefer(inst.vm_delete, 'kimchi-vm') - - vms = inst.vms_get_list() - self.assertTrue('kimchi-vm' in vms) - - inst.vm_start('kimchi-vm') - rollback.prependDefer(inst.vm_poweroff, 'kimchi-vm') - - info = inst.vm_lookup('kimchi-vm') - self.assertEquals('running', info['state']) - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_vm_graphics(self): - inst = model.Model(objstore_loc=self.tmp_store) - params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO} - inst.templates_create(params) - with RollbackContext() as rollback: - params = {'name': 'kimchi-vnc', - 'template': '/plugins/kimchi/templates/test'} - task1 = inst.vms_create(params) - inst.task_wait(task1['id']) - rollback.prependDefer(inst.vm_delete, 'kimchi-vnc') - - info = inst.vm_lookup('kimchi-vnc') - self.assertEquals('vnc', info['graphics']['type']) - self.assertEquals('127.0.0.1', info['graphics']['listen']) - - graphics = {'type': 'spice', 'listen': '127.0.0.1'} - params = {'name': 'kimchi-spice', - 'template': '/plugins/kimchi/templates/test', - 'graphics': graphics} - task2 = inst.vms_create(params) - inst.task_wait(task2['id']) - rollback.prependDefer(inst.vm_delete, 'kimchi-spice') - - info = inst.vm_lookup('kimchi-spice') - self.assertEquals('spice', info['graphics']['type']) - self.assertEquals('127.0.0.1', info['graphics']['listen']) - - inst.template_delete('test') - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_vm_ifaces(self): - inst = model.Model(objstore_loc=self.tmp_store) - with RollbackContext() as rollback: - params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO} - inst.templates_create(params) - rollback.prependDefer(inst.template_delete, 'test') - - # Create a network - net_name = 'test-network' - net_args = {'name': net_name, - 'connection': 'nat', - 'subnet': '127.0.100.0/24'} - inst.networks_create(net_args) - rollback.prependDefer(inst.network_delete, net_name) - inst.network_activate(net_name) - rollback.prependDefer(inst.network_deactivate, net_name) - - for vm_name in ['kimchi-ifaces', 'kimchi-ifaces-running']: - params = {'name': vm_name, - 'template': '/plugins/kimchi/templates/test'} - task = inst.vms_create(params) - inst.task_wait(task['id']) - rollback.prependDefer(inst.vm_delete, vm_name) - - ifaces = inst.vmifaces_get_list(vm_name) - self.assertEquals(1, len(ifaces)) - - iface = inst.vmiface_lookup(vm_name, ifaces[0]) - self.assertEquals(17, len(iface['mac'])) - self.assertEquals("default", iface['network']) - self.assertIn("model", iface) - - # attach network interface to vm - iface_args = {"type": "network", - "network": "test-network", - "model": "virtio"} - mac = inst.vmifaces_create(vm_name, iface_args) - # detach network interface from vm - rollback.prependDefer(inst.vmiface_delete, vm_name, mac) - self.assertEquals(17, len(mac)) - - iface = inst.vmiface_lookup(vm_name, mac) - self.assertEquals("network", iface["type"]) - self.assertEquals("test-network", iface['network']) - self.assertEquals("virtio", iface["model"]) - - # attach network interface to vm without providing model - iface_args = {"type": "network", - "network": "test-network"} - mac = inst.vmifaces_create(vm_name, iface_args) - rollback.prependDefer(inst.vmiface_delete, vm_name, mac) - - iface = inst.vmiface_lookup(vm_name, mac) - self.assertEquals("network", iface["type"]) - self.assertEquals("test-network", iface['network']) - - # update vm interface - newMacAddr = '54:50:e3:44:8a:af' - iface_args = {"mac": newMacAddr} - inst.vmiface_update(vm_name, mac, iface_args) - iface = inst.vmiface_lookup(vm_name, newMacAddr) - self.assertEquals(newMacAddr, iface['mac']) - - # undo mac address change - iface_args = {"mac": mac} - inst.vmiface_update(vm_name, newMacAddr, iface_args) - iface = inst.vmiface_lookup(vm_name, mac) - self.assertEquals(mac, iface['mac']) - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_vm_disk(self): - disk_path = os.path.join(TMP_DIR, 'existent2.iso') - open(disk_path, 'w').close() - modern_disk_bus = get_template_default('modern', 'disk_bus') - - def _attach_disk(expect_bus=modern_disk_bus): - disk_args = {"type": "disk", - "pool": pool, - "vol": vol} - disk = inst.vmstorages_create(vm_name, disk_args) - storage_list = inst.vmstorages_get_list(vm_name) - self.assertEquals(prev_count + 1, len(storage_list)) - - # Check the bus type to be 'virtio' - disk_info = inst.vmstorage_lookup(vm_name, disk) - self.assertEquals(u'disk', disk_info['type']) - self.assertEquals(vol_path, disk_info['path']) - self.assertEquals(expect_bus, disk_info['bus']) - return disk - - inst = model.Model(objstore_loc=self.tmp_store) - with RollbackContext() as rollback: - path = os.path.join(TMP_DIR, 'kimchi-images') - pool = 'test-pool' - vol = 'test-volume.img' - vol_path = "%s/%s" % (path, vol) - if not os.path.exists(path): - os.mkdir(path) - rollback.prependDefer(shutil.rmtree, path) - - args = {'name': pool, - 'path': path, - 'type': 'dir'} - inst.storagepools_create(args) - rollback.prependDefer(inst.storagepool_delete, pool) - - # Activate the pool before adding any volume - inst.storagepool_activate(pool) - rollback.prependDefer(inst.storagepool_deactivate, pool) - - params = {'name': vol, - 'capacity': 1073741824, # 1 GiB - 'allocation': 536870912, # 512 MiB - 'format': 'qcow2'} - task_id = inst.storagevolumes_create(pool, params)['id'] - rollback.prependDefer(inst.storagevolume_delete, pool, vol) - inst.task_wait(task_id) - - vm_name = 'kimchi-cdrom' - params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO} - inst.templates_create(params) - rollback.prependDefer(inst.template_delete, 'test') - params = {'name': vm_name, - 'template': '/plugins/kimchi/templates/test'} - task1 = inst.vms_create(params) - inst.task_wait(task1['id']) - rollback.prependDefer(inst.vm_delete, vm_name) - - prev_count = len(inst.vmstorages_get_list(vm_name)) - self.assertEquals(1, prev_count) - - # Volume format with mismatched type raise error - cdrom_args = {"type": "cdrom", "pool": pool, "vol": vol} - self.assertRaises(InvalidParameter, inst.vmstorages_create, - vm_name, cdrom_args) - - # Cold plug and unplug a disk - disk = _attach_disk() - inst.vmstorage_delete(vm_name, disk) - - # Hot plug a disk - inst.vm_start(vm_name) - disk = _attach_disk() - - # VM disk still there after powered off - inst.vm_poweroff(vm_name) - disk_info = inst.vmstorage_lookup(vm_name, disk) - self.assertEquals(u'disk', disk_info['type']) - inst.vmstorage_delete(vm_name, disk) - - # Specifying pool and path at same time will fail - disk_args = {"type": "disk", - "pool": pool, - "vol": vol, - "path": disk_path} - self.assertRaises( - InvalidParameter, inst.vmstorages_create, vm_name, disk_args) - - old_distro_iso = TMP_DIR + 'rhel4_8.iso' - iso_gen.construct_fake_iso(old_distro_iso, True, '4.8', 'rhel') - - vm_name = 'kimchi-ide-bus-vm' - params = {'name': 'old_distro_template', 'disks': [], - 'cdrom': old_distro_iso} - inst.templates_create(params) - rollback.prependDefer(inst.template_delete, 'old_distro_template') - params = { - 'name': vm_name, - 'template': '/plugins/kimchi/templates/old_distro_template' - } - task2 = inst.vms_create(params) - inst.task_wait(task2['id']) - rollback.prependDefer(inst.vm_delete, vm_name) - - # Need to check the right disk_bus for old distro - disk = _attach_disk(get_template_default('old', 'disk_bus')) - inst.vmstorage_delete('kimchi-ide-bus-vm', disk) - - # Hot plug IDE bus disk does not work - inst.vm_start(vm_name) - self.assertRaises(InvalidOperation, _attach_disk) - inst.vm_poweroff(vm_name) - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_vm_cdrom(self): - inst = model.Model(objstore_loc=self.tmp_store) - with RollbackContext() as rollback: - vm_name = 'kimchi-cdrom' - params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO} - inst.templates_create(params) - rollback.prependDefer(inst.template_delete, 'test') - params = {'name': vm_name, - 'template': '/plugins/kimchi/templates/test'} - task = inst.vms_create(params) - inst.task_wait(task['id']) - rollback.prependDefer(inst.vm_delete, vm_name) - - prev_count = len(inst.vmstorages_get_list(vm_name)) - self.assertEquals(1, prev_count) - - # dummy .iso files - iso_path = os.path.join(TMP_DIR, 'existent.iso') - iso_path2 = os.path.join(TMP_DIR, 'existent2.iso') - open(iso_path, 'w').close() - rollback.prependDefer(os.remove, iso_path) - open(iso_path2, 'w').close() - rollback.prependDefer(os.remove, iso_path2) - wrong_iso_path = '/nonexistent.iso' - - # Create a cdrom - cdrom_args = {"type": "cdrom", - "path": iso_path} - cdrom_dev = inst.vmstorages_create(vm_name, cdrom_args) - storage_list = inst.vmstorages_get_list(vm_name) - self.assertEquals(prev_count + 1, len(storage_list)) - - # Get cdrom info - cd_info = inst.vmstorage_lookup(vm_name, cdrom_dev) - self.assertEquals(u'cdrom', cd_info['type']) - self.assertEquals(iso_path, cd_info['path']) - - # update path of existing cd with - # non existent iso - self.assertRaises(InvalidParameter, inst.vmstorage_update, - vm_name, cdrom_dev, {'path': wrong_iso_path}) - - # Make sure CD ROM still exists after failure - cd_info = inst.vmstorage_lookup(vm_name, cdrom_dev) - self.assertEquals(u'cdrom', cd_info['type']) - self.assertEquals(iso_path, cd_info['path']) - - # update path of existing cd with existent iso of shutoff vm - inst.vmstorage_update(vm_name, cdrom_dev, {'path': iso_path2}) - cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev) - self.assertEquals(iso_path2, cdrom_info['path']) - - # update path of existing cd with existent iso of running vm - inst.vm_start(vm_name) - inst.vmstorage_update(vm_name, cdrom_dev, {'path': iso_path}) - cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev) - self.assertEquals(iso_path, cdrom_info['path']) - - # eject cdrom - cdrom_dev = inst.vmstorage_update(vm_name, cdrom_dev, {'path': ''}) - cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev) - self.assertEquals('', cdrom_info['path']) - inst.vm_poweroff(vm_name) - - # removing non existent cdrom - self.assertRaises(NotFoundError, inst.vmstorage_delete, vm_name, - "fakedev") - - # removing valid cdrom - inst.vmstorage_delete(vm_name, cdrom_dev) - storage_list = inst.vmstorages_get_list(vm_name) - self.assertEquals(prev_count, len(storage_list)) - - # Create a new cdrom using a remote iso - valid_remote_iso_path = utils.get_remote_iso_path() - cdrom_args = {"type": "cdrom", - "path": valid_remote_iso_path} - cdrom_dev = inst.vmstorages_create(vm_name, cdrom_args) - storage_list = inst.vmstorages_get_list(vm_name) - self.assertEquals(prev_count + 1, len(storage_list)) - - # Update remote-backed cdrom with the same ISO - inst.vmstorage_update(vm_name, cdrom_dev, - {'path': valid_remote_iso_path}) - cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev) - cur_cdrom_path = re.sub(":80/", '/', cdrom_info['path']) - self.assertEquals(valid_remote_iso_path, cur_cdrom_path) - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_vm_storage_provisioning(self): - inst = model.Model(objstore_loc=self.tmp_store) - - with RollbackContext() as rollback: - params = {'name': 'test', 'disks': [{'size': 1}], - 'cdrom': UBUNTU_ISO} - inst.templates_create(params) - rollback.prependDefer(inst.template_delete, 'test') - - params = {'name': 'test-vm-1', - 'template': '/plugins/kimchi/templates/test'} - task = inst.vms_create(params) - inst.task_wait(task['id']) - rollback.prependDefer(inst.vm_delete, 'test-vm-1') - - vm_info = inst.vm_lookup(params['name']) - disk_path = '%s/%s-0.img' % ( - inst.storagepool_lookup('default')['path'], vm_info['uuid']) - self.assertTrue(os.access(disk_path, os.F_OK)) - self.assertFalse(os.access(disk_path, os.F_OK)) - - def test_vm_memory_hotplug(self): - config.set("authentication", "method", "pam") - inst = model.Model(None, objstore_loc=self.tmp_store) - orig_params = {'name': 'test', 'memory': 1024, 'cdrom': UBUNTU_ISO} - inst.templates_create(orig_params) - - with RollbackContext() as rollback: - params = {'name': 'kimchi-vm1', - 'template': '/plugins/kimchi/templates/test'} - task1 = inst.vms_create(params) - inst.task_wait(task1['id']) - rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, - 'kimchi-vm1') - # Start vm - inst.vm_start('kimchi-vm1') - rollback.prependDefer(utils.rollback_wrapper, inst.vm_poweroff, - 'kimchi-vm1') - - # Hotplug memory, only available in Libvirt >= 1.2.14 - params = {'memory': 2048} - if inst.capabilities_lookup()['mem_hotplug_support']: - inst.vm_update('kimchi-vm1', params) - rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, - 'kimchi-vm1') - self.assertEquals(params['memory'], - inst.vm_lookup('kimchi-vm1')['memory']) - else: - self.assertRaises(InvalidOperation, inst.vm_update, - 'kimchi-vm1', params) - - def test_vm_edit(self): - config.set("authentication", "method", "pam") - inst = model.Model(None, - objstore_loc=self.tmp_store) - - orig_params = {'name': 'test', 'memory': 1024, 'cpus': 1, - 'cdrom': UBUNTU_ISO} - inst.templates_create(orig_params) - - with RollbackContext() as rollback: - params_1 = {'name': 'kimchi-vm1', - 'template': '/plugins/kimchi/templates/test'} - params_2 = {'name': 'kimchi-vm2', - 'template': '/plugins/kimchi/templates/test'} - task1 = inst.vms_create(params_1) - inst.task_wait(task1['id']) - rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, - 'kimchi-vm1') - task2 = inst.vms_create(params_2) - inst.task_wait(task2['id']) - rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, - 'kimchi-vm2') - - vms = inst.vms_get_list() - self.assertTrue('kimchi-vm1' in vms) - - # make sure "vm_update" works when the domain has a snapshot - inst.vmsnapshots_create(u'kimchi-vm1') - - # update vm graphics when vm is not running - inst.vm_update(u'kimchi-vm1', - {"graphics": {"passwd": "123456"}}) - - inst.vm_start('kimchi-vm1') - rollback.prependDefer(utils.rollback_wrapper, inst.vm_poweroff, - 'kimchi-vm1') - - vm_info = inst.vm_lookup(u'kimchi-vm1') - self.assertEquals('123456', vm_info['graphics']["passwd"]) - self.assertEquals(None, vm_info['graphics']["passwdValidTo"]) - - # update vm graphics when vm is running - inst.vm_update(u'kimchi-vm1', - {"graphics": {"passwd": "abcdef", - "passwdValidTo": 20}}) - vm_info = inst.vm_lookup(u'kimchi-vm1') - self.assertEquals('abcdef', vm_info['graphics']["passwd"]) - self.assertGreaterEqual(20, vm_info['graphics']['passwdValidTo']) - - info = inst.vm_lookup('kimchi-vm1') - self.assertEquals('running', info['state']) - - params = {'name': 'new-vm'} - self.assertRaises(InvalidParameter, inst.vm_update, - 'kimchi-vm1', params) - - # change VM users and groups, when wm is running. - inst.vm_update(u'kimchi-vm1', - {'users': ['root'], 'groups': ['root']}) - vm_info = inst.vm_lookup(u'kimchi-vm1') - self.assertEquals(['root'], vm_info['users']) - self.assertEquals(['root'], vm_info['groups']) - # change VM users and groups by removing all elements, - # when wm is running. - inst.vm_update(u'kimchi-vm1', {'users': [], 'groups': []}) - vm_info = inst.vm_lookup(u'kimchi-vm1') - self.assertEquals([], vm_info['users']) - self.assertEquals([], vm_info['groups']) - - inst.vm_poweroff('kimchi-vm1') - self.assertRaises(OperationFailed, inst.vm_update, - 'kimchi-vm1', {'name': 'kimchi-vm2'}) - - params = {'name': u'��e��-�����', 'cpus': 4, 'memory': 2048} - inst.vm_update('kimchi-vm1', params) - rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, - u'��e��-�����') - self.assertEquals(info['uuid'], inst.vm_lookup(u'��e��-�����')['uuid']) - info = inst.vm_lookup(u'��e��-�����') - for key in params.keys(): - self.assertEquals(params[key], info[key]) - - # change only VM users - groups are not changed (default is empty) - users = inst.users_get_list()[:3] - inst.vm_update(u'��e��-�����', {'users': users}) - self.assertEquals(users, inst.vm_lookup(u'��e��-�����')['users']) - self.assertEquals([], inst.vm_lookup(u'��e��-�����')['groups']) - - # change only VM groups - users are not changed (default is empty) - groups = inst.groups_get_list()[:2] - inst.vm_update(u'��e��-�����', {'groups': groups}) - self.assertEquals(users, inst.vm_lookup(u'��e��-�����')['users']) - self.assertEquals(groups, inst.vm_lookup(u'��e��-�����')['groups']) - - # change VM users and groups by adding a new element to each one - users.append(pwd.getpwuid(os.getuid()).pw_name) - groups.append(grp.getgrgid(os.getgid()).gr_name) - inst.vm_update(u'��e��-�����', {'users': users, 'groups': groups}) - self.assertEquals(users, inst.vm_lookup(u'��e��-�����')['users']) - self.assertEquals(groups, inst.vm_lookup(u'��e��-�����')['groups']) - - # change VM users (wrong value) and groups - # when an error occurs, everything fails and nothing is changed - self.assertRaises(InvalidParameter, inst.vm_update, u'��e��-�����', - {'users': ['userdoesnotexist'], 'groups': []}) - self.assertEquals(users, inst.vm_lookup(u'��e��-�����')['users']) - self.assertEquals(groups, inst.vm_lookup(u'��e��-�����')['groups']) - - # change VM users and groups (wrong value) - # when an error occurs, everything fails and nothing is changed - self.assertRaises(InvalidParameter, inst.vm_update, u'��e��-�����', - {'users': [], 'groups': ['groupdoesnotexist']}) - self.assertEquals(users, inst.vm_lookup(u'��e��-�����')['users']) - self.assertEquals(groups, inst.vm_lookup(u'��e��-�����')['groups']) - - # change VM users and groups by removing all elements - inst.vm_update(u'��e��-�����', {'users': [], 'groups': []}) - self.assertEquals([], inst.vm_lookup(u'��e��-�����')['users']) - self.assertEquals([], inst.vm_lookup(u'��e��-�����')['groups']) - - def test_get_interfaces(self): - inst = model.Model('test:///default', - objstore_loc=self.tmp_store) - expected_ifaces = netinfo.all_favored_interfaces() - ifaces = inst.interfaces_get_list() - self.assertEquals(len(expected_ifaces), len(ifaces)) - for name in expected_ifaces: - iface = inst.interface_lookup(name) - self.assertEquals(iface['name'], name) - self.assertIn('type', iface) - self.assertIn('status', iface) - self.assertIn('ipaddr', iface) - self.assertIn('netmask', iface) - - def test_async_tasks(self): - class task_except(Exception): - pass - - def quick_op(cb, message): - cb(message, True) - - def long_op(cb, params): - time.sleep(params.get('delay', 3)) - cb(params.get('message', ''), params.get('result', False)) - - def abnormal_op(cb, params): - try: - raise task_except - except: - cb("Exception raised", False) - - def continuous_ops(cb, params): - cb("step 1 OK") - time.sleep(2) - cb("step 2 OK") - time.sleep(2) - cb("step 3 OK", params.get('result', True)) - - inst = model.Model('test:///default', - objstore_loc=self.tmp_store) - taskid = add_task('', quick_op, inst.objstore, 'Hello') - inst.task_wait(taskid) - self.assertEquals(1, taskid) - self.assertEquals('finished', inst.task_lookup(taskid)['status']) - self.assertEquals('Hello', inst.task_lookup(taskid)['message']) - - taskid = add_task('', long_op, inst.objstore, - {'delay': 3, 'result': False, - 'message': 'It was not meant to be'}) - self.assertEquals(2, taskid) - self.assertEquals('running', inst.task_lookup(taskid)['status']) - self.assertEquals('OK', inst.task_lookup(taskid)['message']) - inst.task_wait(taskid) - self.assertEquals('failed', inst.task_lookup(taskid)['status']) - self.assertEquals('It was not meant to be', - inst.task_lookup(taskid)['message']) - taskid = add_task('', abnormal_op, inst.objstore, {}) - inst.task_wait(taskid) - self.assertEquals('Exception raised', - inst.task_lookup(taskid)['message']) - self.assertEquals('failed', inst.task_lookup(taskid)['status']) - - taskid = add_task('', continuous_ops, inst.objstore, - {'result': True}) - self.assertEquals('running', inst.task_lookup(taskid)['status']) - inst.task_wait(taskid, timeout=10) - self.assertEquals('finished', inst.task_lookup(taskid)['status']) - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_delete_running_vm(self): - inst = model.Model(objstore_loc=self.tmp_store) - - with RollbackContext() as rollback: - params = {'name': u'test', 'disks': [], 'cdrom': UBUNTU_ISO} - inst.templates_create(params) - rollback.prependDefer(inst.template_delete, 'test') - - params = {'name': u'k������h��-�����', - 'template': u'/plugins/kimchi/templates/test'} - task = inst.vms_create(params) - inst.task_wait(task['id']) - rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, - u'k������h��-�����') - - inst.vm_start(u'k������h��-�����') - self.assertEquals(inst.vm_lookup(u'k������h��-�����')['state'], 'running') - rollback.prependDefer(utils.rollback_wrapper, inst.vm_poweroff, - u'k������h��-�����') - - inst.vm_delete(u'k������h��-�����') - - vms = inst.vms_get_list() - self.assertFalse(u'k������h��-�����' in vms) - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_vm_list_sorted(self): - inst = model.Model(objstore_loc=self.tmp_store) - - with RollbackContext() as rollback: - params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO} - inst.templates_create(params) - rollback.prependDefer(inst.template_delete, 'test') - - params = {'name': 'kimchi-vm', - 'template': '/plugins/kimchi/templates/test'} - task = inst.vms_create(params) - inst.task_wait(task['id']) - rollback.prependDefer(inst.vm_delete, 'kimchi-vm') - - vms = inst.vms_get_list() - - self.assertEquals(vms, sorted(vms, key=unicode.lower)) - - def test_vm_clone(self): - inst = model.Model('test:///default', objstore_loc=self.tmp_store) - - all_vm_names = inst.vms_get_list() - name = all_vm_names[0] - - original_vm = inst.vm_lookup(name) - if original_vm['state'] == u'shutoff': - inst.vm_start(name) - - # the VM 'test' should be running by now, so we can't clone it yet - self.assertRaises(InvalidParameter, inst.vm_clone, name) - - with RollbackContext() as rollback: - inst.vm_poweroff(name) - rollback.prependDefer(inst.vm_start, name) - - # create two simultaneous clones of the same VM - # and make sure both of them complete successfully - task1 = inst.vm_clone(name) - task2 = inst.vm_clone(name) - clone1_name = task1['target_uri'].split('/')[-2] - rollback.prependDefer(inst.vm_delete, clone1_name) - clone2_name = task2['target_uri'].split('/')[-2] - rollback.prependDefer(inst.vm_delete, clone2_name) - inst.task_wait(task1['id']) - task1 = inst.task_lookup(task1['id']) - self.assertEquals('finished', task1['status']) - inst.task_wait(task2['id']) - task2 = inst.task_lookup(task2['id']) - self.assertEquals('finished', task2['status']) - - # update the original VM info because its state has changed - original_vm = inst.vm_lookup(name) - clone_vm = inst.vm_lookup(clone1_name) - - self.assertNotEqual(original_vm['name'], clone_vm['name']) - self.assertTrue(re.match(u'%s-clone-\d+' % original_vm['name'], - clone_vm['name'])) - del original_vm['name'] - del clone_vm['name'] - - self.assertNotEqual(original_vm['uuid'], clone_vm['uuid']) - del original_vm['uuid'] - del clone_vm['uuid'] - - # compare all VM settings except the ones already compared - # (and removed) above (i.e. 'name' and 'uuid') - self.assertEquals(original_vm, clone_vm) - - def test_use_test_host(self): - inst = model.Model('test:///default', - objstore_loc=self.tmp_store) - - with RollbackContext() as rollback: - params = { - 'name': 'test', - 'disks': [], - 'cdrom': UBUNTU_ISO, - 'storagepool': '/plugins/kimchi/storagepools/default-pool', - 'domain': 'test', - 'arch': 'i686' - } - - inst.templates_create(params) - rollback.prependDefer(inst.template_delete, 'test') - - params = {'name': 'kimchi-vm', - 'template': '/plugins/kimchi/templates/test'} - task = inst.vms_create(params) - inst.task_wait(task['id']) - rollback.prependDefer(inst.vm_delete, 'kimchi-vm') - - vms = inst.vms_get_list() - - self.assertTrue('kimchi-vm' in vms) - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_debug_reports(self): - inst = model.Model('test:///default', - objstore_loc=self.tmp_store) - - if not inst.capabilities_lookup()['system_report_tool']: - raise unittest.SkipTest("Without debug report tool") - - try: - timeout = int(os.environ['TEST_REPORT_TIMEOUT']) - except (ValueError, KeyError): - timeout = 120 - - namePrefix = 'unitTestReport' - # sosreport always deletes unsual letters like '-' and '_' in the - # generated report file name. - uuidstr = str(uuid.uuid4()).translate(None, "-_") - reportName = namePrefix + uuidstr - try: - inst.debugreport_delete(namePrefix + '*') - except NotFoundError: - pass - with RollbackContext() as rollback: - report_list = inst.debugreports_get_list() - self.assertFalse(reportName in report_list) - try: - tmp_name = reportName + "_1" - task = inst.debugreports_create({'name': reportName}) - rollback.prependDefer(inst.debugreport_delete, tmp_name) - taskid = task['id'] - inst.task_wait(taskid, timeout) - self.assertEquals('finished', - inst.task_lookup(taskid)['status'], - "It is not necessary an error. " - "You may need to increase the " - "timeout number by " - "TEST_REPORT_TIMEOUT=200 " - "./run_tests.sh test_model") - report_list = inst.debugreports_get_list() - self.assertTrue(reportName in report_list) - name = inst.debugreport_update(reportName, {'name': tmp_name}) - self.assertEquals(name, tmp_name) - report_list = inst.debugreports_get_list() - self.assertTrue(tmp_name in report_list) - except OperationFailed, e: - if 'debugreport tool not found' not in e.message: - raise e - - def test_get_distros(self): - inst = model.Model('test:///default', - objstore_loc=self.tmp_store) - distros = inst.distros_get_list() - for d in distros: - distro = inst.distro_lookup(d) - self.assertIn('name', distro) - self.assertIn('os_distro', distro) - self.assertIn('os_version', distro) - self.assertIn('os_arch', distro) - self.assertIn('path', distro) - - @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') - def test_deep_scan(self): - inst = model.Model(None, - objstore_loc=self.tmp_store) - with RollbackContext() as rollback: - deep_path = os.path.join(TMP_DIR, 'deep-scan') - subdir_path = os.path.join(deep_path, 'isos') - if not os.path.exists(subdir_path): - os.makedirs(subdir_path) - ubuntu_iso = os.path.join(deep_path, 'ubuntu12.04.iso') - sles_iso = os.path.join(subdir_path, 'sles10.iso') - iso_gen.construct_fake_iso(ubuntu_iso, True, '12.04', 'ubuntu') - iso_gen.construct_fake_iso(sles_iso, True, '10', 'sles') - - args = {'name': 'kimchi-scanning-pool', - 'path': deep_path, - 'type': 'kimchi-iso'} - inst.storagepools_create(args) - rollback.prependDefer(shutil.rmtree, deep_path) - rollback.prependDefer(shutil.rmtree, args['path']) - rollback.prependDefer(inst.storagepool_deactivate, args['name']) - - time.sleep(1) - volumes = inst.storagevolumes_get_list(args['name']) - self.assertEquals(len(volumes), 2) - - def test_repository_create(self): - inst = model.Model('test:///default', - objstore_loc=self.tmp_store) - - yum_repos = [{'repo_id': 'fedora-fake', - 'baseurl': 'http://www.fedora.org'}, - {'repo_id': 'fedora-updates-fake', - 'config': - {'mirrorlist': 'http://www.fedoraproject.org'}}] - - deb_repos = [{'baseurl': 'http://archive.ubuntu.com/ubuntu/', - 'config': {'dist': 'quantal'}}, - {'baseurl': 'http://archive.ubuntu.com/ubuntu/', - 'config': {'dist': 'quantal', 'comps': ['main']}}] - - yum_invalid_repos = [] - deb_invalid_repos = [] - - for url in invalid_repository_urls: - wrong_baseurl = {'repo_id': 'wrong-id', 'baseurl': url} - wrong_mirrorlist = {'repo_id': 'wrong-id', - 'baseurl': 'www.example.com', - 'config': {'mirrorlist': url}} - wrong_config_item = { - 'repo_id': 'wrong-id', - 'baseurl': 'www.example.com', - 'config': { - 'gpgkey': 'file:///tmp/KEY-fedora-updates-fake-19'}} - - yum_invalid_repos.append(wrong_baseurl) - yum_invalid_repos.append(wrong_mirrorlist) - yum_invalid_repos.append(wrong_config_item) - - wrong_baseurl['config'] = {'dist': 'tasty'} - wrong_config = {'baseurl': deb_repos[0]['baseurl'], - 'config': { - 'unsupported_item': "a_unsupported_item"}} - deb_invalid_repos.append(wrong_baseurl) - deb_invalid_repos.append(wrong_config) - - repo_type = inst.capabilities_lookup()['repo_mngt_tool'] - if repo_type == 'yum': - test_repos = yum_repos - invalid_repos = yum_invalid_repos - elif repo_type == 'deb': - test_repos = deb_repos - invalid_repos = deb_invalid_repos - else: - # repository management tool was not recognized by Kimchi - # skip test case - return - - # create repositories with invalid data - for repo in invalid_repos: - self.assertRaises(InvalidParameter, inst.repositories_create, repo) - - for repo in test_repos: - system_host_repos = len(inst.repositories_get_list()) - repo_id = inst.repositories_create(repo) - host_repos = inst.repositories_get_list() - self.assertEquals(system_host_repos + 1, len(host_repos)) - - repo_info = inst.repository_lookup(repo_id) - self.assertEquals(repo_id, repo_info['repo_id']) - self.assertEquals(True, repo_info.get('enabled')) - self.assertEquals(repo.get('baseurl', ''), - repo_info.get('baseurl')) - - original_config = repo.get('config', {}) - config_info = repo_info.get('config', {}) - - if repo_type == 'yum': - self.assertEquals(original_config.get('mirrorlist', ''), - config_info.get('mirrorlist', '')) - self.assertEquals(True, config_info['gpgcheck']) - else: - self.assertEquals(original_config['dist'], config_info['dist']) - self.assertEquals(original_config.get('comps', []), - config_info.get('comps', [])) - - inst.repository_delete(repo_id) - self.assertRaises(NotFoundError, inst.repository_lookup, repo_id) - - self.assertRaises(NotFoundError, inst.repository_lookup, 'google') - - def test_repository_update(self): - inst = model.Model('test:///default', - objstore_loc=self.tmp_store) - - yum_repo = {'repo_id': 'fedora-fake', - 'baseurl': 'http://www.fedora.org'} - yum_new_repo = {'baseurl': 'http://www.fedoraproject.org'} - - deb_repo = {'baseurl': 'http://archive.ubuntu.com/ubuntu/', - 'config': {'dist': 'quantal'}} - deb_new_repo = {'baseurl': 'http://br.archive.canonical.com/ubuntu/', - 'config': {'dist': 'utopic'}} - - yum_invalid_repos = [] - deb_invalid_repos = [] - - for url in invalid_repository_urls: - wrong_baseurl = {'baseurl': url} - wrong_mirrorlist = {'baseurl': 'www.example.com', - 'config': {'mirrorlist': url}} - - yum_invalid_repos.append(wrong_baseurl) - yum_invalid_repos.append(wrong_mirrorlist) - - wrong_baseurl['config'] = {'dist': 'tasty'} - deb_invalid_repos.append(wrong_baseurl) - - repo_type = inst.capabilities_lookup()['repo_mngt_tool'] - if repo_type == 'yum': - repo = yum_repo - new_repo = yum_new_repo - invalid_repos = yum_invalid_repos - elif repo_type == 'deb': - repo = deb_repo - new_repo = deb_new_repo - invalid_repos = deb_invalid_repos - else: - # repository management tool was not recognized by Kimchi - # skip test case - return - - system_host_repos = len(inst.repositories_get_list()) - - with RollbackContext() as rollback: - repo_id = inst.repositories_create(repo) - rollback.prependDefer(inst.repository_delete, repo_id) - - host_repos = inst.repositories_get_list() - self.assertEquals(system_host_repos + 1, len(host_repos)) - - # update repositories with invalid data - for tmp_repo in invalid_repos: - self.assertRaises(InvalidParameter, inst.repository_update, - repo_id, tmp_repo) - - new_repo_id = inst.repository_update(repo_id, new_repo) - repo_info = inst.repository_lookup(new_repo_id) - - self.assertEquals(new_repo_id, repo_info['repo_id']) - self.assertEquals(new_repo['baseurl'], repo_info['baseurl']) - self.assertEquals(True, repo_info['enabled']) - inst.repository_update(new_repo_id, repo) - - def test_repository_disable_enable(self): - inst = model.Model('test:///default', - objstore_loc=self.tmp_store) - - yum_repo = {'repo_id': 'fedora-fake', - 'baseurl': 'http://www.fedora.org'} - deb_repo = {'baseurl': 'http://archive.ubuntu.com/ubuntu/', - 'config': {'dist': 'quantal'}} - - repo_type = inst.capabilities_lookup()['repo_mngt_tool'] - if repo_type == 'yum': - repo = yum_repo - elif repo_type == 'deb': - repo = deb_repo - else: - # repository management tool was not recognized by Kimchi - # skip test case - return - - system_host_repos = len(inst.repositories_get_list()) - - repo_id = inst.repositories_create(repo) - - host_repos = inst.repositories_get_list() - self.assertEquals(system_host_repos + 1, len(host_repos)) - - repo_info = inst.repository_lookup(repo_id) - self.assertEquals(True, repo_info['enabled']) - - inst.repository_disable(repo_id) - repo_info = inst.repository_lookup(repo_id) - self.assertEquals(False, repo_info['enabled']) - - inst.repository_enable(repo_id) - repo_info = inst.repository_lookup(repo_id) - self.assertEquals(True, repo_info['enabled']) - - # remove files creates - inst.repository_delete(repo_id) - - -class BaseModelTests(unittest.TestCase): - class FoosModel(object): - def __init__(self): - self.data = {} - - def create(self, params): - self.data.update(params) - - def get_list(self): - return list(self.data) - - class TestModel(wok.basemodel.BaseModel): - def __init__(self): - foo = BaseModelTests.FoosModel() - super(BaseModelTests.TestModel, self).__init__([foo]) - - def test_root_model(self): - t = BaseModelTests.TestModel() - t.foos_create({'item1': 10}) - self.assertEquals(t.foos_get_list(), ['item1']) diff --git a/plugins/kimchi/tests/test_model_network.py b/plugins/kimchi/tests/test_model_network.py deleted file mode 100644 index e4cf5ef..0000000 --- a/plugins/kimchi/tests/test_model_network.py +++ /dev/null @@ -1,149 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import unittest -from functools import partial - -from wok.rollbackcontext import RollbackContext - -from wok.plugins.kimchi.model.model import Model - -from utils import get_free_port, patch_auth, request, rollback_wrapper -from utils import run_server - - -model = None -test_server = None -host = None -port = None -ssl_port = None -cherrypy_port = None - - -def setUpModule(): - global test_server, model, host, port, ssl_port, cherrypy_port - - patch_auth() - model = Model(None, '/tmp/obj-store-test') - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - cherrypy_port = get_free_port('cherrypy_port') - test_server = run_server(host, port, ssl_port, test_mode=True, - cherrypy_port=cherrypy_port, model=model) - - -def tearDownModule(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - - -def _do_network_test(self, model, params): - with RollbackContext() as rollback: - net_name = params['name'] - uri = '/plugins/kimchi/networks/%s' % net_name.encode('utf-8') - - # Create a network - req = json.dumps(params) - resp = self.request('/plugins/kimchi/networks', req, 'POST') - rollback.prependDefer(rollback_wrapper, model.network_delete, - net_name) - self.assertEquals(201, resp.status) - - # Verify the network - resp = self.request(uri) - network = json.loads(resp.read()) - self.assertEquals('inactive', network['state']) - self.assertTrue(network['persistent']) - - # activate the network - resp = self.request(uri + '/activate', '{}', 'POST') - rollback.prependDefer(rollback_wrapper, - model.network_deactivate, net_name) - self.assertEquals(200, resp.status) - resp = self.request(uri) - network = json.loads(resp.read()) - self.assertEquals('active', network['state']) - - # Deactivate the network - resp = self.request(uri + '/deactivate', '{}', 'POST') - self.assertEquals(200, resp.status) - resp = self.request(uri) - network = json.loads(resp.read()) - self.assertEquals('inactive', network['state']) - - # Delete the network - resp = self.request(uri, '{}', 'DELETE') - self.assertEquals(204, resp.status) - - -class NetworkTests(unittest.TestCase): - def setUp(self): - self.request = partial(request, host, ssl_port) - - def test_get_networks(self): - networks = json.loads(self.request('/plugins/kimchi/networks').read()) - self.assertIn('default', [net['name'] for net in networks]) - - with RollbackContext() as rollback: - # Now add a couple of Networks to the mock model - for i in xrange(5): - name = 'network-%i' % i - req = json.dumps({'name': name, - 'connection': 'nat', - 'subnet': '127.0.10%i.0/24' % i}) - - resp = self.request('/plugins/kimchi/networks', req, 'POST') - rollback.prependDefer(model.network_delete, name) - self.assertEquals(201, resp.status) - network = json.loads(resp.read()) - self.assertEquals([], network["vms"]) - - nets = json.loads(self.request('/plugins/kimchi/networks').read()) - self.assertEquals(len(networks) + 5, len(nets)) - - network = json.loads( - self.request('/plugins/kimchi/networks/network-1').read() - ) - keys = [u'name', u'connection', u'interface', u'subnet', u'dhcp', - u'vms', u'in_use', u'autostart', u'state', u'persistent'] - self.assertEquals(sorted(keys), sorted(network.keys())) - - def test_network_lifecycle(self): - # Verify all the supported network type - networks = [{'name': u'k������h��-��et', 'connection': 'isolated'}, - {'name': u'nat-network', 'connection': 'nat'}, - {'name': u'subnet-network', 'connection': 'nat', - 'subnet': '127.0.100.0/24'}] - - # Verify the current system has at least one interface to create a - # bridged network - interfaces = json.loads( - self.request('/plugins/kimchi/interfaces?type=nic').read() - ) - if len(interfaces) > 0: - iface = interfaces[0]['name'] - networks.append({'name': u'bridge-network', 'connection': 'bridge', - 'interface': iface}) - - for net in networks: - _do_network_test(self, model, net) diff --git a/plugins/kimchi/tests/test_model_storagepool.py b/plugins/kimchi/tests/test_model_storagepool.py deleted file mode 100644 index 5f9b966..0000000 --- a/plugins/kimchi/tests/test_model_storagepool.py +++ /dev/null @@ -1,123 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import tempfile -import unittest -from functools import partial - -from wok.rollbackcontext import RollbackContext - -from wok.plugins.kimchi.model.model import Model - -from utils import get_free_port, patch_auth, request -from utils import run_server - - -model = None -test_server = None -host = None -port = None -ssl_port = None -cherrypy_port = None - - -def setUpModule(): - global test_server, model, host, port, ssl_port, cherrypy_port - - patch_auth() - model = Model(None, '/tmp/obj-store-test') - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - cherrypy_port = get_free_port('cherrypy_port') - test_server = run_server(host, port, ssl_port, test_mode=True, - cherrypy_port=cherrypy_port, model=model) - - -def tearDownModule(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - - -class StoragepoolTests(unittest.TestCase): - def setUp(self): - self.request = partial(request, host, ssl_port) - - def test_get_storagepools(self): - storagepools = json.loads( - self.request('/plugins/kimchi/storagepools').read() - ) - self.assertIn('default', [pool['name'] for pool in storagepools]) - - with RollbackContext() as rollback: - # Now add a couple of storage pools - for i in xrange(3): - name = u'k������h��-storagepool-%i' % i - req = json.dumps({'name': name, 'type': 'dir', - 'path': '/var/lib/libvirt/images/%i' % i}) - resp = self.request('/plugins/kimchi/storagepools', req, - 'POST') - rollback.prependDefer(model.storagepool_delete, name) - - self.assertEquals(201, resp.status) - - # Pool name must be unique - req = json.dumps({'name': name, 'type': 'dir', - 'path': '/var/lib/libvirt/images/%i' % i}) - resp = self.request('/plugins/kimchi/storagepools', req, - 'POST') - self.assertEquals(400, resp.status) - - # Verify pool information - resp = self.request('/plugins/kimchi/storagepools/%s' % - name.encode("utf-8")) - p = json.loads(resp.read()) - keys = [u'name', u'state', u'capacity', u'allocated', - u'available', u'path', u'source', u'type', - u'nr_volumes', u'autostart', u'persistent'] - self.assertEquals(sorted(keys), sorted(p.keys())) - self.assertEquals(name, p['name']) - self.assertEquals('inactive', p['state']) - self.assertEquals(True, p['persistent']) - self.assertEquals(True, p['autostart']) - self.assertEquals(0, p['nr_volumes']) - - pools = json.loads( - self.request('/plugins/kimchi/storagepools').read() - ) - self.assertEquals(len(storagepools) + 3, len(pools)) - - # Create a pool with an existing path - tmp_path = tempfile.mkdtemp(dir='/var/lib/kimchi') - rollback.prependDefer(os.rmdir, tmp_path) - req = json.dumps({'name': 'existing_path', 'type': 'dir', - 'path': tmp_path}) - resp = self.request('/plugins/kimchi/storagepools', req, 'POST') - rollback.prependDefer(model.storagepool_delete, 'existing_path') - self.assertEquals(201, resp.status) - - # Reserved pool return 400 - req = json.dumps({'name': 'kimchi_isos', 'type': 'dir', - 'path': '/var/lib/libvirt/images/%i' % i}) - resp = request(host, ssl_port, '/plugins/kimchi/storagepools', req, - 'POST') - self.assertEquals(400, resp.status) diff --git a/plugins/kimchi/tests/test_model_storagevolume.py b/plugins/kimchi/tests/test_model_storagevolume.py deleted file mode 100644 index 46c07bd..0000000 --- a/plugins/kimchi/tests/test_model_storagevolume.py +++ /dev/null @@ -1,280 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import requests -import unittest -from functools import partial - -from wok.config import paths -from wok.rollbackcontext import RollbackContext - -from wok.plugins.kimchi.config import READONLY_POOL_TYPE -from wok.plugins.kimchi.mockmodel import MockModel -from wok.plugins.kimchi.model.model import Model - -from utils import fake_auth_header, get_free_port, patch_auth, request -from utils import rollback_wrapper, run_server, wait_task - - -model = None -test_server = None -host = None -port = None -ssl_port = None -cherrypy_port = None - - -def setUpModule(): - global test_server, model, host, port, ssl_port, cherrypy_port - - patch_auth() - model = Model(None, '/tmp/obj-store-test') - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - cherrypy_port = get_free_port('cherrypy_port') - test_server = run_server(host, port, ssl_port, test_mode=True, - cherrypy_port=cherrypy_port, model=model) - - -def tearDownModule(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - - -def _do_volume_test(self, model, host, ssl_port, pool_name): - def _task_lookup(taskid): - return json.loads( - self.request('/tasks/%s' % taskid).read() - ) - - uri = '/plugins/kimchi/storagepools/%s/storagevolumes' \ - % pool_name.encode('utf-8') - resp = self.request(uri) - self.assertEquals(200, resp.status) - - resp = self.request('/plugins/kimchi/storagepools/%s' % - pool_name.encode('utf-8')) - pool_info = json.loads(resp.read()) - with RollbackContext() as rollback: - # Create storage volume with 'capacity' - vol = 'test-volume' - vol_uri = uri + '/' + vol - req = json.dumps({'name': vol, 'format': 'raw', - 'capacity': 1073741824}) # 1 GiB - resp = self.request(uri, req, 'POST') - if pool_info['type'] in READONLY_POOL_TYPE: - self.assertEquals(400, resp.status) - else: - rollback.prependDefer(rollback_wrapper, model.storagevolume_delete, - pool_name, vol) - self.assertEquals(202, resp.status) - task_id = json.loads(resp.read())['id'] - wait_task(_task_lookup, task_id) - status = json.loads( - self.request('/tasks/%s' % task_id).read() - ) - self.assertEquals('finished', status['status']) - vol_info = json.loads(self.request(vol_uri).read()) - vol_info['name'] = vol - vol_info['format'] = 'raw' - vol_info['capacity'] = 1073741824 - - # Resize the storage volume: increase its capacity to 2 GiB - req = json.dumps({'size': 2147483648}) # 2 GiB - resp = self.request(vol_uri + '/resize', req, 'POST') - self.assertEquals(200, resp.status) - storagevolume = json.loads(self.request(vol_uri).read()) - self.assertEquals(2147483648, storagevolume['capacity']) - - # Resize the storage volume: decrease its capacity to 512 MiB - # FIXME: Due a libvirt bug it is not possible to decrease the - # volume capacity - # For reference: - # - https://bugzilla.redhat.com/show_bug.cgi?id=1021802 - req = json.dumps({'size': 536870912}) # 512 MiB - resp = self.request(vol_uri + '/resize', req, 'POST') - # It is only possible when using MockModel - if isinstance(model, MockModel): - self.assertEquals(200, resp.status) - storagevolume = json.loads(self.request(vol_uri).read()) - self.assertEquals(536870912, storagevolume['capacity']) - else: - self.assertEquals(500, resp.status) - - # Wipe the storage volume - resp = self.request(vol_uri + '/wipe', '{}', 'POST') - self.assertEquals(200, resp.status) - storagevolume = json.loads(self.request(vol_uri).read()) - self.assertEquals(0, storagevolume['allocation']) - - # Clone the storage volume - vol_info = json.loads(self.request(vol_uri).read()) - resp = self.request(vol_uri + '/clone', '{}', 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - cloned_vol_name = task['target_uri'].split('/')[-1] - rollback.prependDefer(model.storagevolume_delete, pool_name, - cloned_vol_name) - wait_task(_task_lookup, task['id']) - task = json.loads( - self.request('/tasks/%s' % task['id']).read() - ) - self.assertEquals('finished', task['status']) - resp = self.request(uri + '/' + cloned_vol_name.encode('utf-8')) - - self.assertEquals(200, resp.status) - cloned_vol = json.loads(resp.read()) - - self.assertNotEquals(vol_info['name'], cloned_vol['name']) - self.assertNotEquals(vol_info['path'], cloned_vol['path']) - for key in ['name', 'path', 'allocation']: - del vol_info[key] - del cloned_vol[key] - - self.assertEquals(vol_info, cloned_vol) - - # Delete the storage volume - resp = self.request(vol_uri, '{}', 'DELETE') - self.assertEquals(204, resp.status) - resp = self.request(vol_uri) - self.assertEquals(404, resp.status) - - # Storage volume upload - # It is done through a sequence of POST and several PUT requests - filename = 'COPYING.LGPL' - filepath = os.path.join(paths.get_prefix(), filename) - filesize = os.stat(filepath).st_size - - # Create storage volume for upload - req = json.dumps({'name': filename, 'format': 'raw', - 'capacity': filesize, 'upload': True}) - resp = self.request(uri, req, 'POST') - if pool_info['type'] in READONLY_POOL_TYPE: - self.assertEquals(400, resp.status) - else: - rollback.prependDefer(rollback_wrapper, model.storagevolume_delete, - pool_name, filename) - self.assertEquals(202, resp.status) - task_id = json.loads(resp.read())['id'] - wait_task(_task_lookup, task_id) - status = json.loads(self.request('/tasks/%s' % - task_id).read()) - self.assertEquals('ready for upload', status['message']) - - # Upload volume content - url = 'https://%s:%s' % (host, ssl_port) + uri + '/' + filename - - # Create a file with 5M to upload - # Max body size is set to 4M so the upload will fail with 413 - newfile = '/tmp/5m-file' - with open(newfile, 'wb') as fd: - fd.seek(5*1024*1024-1) - fd.write("\0") - rollback.prependDefer(os.remove, newfile) - - with open(newfile, 'rb') as fd: - with open(newfile + '.tmp', 'wb') as tmp_fd: - data = fd.read() - tmp_fd.write(data) - - with open(newfile + '.tmp', 'rb') as tmp_fd: - r = requests.put(url, data={'chunk_size': len(data)}, - files={'chunk': tmp_fd}, - verify=False, - headers=fake_auth_header()) - self.assertEquals(r.status_code, 413) - - # Do upload - index = 0 - chunk_size = 2 * 1024 - content = '' - - with open(filepath, 'rb') as fd: - while True: - with open(filepath + '.tmp', 'wb') as tmp_fd: - fd.seek(index*chunk_size) - data = fd.read(chunk_size) - tmp_fd.write(data) - - with open(filepath + '.tmp', 'rb') as tmp_fd: - r = requests.put(url, data={'chunk_size': len(data)}, - files={'chunk': tmp_fd}, - verify=False, - headers=fake_auth_header()) - self.assertEquals(r.status_code, 200) - content += data - index = index + 1 - - if len(data) < chunk_size: - break - - rollback.prependDefer(os.remove, filepath + '.tmp') - resp = self.request(uri + '/' + filename) - self.assertEquals(200, resp.status) - uploaded_path = json.loads(resp.read())['path'] - with open(uploaded_path) as fd: - uploaded_content = fd.read() - - self.assertEquals(content, uploaded_content) - - # Create storage volume with 'url' - url = 'https://github.com/kimchi-project/kimchi/raw/master/COPYING' - req = json.dumps({'url': url}) - resp = self.request(uri, req, 'POST') - - if pool_info['type'] in READONLY_POOL_TYPE: - self.assertEquals(400, resp.status) - else: - rollback.prependDefer(model.storagevolume_delete, pool_name, - 'COPYING') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(_task_lookup, task['id']) - resp = self.request(uri + '/COPYING') - self.assertEquals(200, resp.status) - - -class StorageVolumeTests(unittest.TestCase): - def setUp(self): - self.request = partial(request, host, ssl_port) - - def test_get_storagevolume(self): - uri = '/plugins/kimchi/storagepools/default/storagevolumes' - resp = self.request(uri) - self.assertEquals(200, resp.status) - - keys = [u'name', u'type', u'capacity', u'allocation', u'path', - u'used_by', u'format'] - for vol in json.loads(resp.read()): - resp = self.request(uri + '/' + vol['name']) - self.assertEquals(200, resp.status) - - all_keys = keys[:] - vol_info = json.loads(resp.read()) - if vol_info['format'] == 'iso': - all_keys.extend([u'os_distro', u'os_version', u'bootable']) - - self.assertEquals(sorted(all_keys), sorted(vol_info.keys())) - - def test_storagevolume_action(self): - _do_volume_test(self, model, host, ssl_port, 'default') diff --git a/plugins/kimchi/tests/test_networkxml.py b/plugins/kimchi/tests/test_networkxml.py deleted file mode 100644 index a64b6c2..0000000 --- a/plugins/kimchi/tests/test_networkxml.py +++ /dev/null @@ -1,172 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import ipaddr -import lxml.etree as ET -import unittest - -from wok.xmlutils.utils import xpath_get_text - -from wok.plugins.kimchi.xmlutils import network as nxml - -import utils - - -class NetworkXmlTests(unittest.TestCase): - def test_dhcp_xml(self): - """ - Test network dhcp xml - """ - dhcp_range = {"start": "192.168.122.100", "end": "192.168.122.254"} - host1 = {"mac": "00:16:3e:77:e2:ed", - "name": "foo.example.com", - "ip": "192.168.122.10"} - host2 = {"mac": "00:16:3e:3e:a9:1a", - "name": "bar.example.com", - "ip": "192.168.122.11"} - params = {} - - dhcp = nxml._get_dhcp_elem(**params) - self.assertEquals(None, dhcp) - - params["range"] = dhcp_range - xml = ET.tostring(nxml._get_dhcp_elem(**params)) - start = xpath_get_text(xml, "/dhcp/range/@start") - end = xpath_get_text(xml, "/dhcp/range/@end") - self.assertEquals(dhcp_range['start'], start[0]) - self.assertEquals(dhcp_range['end'], end[0]) - - params["hosts"] = [host1, host2] - xml = ET.tostring(nxml._get_dhcp_elem(**params)) - ip = xpath_get_text(xml, "/dhcp/host/@ip") - self.assertEquals(ip, [host1['ip'], host2['ip']]) - - def test_ip_xml(self): - """ - Test network ip xml - """ - dhcp_range = {"start": "192.168.122.100", "end": "192.168.122.254"} - params = {} - - dhcp = nxml._get_dhcp_elem(**params) - self.assertEquals(None, dhcp) - - params["net"] = "192.168.122.0/255.255.255.0" - params["dhcp"] = {'range': dhcp_range} - xml = ET.tostring(nxml._get_ip_elem(**params)) - start = xpath_get_text(xml, "/ip/dhcp/range/@start")[0] - end = xpath_get_text(xml, "/ip/dhcp/range/@end")[0] - self.assertEquals(dhcp_range['start'], start) - self.assertEquals(dhcp_range['end'], end) - - address = xpath_get_text(xml, "/ip/@address")[0] - netmask = xpath_get_text(xml, "/ip/@netmask")[0] - self.assertEquals(address, params["net"].split("/")[0]) - self.assertEquals(netmask, params["net"].split("/")[1]) - - # test _get_ip_xml can accepts strings: '192.168.122.0/24', - # which is same as "192.168.122.0/255.255.255.0" - params["net"] = "192.168.122.0/24" - xml = ET.tostring(nxml._get_ip_elem(**params)) - netmask = xpath_get_text(xml, "/ip/@netmask")[0] - self.assertEquals(netmask, - str(ipaddr.IPNetwork(params["net"]).netmask)) - - def test_forward_xml(self): - """ - Test network forward xml - """ - params = {"mode": None} - - forward = nxml._get_forward_elem(**params) - self.assertEquals(None, forward) - - params["mode"] = 'nat' - params["dev"] = 'eth0' - xml = ET.tostring(nxml._get_forward_elem(**params)) - mode = xpath_get_text(xml, "/forward/@mode")[0] - dev = xpath_get_text(xml, "/forward/@dev")[0] - self.assertEquals(params['mode'], mode) - self.assertEquals(params['dev'], dev) - - def test_network_xml(self): - """ - Test network xml - """ - params = {"name": "test", - "forward": {"mode": "nat", "dev": ""}, - "net": "192.168.0.0/255.255.255.0"} - xml = nxml.to_network_xml(**params) - name = xpath_get_text(xml, "/network/name")[0] - self.assertEquals(name, params['name']) - - forward_mode = xpath_get_text(xml, "/network/forward/@mode")[0] - self.assertEquals(forward_mode, params['forward']['mode']) - forward_dev = xpath_get_text(xml, "/network/forward/@dev")[0] - self.assertEquals(forward_dev, '') - - address = xpath_get_text(xml, "/network/ip/@address")[0] - self.assertEquals(address, params["net"].split("/")[0]) - netmask = xpath_get_text(xml, "/network/ip/@netmask")[0] - self.assertEquals(netmask, params["net"].split("/")[1]) - - dhcp_start = xpath_get_text(xml, "/network/ip/dhcp/range/@start") - self.assertEquals(dhcp_start, []) - dhcp_end = xpath_get_text(xml, "/network/ip/dhcp/range/@end") - self.assertEquals(dhcp_end, []) - - # test optional params - params['forward']['dev'] = "eth0" - params['dhcp'] = {"range": {'start': '192.168.0.1', - 'end': '192.168.0.254'}} - xml = nxml.to_network_xml(**params) - forward_dev = xpath_get_text(xml, "/network/forward/@dev")[0] - self.assertEquals(forward_dev, params['forward']['dev']) - - dhcp_start = xpath_get_text(xml, "/network/ip/dhcp/range/@start")[0] - self.assertEquals(dhcp_start, params['dhcp']['range']['start']) - dhcp_end = xpath_get_text(xml, "/network/ip/dhcp/range/@end")[0] - self.assertEquals(dhcp_end, params['dhcp']['range']['end']) - - # test _get_ip_xml can accepts strings: '192.168.122.0/24', - # which is same as "192.168.122.0/255.255.255.0" - params["net"] = "192.168.0.0/24" - xml = nxml.to_network_xml(**params) - netmask = xpath_get_text(xml, "/network/ip/@netmask")[0] - self.assertEquals(netmask, - str(ipaddr.IPNetwork(params["net"]).netmask)) - - -class InterfaceXmlTests(unittest.TestCase): - - def test_vlan_tagged_bridge_no_ip(self): - expected_xml = """ - <interface type='bridge' name='br10'> - <start mode='onboot'/> - <bridge> - <interface type='vlan' name='em1.10'> - <vlan tag='10'> - <interface name='em1'/> - </vlan> - </interface> - </bridge> - </interface> - """ - actual_xml = nxml.create_vlan_tagged_bridge_xml('br10', 'em1', '10') - self.assertEquals(actual_xml, utils.normalize_xml(expected_xml)) diff --git a/plugins/kimchi/tests/test_objectstore.py b/plugins/kimchi/tests/test_objectstore.py deleted file mode 100644 index 632786f..0000000 --- a/plugins/kimchi/tests/test_objectstore.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os -import tempfile -import threading -import unittest - -from wok import objectstore -from wok.exception import NotFoundError - - -tmpfile = None - - -def setUpModule(): - global tmpfile - tmpfile = tempfile.mktemp() - - -def tearDownModule(): - os.unlink(tmpfile) - - -class ObjectStoreTests(unittest.TestCase): - def test_objectstore(self): - store = objectstore.ObjectStore(tmpfile) - - with store as session: - # Test create - session.store('f����', 't��st1', {'��': 1}) - session.store('f����', 't��st2', {'��': 2}) - - # Test list - items = session.get_list('f����') - self.assertTrue(u't��st1' in items) - self.assertTrue(u't��st2' in items) - - # Test get - item = session.get('f����', 't��st1') - self.assertEquals(1, item[u'��']) - - # Test delete - session.delete('f����', 't��st2') - self.assertEquals(1, len(session.get_list('f����'))) - - # Test get non-existent item - - self.assertRaises(NotFoundError, session.get, - '��', '��') - - # Test delete non-existent item - self.assertRaises(NotFoundError, session.delete, - 'f����', 't��st2') - - # Test refresh existing item - session.store('f����', 't��st1', {'��': 2}) - item = session.get('f����', 't��st1') - self.assertEquals(2, item[u'��']) - - def test_object_store_threaded(self): - def worker(ident): - with store as session: - session.store('foo', ident, {}) - - store = objectstore.ObjectStore(tmpfile) - - threads = [] - for i in xrange(50): - t = threading.Thread(target=worker, args=(i,)) - t.setDaemon(True) - t.start() - threads.append(t) - - for t in threads: - t.join() - - with store as session: - self.assertEquals(50, len(session.get_list('foo'))) - self.assertEquals(10, len(store._connections.keys())) diff --git a/plugins/kimchi/tests/test_osinfo.py b/plugins/kimchi/tests/test_osinfo.py deleted file mode 100644 index bd2af58..0000000 --- a/plugins/kimchi/tests/test_osinfo.py +++ /dev/null @@ -1,69 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import unittest - -from wok.plugins.kimchi.osinfo import _get_arch, get_template_default, lookup -from wok.plugins.kimchi.osinfo import modern_version_bases - - -class OSInfoTests(unittest.TestCase): - def test_default_lookup(self): - entry = lookup(None, None) - self.assertEquals('unknown', entry['os_distro']) - self.assertEquals('unknown', entry['os_version']) - self.assertEquals(['default'], entry['networks']) - - def test_old_distros(self): - old_versions = {'debian': '5.0', 'ubuntu': '7.04', 'opensuse': '10.1', - 'centos': '5.1', 'rhel': '5.1', 'fedora': '15'} - for distro, version in old_versions.iteritems(): - entry = lookup(distro, version) - self.assertEquals(entry['disk_bus'], - get_template_default('old', 'disk_bus')) - self.assertEquals(entry['nic_model'], - get_template_default('old', 'nic_model')) - - def test_modern_bases(self): - for distro, version in modern_version_bases[_get_arch()].iteritems(): - entry = lookup(distro, version) - self.assertEquals(entry['disk_bus'], - get_template_default('modern', 'disk_bus')) - self.assertEquals(entry['nic_model'], - get_template_default('modern', 'nic_model')) - - def test_modern_distros(self): - # versions based on ppc64 modern distros - modern_versions = {'ubuntu': '14.04', 'opensuse': '13.1', - 'rhel': '6.5', 'fedora': '19', 'sles': '11sp3'} - for distro, version in modern_versions.iteritems(): - entry = lookup(distro, version) - self.assertEquals(entry['disk_bus'], - get_template_default('modern', 'disk_bus')) - self.assertEquals(entry['nic_model'], - get_template_default('modern', 'nic_model')) - - def test_lookup_unknown_distro_version_returns_old_distro(self): - distro = 'unknown_distro' - version = 'unknown_version' - entry = lookup(distro, version) - self.assertEquals(entry['disk_bus'], - get_template_default('old', 'disk_bus')) - self.assertEquals(entry['nic_model'], - get_template_default('old', 'nic_model')) diff --git a/plugins/kimchi/tests/test_plugin.py b/plugins/kimchi/tests/test_plugin.py deleted file mode 100644 index fc8e277..0000000 --- a/plugins/kimchi/tests/test_plugin.py +++ /dev/null @@ -1,126 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import unittest -from functools import partial - -from wok.utils import get_enabled_plugins - -from wok.plugins.kimchi import mockmodel - -import utils - - -test_server = None -model = None -host = None -port = None -ssl_port = None - - -def setUpModule(): - global test_server, model, host, port, ssl_port - - utils.patch_auth() - model = mockmodel.MockModel('/tmp/obj-store-test') - host = '127.0.0.1' - port = utils.get_free_port('http') - ssl_port = utils.get_free_port('https') - test_server = utils.run_server(host, port, ssl_port, test_mode=True, - model=model) - - -def tearDownModule(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - - -@unittest.skipUnless( - 'sample' in [plugin for plugin, _config in get_enabled_plugins()], - 'sample plugin is not enabled, skip this test!') -class PluginTests(unittest.TestCase): - - def setUp(self): - self.request = partial(utils.request, host, ssl_port) - - def _create_rectangle(self, name, length, width): - req = json.dumps({'name': name, 'length': length, 'width': width}) - resp = self.request('/plugins/sample/rectangles', req, 'POST') - return resp - - def _get_rectangle(self, name): - resp = self.request('/plugins/sample/rectangles/%s' % name) - return json.loads(resp.read()) - - def _create_rectangle_and_assert(self, name, length, width): - resp = self._create_rectangle(name, length, width) - self.assertEquals(201, resp.status) - - rectangle = self._get_rectangle(name) - self.assertEquals(rectangle['name'], name) - self.assertEquals(rectangle['length'], length) - self.assertEquals(rectangle['width'], width) - - def _get_rectangles_list(self): - resp = self.request('/plugins/sample/rectangles') - rectangles = json.loads(resp.read()) - name_list = [rectangle['name'] for rectangle in rectangles] - return name_list - - def test_rectangles(self): - # Create two new rectangles - self._create_rectangle_and_assert('small', 10, 8) - self._create_rectangle_and_assert('big', 20, 16) - - # Verify they're in the list - name_list = self._get_rectangles_list() - self.assertIn('small', name_list) - self.assertIn('big', name_list) - - # Update the big rectangle. - req = json.dumps({'length': 40, 'width': 30}) - resp = self.request('/plugins/sample/rectangles/big', req, 'PUT') - self.assertEquals(200, resp.status) - big = self._get_rectangle('big') - self.assertEquals(big['length'], 40) - self.assertEquals(big['width'], 30) - - # Delete two rectangles - resp = self.request('/plugins/sample/rectangles/big', '{}', 'DELETE') - self.assertEquals(204, resp.status) - resp = self.request('/plugins/sample/rectangles/small', '{}', 'DELETE') - self.assertEquals(204, resp.status) - name_list = self._get_rectangles_list() - self.assertEquals([], name_list) - - def test_bad_params(self): - # Bad name - resp = self._create_rectangle(1.0, 30, 40) - self.assertEquals(400, resp.status) - - # Bad length value - resp = self._create_rectangle('test', -10.0, 40) - self.assertEquals(400, resp.status) - - # Missing param for width - req = json.dumps({'name': 'nowidth', 'length': 40}) - resp = self.request('/plugins/sample/rectangles', req, 'POST') - self.assertEquals(400, resp.status) diff --git a/plugins/kimchi/tests/test_rest.py b/plugins/kimchi/tests/test_rest.py deleted file mode 100644 index 243074e..0000000 --- a/plugins/kimchi/tests/test_rest.py +++ /dev/null @@ -1,1327 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import re -import time -import unittest -import urllib2 -import urlparse -from functools import partial - -from wok.rollbackcontext import RollbackContext -from wok.utils import add_task - -from wok.plugins.kimchi import mockmodel -from wok.plugins.kimchi.osinfo import get_template_default - -import iso_gen -from utils import get_free_port, patch_auth, request -from utils import run_server, wait_task - - -test_server = None -model = None -host = None -port = None -ssl_port = None -cherrypy_port = None -fake_iso = '/tmp/fake.iso' - - -def setUpModule(): - global test_server, model, host, port, ssl_port, cherrypy_port - - patch_auth() - model = mockmodel.MockModel('/tmp/obj-store-test') - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - cherrypy_port = get_free_port('cherrypy_port') - test_server = run_server(host, port, ssl_port, test_mode=True, - cherrypy_port=cherrypy_port, model=model) - - # Create fake ISO to do the tests - iso_gen.construct_fake_iso(fake_iso, True, '12.04', 'ubuntu') - iso_gen.construct_fake_iso("/var/lib/libvirt/images/fedora.iso", True, - "17", "fedora") - - -def tearDownModule(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - os.unlink(fake_iso) - os.unlink("/var/lib/libvirt/images/fedora.iso") - - -class RestTests(unittest.TestCase): - def _async_op(self, cb, opaque): - time.sleep(1) - cb('success', True) - - def _except_op(self, cb, opaque): - time.sleep(1) - raise Exception("Oops, this is an exception handle test." - " You can ignore it safely") - cb('success', True) - - def _intermid_op(self, cb, opaque): - time.sleep(1) - cb('in progress') - - def setUp(self): - self.request = partial(request, host, ssl_port) - model.reset() - - def assertHTTPStatus(self, code, *args): - resp = self.request(*args) - self.assertEquals(code, resp.status) - - def test_get_vms(self): - vms = json.loads(self.request('/plugins/kimchi/vms').read()) - # test_rest.py uses MockModel() which connects to libvirt URI - # test:///default. By default this driver already has one VM created - self.assertEquals(1, len(vms)) - - # Create a template as a base for our VMs - req = json.dumps({'name': 'test', 'cdrom': fake_iso}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - test_users = ['root'] - test_groups = ['wheel'] - # Now add a couple of VMs to the mock model - for i in xrange(10): - name = 'vm-%i' % i - req = json.dumps({'name': name, - 'template': '/plugins/kimchi/templates/test', - 'users': test_users, 'groups': test_groups}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - - vms = json.loads(self.request('/plugins/kimchi/vms').read()) - self.assertEquals(11, len(vms)) - - vm = json.loads(self.request('/plugins/kimchi/vms/vm-1').read()) - self.assertEquals('vm-1', vm['name']) - self.assertEquals('shutoff', vm['state']) - self.assertEquals([], vm['users']) - self.assertEquals([], vm['groups']) - - def test_edit_vm(self): - req = json.dumps({'name': 'test', 'cdrom': fake_iso}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - req = json.dumps({'name': 'vm-1', - 'template': '/plugins/kimchi/templates/test'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - - vm = json.loads(self.request('/plugins/kimchi/vms/vm-1').read()) - self.assertEquals('vm-1', vm['name']) - - resp = self.request('/plugins/kimchi/vms/vm-1/start', '{}', 'POST') - self.assertEquals(200, resp.status) - - req = json.dumps({'unsupported-attr': 'attr'}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(400, resp.status) - - req = json.dumps({'name': 'new-vm'}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(400, resp.status) - - req = json.dumps({'cpus': 3}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(200, resp.status) - - # Check if there is support to memory hotplug, once vm is running - resp = self.request('/plugins/kimchi/config/capabilities').read() - conf = json.loads(resp) - req = json.dumps({'memory': 2048}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - if conf['mem_hotplug_support']: - self.assertEquals(200, resp.status) - else: - self.assertEquals(400, resp.status) - - req = json.dumps({"graphics": {'passwd': "abcdef"}}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - info = json.loads(resp.read()) - self.assertEquals('abcdef', info["graphics"]["passwd"]) - self.assertEquals(None, info["graphics"]["passwdValidTo"]) - - resp = self.request('/plugins/kimchi/vms/vm-1/poweroff', '{}', 'POST') - self.assertEquals(200, resp.status) - - req = json.dumps({"graphics": {'passwd': "123456", - 'passwdValidTo': 20}}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - info = json.loads(resp.read()) - self.assertEquals('123456', info["graphics"]["passwd"]) - self.assertGreaterEqual(20, info["graphics"]["passwdValidTo"]) - - req = json.dumps({'name': 12}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(400, resp.status) - - req = json.dumps({'name': ''}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(400, resp.status) - - req = json.dumps({'cpus': -2}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(400, resp.status) - - req = json.dumps({'cpus': 'four'}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(400, resp.status) - - req = json.dumps({'memory': 100}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(400, resp.status) - - req = json.dumps({'memory': 'ten gigas'}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(400, resp.status) - - req = json.dumps({'name': 'new-name', 'cpus': 5, 'UUID': 'notallowed'}) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(400, resp.status) - - params = {'name': u'�����-����d��t��d', 'cpus': 5, 'memory': 3072} - req = json.dumps(params) - resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') - self.assertEquals(303, resp.status) - vm = json.loads( - self.request('/plugins/kimchi/vms/�����-����d��t��d', req).read() - ) - for key in params.keys(): - self.assertEquals(params[key], vm[key]) - - # change only VM users - groups are not changed (default is empty) - resp = self.request('/plugins/kimchi/users', '{}', 'GET') - users = json.loads(resp.read()) - req = json.dumps({'users': users}) - resp = self.request('/plugins/kimchi/vms/�����-����d��t��d', req, 'PUT') - self.assertEquals(200, resp.status) - info = json.loads( - self.request('/plugins/kimchi/vms/�����-����d��t��d', '{}').read() - ) - self.assertEquals(users, info['users']) - - # change only VM groups - users are not changed (default is empty) - resp = self.request('/plugins/kimchi/groups', '{}', 'GET') - groups = json.loads(resp.read()) - req = json.dumps({'groups': groups}) - resp = self.request('/plugins/kimchi/vms/�����-����d��t��d', req, 'PUT') - self.assertEquals(200, resp.status) - info = json.loads( - self.request('/plugins/kimchi/vms/�����-����d��t��d', '{}').read() - ) - self.assertEquals(groups, info['groups']) - - # change VM users (wrong value) and groups - # when an error occurs, everything fails and nothing is changed - req = json.dumps({'users': ['userdoesnotexist'], 'groups': []}) - resp = self.request('/plugins/kimchi/vms/�����-����d��t��d', req, 'PUT') - self.assertEquals(400, resp.status) - - # change VM users and groups (wrong value) - # when an error occurs, everything fails and nothing is changed - req = json.dumps({'users': [], 'groups': ['groupdoesnotexist']}) - resp = self.request('/plugins/kimchi/vms/�����-����d��t��d', req, 'PUT') - self.assertEquals(400, resp.status) - - def test_vm_lifecycle(self): - # Create a Template - req = json.dumps({'name': 'test', 'disks': [{'size': 1}], - 'icon': 'images/icon-debian.png', - 'cdrom': fake_iso}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - # Create a VM - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - self.assertEquals(202, resp.status) - - # Verify the VM - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - self.assertEquals('shutoff', vm['state']) - self.assertEquals('images/icon-debian.png', vm['icon']) - - # Verify the volume was created - vol_uri = '/plugins/kimchi/storagepools/default-pool/storagevolumes/' \ - + '%s-0.img' - resp = self.request(vol_uri % vm['uuid']) - vol = json.loads(resp.read()) - self.assertEquals(1 << 30, vol['capacity']) - self.assertEquals(['test-vm'], vol['used_by']) - - # Start the VM - resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - self.assertEquals('running', vm['state']) - - # Test screenshot - resp = self.request(vm['screenshot'], method='HEAD') - self.assertEquals(200, resp.status) - self.assertTrue(resp.getheader('Content-type').startswith('image')) - - # Clone a running VM - resp = self.request('/plugins/kimchi/vms/test-vm/clone', '{}', 'POST') - self.assertEquals(400, resp.status) - - # Force poweroff the VM - resp = self.request('/plugins/kimchi/vms/test-vm/poweroff', '{}', - 'POST') - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - self.assertEquals('shutoff', vm['state']) - - # Test create VM with same name fails with 400 - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(400, resp.status) - - # Clone a VM - resp = self.request('/plugins/kimchi/vms/test-vm/clone', '{}', 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - task = json.loads( - self.request('/tasks/%s' % task['id'], '{}').read() - ) - self.assertEquals('finished', task['status']) - clone_vm_name = task['target_uri'].split('/')[-2] - self.assertTrue(re.match(u'test-vm-clone-\d+', clone_vm_name)) - - resp = self.request('/plugins/kimchi/vms/test-vm', '{}') - original_vm_info = json.loads(resp.read()) - resp = self.request('/plugins/kimchi/vms/%s' % clone_vm_name, '{}') - self.assertEquals(200, resp.status) - clone_vm_info = json.loads(resp.read()) - - self.assertNotEqual(original_vm_info['name'], clone_vm_info['name']) - del original_vm_info['name'] - del clone_vm_info['name'] - - self.assertNotEqual(original_vm_info['uuid'], clone_vm_info['uuid']) - del original_vm_info['uuid'] - del clone_vm_info['uuid'] - - self.assertEquals(original_vm_info, clone_vm_info) - - # Create a snapshot on a stopped VM - params = {'name': 'test-snap'} - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots', - json.dumps(params), - 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - task = json.loads( - self.request('/tasks/%s' % task['id']).read() - ) - self.assertEquals('finished', task['status']) - - # Look up a non-existing snapshot - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/snap404', - '{}', 'GET') - self.assertEquals(404, resp.status) - - # Look up a snapshot - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/%s' % - params['name'], '{}', 'GET') - self.assertEquals(200, resp.status) - snap = json.loads(resp.read()) - self.assertTrue(int(time.time()) >= int(snap['created'])) - self.assertEquals(params['name'], snap['name']) - self.assertEquals(u'', snap['parent']) - self.assertEquals(u'shutoff', snap['state']) - - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots', '{}', - 'GET') - self.assertEquals(200, resp.status) - snaps = json.loads(resp.read()) - self.assertEquals(1, len(snaps)) - - # Look up current snapshot (the one created above) - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/current', - '{}', 'GET') - self.assertEquals(200, resp.status) - snap = json.loads(resp.read()) - self.assertEquals(params['name'], snap['name']) - - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots', '{}', - 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - snap_name = task['target_uri'].split('/')[-1] - wait_task(self._task_lookup, task['id']) - resp = self.request('/tasks/%s' % task['id'], '{}', - 'GET') - task = json.loads(resp.read()) - self.assertEquals('finished', task['status']) - - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots', '{}', - 'GET') - self.assertEquals(200, resp.status) - snaps = json.loads(resp.read()) - self.assertEquals(2, len(snaps)) - - # Look up current snapshot (the one created above) - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/current', - '{}', 'GET') - self.assertEquals(200, resp.status) - snap = json.loads(resp.read()) - self.assertEquals(snap_name, snap['name']) - - # Revert to snapshot - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/%s/revert' % - params['name'], '{}', 'POST') - self.assertEquals(200, resp.status) - snap = json.loads(resp.read()) - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET') - self.assertEquals(200, resp.status) - vm = json.loads(resp.read()) - self.assertEquals(vm['state'], snap['state']) - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/current', - '{}', 'GET') - self.assertEquals(200, resp.status) - current_snap = json.loads(resp.read()) - self.assertEquals(snap, current_snap) - - # Delete a snapshot - resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/%s' % - params['name'], '{}', 'DELETE') - self.assertEquals(204, resp.status) - - # Suspend the VM - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET') - self.assertEquals(200, resp.status) - vm = json.loads(resp.read()) - self.assertEquals(vm['state'], 'shutoff') - resp = self.request('/plugins/kimchi/vms/test-vm/suspend', '{}', - 'POST') - self.assertEquals(400, resp.status) - resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') - self.assertEquals(200, resp.status) - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET') - self.assertEquals(200, resp.status) - vm = json.loads(resp.read()) - self.assertEquals(vm['state'], 'running') - resp = self.request('/plugins/kimchi/vms/test-vm/suspend', '{}', - 'POST') - self.assertEquals(200, resp.status) - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET') - self.assertEquals(200, resp.status) - vm = json.loads(resp.read()) - self.assertEquals(vm['state'], 'paused') - - # Resume the VM - resp = self.request('/plugins/kimchi/vms/test-vm/resume', '{}', 'POST') - self.assertEquals(200, resp.status) - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET') - self.assertEquals(200, resp.status) - vm = json.loads(resp.read()) - self.assertEquals(vm['state'], 'running') - - # Delete the VM - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') - self.assertEquals(204, resp.status) - - # Delete the Template - resp = self.request('/plugins/kimchi/templates/test', '{}', 'DELETE') - self.assertEquals(204, resp.status) - - # Verify the volume was deleted - self.assertHTTPStatus(404, vol_uri % vm['uuid']) - - def test_vm_graphics(self): - # Create a Template - req = json.dumps({'name': 'test', 'cdrom': fake_iso}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - # Create a VM with default args - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - # Verify the VM - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - self.assertEquals('127.0.0.1', vm['graphics']['listen']) - self.assertEquals('vnc', vm['graphics']['type']) - # Delete the VM - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') - self.assertEquals(204, resp.status) - - # Create a VM with specified graphics type and listen - graphics = {'type': 'vnc', 'listen': '127.0.0.1'} - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test', - 'graphics': graphics}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - # Verify the VM - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - self.assertEquals('127.0.0.1', vm['graphics']['listen']) - self.assertEquals('vnc', vm['graphics']['type']) - # Delete the VM - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') - self.assertEquals(204, resp.status) - - # Create a VM with listen as ipv6 address - graphics = {'type': 'spice', 'listen': 'fe00::0'} - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test', - 'graphics': graphics}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - # Verify the VM - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - self.assertEquals('fe00::0', vm['graphics']['listen']) - self.assertEquals('spice', vm['graphics']['type']) - # Delete the VM - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') - self.assertEquals(204, resp.status) - - # Create a VM with specified graphics type and default listen - graphics = {'type': 'spice'} - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test', - 'graphics': graphics}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - # Verify the VM - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - self.assertEquals('127.0.0.1', vm['graphics']['listen']) - self.assertEquals('spice', vm['graphics']['type']) - # Delete the VM - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') - self.assertEquals(204, resp.status) - - # Try to create a VM with invalid graphics type - graphics = {'type': 'invalid'} - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test', - 'graphics': graphics}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(400, resp.status) - - # Try to create a VM with invalid graphics listen - graphics = {'type': 'spice', 'listen': 'invalid'} - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test', - 'graphics': graphics}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(400, resp.status) - - # Delete the Template - resp = self.request('/plugins/kimchi/templates/test', '{}', 'DELETE') - self.assertEquals(204, resp.status) - - def test_vm_storage_devices(self): - - with RollbackContext() as rollback: - # Create a template as a base for our VMs - req = json.dumps({'name': 'test', 'cdrom': fake_iso}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - # Delete the template - rollback.prependDefer(self.request, - '/plugins/kimchi/templates/test', '{}', - 'DELETE') - - # Create a VM with default args - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - # Delete the VM - rollback.prependDefer(self.request, '/plugins/kimchi/vms/test-vm', - '{}', 'DELETE') - - # Check storage devices - resp = self.request('/plugins/kimchi/vms/test-vm/storages', '{}', - 'GET') - devices = json.loads(resp.read()) - self.assertEquals(2, len(devices)) - dev_types = [] - for d in devices: - self.assertIn(u'type', d.keys()) - self.assertIn(u'dev', d.keys()) - self.assertIn(u'path', d.keys()) - dev_types.append(d['type']) - - self.assertEquals(['cdrom', 'disk'], sorted(dev_types)) - - # Attach cdrom with nonexistent iso - req = json.dumps({'dev': 'hdx', - 'type': 'cdrom', - 'path': '/tmp/nonexistent.iso'}) - resp = self.request('/plugins/kimchi/vms/test-vm/storages', req, - 'POST') - self.assertEquals(400, resp.status) - - # Create temp storage pool - req = json.dumps({'name': 'tmp', - 'capacity': 1024, - 'allocated': 512, - 'path': '/tmp', - 'type': 'dir'}) - resp = self.request('/plugins/kimchi/storagepools', req, 'POST') - self.assertEquals(201, resp.status) - resp = self.request('/plugins/kimchi/storagepools/tmp/activate', - req, 'POST') - self.assertEquals(200, resp.status) - - # 'name' is required for this type of volume - req = json.dumps({'capacity': 1024, - 'allocation': 512, - 'type': 'disk', - 'format': 'raw'}) - resp = self.request( - '/plugins/kimchi/storagepools/tmp/storagevolumes', req, 'POST' - ) - self.assertEquals(400, resp.status) - req = json.dumps({'name': "attach-volume", - 'capacity': 1024, - 'allocation': 512, - 'type': 'disk', - 'format': 'raw'}) - resp = self.request( - '/plugins/kimchi/storagepools/tmp/storagevolumes', req, 'POST' - ) - self.assertEquals(202, resp.status) - time.sleep(1) - - # Attach cdrom with both path and volume specified - open('/tmp/existent.iso', 'w').close() - req = json.dumps({'dev': 'hdx', - 'type': 'cdrom', - 'pool': 'tmp', - 'vol': 'attach-volume', - 'path': '/tmp/existent.iso'}) - resp = self.request( - '/plugins/kimchi/vms/test-vm/storages', req, 'POST' - ) - self.assertEquals(400, resp.status) - - # Attach disk with both path and volume specified - req = json.dumps({'dev': 'hdx', - 'type': 'disk', - 'pool': 'tmp', - 'vol': 'attach-volume', - 'path': '/tmp/existent.iso'}) - resp = self.request( - '/plugins/kimchi/vms/test-vm/storages', req, 'POST' - ) - self.assertEquals(400, resp.status) - - # Attach disk with only pool specified - req = json.dumps({'dev': 'hdx', - 'type': 'cdrom', - 'pool': 'tmp'}) - resp = self.request( - '/plugins/kimchi/vms/test-vm/storages', req, 'POST' - ) - self.assertEquals(400, resp.status) - - # Attach disk with pool and vol specified - req = json.dumps({'type': 'disk', - 'pool': 'tmp', - 'vol': 'attach-volume'}) - resp = self.request( - '/plugins/kimchi/vms/test-vm/storages', req, 'POST' - ) - self.assertEquals(201, resp.status) - cd_info = json.loads(resp.read()) - self.assertEquals('disk', cd_info['type']) - - # Attach a cdrom with existent dev name - req = json.dumps({'type': 'cdrom', - 'path': '/tmp/existent.iso'}) - resp = self.request( - '/plugins/kimchi/vms/test-vm/storages', req, 'POST' - ) - self.assertEquals(201, resp.status) - cd_info = json.loads(resp.read()) - cd_dev = cd_info['dev'] - self.assertEquals('cdrom', cd_info['type']) - self.assertEquals('/tmp/existent.iso', cd_info['path']) - # Delete the file and cdrom - rollback.prependDefer(self.request, - '/plugins/kimchi/vms/test-vm/storages/hdx', - '{}', 'DELETE') - os.remove('/tmp/existent.iso') - - # Change path of storage cdrom - cdrom = u'http://fedora.mirrors.tds.net/pub/fedora/releases/20/'\ - 'Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso' - req = json.dumps({'path': cdrom}) - resp = self.request('/plugins/kimchi/vms/test-vm/storages/' + - cd_dev, req, 'PUT') - self.assertEquals(200, resp.status) - cd_info = json.loads(resp.read()) - self.assertEquals(urlparse.urlparse(cdrom).path, - urlparse.urlparse(cd_info['path']).path) - - # Test GET - devs = json.loads( - self.request('/plugins/kimchi/vms/test-vm/storages').read() - ) - self.assertEquals(4, len(devs)) - - # Detach storage cdrom - resp = self.request('/plugins/kimchi/vms/test-vm/storages/' + - cd_dev, '{}', 'DELETE') - self.assertEquals(204, resp.status) - - # Test GET - devs = json.loads( - self.request('/plugins/kimchi/vms/test-vm/storages').read() - ) - self.assertEquals(3, len(devs)) - resp = self.request('/plugins/kimchi/storagepools/tmp/deactivate', - {}, 'POST') - self.assertEquals(200, resp.status) - resp = self.request('/plugins/kimchi/storagepools/tmp', {}, - 'DELETE') - self.assertEquals(204, resp.status) - - def test_vm_iface(self): - - with RollbackContext() as rollback: - # Create a template as a base for our VMs - req = json.dumps({'name': 'test', 'cdrom': fake_iso}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - # Delete the template - rollback.prependDefer(self.request, - '/plugins/kimchi/templates/test', '{}', - 'DELETE') - - # Create a VM with default args - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - # Delete the VM - rollback.prependDefer(self.request, - '/plugins/kimchi/vms/test-vm', '{}', - 'DELETE') - - # Create a network - req = json.dumps({'name': 'test-network', - 'connection': 'nat', - 'net': '127.0.1.0/24'}) - resp = self.request('/plugins/kimchi/networks', req, 'POST') - self.assertEquals(201, resp.status) - # Delete the network - rollback.prependDefer(self.request, - '/plugins/kimchi/networks/test-network', - '{}', 'DELETE') - - ifaces = json.loads( - self.request('/plugins/kimchi/vms/test-vm/ifaces').read() - ) - self.assertEquals(1, len(ifaces)) - - for iface in ifaces: - res = json.loads( - self.request('/plugins/kimchi/vms/test-vm/ifaces/%s' % - iface['mac']).read() - ) - self.assertEquals('default', res['network']) - self.assertEquals(17, len(res['mac'])) - self.assertEquals(get_template_default('old', 'nic_model'), - res['model']) - - # try to attach an interface without specifying 'model' - req = json.dumps({'type': 'network'}) - resp = self.request('/plugins/kimchi/vms/test-vm/ifaces', req, - 'POST') - self.assertEquals(400, resp.status) - - # attach network interface to vm - req = json.dumps({"type": "network", - "network": "test-network", - "model": "virtio"}) - resp = self.request('/plugins/kimchi/vms/test-vm/ifaces', req, - 'POST') - self.assertEquals(201, resp.status) - iface = json.loads(resp.read()) - - self.assertEquals('test-network', iface['network']) - self.assertEquals(17, len(iface['mac'])) - self.assertEquals('virtio', iface['model']) - self.assertEquals('network', iface['type']) - - # update vm interface - newMacAddr = '54:50:e3:44:8a:af' - req = json.dumps({"network": "default", "model": "virtio", - "type": "network", "mac": newMacAddr}) - resp = self.request('/plugins/kimchi/vms/test-vm/ifaces/%s' % - iface['mac'], req, 'PUT') - self.assertEquals(303, resp.status) - iface = json.loads( - self.request('/plugins/kimchi/vms/test-vm/ifaces/%s' % - newMacAddr).read() - ) - self.assertEquals(newMacAddr, iface['mac']) - - # detach network interface from vm - resp = self.request('/plugins/kimchi/vms/test-vm/ifaces/%s' % - iface['mac'], '{}', 'DELETE') - self.assertEquals(204, resp.status) - - def test_vm_customise_storage(self): - # Create a Template - req = json.dumps({'name': 'test', 'cdrom': fake_iso, - 'disks': [{'size': 1}]}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - # Create alternate storage - req = json.dumps({'name': 'alt', - 'capacity': 1024, - 'allocated': 512, - 'path': '/tmp', - 'type': 'dir'}) - resp = self.request('/plugins/kimchi/storagepools', req, 'POST') - self.assertEquals(201, resp.status) - resp = self.request('/plugins/kimchi/storagepools/alt/activate', req, - 'POST') - self.assertEquals(200, resp.status) - - # Create a VM - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test', - 'storagepool': '/plugins/kimchi/storagepools/alt'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - resp = self.request('/plugins/kimchi/vms/test-vm', {}, 'GET') - vm_info = json.loads(resp.read()) - - # Test template not changed after vm customise its pool - t = json.loads(self.request('/plugins/kimchi/templates/test').read()) - self.assertEquals(t['storagepool'], - '/plugins/kimchi/storagepools/default-pool') - - # Verify the volume was created - vol_uri = '/plugins/kimchi/storagepools/alt/storagevolumes/%s-0.img' \ - % vm_info['uuid'] - resp = self.request(vol_uri) - vol = json.loads(resp.read()) - self.assertEquals(1 << 30, vol['capacity']) - - # Delete the VM - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') - self.assertEquals(204, resp.status) - - # Verify the volume was deleted - self.assertHTTPStatus(404, vol_uri) - - def test_scsi_fc_storage(self): - # Create scsi fc pool - req = json.dumps({'name': 'scsi_fc_pool', - 'type': 'scsi', - 'source': {'adapter_name': 'scsi_host2'}}) - resp = self.request('/plugins/kimchi/storagepools', req, 'POST') - self.assertEquals(201, resp.status) - - # Test create vms using lun of this pool - # activate the storage pool - resp = self.request( - '/plugins/kimchi/storagepools/scsi_fc_pool/activate', '{}', 'POST' - ) - - # Create template fails because SCSI volume is missing - tmpl_params = { - 'name': 'test_fc_pool', 'cdrom': fake_iso, - 'storagepool': '/plugins/kimchi/storagepools/scsi_fc_pool' - } - req = json.dumps(tmpl_params) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(400, resp.status) - - # Choose SCSI volume to create template - resp = self.request( - '/plugins/kimchi/storagepools/scsi_fc_pool/storagevolumes' - ) - lun_name = json.loads(resp.read())[0]['name'] - - tmpl_params['disks'] = [{'index': 0, 'volume': lun_name}] - req = json.dumps(tmpl_params) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - # Create vm in scsi pool - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test_fc_pool'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - - # Start the VM - resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - self.assertEquals('running', vm['state']) - - # Force poweroff the VM - resp = self.request('/plugins/kimchi/vms/test-vm/poweroff', '{}', - 'POST') - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - self.assertEquals('shutoff', vm['state']) - - # Delete the VM - resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') - self.assertEquals(204, resp.status) - - def test_unnamed_vms(self): - # Create a Template - req = json.dumps({'name': 'test', 'cdrom': fake_iso}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - # Create 5 unnamed vms from this template - for i in xrange(1, 6): - req = json.dumps({'template': '/plugins/kimchi/templates/test'}) - task = json.loads(self.request('/plugins/kimchi/vms', - req, 'POST').read()) - wait_task(self._task_lookup, task['id']) - resp = self.request('/plugins/kimchi/vms/test-vm-%i' % i, {}, - 'GET') - self.assertEquals(resp.status, 200) - count = len(json.loads(self.request('/plugins/kimchi/vms').read())) - self.assertEquals(6, count) - - def test_create_vm_without_template(self): - req = json.dumps({'name': 'vm-without-template'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(400, resp.status) - resp = json.loads(resp.read()) - self.assertIn(u"KCHVM0016E:", resp['reason']) - - def test_create_vm_with_bad_template_uri(self): - req = json.dumps({'name': 'vm-bad-template', - 'template': '/mytemplate'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(400, resp.status) - resp = json.loads(resp.read()) - self.assertIn(u"KCHVM0012E", resp['reason']) - - def test_create_vm_with_img_based_template(self): - resp = json.loads( - self.request( - '/plugins/kimchi/storagepools/default-pool/storagevolumes' - ).read() - ) - self.assertEquals(0, len(resp)) - - # Create a Template - mock_base = '/tmp/mock.img' - open(mock_base, 'w').close() - req = json.dumps({'name': 'test', 'disks': [{'base': mock_base}]}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - req = json.dumps({'template': '/plugins/kimchi/templates/test'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - - # Test storage volume created with backing store of base file - resp = json.loads( - self.request( - '/plugins/kimchi/storagepools/default-pool/storagevolumes' - ).read() - ) - self.assertEquals(1, len(resp)) - - def _create_pool(self, name): - req = json.dumps({'name': name, - 'capacity': 10240, - 'allocated': 5120, - 'path': '/var/lib/libvirt/images/', - 'type': 'dir'}) - resp = self.request('/plugins/kimchi/storagepools', req, 'POST') - self.assertEquals(201, resp.status) - - # Verify the storage pool - storagepool = json.loads(self.request('/plugins/kimchi/storagepools/%s' - % name).read()) - self.assertEquals('inactive', storagepool['state']) - return name - - def _delete_pool(self, name): - # Delete the storage pool - resp = self.request('/plugins/kimchi/storagepools/%s' % name, '{}', - 'DELETE') - self.assertEquals(204, resp.status) - - def test_iso_scan_shallow(self): - # fake environment preparation - self._create_pool('pool-3') - self.request('/plugins/kimchi/storagepools/pool-3/activate', '{}', - 'POST') - params = {'name': 'fedora.iso', - 'capacity': 1073741824, # 1 GiB - 'type': 'file', - 'format': 'iso'} - task_info = model.storagevolumes_create('pool-3', params) - wait_task(self._task_lookup, task_info['id']) - - storagevolume = json.loads( - self.request( - '/plugins/kimchi/storagepools/kimchi_isos/storagevolumes/' - ).read() - )[0] - self.assertEquals('fedora.iso', storagevolume['name']) - self.assertEquals('iso', storagevolume['format']) - self.assertEquals('/var/lib/libvirt/images/fedora.iso', - storagevolume['path']) - self.assertEquals(1073741824, storagevolume['capacity']) # 1 GiB - self.assertEquals(0, storagevolume['allocation']) - self.assertEquals('17', storagevolume['os_version']) - self.assertEquals('fedora', storagevolume['os_distro']) - self.assertEquals(True, storagevolume['bootable']) - - # Create a template - # In real model os distro/version can be omitted - # as we will scan the iso - req = json.dumps({'name': 'test', - 'cdrom': storagevolume['path'], - 'os_distro': storagevolume['os_distro'], - 'os_version': storagevolume['os_version']}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - # Verify the template - t = json.loads(self.request('/plugins/kimchi/templates/test').read()) - self.assertEquals('test', t['name']) - self.assertEquals('fedora', t['os_distro']) - self.assertEquals('17', t['os_version']) - self.assertEquals(get_template_default('old', 'memory'), t['memory']) - - # Deactivate or destroy scan pool return 405 - resp = self.request( - '/plugins/kimchi/storagepools/kimchi_isos/storagevolumes' - '/deactivate', '{}', 'POST' - ) - self.assertEquals(405, resp.status) - - resp = self.request( - '/plugins/kimchi/storagepools/kimchi_isos/storagevolumes', - '{}', 'DELETE' - ) - self.assertEquals(405, resp.status) - - # Delete the template - resp = self.request('/plugins/kimchi/templates/%s' % t['name'], '{}', - 'DELETE') - self.assertEquals(204, resp.status) - - resp = self.request('/plugins/kimchi/storagepools/pool-3/deactivate', - '{}', 'POST') - self.assertEquals(200, resp.status) - self._delete_pool('pool-3') - - def test_screenshot_refresh(self): - # Create a VM - req = json.dumps({'name': 'test', 'cdrom': fake_iso}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - req = json.dumps({'name': 'test-vm', - 'template': '/plugins/kimchi/templates/test'}) - resp = self.request('/plugins/kimchi/vms', req, 'POST') - task = json.loads(resp.read()) - wait_task(self._task_lookup, task['id']) - - # Test screenshot for shut-off state vm - resp = self.request('/plugins/kimchi/vms/test-vm/screenshot') - self.assertEquals(404, resp.status) - - # Test screenshot for running vm - resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - - resp = self.request(vm['screenshot'], method='HEAD') - self.assertEquals(200, resp.status) - self.assertTrue(resp.getheader('Content-type').startswith('image')) - - # Test screenshot sub-resource redirect - resp = self.request('/plugins/kimchi/vms/test-vm/screenshot') - self.assertEquals(200, resp.status) - self.assertEquals('image/png', resp.getheader('content-type')) - lastMod1 = resp.getheader('last-modified') - - # Take another screenshot instantly and compare the last Modified date - resp = self.request('/plugins/kimchi/vms/test-vm/screenshot') - lastMod2 = resp.getheader('last-modified') - self.assertEquals(lastMod2, lastMod1) - - resp = self.request('/plugins/kimchi/vms/test-vm/screenshot', '{}', - 'DELETE') - self.assertEquals(405, resp.status) - - # No screenshot after stopped the VM - self.request('/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST') - resp = self.request('/plugins/kimchi/vms/test-vm/screenshot') - self.assertEquals(404, resp.status) - - # Picture link not available after VM deleted - self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') - vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) - img_lnk = vm['screenshot'] - self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') - resp = self.request(img_lnk) - self.assertEquals(404, resp.status) - - def test_interfaces(self): - resp = self.request('/plugins/kimchi/interfaces').read() - self.assertIn('name', resp) - interfaces = json.loads(resp) - keys = ['name', 'type', 'ipaddr', 'netmask', 'status'] - for interface in interfaces: - self.assertEquals(sorted(keys), sorted(interface.keys())) - - def _task_lookup(self, taskid): - return json.loads( - self.request('/tasks/%s' % taskid).read() - ) - - def test_tasks(self): - id1 = add_task('/tasks/1', self._async_op, - model.objstore) - id2 = add_task('/tasks/2', self._except_op, - model.objstore) - id3 = add_task('/tasks/3', self._intermid_op, - model.objstore) - - target_uri = urllib2.quote('^/tasks/*', safe="") - filter_data = 'status=running&target_uri=%s' % target_uri - tasks = json.loads( - self.request('/tasks?%s' % filter_data).read() - ) - self.assertEquals(3, len(tasks)) - - tasks = json.loads(self.request('/tasks').read()) - tasks_ids = [int(t['id']) for t in tasks] - self.assertEquals(set([id1, id2, id3]) - set(tasks_ids), set([])) - wait_task(self._task_lookup, id2) - foo2 = json.loads( - self.request('/tasks/%s' % id2).read() - ) - keys = ['id', 'status', 'message', 'target_uri'] - self.assertEquals(sorted(keys), sorted(foo2.keys())) - self.assertEquals('failed', foo2['status']) - wait_task(self._task_lookup, id3) - foo3 = json.loads( - self.request('/tasks/%s' % id3).read() - ) - self.assertEquals('in progress', foo3['message']) - self.assertEquals('running', foo3['status']) - - def test_config(self): - resp = self.request('/plugins/kimchi/config').read() - conf = json.loads(resp) - keys = ["display_proxy_port", "version"] - self.assertEquals(keys, sorted(conf.keys())) - - def test_capabilities(self): - resp = self.request('/plugins/kimchi/config/capabilities').read() - conf = json.loads(resp) - - keys = [u'libvirt_stream_protocols', u'qemu_stream', u'qemu_spice', - u'screenshot', u'system_report_tool', u'update_tool', - u'repo_mngt_tool', u'federation', u'kernel_vfio', u'auth', - u'nm_running', u'mem_hotplug_support'] - self.assertEquals(sorted(keys), sorted(conf.keys())) - - def test_peers(self): - resp = self.request('/plugins/kimchi/peers').read() - self.assertEquals([], json.loads(resp)) - - def test_distros(self): - resp = self.request('/plugins/kimchi/config/distros').read() - distros = json.loads(resp) - for distro in distros: - self.assertIn('name', distro) - self.assertIn('os_distro', distro) - self.assertIn('os_version', distro) - self.assertIn('path', distro) - - # Test in X86 - ident = "Fedora 20" - resp = self.request('/plugins/kimchi/config/distros/%s' % - urllib2.quote(ident)).read() - distro = json.loads(resp) - if os.uname()[4] in ['x86_64', 'amd64']: - self.assertEquals(distro['name'], ident) - self.assertEquals(distro['os_distro'], "fedora") - self.assertEquals(distro['os_version'], "20") - self.assertEquals(distro['os_arch'], "x86_64") - self.assertIn('path', distro) - else: - # Distro not found error - self.assertIn('KCHDISTRO0001E', distro.get('reason')) - - # Test in PPC - ident = "Fedora 20 (PPC64)" - resp = self.request('/plugins/kimchi/config/distros/%s' % - urllib2.quote(ident)).read() - distro = json.loads(resp) - if os.uname()[4] == 'ppc64': - self.assertEquals(distro['name'], ident) - self.assertEquals(distro['os_distro'], "fedora") - self.assertEquals(distro['os_version'], "20") - self.assertEquals(distro['os_arch'], "ppc64") - self.assertIn('path', distro) - else: - # Distro not found error - self.assertIn('KCHDISTRO0001E', distro.get('reason')) - - def test_debugreports(self): - resp = request(host, ssl_port, '/plugins/kimchi/debugreports') - self.assertEquals(200, resp.status) - - def _report_delete(self, name): - request(host, ssl_port, '/plugins/kimchi/debugreports/%s' % name, '{}', - 'DELETE') - - def test_create_debugreport(self): - req = json.dumps({'name': 'report1'}) - with RollbackContext() as rollback: - resp = request(host, ssl_port, '/plugins/kimchi/debugreports', req, - 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - # make sure the debugreport doesn't exist until the - # the task is finished - wait_task(self._task_lookup, task['id']) - rollback.prependDefer(self._report_delete, 'report2') - resp = request(host, ssl_port, - '/plugins/kimchi/debugreports/report1') - debugreport = json.loads(resp.read()) - self.assertEquals("report1", debugreport['name']) - self.assertEquals(200, resp.status) - req = json.dumps({'name': 'report2'}) - resp = request(host, ssl_port, - '/plugins/kimchi/debugreports/report1', req, 'PUT') - self.assertEquals(303, resp.status) - - def test_debugreport_download(self): - req = json.dumps({'name': 'report1'}) - with RollbackContext() as rollback: - resp = request(host, ssl_port, '/plugins/kimchi/debugreports', req, - 'POST') - self.assertEquals(202, resp.status) - task = json.loads(resp.read()) - # make sure the debugreport doesn't exist until the - # the task is finished - wait_task(self._task_lookup, task['id'], 20) - rollback.prependDefer(self._report_delete, 'report1') - resp = request(host, ssl_port, - '/plugins/kimchi/debugreports/report1') - debugreport = json.loads(resp.read()) - self.assertEquals("report1", debugreport['name']) - self.assertEquals(200, resp.status) - resp = request(host, ssl_port, - '/plugins/kimchi/debugreports/report1/content') - self.assertEquals(200, resp.status) - resp = request(host, ssl_port, - '/plugins/kimchi/debugreports/report1') - debugre = json.loads(resp.read()) - resp = request(host, ssl_port, debugre['uri']) - self.assertEquals(200, resp.status) - - def test_repositories(self): - def verify_repo(t, res): - for field in ('repo_id', 'enabled', 'baseurl', 'config'): - if field in t.keys(): - self.assertEquals(t[field], res[field]) - - base_uri = '/plugins/kimchi/host/repositories' - resp = self.request(base_uri) - self.assertEquals(200, resp.status) - # Already have one repo in Kimchi's system - self.assertEquals(1, len(json.loads(resp.read()))) - - # Create a repository - repo = {'repo_id': 'fedora-fake', - 'baseurl': 'http://www.fedora.org'} - req = json.dumps(repo) - resp = self.request(base_uri, req, 'POST') - self.assertEquals(201, resp.status) - - # Verify the repository - res = json.loads(self.request('%s/fedora-fake' % base_uri).read()) - verify_repo(repo, res) - - # Update the repository - params = {} - params['baseurl'] = repo['baseurl'] = 'http://www.fedoraproject.org' - resp = self.request('%s/fedora-fake' % base_uri, json.dumps(params), - 'PUT') - - # Verify the repository - res = json.loads(self.request('%s/fedora-fake' % base_uri).read()) - verify_repo(repo, res) - - # Delete the repository - resp = self.request('%s/fedora-fake' % base_uri, '{}', 'DELETE') - self.assertEquals(204, resp.status) - - -class HttpsRestTests(RestTests): - """ - Run all of the same tests as above, but use https instead - """ - def setUp(self): - self.request = partial(request, host, ssl_port) - model.reset() diff --git a/plugins/kimchi/tests/test_rollbackcontext.py b/plugins/kimchi/tests/test_rollbackcontext.py deleted file mode 100644 index 6eac6d0..0000000 --- a/plugins/kimchi/tests/test_rollbackcontext.py +++ /dev/null @@ -1,99 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import unittest - -from wok.rollbackcontext import RollbackContext - - -class FirstError(Exception): - '''A hypothetical exception to be raise in the test firstly.''' - pass - - -class SecondError(Exception): - '''A hypothetical exception to be raise in the test secondly.''' - pass - - -class RollbackContextTests(unittest.TestCase): - - def setUp(self): - self._counter = 0 - - def _inc_counter(self): - self._counter += 1 - - def _raise(self, exception=FirstError): - raise exception() - - def test_rollback(self): - with RollbackContext() as rollback: - rollback.prependDefer(self._inc_counter) - rollback.prependDefer(self._inc_counter) - self.assertEquals(self._counter, 2) - - def test_raise(self): - try: - with RollbackContext() as rollback: - rollback.prependDefer(self._inc_counter) - rollback.prependDefer(self._inc_counter) - raise FirstError() - rollback.prependDefer(self._inc_counter) - except FirstError: - # All undo before the FirstError should be run - self.assertEquals(self._counter, 2) - else: - self.fail('Should have raised FirstError') - - def test_raise_undo(self): - try: - with RollbackContext() as rollback: - rollback.prependDefer(self._inc_counter) - rollback.prependDefer(self._raise) - rollback.prependDefer(self._inc_counter) - except FirstError: - # All undo should be run - self.assertEquals(self._counter, 2) - else: - self.fail('Should have raised FirstError') - - def test_raise_prefer_original(self): - try: - with RollbackContext() as rollback: - rollback.prependDefer(self._raise, SecondError) - raise FirstError() - except FirstError: - pass - except SecondError: - self.fail('Should have preferred FirstError to SecondError') - else: - self.fail('Should have raised FirstError') - - def test_raise_prefer_first_undo(self): - try: - with RollbackContext() as rollback: - rollback.prependDefer(self._raise, SecondError) - rollback.prependDefer(self._raise, FirstError) - except FirstError: - pass - except SecondError: - self.fail('Should have preferred FirstError to SecondError') - else: - self.fail('Should have raised FirstError') diff --git a/plugins/kimchi/tests/test_server.py b/plugins/kimchi/tests/test_server.py deleted file mode 100644 index d5ef565..0000000 --- a/plugins/kimchi/tests/test_server.py +++ /dev/null @@ -1,289 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import base64 -import cherrypy -import json -import os -import tempfile -import threading -import unittest -from functools import partial - -from wok.control.base import Collection, Resource - -from wok.plugins.kimchi import mockmodel - -import utils - - -test_server = None -model = None -host = None -port = None -ssl_port = None -cherrypy_port = None -tmpfile = None - - -def setUpModule(): - global test_server, model, host, port, ssl_port, cherrypy_port, tmpfile - - utils.patch_auth() - tmpfile = tempfile.mktemp() - model = mockmodel.MockModel(tmpfile) - host = '127.0.0.1' - port = utils.get_free_port('http') - ssl_port = utils.get_free_port('https') - cherrypy_port = utils.get_free_port('cherrypy_port') - test_server = utils.run_server(host, port, ssl_port, test_mode=True, - cherrypy_port=cherrypy_port, model=model) - - -def tearDownModule(): - test_server.stop() - os.unlink(tmpfile) - - -class ServerTests(unittest.TestCase): - def setUp(self): - self.request = partial(utils.request, host, ssl_port) - model.reset() - - def assertValidJSON(self, txt): - try: - json.loads(txt) - except ValueError: - self.fail("Invalid JSON: %s" % txt) - - def test_server_start(self): - """ - Test that we can start a server and receive HTTP:200. - """ - resp = self.request('/') - self.assertEquals(200, resp.status) - - def test_multithreaded_connection(self): - def worker(): - for i in xrange(100): - ret = model.vms_get_list() - self.assertEquals('test', ret[0]) - - threads = [] - for i in xrange(100): - t = threading.Thread(target=worker) - t.setDaemon(True) - t.start() - threads.append(t) - for t in threads: - t.join() - - def test_collection(self): - c = Collection(model) - - # The base Collection is always empty - cherrypy.request.method = 'GET' - cherrypy.request.headers['Accept'] = 'application/json' - self.assertEquals('[]', c.index()) - - # POST and DELETE raise HTTP:405 by default - for method in ('POST', 'DELETE'): - cherrypy.request.method = method - try: - c.index() - except cherrypy.HTTPError, e: - self.assertEquals(405, e.code) - else: - self.fail("Expected exception not raised") - - def test_resource(self): - r = Resource(model) - - # Test the base Resource representation - cherrypy.request.method = 'GET' - cherrypy.request.headers['Accept'] = 'application/json' - self.assertEquals('{}', r.index()) - - # POST and DELETE raise HTTP:405 by default - for method in ('POST', 'DELETE'): - cherrypy.request.method = method - try: - r.index() - except cherrypy.HTTPError, e: - self.assertEquals(405, e.code) - else: - self.fail("Expected exception not raised") - - def test_404(self): - """ - A non-existent path should return HTTP:404 - """ - url_list = ['/plugins/kimchi/doesnotexist', '/plugins/kimchi/vms/blah'] - for url in url_list: - resp = self.request(url) - self.assertEquals(404, resp.status) - - # Verify it works for DELETE too - resp = self.request('/plugins/kimchi/templates/blah', '', 'DELETE') - self.assertEquals(404, resp.status) - - def test_accepts(self): - """ - Verify the following expectations regarding the client Accept header: - If omitted, default to html - If 'application/json', serve the rest api - If 'text/html', serve the UI - If both of the above (in any order), serve the rest api - If neither of the above, HTTP:406 - """ - resp = self.request("/", headers={}) - location = resp.getheader('location') - self.assertTrue(location.endswith("login.html")) - resp = self.request("/login.html", headers={}) - self.assertTrue('<!doctype html>' in resp.read().lower()) - - resp = self.request("/", headers={'Accept': 'application/json'}) - self.assertValidJSON(resp.read()) - - resp = self.request("/", headers={'Accept': 'text/html'}) - location = resp.getheader('location') - self.assertTrue(location.endswith("login.html")) - - resp = self.request("/", headers={'Accept': - 'application/json, text/html'}) - self.assertValidJSON(resp.read()) - - resp = self.request("/", headers={'Accept': - 'text/html, application/json'}) - self.assertValidJSON(resp.read()) - - h = {'Accept': 'text/plain'} - resp = self.request('/', None, 'GET', h) - self.assertEquals(406, resp.status) - - def test_auth_unprotected(self): - hdrs = {'AUTHORIZATION': ''} - uris = ['/plugins/kimchi/js/kimchi.min.js', - '/plugins/kimchi/css/theme-default.min.css', - '/plugins/kimchi/images/icon-vm.png', - '/libs/jquery-1.10.0.min.js', - '/login.html', - '/logout'] - - for uri in uris: - resp = self.request(uri, None, 'HEAD', hdrs) - self.assertEquals(200, resp.status) - - def test_auth_protected(self): - hdrs = {'AUTHORIZATION': ''} - uris = ['/plugins/kimchi/vms', - '/plugins/kimchi/vms/doesnotexist', - '/tasks'] - - for uri in uris: - resp = self.request(uri, None, 'GET', hdrs) - self.assertEquals(401, resp.status) - - def test_auth_bad_creds(self): - # Test HTTPBA - hdrs = {'AUTHORIZATION': "Basic " + base64.b64encode("nouser:badpass")} - resp = self.request('/plugins/kimchi/vms', None, 'GET', hdrs) - self.assertEquals(401, resp.status) - - # Test REST API - hdrs = {'AUTHORIZATION': ''} - req = json.dumps({'username': 'nouser', 'password': 'badpass'}) - resp = self.request('/login', req, 'POST', hdrs) - self.assertEquals(401, resp.status) - - def test_auth_browser_no_httpba(self): - # Kimchi detects REST requests from the browser by looking for a - # specific header - hdrs = {"X-Requested-With": "XMLHttpRequest"} - - # Try our request (Note that request() will add a valid HTTPBA header) - resp = self.request('/plugins/kimchi/vms', None, 'GET', hdrs) - self.assertEquals(401, resp.status) - self.assertEquals(None, resp.getheader('WWW-Authenticate')) - - def test_auth_session(self): - hdrs = {'AUTHORIZATION': '', - 'Content-Type': 'application/json', - 'Accept': 'application/json'} - - # Test we are logged out - resp = self.request('/tasks', None, 'GET', hdrs) - self.assertEquals(401, resp.status) - - # Execute a login call - user, pw = mockmodel.fake_user.items()[0] - req = json.dumps({'username': user, 'password': pw}) - resp = self.request('/login', req, 'POST', hdrs) - self.assertEquals(200, resp.status) - - user_info = json.loads(resp.read()) - self.assertEquals(sorted(user_info.keys()), - ['groups', 'roles', 'username']) - roles = user_info['roles'] - for tab, role in roles.iteritems(): - self.assertEquals(role, u'admin') - - cookie = resp.getheader('set-cookie') - hdrs['Cookie'] = cookie - - # Test we are logged in with the cookie - resp = self.request('/tasks', None, 'GET', hdrs) - self.assertEquals(200, resp.status) - - # Execute a logout call - resp = self.request('/logout', '{}', 'POST', hdrs) - self.assertEquals(200, resp.status) - del hdrs['Cookie'] - - # Test we are logged out - resp = self.request('/tasks', None, 'GET', hdrs) - self.assertEquals(401, resp.status) - - def test_get_param(self): - # Create a mock ISO file - mockiso = '/tmp/mock.iso' - open('/tmp/mock.iso', 'w').close() - - # Create 2 different templates - req = json.dumps({'name': 'test-tmpl1', 'cdrom': mockiso}) - self.request('/plugins/kimchi/templates', req, 'POST') - - req = json.dumps({'name': 'test-tmpl2', 'cdrom': mockiso}) - self.request('/plugins/kimchi/templates', req, 'POST') - - # Remove mock iso - os.unlink(mockiso) - - # Get the templates - resp = self.request('/plugins/kimchi/templates') - self.assertEquals(200, resp.status) - res = json.loads(resp.read()) - self.assertEquals(2, len(res)) - - # Get a specific template - resp = self.request('/plugins/kimchi/templates?name=test-tmpl1') - self.assertEquals(200, resp.status) - res = json.loads(resp.read()) - self.assertEquals(1, len(res)) - self.assertEquals('test-tmpl1', res[0]['name']) diff --git a/plugins/kimchi/tests/test_storagepoolxml.py b/plugins/kimchi/tests/test_storagepoolxml.py deleted file mode 100644 index 7e45cca..0000000 --- a/plugins/kimchi/tests/test_storagepoolxml.py +++ /dev/null @@ -1,171 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import lxml.etree as ET -import unittest - -from wok.plugins.kimchi.model.libvirtstoragepool import StoragePoolDef - - -class StoragepoolXMLTests(unittest.TestCase): - def test_get_storagepool_xml(self): - poolDefs = [ - {'def': - {'type': 'dir', - 'name': 'unitTestDirPool', - 'path': '/var/temp/images'}, - 'xml': - """ - <pool type='dir'> - <name>unitTestDirPool</name> - <target> - <path>/var/temp/images</path> - </target> - </pool> - """}, - {'def': - {'type': 'netfs', - 'name': 'unitTestNFSPool', - 'source': {'host': '127.0.0.1', - 'path': '/var/export'}}, - 'xml': - """ - <pool type='netfs'> - <name>unitTestNFSPool</name> - <source> - <host name='127.0.0.1'/> - <dir path='/var/export'/> - </source> - <target> - <path>/var/lib/kimchi/nfs_mount/unitTestNFSPool</path> - </target> - </pool> - """}, - {'def': - {'type': 'logical', - 'name': 'unitTestLogicalPool', - 'source': {'devices': ['/dev/hda', '/dev/hdb']}}, - 'xml': - """ - <pool type='logical'> - <name>unitTestLogicalPool</name> - <source> - <device path="/dev/hda" /> - <device path="/dev/hdb" /> - </source> - <target> - <path>/dev/unitTestLogicalPool</path> - </target> - </pool> - """}, - {'def': - {'type': 'iscsi', - 'name': 'unitTestISCSIPool', - 'source': { - 'host': '127.0.0.1', - 'target': 'iqn.2003-01.org.linux-iscsi.localhost'}}, - 'xml': - """ - <pool type='iscsi'> - <name>unitTestISCSIPool</name> - <source> - <host name='127.0.0.1' /> - <device path='iqn.2003-01.org.linux-iscsi.localhost'/> - </source> - <target> - <path>/dev/disk/by-id</path> - </target> - </pool> - """}, - {'def': - {'type': 'iscsi', - 'name': 'unitTestISCSIPoolPort', - 'source': { - 'host': '127.0.0.1', - 'port': 3266, - 'target': 'iqn.2003-01.org.linux-iscsi.localhost'}}, - 'xml': - """ - <pool type='iscsi'> - <name>unitTestISCSIPoolPort</name> - <source> - <host name='127.0.0.1' port='3266' /> - <device path='iqn.2003-01.org.linux-iscsi.localhost'/> - </source> - <target> - <path>/dev/disk/by-id</path> - </target> - </pool> - """}, - {'def': - {'type': 'iscsi', - 'name': 'unitTestISCSIPoolAuth', - 'source': { - 'host': '127.0.0.1', - 'target': 'iqn.2003-01.org.linux-iscsi.localhost', - 'auth': {'username': 'testUser', - 'password': 'ActuallyNotUsedInPoolXML'}}}, - 'xml': - """ - <pool type='iscsi'> - <name>unitTestISCSIPoolAuth</name> - <source> - <host name='127.0.0.1' /> - <device path='iqn.2003-01.org.linux-iscsi.localhost'/> - <auth type='chap' username='testUser'> - <secret type='iscsi' usage='unitTestISCSIPoolAuth'/> - </auth> - </source> - <target> - <path>/dev/disk/by-id</path> - </target> - </pool> - """}, - {'def': - {'type': 'scsi', - 'name': 'unitTestSCSIFCPool', - 'path': '/dev/disk/by-path', - 'source': { - 'name': 'scsi_host3', - 'adapter': { - 'type': 'fc_host', - 'wwpn': '0123456789abcdef', - 'wwnn': 'abcdef0123456789'}}}, - 'xml': - """ - <pool type='scsi'> - <name>unitTestSCSIFCPool</name> - <source> - <adapter type='fc_host' name='scsi_host3' - wwnn='abcdef0123456789' wwpn='0123456789abcdef'></adapter> - </source> - <target> - <path>/dev/disk/by-path</path> - </target> - </pool> - """}] - - for poolDef in poolDefs: - defObj = StoragePoolDef.create(poolDef['def']) - xmlStr = defObj.xml - - parser = ET.XMLParser(remove_blank_text=True) - t1 = ET.fromstring(xmlStr, parser) - t2 = ET.fromstring(poolDef['xml'], parser) - self.assertEquals(ET.tostring(t1), ET.tostring(t2)) diff --git a/plugins/kimchi/tests/test_template.py b/plugins/kimchi/tests/test_template.py deleted file mode 100644 index c7de182..0000000 --- a/plugins/kimchi/tests/test_template.py +++ /dev/null @@ -1,387 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -import unittest -from functools import partial - -from wok.plugins.kimchi.config import READONLY_POOL_TYPE -from wok.plugins.kimchi.mockmodel import MockModel - -from utils import get_free_port, patch_auth, request, run_server - - -model = None -test_server = None -host = None -port = None -ssl_port = None -cherrypy_port = None - - -def setUpModule(): - global test_server, model, host, port, ssl_port, cherrypy_port - - patch_auth() - model = MockModel('/tmp/obj-store-test') - host = '127.0.0.1' - port = get_free_port('http') - ssl_port = get_free_port('https') - cherrypy_port = get_free_port('cherrypy_port') - test_server = run_server(host, port, ssl_port, test_mode=True, - cherrypy_port=cherrypy_port, model=model) - - -def tearDownModule(): - test_server.stop() - os.unlink('/tmp/obj-store-test') - - -class TemplateTests(unittest.TestCase): - def setUp(self): - self.request = partial(request, host, ssl_port) - model.reset() - - def test_tmpl_lifecycle(self): - resp = self.request('/plugins/kimchi/templates') - self.assertEquals(200, resp.status) - self.assertEquals(0, len(json.loads(resp.read()))) - - # Create a template without cdrom and disk specified fails with 400 - t = {'name': 'test', 'os_distro': 'ImagineOS', - 'os_version': '1.0', 'memory': 1024, 'cpus': 1, - 'storagepool': '/plugins/kimchi/storagepools/alt'} - req = json.dumps(t) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(400, resp.status) - - # Create a template - t = {'name': 'test', 'cdrom': '/tmp/mock.iso'} - req = json.dumps(t) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - # Verify the template - keys = ['name', 'icon', 'invalid', 'os_distro', 'os_version', 'cpus', - 'memory', 'cdrom', 'disks', 'storagepool', 'networks', - 'folder', 'graphics', 'cpu_info'] - tmpl = json.loads( - self.request('/plugins/kimchi/templates/test').read() - ) - self.assertEquals(sorted(tmpl.keys()), sorted(keys)) - - # Verify if default disk format was configured - self.assertEquals(tmpl['disks'][0]['format'], 'qcow2') - - # Clone a template - resp = self.request('/plugins/kimchi/templates/test/clone', '{}', - 'POST') - self.assertEquals(303, resp.status) - - # Verify the cloned template - tmpl_cloned = json.loads( - self.request('/plugins/kimchi/templates/test-clone1').read() - ) - del tmpl['name'] - del tmpl_cloned['name'] - self.assertEquals(tmpl, tmpl_cloned) - - # Delete the cloned template - resp = self.request('/plugins/kimchi/templates/test-clone1', '{}', - 'DELETE') - self.assertEquals(204, resp.status) - - # Create a template with same name fails with 400 - req = json.dumps({'name': 'test', 'cdrom': '/tmp/mock.iso'}) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(400, resp.status) - - # Create an image based template - open('/tmp/mock.img', 'w').close() - t = {'name': 'test_img_template', - 'disks': [{'base': '/tmp/mock.img'}]} - req = json.dumps(t) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - os.remove('/tmp/mock.img') - - # Test disk format - t = {'name': 'test-format', 'cdrom': '/tmp/mock.iso', - 'disks': [{'index': 0, 'size': 10, 'format': 'vmdk'}]} - req = json.dumps(t) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - tmpl = json.loads( - self.request('/plugins/kimchi/templates/test-format').read() - ) - self.assertEquals(tmpl['disks'][0]['format'], 'vmdk') - - def test_customized_tmpl(self): - # Create a template - t = {'name': 'test', 'cdrom': '/tmp/mock.iso'} - req = json.dumps(t) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - tmpl = json.loads( - self.request('/plugins/kimchi/templates/test').read() - ) - - # Update name - new_name = u'k������h��Tmpl' - new_tmpl_uri = '/plugins/kimchi/templates/%s' \ - % new_name.encode('utf-8') - req = json.dumps({'name': new_name}) - resp = self.request('/plugins/kimchi/templates/test', req, 'PUT') - self.assertEquals(303, resp.status) - resp = self.request(new_tmpl_uri) - update_tmpl = json.loads(resp.read()) - self.assertEquals(new_name, update_tmpl['name']) - del tmpl['name'] - del update_tmpl['name'] - self.assertEquals(tmpl, update_tmpl) - - # Update icon - req = json.dumps({'icon': 'kimchi/images/icon-fedora.png'}) - resp = self.request(new_tmpl_uri, req, 'PUT') - self.assertEquals(200, resp.status) - update_tmpl = json.loads(resp.read()) - self.assertEquals('kimchi/images/icon-fedora.png', update_tmpl['icon']) - - # Update os_distro and os_version - req = json.dumps({'os_distro': 'fedora', 'os_version': '21'}) - resp = self.request(new_tmpl_uri, req, 'PUT') - self.assertEquals(200, resp.status) - update_tmpl = json.loads(resp.read()) - self.assertEquals('fedora', update_tmpl['os_distro']) - self.assertEquals('21', update_tmpl['os_version']) - - # Update cpus - req = json.dumps({'cpus': 2}) - resp = self.request(new_tmpl_uri, req, 'PUT') - self.assertEquals(200, resp.status) - update_tmpl = json.loads(resp.read()) - self.assertEquals(2, update_tmpl['cpus']) - - # Update memory - req = json.dumps({'memory': 2048}) - resp = self.request(new_tmpl_uri, req, 'PUT') - self.assertEquals(200, resp.status) - update_tmpl = json.loads(resp.read()) - self.assertEquals(2048, update_tmpl['memory']) - - # Update cpu_info - resp = self.request(new_tmpl_uri) - cpu_info = json.loads(resp.read())['cpu_info'] - self.assertEquals(cpu_info, {}) - self.assertEquals(cpu_info.get('topology'), None) - - cpu_info_data = {'cpu_info': {'topology': {'sockets': 1, - 'cores': 2, - 'threads': 1}}} - resp = self.request(new_tmpl_uri, json.dumps(cpu_info_data), 'PUT') - self.assertEquals(200, resp.status) - update_tmpl = json.loads(resp.read()) - self.assertEquals(update_tmpl['cpu_info'], cpu_info_data['cpu_info']) - - # Update cdrom - cdrom_data = {'cdrom': '/tmp/mock2.iso'} - resp = self.request(new_tmpl_uri, json.dumps(cdrom_data), 'PUT') - self.assertEquals(200, resp.status) - update_tmpl = json.loads(resp.read()) - self.assertEquals(update_tmpl['cdrom'], cdrom_data['cdrom']) - - # Update disks - disk_data = {'disks': [{'index': 0, 'size': 10}, - {'index': 1, 'size': 20}]} - resp = self.request(new_tmpl_uri, json.dumps(disk_data), 'PUT') - self.assertEquals(200, resp.status) - resp = self.request(new_tmpl_uri) - self.assertEquals(200, resp.status) - updated_tmpl = json.loads(resp.read()) - self.assertEquals(updated_tmpl['disks'], disk_data['disks']) - - # For all supported types, edit the template and check if - # the change was made. - disk_types = ['bochs', 'cloop', 'cow', 'dmg', 'qcow', 'qcow2', - 'qed', 'raw', 'vmdk', 'vpc'] - for disk_type in disk_types: - disk_data = {'disks': [{'index': 0, 'format': disk_type, - 'size': 10}]} - resp = self.request(new_tmpl_uri, json.dumps(disk_data), 'PUT') - self.assertEquals(200, resp.status) - - resp = self.request(new_tmpl_uri) - self.assertEquals(200, resp.status) - updated_tmpl = json.loads(resp.read()) - self.assertEquals(updated_tmpl['disks'], disk_data['disks']) - - # Update folder - folder_data = {'folder': ['mock', 'isos']} - resp = self.request(new_tmpl_uri, json.dumps(folder_data), 'PUT') - self.assertEquals(200, resp.status) - update_tmpl = json.loads(resp.read()) - self.assertEquals(update_tmpl['folder'], folder_data['folder']) - - # Update graphics - req = json.dumps({'graphics': {'type': 'spice'}}) - resp = self.request(new_tmpl_uri, req, 'PUT') - self.assertEquals(200, resp.status) - update_tmpl = json.loads(resp.read()) - self.assertEquals('spice', update_tmpl['graphics']['type']) - - req = json.dumps({'graphics': {'type': 'vnc', 'listen': 'fe00::0'}}) - resp = self.request(new_tmpl_uri, req, 'PUT') - self.assertEquals(200, resp.status) - update_tmpl = json.loads(resp.read()) - self.assertEquals('vnc', update_tmpl['graphics']['type']) - self.assertEquals('fe00::0', update_tmpl['graphics']['listen']) - - def test_customized_network(self): - # Create a template - t = {'name': 'test', 'cdrom': '/tmp/mock.iso'} - req = json.dumps(t) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - # Create networks to be used for testing - networks = [{'name': u'k������h��-��et', 'connection': 'isolated'}, - {'name': u'nat-network', 'connection': 'nat'}, - {'name': u'subnet-network', 'connection': 'nat', - 'subnet': '127.0.100.0/24'}] - - # Verify the current system has at least one interface to create a - # bridged network - interfaces = json.loads( - self.request('/plugins/kimchi/interfaces?type=nic').read() - ) - if len(interfaces) > 0: - iface = interfaces[0]['name'] - networks.append({'name': u'bridge-network', 'connection': 'bridge', - 'interface': iface}) - networks.append({'name': u'bridge-network', 'connection': 'bridge', - 'interface': iface, 'vlan_id': 987}) - - tmpl_nets = [] - for net in networks: - self.request('/plugins/kimchi/networks', json.dumps(net), 'POST') - tmpl_nets.append(net['name']) - req = json.dumps({'networks': tmpl_nets}) - resp = self.request('/plugins/kimchi/templates/test', req, 'PUT') - self.assertEquals(200, resp.status) - - def test_customized_storagepool(self): - # Create a template - t = {'name': 'test', 'cdrom': '/tmp/mock.iso'} - req = json.dumps(t) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - # MockModel always returns 2 partitions (vdx, vdz) - partitions = json.loads( - self.request('/plugins/kimchi/host/partitions').read() - ) - devs = [dev['path'] for dev in partitions] - - # MockModel always returns 3 FC devices - fc_devs = json.loads( - self.request('/plugins/kimchi/host/devices?_cap=fc_host').read() - ) - fc_devs = [dev['name'] for dev in fc_devs] - - poolDefs = [ - {'type': 'dir', 'name': u'k������h��UnitTestDirPool', - 'path': '/tmp/kimchi-images'}, - {'type': 'netfs', 'name': u'k������h��UnitTestNSFPool', - 'source': {'host': 'localhost', - 'path': '/var/lib/kimchi/nfs-pool'}}, - {'type': 'scsi', 'name': u'k������h��UnitTestSCSIFCPool', - 'source': {'adapter_name': fc_devs[0]}}, - {'type': 'iscsi', 'name': u'k������h��UnitTestISCSIPool', - 'source': {'host': '127.0.0.1', - 'target': 'iqn.2015-01.localhost.kimchiUnitTest'}}, - {'type': 'logical', 'name': u'k������h��UnitTestLogicalPool', - 'source': {'devices': [devs[0]]}}] - - for pool in poolDefs: - self.request('/plugins/kimchi/storagepools', json.dumps(pool), - 'POST') - pool_uri = '/plugins/kimchi/storagepools/%s' \ - % pool['name'].encode('utf-8') - self.request(pool_uri + '/activate', '{}', 'POST') - - req = None - if pool['type'] in READONLY_POOL_TYPE: - resp = self.request(pool_uri + '/storagevolumes') - vols = json.loads(resp.read()) - if len(vols) > 0: - vol = vols[0]['name'] - req = json.dumps({'storagepool': pool_uri, - 'disks': [{'volume': vol}]}) - else: - req = json.dumps({'storagepool': pool_uri}) - - if req is not None: - resp = self.request('/plugins/kimchi/templates/test', req, - 'PUT') - self.assertEquals(200, resp.status) - - def test_tmpl_integrity(self): - # Create a network and a pool for testing template integrity - net = {'name': u'nat-network', 'connection': 'nat'} - self.request('/plugins/kimchi/networks', json.dumps(net), 'POST') - - pool = {'type': 'dir', 'name': 'dir-pool', 'path': '/tmp/dir-pool'} - self.request('/plugins/kimchi/storagepools', json.dumps(pool), 'POST') - pool_uri = '/plugins/kimchi/storagepools/%s' \ - % pool['name'].encode('utf-8') - self.request(pool_uri + '/activate', '{}', 'POST') - - # Create a template using the custom network and pool - t = {'name': 'test', 'cdrom': '/tmp/mock.iso', - 'networks': ['nat-network'], - 'storagepool': '/plugins/kimchi/storagepools/dir-pool'} - req = json.dumps(t) - resp = self.request('/plugins/kimchi/templates', req, 'POST') - self.assertEquals(201, resp.status) - - # Try to delete network - # It should fail as it is associated to a template - resp = self.request('/plugins/kimchi/networks/nat-network', '{}', - 'DELETE') - self.assertIn("KCHNET0017E", json.loads(resp.read())["reason"]) - - # Update template to release network and then delete it - params = {'networks': []} - req = json.dumps(params) - self.request('/plugins/kimchi/templates/test', req, 'PUT') - resp = self.request('/plugins/kimchi/networks/nat-network', '{}', - 'DELETE') - self.assertEquals(204, resp.status) - - # Try to delete the storagepool - # It should fail as it is associated to a template - resp = self.request('/plugins/kimchi/storagepools/dir-pool', '{}', - 'DELETE') - self.assertEquals(400, resp.status) - - # Verify the template - res = json.loads(self.request('/plugins/kimchi/templates/test').read()) - self.assertEquals(res['invalid']['cdrom'], ['/tmp/mock.iso']) diff --git a/plugins/kimchi/tests/test_utils.py b/plugins/kimchi/tests/test_utils.py deleted file mode 100644 index bcb14e2..0000000 --- a/plugins/kimchi/tests/test_utils.py +++ /dev/null @@ -1,69 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import unittest - -from wok.exception import InvalidParameter -from wok.utils import convert_data_size - - -class UtilsTests(unittest.TestCase): - def test_convert_data_size(self): - failure_data = [{'val': None, 'from': 'MiB'}, - {'val': self, 'from': 'MiB'}, - {'val': 1, 'from': None}, - {'val': 1, 'from': ''}, - {'val': 1, 'from': 'foo'}, - {'val': 1, 'from': 'kib'}, - {'val': 1, 'from': 'MiB', 'to': None}, - {'val': 1, 'from': 'MiB', 'to': ''}, - {'val': 1, 'from': 'MiB', 'to': 'foo'}, - {'val': 1, 'from': 'MiB', 'to': 'kib'}] - - for d in failure_data: - if 'to' in d: - self.assertRaises(InvalidParameter, convert_data_size, - d['val'], d['from'], d['to']) - else: - self.assertRaises(InvalidParameter, convert_data_size, - d['val'], d['from']) - - success_data = [{'got': convert_data_size(5, 'MiB', 'MiB'), - 'want': 5}, - {'got': convert_data_size(5, 'MiB', 'KiB'), - 'want': 5120}, - {'got': convert_data_size(5, 'MiB', 'M'), - 'want': 5.24288}, - {'got': convert_data_size(5, 'MiB', 'GiB'), - 'want': 0.0048828125}, - {'got': convert_data_size(5, 'MiB', 'Tb'), - 'want': 4.194304e-05}, - {'got': convert_data_size(5, 'KiB', 'MiB'), - 'want': 0.0048828125}, - {'got': convert_data_size(5, 'M', 'MiB'), - 'want': 4.76837158203125}, - {'got': convert_data_size(5, 'GiB', 'MiB'), - 'want': 5120}, - {'got': convert_data_size(5, 'Tb', 'MiB'), - 'want': 596046.4477539062}, - {'got': convert_data_size(5, 'MiB'), - 'want': convert_data_size(5, 'MiB', 'B')}] - - for d in success_data: - self.assertEquals(d['got'], d['want']) diff --git a/plugins/kimchi/tests/test_vmtemplate.py b/plugins/kimchi/tests/test_vmtemplate.py deleted file mode 100644 index 0bca215..0000000 --- a/plugins/kimchi/tests/test_vmtemplate.py +++ /dev/null @@ -1,116 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os -import unittest -import uuid - -from wok.xmlutils.utils import xpath_get_text - -from wok.plugins.kimchi.osinfo import get_template_default -from wok.plugins.kimchi.vmtemplate import VMTemplate - - -class VMTemplateTests(unittest.TestCase): - def setUp(self): - self.iso = '/tmp/mock.iso' - open(self.iso, 'w').close() - - def tearDown(self): - os.unlink(self.iso) - - def test_minimal_construct(self): - disk_bus = get_template_default('old', 'disk_bus') - memory = get_template_default('old', 'memory') - nic_model = get_template_default('old', 'nic_model') - fields = (('name', 'test'), ('os_distro', 'unknown'), - ('os_version', 'unknown'), ('cpus', 1), - ('memory', memory), ('networks', ['default']), - ('disk_bus', disk_bus), ('nic_model', nic_model), - ('graphics', {'type': 'vnc', 'listen': '127.0.0.1'}), - ('cdrom', self.iso)) - - args = {'name': 'test', 'cdrom': self.iso} - t = VMTemplate(args) - for name, val in fields: - self.assertEquals(val, t.info.get(name)) - - def test_construct_overrides(self): - graphics = {'type': 'spice', 'listen': '127.0.0.1'} - args = {'name': 'test', 'disks': [{'size': 10}, {'size': 20}], - 'graphics': graphics, "cdrom": self.iso} - t = VMTemplate(args) - self.assertEquals(2, len(t.info['disks'])) - self.assertEquals(graphics, t.info['graphics']) - - def test_specified_graphics(self): - # Test specified listen - graphics = {'type': 'vnc', 'listen': '127.0.0.1'} - args = {'name': 'test', 'disks': [{'size': 10}, {'size': 20}], - 'graphics': graphics, 'cdrom': self.iso} - t = VMTemplate(args) - self.assertEquals(graphics, t.info['graphics']) - - # Test specified type - graphics = {'type': 'spice', 'listen': '127.0.0.1'} - args['graphics'] = graphics - t = VMTemplate(args) - self.assertEquals(graphics, t.info['graphics']) - - # If no listen specified, test the default listen - graphics = {'type': 'vnc'} - args['graphics'] = graphics - t = VMTemplate(args) - self.assertEquals(graphics['type'], t.info['graphics']['type']) - self.assertEquals('127.0.0.1', t.info['graphics']['listen']) - - def test_to_xml(self): - graphics = {'type': 'spice', 'listen': '127.0.0.1'} - vm_uuid = str(uuid.uuid4()).replace('-', '') - if os.uname()[4] in ['ppc', 'ppc64', 'ppc64le']: - maxmem = 3328 - else: - maxmem = 3072 - t = VMTemplate({'name': 'test-template', 'cdrom': self.iso, - 'max_memory': maxmem << 10}) - xml = t.to_vm_xml('test-vm', vm_uuid, graphics=graphics) - self.assertEquals(vm_uuid, xpath_get_text(xml, "/domain/uuid")[0]) - self.assertEquals('test-vm', xpath_get_text(xml, "/domain/name")[0]) - expr = "/domain/devices/graphics/@type" - self.assertEquals(graphics['type'], xpath_get_text(xml, expr)[0]) - expr = "/domain/devices/graphics/@listen" - self.assertEquals(graphics['listen'], xpath_get_text(xml, expr)[0]) - expr = "/domain/maxMemory/@slots" - self.assertEquals('2', xpath_get_text(xml, expr)[0]) - - def test_arg_merging(self): - """ - Make sure that default parameters from osinfo do not override user- - provided parameters. - """ - graphics = {'type': 'vnc', 'listen': '127.0.0.1'} - args = {'name': 'test', 'os_distro': 'opensuse', 'os_version': '12.3', - 'cpus': 2, 'memory': 2048, 'networks': ['foo'], - 'cdrom': self.iso, 'graphics': graphics} - t = VMTemplate(args) - self.assertEquals(2, t.info.get('cpus')) - self.assertEquals(2048, t.info.get('memory')) - self.assertEquals(['foo'], t.info.get('networks')) - self.assertEquals(self.iso, t.info.get('cdrom')) - self.assertEquals(graphics, t.info.get('graphics')) diff --git a/plugins/kimchi/tests/test_yumparser.py b/plugins/kimchi/tests/test_yumparser.py deleted file mode 100644 index be5e95c..0000000 --- a/plugins/kimchi/tests/test_yumparser.py +++ /dev/null @@ -1,162 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os -import tempfile -import unittest - -from wok.rollbackcontext import RollbackContext - -from wok.plugins.kimchi.model import model -from wok.plugins.kimchi.yumparser import delete_repo_from_file, get_repo_files -from wok.plugins.kimchi.yumparser import get_yum_packages_list_update -from wok.plugins.kimchi.yumparser import get_yum_repositories -from wok.plugins.kimchi.yumparser import write_repo_to_file, YumRepoObject - - -TEMP_REPO_FILE = '' - - -def _is_yum_distro(): - inst = model.Model('test:///default') - repo_type = inst.capabilities_lookup()['repo_mngt_tool'] - return repo_type == 'yum' - - -def _create_fake_repos(repo_file_name): - repo1 = YumRepoObject('fake-repo-1', repo_file_name) - repo2 = YumRepoObject('fake-repo-2', repo_file_name) - repo3 = YumRepoObject('fake-repo-3', repo_file_name) - repo4 = YumRepoObject('fake-repo-4', repo_file_name) - repos = [repo1, repo2, repo3, repo4] - return repos - - -def _create_empty_repo_file(): - data = """ -# -# This is a repository file with no repositories at all -# No repositories must be added after reading this file. -# - """ - _, tmp_file_name = tempfile.mkstemp(suffix='.repo', - dir='/etc/yum.repos.d') - with open(tmp_file_name, 'w') as f: - f.writelines(data) - - return tmp_file_name - - -def _create_fake_repos_file(): - _, tmp_file_name = tempfile.mkstemp(suffix='.repo', - dir='/etc/yum.repos.d') - - fake_repos = _create_fake_repos(tmp_file_name) - file_data = '' - for repo in fake_repos: - file_data += str(repo) + '\n' - - with open(tmp_file_name, 'w') as f: - f.writelines(file_data) - - return tmp_file_name - - -def _generate_yumcheckupdate_output(): - output = """ -Repository 'REPOSITORY1' is missing name in configuration, using id -Repository 'REPOSITORY1-OPTIONAL' is missing name in configuration, using id - -PACKAGE1.noarch 20150611.-gg-FAKE1 REPOSITORY1 -PACKAGE2.x86_64 20150611.-no-FAKE2 REPOSITORY2 -PACKAGE3.dot.dot.i386 20150611.-re-FAKE3 REPOSITORY3 - -Obsoleting Packages -OBSOLETE4.dot.dot.i386 20150611.FAKE4 REPOSITORY4 -OBSOLETE5.dot.dot.fakearch 20150611.FAKE5 REPOSITORY5 - """ - return output - - -@unittest.skipIf(not _is_yum_distro(), 'Skipping: YUM exclusive test') -def setUpModule(): - global TEMP_REPO_FILE - TEMP_REPO_FILE = _create_fake_repos_file() - - -@unittest.skipIf(not _is_yum_distro(), 'Skipping: YUM exclusive test') -def tearDownModule(): - os.remove(TEMP_REPO_FILE) - - -@unittest.skipIf(not _is_yum_distro(), 'Skipping: YUM exclusive test') -class YumParserTests(unittest.TestCase): - - def test_get_yum_repositories(self): - repo_files = get_repo_files() - repo_objects = get_yum_repositories() - self.assertGreaterEqual(len(repo_objects), len(repo_files)) - - def test_empty_repo_file(self): - with RollbackContext() as rollback: - repos = get_yum_repositories() - tmp_file_name = _create_empty_repo_file() - rollback.prependDefer(os.remove, tmp_file_name) - repos_after = get_yum_repositories() - self.assertEqual(len(repos_after), len(repos)) - - def test_update_repo_attributes(self): - repos = get_yum_repositories() - fake_repo_2 = repos['fake-repo-2'] - fake_repo_2.disable() - fake_repo_2.name = 'This is a fake repo' - fake_repo_2.baseurl = 'http://a.fake.repo.url' - fake_repo_2.gpgkey = 'file://a/fake/gpg/key.fake' - fake_repo_2.gpgcheck = False - fake_repo_2.metalink = 'this is not a true metalink' - fake_repo_2.mirrorlist = 'fake mirrorlist' - write_repo_to_file(fake_repo_2) - - repos = get_yum_repositories() - fake_repo_2 = repos['fake-repo-2'] - self.assertEqual(False, fake_repo_2.enabled) - self.assertEqual(False, fake_repo_2.gpgcheck) - self.assertEqual('This is a fake repo', fake_repo_2.name) - self.assertEqual('http://a.fake.repo.url', fake_repo_2.baseurl) - self.assertEqual('file://a/fake/gpg/key.fake', fake_repo_2.gpgkey) - self.assertEqual('this is not a true metalink', fake_repo_2.metalink) - self.assertEqual('fake mirrorlist', fake_repo_2.mirrorlist) - - def test_delete_repo_from_file(self): - repos = get_yum_repositories() - fake_repo_3 = repos['fake-repo-3'] - delete_repo_from_file(fake_repo_3) - - repos = get_yum_repositories() - repos_id = repos.keys() - self.assertNotIn('fake-repo-3', repos_id) - - def test_yum_checkupdate_parsing(self): - output = _generate_yumcheckupdate_output() - packages = get_yum_packages_list_update(output) - self.assertEqual(len(packages), 3) - self.assertEqual(packages[0].ui_from_repo, 'REPOSITORY1') - self.assertEqual(packages[1].version, '20150611.-no-FAKE2') - self.assertEqual(packages[2].name, 'PACKAGE3.dot.dot') - self.assertEqual(packages[2].arch, 'i386') diff --git a/plugins/kimchi/tests/utils.py b/plugins/kimchi/tests/utils.py deleted file mode 100644 index ecaa87f..0000000 --- a/plugins/kimchi/tests/utils.py +++ /dev/null @@ -1,260 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -import base64 -import cherrypy -import grp -import httplib -import inspect -import json -import os -import socket -import ssl -import sys -import threading -import time -import unittest -from contextlib import closing -from lxml import etree - -import wok.server -from wok.config import config, PluginPaths -from wok.auth import User, USER_NAME, USER_GROUPS, USER_ROLES, tabs -from wok.exception import NotFoundError, OperationFailed -from wok.utils import wok_log - -from wok.plugins.kimchi import mockmodel - - -_ports = {} - -# provide missing unittest decorators and API for python 2.6; these decorators -# do not actually work, just avoid the syntax failure -if sys.version_info[:2] == (2, 6): - def skipUnless(condition, reason): - if not condition: - sys.stderr.write('[expected failure] ') - raise Exception(reason) - return lambda obj: obj - - unittest.skipUnless = skipUnless - unittest.expectedFailure = lambda obj: obj - - def assertGreater(self, a, b, msg=None): - if not a > b: - self.fail('%s not greater than %s' % (repr(a), repr(b))) - - def assertGreaterEqual(self, a, b, msg=None): - if not a >= b: - self.fail('%s not greater than or equal to %s' - % (repr(a), repr(b))) - - def assertIsInstance(self, obj, cls, msg=None): - if not isinstance(obj, cls): - self.fail('%s is not an instance of %r' % (repr(obj), cls)) - - def assertIn(self, a, b, msg=None): - if a not in b: - self.fail("%s is not in %b" % (repr(a), repr(b))) - - def assertNotIn(self, a, b, msg=None): - if a in b: - self.fail("%s is in %b" % (repr(a), repr(b))) - - unittest.TestCase.assertGreaterEqual = assertGreaterEqual - unittest.TestCase.assertGreater = assertGreater - unittest.TestCase.assertIsInstance = assertIsInstance - unittest.TestCase.assertIn = assertIn - unittest.TestCase.assertNotIn = assertNotIn - - -def get_free_port(name='http'): - global _ports - if _ports.get(name) is not None: - return _ports[name] - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - with closing(sock): - try: - sock.bind(("0.0.0.0", 0)) - except: - raise Exception("Could not find a free port") - _ports[name] = sock.getsockname()[1] - return _ports[name] - - -def run_server(host, port, ssl_port, test_mode, cherrypy_port=None, - model=None, environment='development'): - - if cherrypy_port is None: - cherrypy_port = get_free_port('cherrypy_port') - - if ssl_port is None: - ssl_port = get_free_port('https') - - args = type('_', (object,), - {'host': host, 'port': port, 'ssl_port': ssl_port, - 'cherrypy_port': cherrypy_port, 'max_body_size': '4*1024', - 'ssl_cert': '', 'ssl_key': '', - 'test': test_mode, 'access_log': '/dev/null', - 'error_log': '/dev/null', 'environment': environment, - 'log_level': 'debug'})() - if model is not None: - setattr(args, 'model', model) - - s = wok.server.Server(args) - t = threading.Thread(target=s.start) - t.setDaemon(True) - t.start() - cherrypy.engine.wait(cherrypy.engine.states.STARTED) - return s - - -def silence_server(): - """ - Silence server status messages on stdout - """ - cherrypy.config.update({"environment": "embedded"}) - - -def running_as_root(): - return os.geteuid() == 0 - - -def _request(conn, path, data, method, headers): - if headers is None: - headers = {'Content-Type': 'application/json', - 'Accept': 'application/json'} - if 'AUTHORIZATION' not in headers.keys(): - user, pw = mockmodel.fake_user.items()[0] - hdr = "Basic " + base64.b64encode("%s:%s" % (user, pw)) - headers['AUTHORIZATION'] = hdr - conn.request(method, path, data, headers) - return conn.getresponse() - - -def request(host, port, path, data=None, method='GET', headers=None): - # verify if HTTPSConnection has context parameter - if "context" in inspect.getargspec(httplib.HTTPSConnection.__init__).args: - context = ssl._create_unverified_context() - conn = httplib.HTTPSConnection(host, port, context=context) - else: - conn = httplib.HTTPSConnection(host, port) - - return _request(conn, path, data, method, headers) - - -def get_remote_iso_path(): - """ - Get a remote iso with the right arch from the distro files shipped - with kimchi. - """ - host_arch = os.uname()[4] - remote_path = '' - with open(os.path.join(PluginPaths('kimchi').conf_dir, 'distros.d', - 'fedora.json')) as fedora_isos: - # Get a list of dicts - json_isos_list = json.load(fedora_isos) - for iso in json_isos_list: - if (iso.get('os_arch')) == host_arch: - remote_path = iso.get('path') - break - - return remote_path - - -class FakeUser(User): - auth_type = "fake" - sudo = True - - def __init__(self, username): - self.user = {} - self.user[USER_NAME] = username - self.user[USER_GROUPS] = None - self.user[USER_ROLES] = dict.fromkeys(tabs, 'user') - - def get_groups(self): - return sorted([group.gr_name for group in grp.getgrall()])[0:3] - - def get_roles(self): - if self.sudo: - self.user[USER_ROLES] = dict.fromkeys(tabs, 'admin') - return self.user[USER_ROLES] - - def get_user(self): - return self.user - - @staticmethod - def authenticate(username, password, service="passwd"): - try: - return mockmodel.fake_user[username] == password - except KeyError, e: - raise OperationFailed("WOKAUTH0001E", {'username': 'username', - 'code': e.message}) - - -def patch_auth(sudo=True): - """ - Override the authenticate function with a simple test against an - internal dict of users and passwords. - """ - config.set("authentication", "method", "fake") - FakeUser.sudo = sudo - - -def normalize_xml(xml_str): - return etree.tostring(etree.fromstring(xml_str, - etree.XMLParser(remove_blank_text=True))) - - -def wait_task(task_lookup, taskid, timeout=10): - for i in range(0, timeout): - task_info = task_lookup(taskid) - if task_info['status'] == "running": - wok_log.info("Waiting task %s, message: %s", - taskid, task_info['message']) - time.sleep(1) - else: - return - wok_log.error("Timeout while process long-run task, " - "try to increase timeout value.") - - -# The action functions in model backend raise NotFoundError exception if the -# element is not found. But in some tests, these functions are called after -# the element has been deleted if test finishes correctly, then NofFoundError -# exception is raised and rollback breaks. To avoid it, this wrapper ignores -# the NotFoundError. -def rollback_wrapper(func, resource, *args): - try: - func(resource, *args) - except NotFoundError: - # VM has been deleted already - return - - -# This function is used to test storage volume upload. -# If we use self.request, we may encode multipart formdata by ourselves -# requests lib take care of encode part, so use this lib instead -def fake_auth_header(): - headers = {'Accept': 'application/json'} - user, pw = mockmodel.fake_user.items()[0] - hdr = "Basic " + base64.b64encode("%s:%s" % (user, pw)) - headers['AUTHORIZATION'] = hdr - return headers diff --git a/plugins/kimchi/ui/Makefile.am b/plugins/kimchi/ui/Makefile.am deleted file mode 100644 index 21fe703..0000000 --- a/plugins/kimchi/ui/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2013 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -SUBDIRS = config css images js pages spice-html5 - -uidir = $(datadir)/wok/plugins/kimchi/ui diff --git a/plugins/kimchi/ui/config/Makefile.am b/plugins/kimchi/ui/config/Makefile.am deleted file mode 100644 index e3b3d19..0000000 --- a/plugins/kimchi/ui/config/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2013 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -xmldir = $(datadir)/wok/plugins/kimchi/ui/config - -dist_xml_DATA = \ - tab-ext.xml \ - $(NULL) diff --git a/plugins/kimchi/ui/config/tab-ext.xml b/plugins/kimchi/ui/config/tab-ext.xml deleted file mode 100644 index ee88c88..0000000 --- a/plugins/kimchi/ui/config/tab-ext.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<tabs-ext> - <tab> - <access role="admin" mode="admin"/> - <access role="user" mode="none"/> - - <title>Host</title> - <path>plugins/kimchi/host.html</path> - </tab> - <tab> - <access role="admin" mode="admin"/> - <access role="user" mode="byInstance"/> - - <title>Guests</title> - <path>plugins/kimchi/guests.html</path> - </tab> - <tab> - <access role="admin" mode="admin"/> - <access role="user" mode="none"/> - - <title>Templates</title> - <path>plugins/kimchi/templates.html</path> - </tab> - <tab> - <access role="admin" mode="admin"/> - <access role="user" mode="read-only"/> - - <title>Storage</title> - <path>plugins/kimchi/storage.html</path> - </tab> - <tab> - <access role="admin" mode="admin"/> - <access role="user" mode="read-only"/> - - <title>Network</title> - <path>plugins/kimchi/network.html</path> - </tab> -</tabs-ext> diff --git a/plugins/kimchi/ui/css/Makefile.am b/plugins/kimchi/ui/css/Makefile.am deleted file mode 100644 index 5071d29..0000000 --- a/plugins/kimchi/ui/css/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2013 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -EXTRA_DIST = theme-default - -cssdir = $(datadir)/wok/plugins/kimchi/ui/css -dist_css_DATA = theme-default.min.css - -theme-default.min.css: theme-default/*.css - cat $^ > $@ - -CLEANFILES = theme-default.min.css diff --git a/plugins/kimchi/ui/css/theme-default/guest-edit.css b/plugins/kimchi/ui/css/theme-default/guest-edit.css deleted file mode 100644 index b661159..0000000 --- a/plugins/kimchi/ui/css/theme-default/guest-edit.css +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#guest-edit-window { - font-size: 13px; - height: 420px; - width: 820px; -} - -#guest-edit-window #action-button-container { - padding-right: 0; -} - -#guest-edit-window #guest-edit-button-cancel { - margin-left: 10px; -} - -#guest-edit-tabs { - background: transparent; - border: none; - height: 100%; - padding: 0; -} - -#form-guest-edit-general { - padding: 1em; -} - -#form-guest-edit-general .edit-general-inline { - display: inline-block; -} - -#form-guest-edit-storage input[readonly] { - background: none; - border-color: transparent; - text-overflow: ellipsis; -} - -.guest-edit-fieldset { - padding-right: 0; -} - -.guest-edit-wrapper-label { - height: 30px; - line-height: 30px; - margin-top: 10px; - vertical-align: top; - min-width: 100px; - font-weight: lighter; - font-family: 'Helvetica Neue', Helvetica, Arial; -} - -#form-guest-edit-storage .guest-edit-wrapper-label { - width: 60px; -} - -.guest-edit-wrapper-controls { - width: 470px; - margin-top: 5px;�� -} - -#form-guest-edit-storage .guest-edit-wrapper-controls { - width: 486px; -} - -.guest-edit-wrapper-controls input[type="text"] { - font-size: 16px; - height: 30px; - width: 450px; - border: 1px solid #CCCCCC; -} - -.guest-edit-wrapper-controls input[type="text"][disabled] { - color: #bbb; - background-color: #fafafa; - cursor: not-allowed; - border: 1px solid #CCCCCC; -} - -.guest-edit-cdrom-row-container { - max-height: 180px; - overflow: auto; -} - -.guest-edit-cdrom-row-container input[type="text"] { - width: 400px; -} - -#form-guest-edit-storage .header, -.guest-edit-snapshot .header, -.guest-edit-interface .header, -#form-guest-edit-permission .ldap .header { - margin-bottom: 8px; - padding-bottom: 2px; - font-weight: bold; - border-bottom: 1px solid #999999; - overflow: hidden; -} - -#form-guest-edit-storage .body .item, -.guest-edit-snapshot .body .item, -.guest-edit-snapshot .task .item, -.guest-edit-interface .body .item { - margin: 5px 0; -} - -#form-guest-edit-storage .cell, -.guest-edit-interface .cell { - display: inline-block; - width: 200px; -} - -.guest-edit-snapshot .cell { - display: inline-block; -} - -.guest-edit-snapshot .sel { - width: 25px; - vertical-align: top; -} - -.guest-edit-snapshot .icon { - background: url('../images/theme-default/kimchi-loading15x15.gif') no-repeat; - display: block; - width: 16px; - height: 16px; - vertical-align: middle; - margin-left: 2px; -} - -.guest-edit-snapshot .name { - width: 400px; -} - -.guest-edit-snapshot .created { - width: 270px; -} - -#form-guest-edit-storage .cell.dev { - width: 60px; -} - -#form-guest-edit-storage .cell.path { - width: 440px; -} - -#form-guest-edit-storage .cell.dev input, -#form-guest-edit-storage .cell.path input { - box-sizing: border-box; - width: 100%; -} - -.guest-edit-interface .body select { - width: 180px; - padding: 0px; -} - -#form-guest-edit-storage .action-area, -.guest-edit-snapshot .action-area, -.guest-edit-interface .action-area { - float: right; -} - -#form-guest-edit-storage .action-area { - line-height: 24px; -} - -#form-guest-edit-storage button, -.guest-edit-snapshot button, -.guest-edit-interface button { - width: 20px; - height: 20px; -} - -#form-guest-edit-storage .body button:not(:last-child), -.guest-edit-interface .body button:not(:last-child) { - margin-right: 2px; -} - -.guest-edit-snapshot .hide, -.guest-edit-interface .hide { - display: none!important; -} - -.guest-edit-permission .pam { - height: 220px; - padding: 5px 10px!important; -} - -.guest-edit-permission .hide { - display: none; -} - -.guest-edit-permission .pam .column { - display: inline-block; - vertical-align: top; -} - -.guest-edit-permission .pam .title { - margin-bottom: 3px; -} - -.guest-edit-permission .pam input[type="text"] { - margin-bottom: 3px; - font-size: 12px; - width: 97%; -} - -.guest-edit-permission .pam .body { - border: 1px solid #999999; - font-size: 12px; - padding: 1px; - height: 192px; - overflow: auto; -} - -.guest-edit-permission .pam .body .head { - margin-bottom: 3px; - font-weight: bold; - background: linear-gradient(to bottom, #E5E5E5 0%, #C4C4C4 100%) repeat scroll 0 0 transparent; -} - -.guest-edit-permission .pam .body .item { - padding: 2px 3px; - margin-bottom: 1px; - cursor: pointer; -} - -.guest-edit-permission .pam .body .item:hover { - background-color: #AAAAAA; -} - -.guest-edit-permission .pam .body .item-picked { - background-color: #BBBBBB; -} - -.guest-edit-permission .pam .body .item .icon { - display: inline-block; - height: 15px; - width: 15px; - vertical-align: bottom; -} - -.guest-edit-permission .pam .body .item .user-icon { - background: url('../images/theme-default/user.png') no-repeat scroll; - background-size: 15px 15px; -} - -.guest-edit-permission .pam .body .item .group-icon { - background: url('../images/theme-default/group.png') no-repeat scroll; - background-size: 15px 15px; -} - -.guest-edit-permission .pam .body .column-user { - width: 48%; -} -.guest-edit-permission .pam .body .column-group { - width: 50%; -} - -.guest-edit-permission .pam .control { - width: 5%; -} - -.guest-edit-permission .pam .control button { - width: 26px; - margin-left: 7px; -} - -.guest-edit-permission .pam .control button:first-child { - margin-top: 110px; - margin-bottom: 2px; -} - -.guest-edit-permission .pam .control .ui-button-text-only .ui-button-text { - padding: 2px 8px; -} - -.guest-edit-permission .pam .avail { - width: 46%; -} - -.guest-edit-permission .pam .selected { - width: 46%; - float: right; -} - -#form-guest-edit-permission .ldap .body .item { - margin: 8px 0; -} - -#form-guest-edit-permission .ldap .cell { - width: 250px; -} - -#form-guest-edit-permission .ldap .action-area { - float: right; - line-height: 24px; -} - -#form-guest-edit-permission .ldap button { - width: 20px; - height: 20px; -} - -#form-guest-edit-permission input[type="text"] { - width: 300px; -} - -#form-guest-edit-permission .ldap .header button { - margin-bottom: 1px; -} - -#form-guest-edit-permission .ldap .checked { - border-color: red; - border-style: solid; - border-width: 1px; -} - -#form-guest-edit-permission .ldap .checked.hide { - display: none; -} - -.guest-edit-pci { - height: 79%; - overflow: auto; - font-size: 12px; -} - -.guest-edit-pci .guest-scroll-indent { - width: 783px; -} - -.guest-edit-pci .filter { - height: 35px; - margin-right: 5px; - overflow: hidden; -} - -.guest-edit-pci .group { - float: right; -} - -.guest-edit-pci .filter .control { - border: 1px solid #AAAAAA; - font-size: 12px; - background-color: white; -} - -.guest-edit-pci .filter select { - border-right: 0px!important; - border-radius: 7px 0px 0px 7px; - padding: 2px 2px 2px 7px; - width: 100px; - height: 24px; -} - -.guest-edit-pci .filter select option { - padding-left: 7px; -} - -.guest-edit-pci .filter input { - border-radius: 0px 7px 7px 0px; - padding: 3px 3px 3px 10px; - width: 200px; - height: 16px; - font-style: italic; -} - -.guest-edit-pci .header { - margin-bottom: 8px; - padding-bottom: 2px; - font-weight: bold; - border-bottom: 1px solid #999999; -} - -.guest-edit-pci .item { - margin-bottom: 4px; - overflow: hidden; -} - -.guest-edit-pci .cell { - display: inline-block; - vertical-align: middle; - margin-right: 10px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.guest-edit-pci .item button { - width: 20px; - height: 20px; - float: right; -} - -.guest-edit-pci .name { - width: 18%; - max-width: 18%; -} - -.guest-edit-pci .product { - width: 45%; - max-width: 45%; -} - -.guest-edit-pci .vendor { - width: 25%; - max-width: 25%; -} diff --git a/plugins/kimchi/ui/css/theme-default/guest-storage-add.css b/plugins/kimchi/ui/css/theme-default/guest-storage-add.css deleted file mode 100644 index 9cc41e8..0000000 --- a/plugins/kimchi/ui/css/theme-default/guest-storage-add.css +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#guest-storage-add-window { - font-size: 13px; - height: 600px; - width: 700px; -} - -.guest-storage-add-fieldset { - padding: 1em; -} - -#guest-storage-add-window .btn { - width: 587px; -} - -#form-guest-storage-add .form-section .field { - overflow: visible; -} - -#guest-storage-add-window input[type="text"] { - font-size: 16px; - height: 38px; - background: #fff; - -webkit-border-radius: 5px; - border-radius: 5px; - box-shadow: 2px 2px 2px #eee inset; - border-top: 1px solid #bbb; - border-left: 1px solid #bbb; - padding-left: 10px; - width: 600px; -} - -#guest-storage-add-window input[type="text"][disabled] { - color: #bbb; - background-color: #fafafa; - cursor: not-allowed; -} - -.guest-storage-add-wrapper-label, .guest-storage-add-wrapper-controls { - display: inline-block; -} - -.guest-storage-add-wrapper-label { - height: 38px; - line-height: 38px; - margin-top: 5px; - vertical-align: top; - width: 80px; -} - -.guest-storage-add-wrapper-controls { - width: 470px; -} - -#vm-storage-button-add[disabled] { - background: #c0c0c0; - color: #ddd; - padding-left: 26px; -} - -#vm-storage-button-add.loading[disabled] { - background: url("../../images/theme-default/loading.gif") 7px center no-repeat #c0c0c0; - color: #ddd; - padding-left: 26px; -} diff --git a/plugins/kimchi/ui/css/theme-default/host.css b/plugins/kimchi/ui/css/theme-default/host.css deleted file mode 100644 index a0cccb1..0000000 --- a/plugins/kimchi/ui/css/theme-default/host.css +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -.host-panel { - font-size: 12px; - margin-bottom: 100px; -} - -.host-panel .logo-container, .host-panel .info-container, -.host-panel .section-label, .host-panel .section-value { - display: inline-block; - vertical-align: top; -} - -.host-panel .section-label { - display: inline-block; - margin-right: 1em; - vertical-align: top; -} - -.host-panel .logo { - background: url("plugins/kimchi/images/icon-vm.png") no-repeat left top; - height: 128px; - width: 128px; -} - -.host-panel .hostname { - text-decoration: underline; -} - -.host-panel .action-panel { - margin-top: 2em; - padding-left: 10px; -} - -.host-panel .button-icon { - background: url("../images/theme-default/host-icon-sprite.png") no-repeat - left top; - display: inline-block; - height: 12px; - width: 12px; -} - -.host-panel .action-icon-stop { - background-position: -14px 0; -} - -.host-panel .action-icon-restart { - background-position: -28px 0; -} - -.host-panel .action-icon-download { - background-position: -42px 0; -} - -.host-panel .action-icon-connect { - background-position: -56px 0; -} - -.host-panel .action-icon-add { - background-position: -70px 0; -} - -.host-panel .action-icon-edit { - background-position: -84px 0; -} - -.host-panel .action-icon-remove { - background-position: -98px 0; -} - -.host-panel button:disabled .action-icon-start { - background-position: 0 -14px; -} - -.host-panel button:disabled .action-icon-stop { - background-position: -14px -14px; -} - -.host-panel button:disabled .action-icon-restart { - background-position: -28px -14px; -} - -.host-panel button:disabled .action-icon-download { - background-position: -42px -14px; -} - -.host-panel button:disabled .action-icon-connect { - background-position: -56px -14px; -} - -.host-panel button:disabled .action-icon-add { - background-position: -70px -14px; -} - -.host-panel button:disabled .action-icon-edit { - background-position: -84px -14px; -} - -.host-panel button:disabled .action-icon-remove { - background-position: -98px -14px; -} - -.host-panel .info-container { - padding-top: 16px; - width: 890px; -} - -.host-panel .section-header { - background: #EEE; - border-radius: 5px; - cursor: pointer; - line-height: 2em; - margin: 1em 0 1em; - padding-left: 6px; -} - -.host-panel .section-header:hover { - background: #06f; - color: white; -} - -.host-panel .section-content { - padding-left: 1em; -} - -.host-panel .section-header .arrow { - border-color: transparent; - border-style: solid; - display: inline-block; - margin-right: 6px; - width: 0; -} - -.host-panel .section-header[aria-expanded="true"] .arrow { - border-top-color: black; - border-width: 8px 4px 0; - border-bottom: none; -} - -.host-panel .section-header[aria-expanded="true"]:hover .arrow { - border-top-color: white; -} - -.host-panel .section-header[aria-expanded="false"] .arrow { - border-left-color: black; - border-right: none; - border-width: 4px 0 4px 8px; -} - -.host-panel .section-header[aria-expanded="false"]:hover .arrow { - border-left-color: white; -} - -.host-panel .section-row { - line-height: 1.6em; - margin-bottom: 1em; -} - -.host-panel .section-label { - width: 100px; -} - -#frequency-textbox { - width: 20px; -} - -#container-chart-cpu, -#container-chart-memory, -#container-chart-disk-io, -#container-chart-network-io { - border: 1px solid white; - box-shadow: 2px 2px 2px gray, 2px -2px 2px gray, -2px -2px 2px gray, -2px - 2px 2px gray; - height: 100px; - width: 500px; -} - -#container-chart-disk-io .disk-write, -#container-chart-network-io .network-sent { - stroke: #f80; -} - -/* Debug Report */ -.cell-text-wrapper { - margin-left: 10px; -} - -.host-panel #available-reports-grid { - border-color: #ddd; - height: 400px; - width: 850px; -} - -.host-panel select#available-reports-list { - width: 300px; -} - -.host-panel select#available-reports-list option { - margin: .2em 1em; -} - -.debug-report-name, -.debug-report-time { - width: 424px; -} - -#id-debug-img { - background: url(../images/theme-default/kimchi-loading15x15.gif) 12px - center no-repeat; - padding-left: 23px; -} - -/* End of Debug Report */ - -/* Software Updates */ -.host-panel #software-updates-grid { - border-color: #ddd; - height: 300px; - width: 850px; -} - -.software-update-name, -.software-update-repos { - width: 224px; -} - -.software-update-version, -.software-update-arch { - width: 200px; -} - -.host-panel #software-updates-progress-textarea { - border: 1px solid #ddd; - box-sizing: border-box; - height: 100px; - padding: .2em .5em; - resize: vertical; - width: 852px; -} -/* End of Software Updates */ - -/* Repository */ -.host-panel #repositories-grid { - border-color: #ddd; - height: 200px; - width: 850px; -} - -.host-panel #repositories-grid .repository-id { - width: 120px; -} - -.host-panel #repositories-grid .repository-name { - width: 640px; -} - -.host-panel #repositories-grid .repository-enabled { - width: 88px; -} - -.host-panel #repositories-grid .repository-baseurl.deb { - width: 400px; -} - -.host-panel #repositories-grid .repository-enabled.deb { - width: 100px; -} - -.host-panel #repositories-grid .repository-gpgcheck.deb { - width: 150px; -} -/* End of Repository */ diff --git a/plugins/kimchi/ui/css/theme-default/icon.css b/plugins/kimchi/ui/css/theme-default/icon.css deleted file mode 100644 index f82d45d..0000000 --- a/plugins/kimchi/ui/css/theme-default/icon.css +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - /* Generated at http://colorzilla.com/gradient-editor/ */ - -.btn.loading { - box-shadow: none; - cursor: default; -} - -.btn.loading .icon { - background: url(../images/theme-default/icon-load.png) center - center no-repeat; -} - -.btn.pause-gray .icon { - background: url(../images/theme-default/ac22_pause_grey.png) center - center no-repeat; -} - -.btn.resume-gray .icon { - background: url(../images/theme-default/ac24_resume_grey.png) center - center no-repeat; -} - -.icon.reset { - background: url(../images/theme-default/icon-reset.png) center - center no-repeat; -} - -.icon.power-up { - background: url(../images/theme-default/icon-power-up.png) center - center no-repeat; -} - -.icon.power-down { - background: url(../images/theme-default/icon-power-down.png) center - center no-repeat; -} - -.icon.pause { - background: url(../images/theme-default/ac22_pause.png) center - center no-repeat; -} - -.icon.resume { - background: url(../images/theme-default/ac24_resume.png) center - center no-repeat; -} - -.icon.search { - background: url(../images/theme-default/icon-search.png) no-repeat - center center; -} - -.icon.sort { - background: url(../images/theme-default/icon-sort.png) no-repeat - center center; -} - -.icon.design { - background: url(../images/theme-default/icon-design.png) no-repeat - center center; -} - -.icon.list { - background: url(../images/theme-default/icon-list.png) no-repeat - center center; -} - -.icon.detail { - background: url(../images/theme-default/icon-detail.png) no-repeat - center center; -} - -.icon.add { - line-height: 32px; - text-align: center; - text-shadow: -1px -1px 1px #aaa, 1px 1px 1px #eee; - font-size: 38px; - font-weight: bold; - color: #7cae0a; -} - -.icon.tree { - width: 42px; - background: url(../images/theme-default/icon-tree.png) no-repeat - center center; -} - - diff --git a/plugins/kimchi/ui/css/theme-default/list.css b/plugins/kimchi/ui/css/theme-default/list.css deleted file mode 100644 index 8c78623..0000000 --- a/plugins/kimchi/ui/css/theme-default/list.css +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -.list-vm { - margin: 10px; -} - -/* Generated at http://colorzilla.com/gradient-editor/ */ -.list-vm>li { - margin-bottom: 10px; - background: #ffffff; - background: -moz-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: -webkit-gradient(linear, left top, left bottom, - color-stop(0%, #ffffff), color-stop(100%, #e5e5e5)); - background: -webkit-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: -o-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: -ms-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: linear-gradient(to bottom, #ffffff 0%, #e5e5e5 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', - endColorstr='#e5e5e5', GradientType=0); - border: 1px solid #ccc; - color: #333; - -webkit-border-radius: 8px; - -moz-border-radius: 8px; - border-radius: 8px; -} - -.list-vm li>* { - height: 130px; - display: table-cell; - vertical-align: top; - position: relative; - border-left: 1px solid #ccc; - border-right: 1px solid #fff; -} - -.list-vm li>*:FIRST-CHILD { - border-left: none; -} - -.list-vm li>*:LAST-CHILD { - border-right: none; -} - -.list-vm li>.guest-tile{ - text-align: center; - vertical-align: middle; -} - -.list-vm .handle { - display: block; - width: 50px; - height: 130px; - box-sizing: border-box; - box-shadow: inset 4px 4px 4px #0289e2, inset -4px -4px 4px #04385d; - background: #0b6bad url(../images/theme-default/arrow_out.png) center - center no-repeat; - border-top-right: 1px solid #CCC; - -webkit-border-top-right-radius: 8px; - -moz-border-top-right-radius: 8px; - border-top-right-radius: 8px; - border-bottom-right: 1px solid #CCC; - -webkit-border-bottom-right-radius: 8px; - -moz-border-bottom-right-radius: 8px; - border-bottom-right-radius: 8px; -} - -.list-vm .subtitle { - color: #666; - font-size: 13px; - text-align: center; - line-height: 10px; - font-weight: bold; -} - -.list-vm .tile .imgload { - display: none; -} - -.list-vm .tile.shutoff .imgactive { - max-height: 110px; - max-width: 170px; - height: auto; - width: auto; - display:inline; - border: none; - position: relative; -} - -.list-vm .tile.paused .imgactive { - max-height: 110px; - max-width: 170px; - height: auto; - width: auto; - display:inline; - border: none; - position: relative; -} - -.list-vm .tile.running .imgactive{ - max-height: 110px; - max-width: 170px; - height: auto; - width: auto; - display:inline; - border: none; - cursor: crosshair; - cursor: -moz-zoom-in; - cursor: -webkit-zoom-in; -} - -.list-vm .tile .overlay { - max-height: 110px; - max-width: 170px; - height: auto; - width: auto; - position:absolute; - bottom:0; - right:0; - display:none; -} - -.guest-type { - width: 257px; -} - -.guest-cpu { - width: 91px; -} - -.guest-network { - width: 91px; -} - -.guest-storage { - width: 91px; -} - -.guest-tile { - width: 190px; -} - -.guest-users { - width: 93px; -} - -.guest-actions { - width: 125px; - min-width: 125px; -} - -.guest-handle { - width: 50px; -} - -.guest-general { - padding: 10px; - border-bottom: 1px solid #ccc; - width: 237px; -} - -.guest-ip { - padding: 0 10px; - border-top: 1px solid #fff; -} - -.guest-general .title { - color: #666; - font-size: 16px; - font-weight: normal; - height: 25px; - line-height: 25px; - text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; - max-width: 237px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.guest-general .text { - font-weight: bold; - color: #999; - font-size: 11px; - text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; -} - -.guest-users .top { - border-bottom: 1px solid #ccc; - padding: 3px 10px; -} - -.guest-users .bottom { - border-top: 1px solid #fff; - padding: 3px 10px; -} - -.guest-users .users { - height: 45px; - line-height: 45px; - background: url(../images/theme-default/icon-user.png) left - center no-repeat; - padding-left: 50px; - font-size: 36px; - font-weight: bold; -} - -.guest-users .snapshots { - height: 40px; - line-height: 40px; - background: url(../images/theme-default/icon-camera.png) left - center no-repeat; - padding-left: 50px; - font-size: 36px; - font-weight: bold; -} - -.guest-users .mini-text { - font-size: 11px; - font-weight: normal; - text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; -} - -.guest-actions .top { - padding: 7px 10px; - width: 200px; -} - -.guest-actions .top button { - display: inline-block; - width: 42px; - height: 42px; -} - -@-moz-document url-prefix() { - .guest-actions .top button span { - margin-left: -3px; - margin-top: -1px; - } -} - -.guest-actions .bottom { - padding: 0 10px; -} - -.list-vm .tile { - max-width: 170px; - max-height: 110px; - width: auto; - height: auto; - margin: 10px; -} - -.list-vm .tile:not(.shutoff) && .tile:not(.paused) img { - box-shadow: -1px -1px 2px rgb(0, 0, 0, .25), 3px 3px 3px #fff; -} - -.list-vm .shutoff { - position: relative; - box-shadow: none !important; -} - -.list-vm .shutoff img { - opacity: 0.4; -} - -.list-vm .paused { - position: relative; - box-shadow: none !important; -} - -.list-vm .paused img { - opacity: 0.6; -} - -.list-title { - color: #666; - font-weight: bold; - font-size: 12px; - overflow: hidden; - margin: 10px; -} - -.list-title li { - display: table-cell; - padding: 0 1px; -} - -.list-no-result { - font-size: 16px; - height: 48px; - line-height: 48px; - text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; - padding-left: 10px; -} - -.guest-pending { - margin: 10px; -} - -.guest-pending .icon { - background: url('../images/theme-default/kimchi-loading15x15.gif') no-repeat; - display: inline-block; - width: 20px; - height: 20px; - vertical-align: middle; -} - -.guest-pending .text { - color: #666666; - margin-left: 5px; - text-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #FFFFFF; -} diff --git a/plugins/kimchi/ui/css/theme-default/network.css b/plugins/kimchi/ui/css/theme-default/network.css deleted file mode 100644 index fc8a24f..0000000 --- a/plugins/kimchi/ui/css/theme-default/network.css +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -.network { - margin: 5px; -} - -.network .grid-control { - height: 40px; - padding: 5px 0; -} - -.network .grid-control .filter { - width: 300px; - padding: 5px; - float: right; -} - -.network .list .column-name { - width: 20%; - max-width: 20%; - text-overflow: ellipsis; -} - -.network .list .column-state { - width: 10%; -} - -.network .list .column-type { - width: 15%; -} - -.network .list .column-interface { - width: 15%; -} - -.network .list .column-space { - width: 25%; -} - -.network .list .column-action { - display: inline-block; - float: right; - height: 40px; -} - -.network .list .hide-action-item { - display: none; -} - -.network .list .menu-container { - display: none; - top: 58px; -} - -.network .list .action-button { - float: right; - margin-top: 2px; - margin-left: 5px; -} - -.network .list .action-button-icon { - background: url("../images/theme-default/arrow-down-black.png") no-repeat - scroll center center transparent; -} - -.network .list .ui-state-disabled { - margin: 0px; -} - -.network .list .network-state { - display: inline-block; - height: 16px; - width: 16px; - border-radius: 8px; - margin-left: 10px; -} - -.network .list .nw-loading { - background: #c0c0c0 url(../images/theme-default/loading.gif) - center no-repeat; -} - -.network .list .up { - background: linear-gradient(to bottom, #BFD255 0%, #8EB92A 50%, - #72AA00 51%, #9ECB2D 100%) repeat scroll 0 0 transparent; -} - -.network .list .down { - background: linear-gradient(to bottom, #AFAFAF 0%, #AFAFAF 50%, - #AFAFAF 51%, #AFAFAF 100%) repeat scroll 0 0 transparent; -} - -.network-config { - font-family: Arial; - font-size: 12px; - margin-bottom: 40px; - display: none; -} - -.network-config .section-container { - margin-top: 20px; -} - -.network-config .section-container:first-child { - margin-top: 10px; -} - -.network-config .section-container:last-child { - height: 200px; -} - -.network-config .section-container .bridged-inline { - display: inline-block; - vertical-align: top; - max-width: 520px; -} - -.network-config .section-header { - font-size: 14px; - font-weight: lighter; -} - -.network-config .section-content { - margin-top: 10px; -} - -.network-config input[type="text"] { - border: 1px solid #CCCCCC; - font-size: 16px; - height: 30px; - width: 300px; - line-height: 30px; - padding: 0 5px; -} - -.network-config input.invalid-field[type="text"] { - border-color: #FF4444; -} - -.network-config input.invalid-field[type="text"][disabled] { - border-color: #666666; -} - -.network-config input[type="radio"] { - margin-right: 5px; - margin-top: 0px; -} - -.network-config select { - color: #666666; - border: solid 1px; - background-color: white; - padding: 3px 4px 3px 0; -} - -.network-config .input-container { - height: 20px; -} - -.network-config label { - vertical-align: top; -} - -.network-type-wrapper-controls input[type="text"] { - height: 38px; - line-height: 38px; - background: #fff; - -webkit-border-radius: 5px; - border-radius: 5px; - box-shadow: 2px 2px 2px #eee inset; - border-top: 1px solid #bbb; - border-left: 1px solid #bbb; - padding: 0 10px; - margin-top: 5px; - width: 50px; -} - -.network-type-wrapper-controls > .dropdown { - margin: 5px 0 0 1px; - width: 180px; -} - -.network-type-wrapper-controls input[type="text"][disabled] { - color: #bbb; - background-color: #fafafa; - cursor: not-allowed; -} - -.network-type-wrapper-controls span[type="text"] { - padding: 0 10px; -} - -.bridge-option-column { - display: inline-block; - vertical-align: middle; -} - -.bridge-option-column label { - margin-left: 42px; -} - -.network-type-wrapper-controls { - width: 80px; - display: inline-block; - vertical-align: top; - padding: 5px 5px 5px 22px; -} - -#enableVlan { - margin-left: 42px; - vertical-align: middle; -} - -#labelEnableVlan { - vertical-align: middle; -} - -#labelNetworkVlanID { - margin-left: 42px; - vertical-align: middle; - display: none; -} - -#networkVlanID { - width: 80px; - vertical-align: middle; - display: none; -} - -.network-config .input-hint-icon { - margin: -1px 1px 0 0; - display: inline-block; -} - -.network-config .input-hint { - margin-top: 3px; -} - -.network-config .input-hint-text { - color: #999999; - font-weight: lighter; - font-size: 12px; -} - -.ui-state-default a { - color: #212121; -} - -#networkConfig { - padding-left: 30px; -} diff --git a/plugins/kimchi/ui/css/theme-default/report-add.css b/plugins/kimchi/ui/css/theme-default/report-add.css deleted file mode 100644 index 8020182..0000000 --- a/plugins/kimchi/ui/css/theme-default/report-add.css +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#report-add-window { - height: 300px; - width: 400px; -} - -#report-add-window .field { - font-size: 12px; -} - -#report-name-textbox { - margin: 0; - width: 100%; -} - -.info-add-debug-report { - font-size: 12px; - color: #999999; - font-weight: lighter; - font-family: 'Helvetica Neue', Helvetica, Arial; -} \ No newline at end of file diff --git a/plugins/kimchi/ui/css/theme-default/report-rename.css b/plugins/kimchi/ui/css/theme-default/report-rename.css deleted file mode 100644 index 2fb2698..0000000 --- a/plugins/kimchi/ui/css/theme-default/report-rename.css +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#report-rename-window { - height: 300px; - width: 400px; -} - -#report-rename-window .field { - font-size: 12px; -} - -#report-name-textbox { - -moz-box-sizing: border-box; - box-sizing: border-box; - margin: 0; - width: 100%; -} - -.info-debug-report-rename { - font-size: 12px; - color: #999999; - font-weight: lighter; - font-family: 'Helvetica Neue', Helvetica, Arial; -} diff --git a/plugins/kimchi/ui/css/theme-default/repository-add.css b/plugins/kimchi/ui/css/theme-default/repository-add.css deleted file mode 100644 index 4344569..0000000 --- a/plugins/kimchi/ui/css/theme-default/repository-add.css +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#repository-add-window { - height: 500px; - width: 1000px; -} - -#repository-add-window span.required { - color: red; - padding-left: 5px; - vertical-align: top; -} - -#repository-add-window .textbox-wrapper input[type="text"] { - box-sizing: border-box; - width: 100%; -} - -#repository-add-window .textbox-wrapper label { - vertical-align: middle; -} - -#isMirrorLabel { - font-size: 14px; - font-weight: lighter; - font-family: 'Helvetica Neue', Helvetica, Arial; -} \ No newline at end of file diff --git a/plugins/kimchi/ui/css/theme-default/repository-edit.css b/plugins/kimchi/ui/css/theme-default/repository-edit.css deleted file mode 100644 index 383a7fe..0000000 --- a/plugins/kimchi/ui/css/theme-default/repository-edit.css +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -.yum div#repository-edit-window { - height: 680px; - width: 1000px; -} - -.deb div#repository-edit-window { - height: 480px; - width: 1000px; -} - - -.repository-edit-fieldset { - float: left; - padding: 0 30px; - width: 95%; -} - -.repository-edit-wrapper-label, .repository-edit-wrapper-controls { - display: inline-block; - height: 30px; - line-height: 30px; - font-size: 14px; - vertical-align: top; -} - -.repository-edit-wrapper-label { - margin-top: 10px; - width: 150px; -} - -.repository-edit-wrapper-controls label { - vertical-align: middle; -} - -.repository-edit-wrapper-controls { - width: 100%; -} - -.repository-edit-wrapper-controls input[type="text"] { - font-size: 16px; - height: 30px; - line-height: 30px; - padding: 0 10px; - width: 100%; - -moz-box-sizing: border-box; - box-sizing: border-box; - border: 1px solid #CCCCCC; -} - - -.repository-edit-wrapper-controls input[type="text"][readonly] { - color: #bbb; - background-color: #fafafa; -} - - -.repository-edit-wrapper-controls input[type="text"][disabled] { - color: #bbb; - background-color: #fafafa; - cursor: not-allowed; -} - - -.deb .yum{ - display: none; -} - - -.yum .deb{ - display: none; -} diff --git a/plugins/kimchi/ui/css/theme-default/storage.css b/plugins/kimchi/ui/css/theme-default/storage.css deleted file mode 100644 index 88447b5..0000000 --- a/plugins/kimchi/ui/css/theme-default/storage.css +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* STORAGE */ -.storage { - margin: 5px; -} - - -.storage .grid-control { - height: 40px; - padding: 5px 0; -} - -.storage .grid-control .filter { - width: 300px; - padding: 5px; - float: right; -} - -.storage-allocate-padding-user { - padding-right: 108px; -} - -.usage { - float: right; - margin-right: 30px; -} - -.list-storage .storage-li>.guest-tile { - text-align: center; - vertical-align: middle; -} - -.list-storage .subtitle { - color: #666; - font-size: 13px; - text-align: center; - line-height: 10px; - font-weight: bold; -} - -.list-storage .tile .imgload { - display: none; - max-height: 110px; - max-width: 170px; - height: auto; - width: auto; -} - -.list-storage .tile .imgactive { - max-height: 110px; - max-width: 170px; - height: auto; - width: auto; -} - -.storage-volum { - height: 40px; - width: 186px; - display: table-cell; - vertical-align: top; - position: relative; - border-left: 1px solid #ccc; - border-right: 1px solid #fff; -} - -.storage-name { - width: 15%; -} - -.storage-state { - width: 10%; -} - -.storage-type { - width: 10%; -} - -.storage-capacity { - width: 10%; -} - -.storage-allocate { - width: 10%; -} - -.storage-location { - width: 30%; -} - -.storage-button { - width: 9%; -} - -.handle { - width: 2%; -} - -.status-dot { - background: #72AA00; - background: linear-gradient(to bottom, #BFD255 0%, #8EB92A 50%, - #72AA00 51%, #9ECB2D 100%) repeat scroll 0 0 transparent; - border: 1px solid #72AA00; - border-radius: 13px; - box-shadow: 3px 3px 3px #FFFFFF, -3px -3px 3px #DDDDDD; - height: 13px; - width: 13px; - margin-left: 10px; -} - -.toolable { - position: relative; -} - -.toolable .tooltip { - display: none; - border: 2px solid #0B6BAD; - background: #fff; - padding: 6px; - position: absolute; - color: #666666; - font-weight: bold; - font-size: 11px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; - z-index: 100; - top: -300%; - left: -140%; - white-space: nowrap; -} - -.toolable:hover .tooltip { - display: block; -} - -.toolable .tooltip:after { - -moz-border-bottom-colors: none; - -moz-border-left-colors: none; - -moz-border-right-colors: none; - -moz-border-top-colors: none; - border-color: #fff transparent transparent; - border-image: none; - border-style: solid; - border-width: 7px; - content: ""; - display: block; - left: 15px; - position: absolute; - bottom: -14px; -} - -.toolable .tooltip:before { - -moz-border-bottom-colors: none; - -moz-border-left-colors: none; - -moz-border-right-colors: none; - -moz-border-top-colors: none; - border-color: #0B6BAD transparent transparent; - border-image: none; - border-style: solid; - border-width: 8px; - content: ""; - display: block; - left: 14px; - position: absolute; - bottom: -18px; -} - -.inactive { - background: #E80501; - background: linear-gradient(to bottom, #E88692 0%, #E84845 50%, - #E80501 51%, #E84845 100%) repeat scroll 0 0 transparent; - border: 1px solid #FF340C; -} - -.storage-volumes { - width: 90px; -} - -.storage-actions { - width: 125px; -} - -.storage-action { - width: 70px; -} - -.detail-view-icon { - background: url(../images/large_details_icon.png) no-repeat center - center; - height: 30px; - width: 42px; -} - -.volumes { - background: #73716F; - width: 1004px; - display: none; - margin-top: 10px; - border: 1px solid rgb(204, 204, 204); -} - -.volumeslist { - padding: 7px; - max-height: 272px; - min-height: 136px; - overflow: auto; - color: #ffffff; -} - -.volumes>.footer { - height: 48px; - z-index: 100; - box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.15); -} - -.volume-title { - float: left; - padding: 4px; - margin-bottom: 5px; - width: 130px; -} - -.pool-empty { - text-align:center; - line-height:136px; -} -.volume-title>.volume-name { - font-size: 14px; - font-weight: normal; - padding-bottom: 5px; - max-width: 120px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.volume-box { - border-radius: 8px; - background: white; - color: #666666; - float: left; - height: 100px; - margin: 7px; - padding: 10px; - width: 205px; - border: 1px solid rgb(204, 204, 204); -} - -.volume-box .volume-state { - font-size: 75%; -} - -.volume-box .label { - color: white; - font-weight: bold; - padding: 1px 5px; - text-shadow: none; -} - -.volume-box .used { - background-color: #FF7121; - border-radius: 5px 5px 5px 5px; -} - -.volume-box .free { - background: none repeat scroll 0 0 #72AA00; - border-radius: 5px 5px 5px 5px; -} - -.volume-setting { - float: right; - padding: 5px; -} - -.volume-setting>* { - height: 16px; - width: 16px; - border: none; - float: left; - padding: 2px; - cursor: pointer; -} - -.field>select { - height: 30px; - width: 160px; - font-size: 14px; - padding-left: 8px; -} - -.clear { - clear: both; -} - -.volume-text { - color: #999999; - float: left; - font-size: 10px; - font-weight: bold; - height: 18px; - line-height: 18px; - width: 142px; - max-width: 85px; - overflow: hidden; - text-overflow: ellipsis; -} - -.volume-textquota { - color: #999999; - float: left; - font-size: 10px; - font-weight: bold; - height: 18px; - line-height: 18px; - width: 142px; - max-width: 95px; - overflow: hidden; - text-overflow: ellipsis; -} - -.volume-type-position { - display: inline; - padding-right: 5px; - clear: both; - width: 90px; - border-right: 1px solid #999; - float: left; - white-space: nowrap; -} - -.volume-quota-position { - display: inline; - width: 90px; - padding-left: 5px; - float: left; - border-left: 1px solid #eee; - white-space: nowrap; -} - -.list-storage .storage-li[data-stat="active"]>.handle>.arrow-down { - background: url(../images/theme-default/arrow-down.png) no-repeat center - center; - height: 18px; - width: 18px; -} - -.list-storage .storage-li[data-stat="inactive"]>.handle>.arrow-down { - background: url(../images/theme-default/arrow-down-disable.png) no-repeat - center center; - height: 18px; - width: 18px; -} - -.arrow-up { - background: url(../images/theme-default/arrow-up.png) no-repeat center - center; - height: 18px; - width: 18px; -} - -.storage-icon { - border: 1px solid #CCCCCC; - border-radius: 8px 8px 8px 8px; - height: 40px; - width: 40px; - margin: 0 10px 10px 0; - float: left; - display: inline; -} - -.volume-default { - background: url(../images/theme-default/icon-volume-default.png) - no-repeat center center; -} - -.icon-raw { - background: url(../images/theme-default/icon-raw.png) no-repeat center - center; -} - -.icon-qcow2 { - background: url(../images/theme-default/icon-qcow2.png) no-repeat center - center; -} - -.icon-iso { - background: url(../images/theme-default/icon-iso.png) no-repeat center - center; -} - -.host-partition { - padding-left:13px; -} - -.host-partition>div { - font-size: 13px; - height: 18px; - padding: 10px; - color: #666; - float: left; - max-width: 200px; - overflow: hidden; - text-overflow: ellipsis; - font-weight: bold; - line-height: 18px; - white-space: nowrap; -} - -.storage-type-wrapper-controls { - width: 300px; - display: inline-block; - vertical-align: top; - padding: 5px 5px 5px 22px; -} - -.storage-type-wrapper-controls input[type="text"] { - height: 38px; - line-height: 38px; - background: #fff; - -webkit-border-radius: 5px; - border-radius: 5px; - box-shadow: 2px 2px 2px #eee inset; - border-top: 1px solid #bbb; - border-left: 1px solid #bbb; - padding: 0 10px; - margin-top: 5px; - width: 250px; -} - -.storage-type-wrapper-controls > .dropdown { - margin: 5px 0 0 1px; - width: 200px; -} - -.storage-type-wrapper-controls input[type="text"][disabled] { - color: #bbb; - background-color: #fafafa; - cursor: not-allowed; -} - -.storage-add-input-width { - width: 285px; -} - -.form-section .storage-field { - overflow: visible; -} - -.storage-base-input-width { - width: 300px; -} - -.storage-window { - width: 600px; - height: 700px; -} - -.storage-port-width { - width:40px; -} - -.storage-auth-width { - width: 150px; -} - -.storage-window .form-section .field { - overflow: visible; -} - -#pool-loading { - margin: 10px 15px; - background: #C0C0C0 url(../images/theme-default/loading.gif) 7px - center no-repeat; - padding: 0 20px 0 26px; -} - -.storage-admin .filter-select { - display: inline-block; - position: relative; -} - -#iscsiportId, .storage-admin .filter-select input { - border: 1px solid #CCCCCC; - border-radius: 1px; - font-size: 14px; - padding: 3px 3px 3px 10px; - height: 30px; -} - -.storage-admin .filter-select input::-ms-clear { - display: none; -} - -#iSCSIServer input { - width: 410px; -} - -#iscsiportId { - width: 60px; -} - -#iSCSITarget input { - width: 493px; -} - -/* Progress bar */ -.volume-progress { - clear: both; - width: 140px; -} - -.volume-progress .progress-bar-outer { - background: #ccc; - height: 4px; - overflow: hidden; - width: 100%; -} - -.volume-progress .progress-bar-inner { - background: #090; - height: 100%; - width: 0%; -} - -.volume-progress .progress-label { - color: #999; - font-size: 10px; - line-height: 16px; -} - -.volume-progress .progress-transferred { - float: right; -} -/* End of Progress bar */ diff --git a/plugins/kimchi/ui/css/theme-default/storagepool-add-volume.css b/plugins/kimchi/ui/css/theme-default/storagepool-add-volume.css deleted file mode 100644 index 6e8a551..0000000 --- a/plugins/kimchi/ui/css/theme-default/storagepool-add-volume.css +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#sp-add-volume-window { - height: 400px; - width: 500px; -} - -#sp-add-volume-window .textbox-wrapper input[type="text"] { - box-sizing: border-box; - width: 100%; -} - -#sp-add-volume-window .textbox-wrapper label { - vertical-align: middle; -} - -#sp-add-volume-window input[type="text"][disabled] { - color: #bbb; - background-color: #fafafa; - cursor: not-allowed; -} diff --git a/plugins/kimchi/ui/css/theme-default/template-edit.css b/plugins/kimchi/ui/css/theme-default/template-edit.css deleted file mode 100644 index 7c93117..0000000 --- a/plugins/kimchi/ui/css/theme-default/template-edit.css +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#template-edit-window { - font-size: 13px; - height: 500px; - width: 800px; -} - -#edit-template-tabs { - background: none repeat scroll 0 0 transparent; - border: medium none; - height: 100%; - padding: 0; -} - -#edit-template-tabs .form-template-inline-wrapper { - display: inline-block; - vertical-align: top; -} - -.template-edit-wrapper-label { - vertical-align: top; - min-width: 100px; - height: 35px; - line-height: 35px; - margin: 7px 0 8px; -} - -.template-edit-wrapper-controls { - vertical-align: top; - width: 400px; -} - -.template-edit-wrapper-controls input[type="text"] { - height: 38px; - line-height: 38px; - background: #fff; - -webkit-border-radius: 5px; - border-radius: 5px; - box-shadow: 2px 2px 2px #eee inset; - box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - border-top: 1px solid #bbb; - border-left: 1px solid #bbb; - padding: 0 10px; - margin-top: 5px; - width: 100%; -} - -.template-edit-wrapper-controls > .dropdown { - margin: 5px 0 0 1px; - width: 372px; -} - -.template-edit-wrapper-controls input[type="text"][disabled] { - color: #bbb; - background-color: #fafafa; - cursor: not-allowed; -} - -#edit-template-tabs .template-tab-header { - margin-bottom: 8px; - padding-bottom: 2px; - font-weight: bold; - border-bottom: 1px solid #999999; - overflow: hidden; -} - -#edit-template-tabs .template-tab-header .action-area { - float: right; - height: 20px; - width: 20px; -} - -#edit-template-tabs .template-interface-cell { - display: inline-block; - width: 250px; -} - -#edit-template-tabs .template-storage-cell{ - display: inline-block; - width: 180px; -} - -#edit-template-tabs .template-storage-cell label { - height: 25px; - padding: 2px; - border: 1px; -} - -#form-template-storage .template-tab-body select { - width: 140px; -} - -#form-template-storage .template-tab-body input { - width: 56px; - height: 17px; -} - -#form-template-storage .template-tab-body .template-storage-name { - width: 170px; -} - -#form-template-storage .template-tab-body .template-storage-disk-format { - width: 160px; -} - -#edit-template-tabs .template-tab-body input[readonly] { - background: none repeat scroll 0 0 rgba(0, 0, 0, 0); - border-color: transparent; - text-overflow: ellipsis; -} - -#edit-template-tabs .template-tab-body .item { - height: 25px; -} - -#form-template-interface .template-tab-body select { - width: 180px; -} - -#edit-template-tabs .template-tab-body .action-area { - float: right; -} - -#edit-template-tabs .template-tab-body .action-area button { - width: 20px; - height: 20px; -} - -#edit-template-tabs .hide { - display: none; -} - -#form-template-processor select, -#form-template-processor input[type="text"] { - margin-left: 10px; -} - -#form-template-processor input[type="checkbox"] { - margin-right: 5px; -} - -#form-template-processor .manual { - margin-top: 10px; - margin-left: -3px; -} - -#form-template-processor .topology { - margin: 10px 30px; -} - -#form-template-processor .topology div { - margin-bottom: 10px; -} - -#form-template-processor .topology select { - width: 80px; -} diff --git a/plugins/kimchi/ui/css/theme-default/template.css b/plugins/kimchi/ui/css/theme-default/template.css deleted file mode 100644 index 27fe404..0000000 --- a/plugins/kimchi/ui/css/theme-default/template.css +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -.tile-template>li>label:hover .summary { - opacity: 0.1; -} - -.tile-template>li>label:hover .list-info { - top: 0; -} - -.tile-template .summary { - -webkit-transition: opacity 0.25s; - -moz-transition: opacity 0.25s; - transition: opacity 0.25s; -} - -.tile-template .list-info { - -webkit-transition: top 0.25s; - -moz-transition: top 0.25s; - transition: top 0.25s; - position: absolute; - top: 100%; - width: 100%; -} - -.tile-template .list-info>li { - border-bottom: 1px dotted #ccc; - padding: 5px; - font-size: 12px; - line-height: 20px; - overflow: hidden; - width: 96%; -} - -.tile-template .list-info>li>label { - display: inline-block; - color: #111; - width: auto; - text-align: left; - cursor: pointer; -} - -.tile-template .list-info>li>span { - float: right; - color: #444693; - width: auto; - text-align: right; -} - -.os-icon { - text-align: center; -} - -.os-icon .title { - display: block; - font-size: 14px; - margin-bottom: 5px; - overflow: hidden; - width: 260px; - word-break: break-all; - word-wrap: break-word; - height: 50px; - line-height: 25px; -} - -.os-icon img { - margin-top: 7px; - width: 64px; - height: 64px; -} diff --git a/plugins/kimchi/ui/css/theme-default/template_add.css b/plugins/kimchi/ui/css/theme-default/template_add.css deleted file mode 100644 index f1e28c5..0000000 --- a/plugins/kimchi/ui/css/theme-default/template_add.css +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -.page-list { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - overflow: hidden; -} - -.page { - position: absolute; - left: 100%; - width: 100%; - height: 100%; - overflow: auto; -} - -.page>header { - position: relative; - overflow: hidden; -} - -.button-group { - margin-left: 5px; -} - -.back { - float: left; display : block; - width: 50px; - height: 52px; - background: url(../images/theme-default/icon-back.png) center - center no-repeat; - cursor: pointer; - display: block; -} - -.step-title { - color: #333; - font-size: 18px; - font-weight: normal; - padding: 15px 10px; -} - -.step-choose>li>a { - display: block; - margin: 0 10px 10px; - padding: 20px 10px 20px 65px; - border: 2px solid #ccc; - background: url(../images/theme-default/icon-local.png) 15px - center no-repeat; - cursor: pointer; -} - -.step-choose>li>a.local { - background-image: url(../images/theme-default/icon-local.png); -} - -.step-choose>li>a.remote { - background-image: url(../images/theme-default/icon-remote.png); -} - -.step-choose>li>a:HOVER { - border: 2px solid #06C; -} - -.step-subtitle { - font-size: 16px; - height: 48px; - line-height: 48px; - color: #06C; - margin: 0 10px; - font-weight: bold; - text-shadow: -1px -1px 1px #eaeaea, 1px 1px 1px #fff; -} - -.custom-iso-field { - position: relative; - padding: 0 10px 10px; -} - -.custom-iso-field>.input-wrapper { - margin-right: 110px; -} - -.custom-iso-field>.input-wrapper>input.text { - padding: 10px; - color: #333; - font-size: 13px; - background: #fff; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; - box-shadow: 2px 2px 2px #eee inset; - border-top: 1px solid #bbb; - border-left: 1px solid #bbb; - width: 100%; -} - -.custom-iso-field>button { - position: absolute; - top: -6px; - right: 8px; -} - -.iso-field .button-field { - padding: 0 20px; - text-align: right; -} - -.check-all { - display: inline-block; - position: relative; - height: 38px; - line-height: 38px; - margin: 5px; - font-size: 13px; -} - -.check-all input { - margin: 0 5px 0 0; -} - -.box { - background: #ffffff; - background: -moz-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: -webkit-gradient(linear, left top, left bottom, - color-stop(0%, #ffffff), color-stop(100%, #e5e5e5)); - background: -webkit-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: -o-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: -ms-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: linear-gradient(to bottom, #ffffff 0%, #e5e5e5 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', - endColorstr='#e5e5e5', GradientType=0); - border: 1px solid #ccc; - color: #333; - text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; - -webkit-border-radius: 8px; - -moz-border-radius: 8px; - border-radius: 8px; -} - -.box:HOVER { - border: 1px solid #aaa; - -webkit-box-shadow: #bbb 0px 0px 5px; - box-shadow: #bbb 0px 0px 5px; -} - -.box-iso { - padding: 10px; - margin: 5px; - overflow: hidden; -} - -.iso-icon { - float: left; - width: 58px; - height: 58px; - margin: 0 5px 0 0; - border: 1px solid #CCCCCC; - border-radius: 8px; - background: url(../images/icon-vm.png) center center no-repeat; - background-size: 58px; -} - -.iso-icon.centos { - background-image: url(../images/icon-centos.png); -} - -.iso-icon.debian { - background-image: url(../images/icon-debian.png); -} - -.iso-icon.fedora { - background-image: url(../images/icon-fedora.png); -} - -.iso-icon.opensuse { - background-image: url(../images/icon-opensuse.png); -} - -.iso-icon.ubuntu { - background-image: url(../images/icon-ubuntu.png); -} - -.iso-icon.gentoo { - background-image: url(../images/icon-gentoo.png); -} - -.list-iso { - overflow: hidden; - margin: 5px; -} - -.list-iso li { - float: left; - width: 320px; -} - -.list-iso>li>label { - display: block; - cursor: pointer; -} - -.list-iso>li>label>input[type="checkbox"] { - display: none; -} - -.list-iso>li>label>input[type="checkbox"]:CHECKED+.box-iso { - border: 1px solid rgb(11, 107, 173); - -webkit-box-shadow: rgb(11, 107, 173) 0px 0px 4px; - box-shadow: rgb(11, 107, 173) 0px 0px 4px; -} - -.iso-title { - margin: 0; - display: block; - position: relative; - height: 23px; - line-height: 23px; - font-size: 14px; - font-weight: normal; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.iso-title>label>input { - display: block; - position: absolute; - top: 0; - right: 2px; -} - -.iso-info { - margin-top: 5px; - overflow: hidden; -} - -.iso-info-col { - float: left; - width: 50%; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0 0 0 5px; -} - -.iso-info-col:FIRST-CHILD { - padding: 0 5px 0 0; - border-right: 1px solid #999; -} - -.iso-info-item { - font-weight: bold; - color: #999; - font-size: 11px; - line-height: 18px; - max-width: 106px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -#iso-search { - margin: 10px 15px; -} - -#iso-search-loading { - margin: 10px 15px; - background: #C0C0C0 url(../images/theme-default/loading.gif) 7px - center no-repeat; - padding: 0 20px 0 26px; -} - -#iso-more-loading { - background: #C0C0C0 url(../images/theme-default/loading.gif) 7px - center no-repeat; - padding: 0 20px 0 26px; -} - -#vm-image-local-box .body { - margin: 30px 0 0 26px; -} - -#vm-image-local-box .body input { - background: none repeat scroll 0 0 #FFFFFF; - border-left: 1px solid #BBBBBB; - border-radius: 5px 5px 5px 5px; - border-top: 1px solid #BBBBBB; - box-shadow: 2px 2px 2px #EEEEEE inset; - color: #333333; - font-size: 13px; - padding: 10px; - margin-left: 10px; - width: 600px; -} - -#vm-image-local-box .body button { - margin-left: 10px; -} diff --git a/plugins/kimchi/ui/css/theme-default/template_list.css b/plugins/kimchi/ui/css/theme-default/template_list.css deleted file mode 100644 index 3161a33..0000000 --- a/plugins/kimchi/ui/css/theme-default/template_list.css +++ /dev/null @@ -1,267 +0,0 @@ -/* -* Project Kimchi -* -* Copyright IBM, Corp. 2013-2014 -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -.list-template.framework { - float: left; - clear: both; -} - -.template-box { - border-radius: 8px 8px 8px 8px; - box-shadow: none; - color: #666666; - float: left; - height: auto; - margin: 10px 11px 10px 0; - padding: 10px; - width: 308px; -} - -.template-title { - font-size: 16px; - height: 25px; - line-height: 25px; -} - -.template-icon { - border: 1px solid #CCCCCC; - border-radius: 8px 8px 8px 8px; - height: 58px; - margin: 0 10px 10px 0; - width: 48px; -} - -.template-icon img { - width: 58px; -} - -.template-text { - color: #999999; - float: left; - font-size: 11px; - font-weight: bold; - height: 18px; - line-height: 18px; - width: 142px; - display: table; -} - -.white-box { - background: #ffffff; - background: -moz-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: -webkit-gradient(linear, left top, left bottom, - color-stop(0%, #ffffff), color-stop(100%, #e5e5e5)); - background: -webkit-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: -o-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: -ms-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); - background: linear-gradient(to bottom, #ffffff 0%, #e5e5e5 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', - endColorstr='#e5e5e5', GradientType=0); - border: 1px solid #CCCCCC; - color: #333333; - text-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #FFFFFF; -} - -.row-select { - -moz-border-bottom-colors: none; - -moz-border-left-colors: none; - -moz-border-right-colors: none; - -moz-border-top-colors: none; - background: linear-gradient(to bottom, #FFFFFF 0%, #E5E5E5 100%) repeat - scroll 0 0 transparent; - border-color: #999999 #AAAAAA #AAAAAA #999999; - border-image: none; - border-radius: 5px 5px 5px 5px; - border-right: 1px solid #AAAAAA; - border-style: solid; - border-width: 1px; - float: left; - font-size: 13px; - height: 42px; - line-height: 42px; - margin: 5px 0 0 10px; - padding-left: 10px; - text-align: left; - text-shadow: -1px -1px 1px #AAAAAA, 1px 1px 1px #FFFFFF; - width: 100px; -} - -.bevel3 { - box-shadow: -2px -2px 2px #EAEAEA, 2px 2px 2px #FFFFFF, 3px 3px 3px white - inset, -3px -3px 3px rgba(0, 0, 0, 0.25) inset; - color: #333333; -} - -.row-drop { - left: 10px; - position: relative; - top: 50px; -} - -.template-action-hidden { - visibility: hidden; -} - -.template-action-show { - visibility: visible; - display: block; -} - -template-hidden { - display: none; -} - -.select-drop { - background: none repeat scroll 0 0 #EEEEEE; - border: 2px solid #096AAD; - border-radius: 5px 5px 5px 5px; - box-shadow: 6px 6px 6px; - height: 147px; - left: 0; - position: absolute; - top: 8px; - width: 250px; - z-index: 2147483647; -} - -.button-drop { - background: linear-gradient(to bottom, #EEEEEE 0%, #CCCCCC 10px, #CCCCCC - 96%, #A5A5A5 100%) repeat scroll 0 0 transparent; -} - -.action-bevel { - box-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #EEEEEE; -} - -.template-border { - border: 1px solid rgb(204, 204, 204); -} - -.template-button-position { - position: relative; - left: 250px; - top: 55px; - z-index: 5555; -} - -.tempate-action-position { - float: right; - width: 83px; - margin: 0; -} - -.template-actiontext-position { - width: 250px; - height: 160px; -} - -.template-line { - left: 200px; -} - -.template-os-position { - padding-right: 10px; - clear: both; - width: 142px; - border-right: 1px solid #999; - float: left; -} - -.template-cpu-position { - border-left: 1px solid #eee; - padding-left: 10px; - float: left; - width: 132px; -} - -.template-icon-position { - float: left; - height: 58px; - width: 58px; -} - -.template-icon img.template-type-icon-position { - width: 20px; - height: 20px; - position: relative; - top: -15px; - left: 49px; -} - -.template-title-position { - float: left; - width: 120px; -} - -.template-results { - background: linear-gradient(to bottom, #FFFFFF 35px, rgba(255, 255, 255, 0) - 100%) repeat scroll 0 0 transparent; - float: left; - height: 60px; - margin-bottom: -22px; - padding-left: 10px; - width: 1014px; -} - -.select-row-action { - background: linear-gradient(to bottom, #FFFFFF 0%, #E5E5E5 100%) repeat - scroll 0 0 transparent; - border: 1px solid #CCCCCC; - border-radius: 5px 5px 5px 5px; - float: left; - font-size: 13px; - height: 38px; - line-height: 38px; - margin: 10px 10px 0; - text-align: center; - text-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #FFFFFF; - width: 230px; -} - -.select-row-delete { - background: linear-gradient(to bottom, #FF3019 0%, #CF0404 100%) repeat - scroll 0 0 transparent; - border: 1px solid #B10F14; - border-radius: 5px 5px 5px 5px; - color: #FFFFFF; - float: left; - font-size: 13px; - font-weight: bold; - height: 38px; - line-height: 38px; - margin: 10px 10px 0; - text-align: center; - text-shadow: -1px -1px 1px #9E0505, 1px 1px 1px #FC5D4C; - width: 230px; -} - -.template-general .title { - color: black; - font-size: 16px; - font-weight: normal; - height: 25px; - line-height: 25px; - text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; - max-width: 130px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.processing { - cursor: wait; -} diff --git a/plugins/kimchi/ui/images/Makefile.am b/plugins/kimchi/ui/images/Makefile.am deleted file mode 100644 index ca3ee6e..0000000 --- a/plugins/kimchi/ui/images/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2013 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -SUBDIRS = theme-default - -imagedir = $(datadir)/wok/plugins/kimchi/ui/images - -dist_image_DATA = *.png diff --git a/plugins/kimchi/ui/images/icon-centos.png b/plugins/kimchi/ui/images/icon-centos.png deleted file mode 100644 index 5afb7b4b63462412d825f63542beb1f7e26b3d7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4734 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 M07*qoM6N<$f~4IfuK)l5 diff --git a/plugins/kimchi/ui/images/icon-debian.png b/plugins/kimchi/ui/images/icon-debian.png deleted file mode 100644 index ff49a39696fdfa5f232b0e79de04d90af6557111..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4239 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 D^V29c diff --git a/plugins/kimchi/ui/images/icon-fedora.png b/plugins/kimchi/ui/images/icon-fedora.png deleted file mode 100644 index 7b9dd06d1f766a3285cd0fb587c0be4114bfac47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4449 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 S9$oyI0D9VncWN{pBmW0TFKp8Q diff --git a/plugins/kimchi/ui/images/icon-gentoo.png b/plugins/kimchi/ui/images/icon-gentoo.png deleted file mode 100644 index 50d928fbfa30560fe873cf3de438a8f0c10a8f96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15307 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 diff --git a/plugins/kimchi/ui/images/icon-opensuse.png b/plugins/kimchi/ui/images/icon-opensuse.png deleted file mode 100644 index 83fe4d5df0f59b52dd609b3bd16838f4d2570ab8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3046 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 diff --git a/plugins/kimchi/ui/images/icon-ubuntu.png b/plugins/kimchi/ui/images/icon-ubuntu.png deleted file mode 100644 index d92c00f357b6b0e1542413f6aaf0de8ef4b8d130..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4818 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 T?|XFr3GiA;OR-Yk^22`sn~zF< diff --git a/plugins/kimchi/ui/images/icon-vm.png b/plugins/kimchi/ui/images/icon-vm.png deleted file mode 100644 index 50dac50c5a0ee59f4e79170434f53bb3b94390e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2976 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 diff --git a/plugins/kimchi/ui/images/theme-default/Makefile.am b/plugins/kimchi/ui/images/theme-default/Makefile.am deleted file mode 100644 index 7e11d75..0000000 --- a/plugins/kimchi/ui/images/theme-default/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2013 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -imagedir = $(datadir)/wok/plugins/kimchi/ui/images/theme-default - -dist_image_DATA = *.png *.gif diff --git a/plugins/kimchi/ui/images/theme-default/ac22_pause.png b/plugins/kimchi/ui/images/theme-default/ac22_pause.png deleted file mode 100644 index 9258aee87f0e2f430cf1fb12a4588f763f3c0a62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1219 zcmbVMO>Em#9CtTbM!QYZ3R7EwV!5LOiP*7Yo5gCV96yIfTDmTcw6Ieh`=v3h{fzyx zq`hSAssY^&+X3-;7(IbDF^V*#0ostNNpJ&chiPJ(*f=3gfS^*?io$c-6b{vpux!5% z|9-#!$NT^N=IF@FyE^+iDT>;a83s8r_K~M&M+bTTG<W|x8G5l^z+<R{tA-CL)j~x` zXB=Y!=AdCszxFL0q^RvBJ72(s>><TO4r_!Mw&r+*O;LkGHP0|7A*PFP!giC)FJE3` zXxmCMN2P2m>uIoT56}2;Y-S{H&P<vKiy3-}9;_)uz=7DHYtED#D77TBrmK*7xXm&2 z8U#-!nRTZM*-=_UKBOf!9yMb;Ps=jPi;^t!FVI4a7q}R?<tQ&IlB@_X(i;~;toc?+ z$$|8SEwV~7WsE(A<EqsvTaB~GpWygJA`xl`LX;q)!L*BwTGS2tTM7UMrf+-LMlKyH z8bwsWNrrg39)ja#vzx+hu#qT|GOlKL9M8r$#|h(FLkBnq|8ZkWbdaC+AeVyys`w^3 zk5Ye&Omg>VLm`lOqa5~aawx_WKxV~(F3x}?L%y(<Z7H#MN&~u_5<ptiMV?RbaS4!> zrVD8v@O(>SE3PK#KozA#S`-LU7gZ6cs;KfBkmKouAhfs{H^7E#!j@f|*xleBd?Z)V zd}v_g=MkD}RlsN&VHA{+M{8p;{oGO8wNN#9K0KcFXaV%?<Iqa`$f4KrtJquEkBR>k z_d3`5KRM%wGhA34|0<T&7OB8+x>@>UvDrM(B^~3F);Mrp0;H{e&j2-FyH#9mHixz+ zsjfH1Eo=U_E3<{C2X?pDPc)w0Q`h${U)cTry;r_#-0i-(^1+#R+i$(o+oLyy)rrPR zGqQa6RQ*y<Z%_B&waD#}Gs^kZ<Eed1jiuqwm$peKfB56{kCElaPu<xWX*Tygy#8yQ z9UWc(m4ngZo|4tA&$sX2aW%f${zc=`{>0DYC!VN3CJ3Lly+xgTeKuD)G@tA0Klky% zS!JL@nLTnk9qqeZzOi_&{C$L3`Rl_Qi*JAZ>Yq=2M&<4|=XMg!2b~wc+G{MR(t(fO w>*#y%<Tu#??U}`^+b$Q*9#iveH;<`QTL-02da<sDMK=7cWb_g6NosuVZ*kO>5C8xG diff --git a/plugins/kimchi/ui/images/theme-default/ac22_pause_grey.png b/plugins/kimchi/ui/images/theme-default/ac22_pause_grey.png deleted file mode 100644 index 7cde85bcb26ca808b9b02d5336872f10556585a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1175 zcmbVMUue{J98c{SYPo?ZqV0n};)|2JOMXc%y~}#Gy(HIO+0}Br&chc?lV97|CciBC z)w`CVuHZZen`;>q!NH~v?x9Y7Dzb+TRHmS);FB+cii#l4hoNGz{?hikJroBENq)cY zFW=AS`#;Bfx;rB48`m=o6UlXI1-drUXUp1;>HE>d^Q&~(O7s%x#RH^l_=st@a6bY$ z#~4HfWLRTgUPmnqQ$JuAOQe+lTrsf|H$t6w#qlVbVOm-%o?#9n0{YRQ?WWlmzt6G2 zw$kjLM4r!kDjKpo$9>d0-d!}uhs~75w(bHg6@?Nwh!~*ajJSbPNwbT*3f+gt919jz z$Z(ona;lW?0V?(pNW{gM$wLTaIS!?SEW;=ecqni@z2z8`l!UAZ&0zUrsWsmkPzqXh z*%p=3><}TI!g1wtIbIgy*dOFzDwPU31R+K>V!@b8j7rQ6w$~Um6qvs45gWT8WHkEm zC`q%_)1?p`FP~o_c7x?a(Ufr&!{cC_=Nu=DYf(EO1@w;_t7-?uF%NMC6yQ<cr1cos zUIWwIeb`W_NWD>Z`!+3#F`{8})Il!EX=#>ziCea%@M1>QbU7nvSxJ{5%s?@rQAyQ> zEYu*Zajb?-3eBR(C#7sshY;#gQphxC+ck+-)ufnJ#Tqu}2E=epRI_VSyUSSdgIGoN zkwLIu#CW9E0X;*Q;9v-QK<$;mjy<+(;d1b4Se~V5HRRg|k(Kqa0~YhE*sIv*rT>b1 z32XhIoN?3{E^Ll}HB0S?c3`+&X?-fJ3=eYY#Q1bH&XxYUOvmcaoYr2f-0PoTSZJ+J zGaKuFVj6^FlarIb%*@=_c<offl__vP^D+Rfmu6?npH+9yD5o}m%``PNmBebKF#qJ% zwr}PRFLb?o`wG|fbgrw;O`ZPatR9U<r+E2BU)xQvuUdEVLEBd+HjQdmH|(hH-!gr< z+Sf6Ag+FlTSN+W9@AgUu?sylUrsSi4bUlxpeCF-_aZPc)@rz)Bzwqs$H?Lnl-1+nE zZNlC5ogI&|9~C0kBj>)K9Pawz@pRkY`;PY=8`;oyq>edy=*0QyXoDR7Dsp<a_FHEE F#Cyajgunm* diff --git a/plugins/kimchi/ui/images/theme-default/ac24_resume.png b/plugins/kimchi/ui/images/theme-default/ac24_resume.png deleted file mode 100644 index 6f1f16f52f2c000a7413e22a0105c5d0b09c7a2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1341 zcmeAS@N?(olHy`uVBq!ia0vp^Qa~)h!3HFsG`&3vq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FfgZOhD4M^`1)8S=jZArg4F0$<Q4#RGcefLR}>^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&iz}FXUa9%MqpnyT9Uy)d#Z>VRWpPLKv7g%+1Nl+@n8CX>phg24%>IbD3 z=a&{G1LGr28KxN+cK9s<DFnL4%D*TR7%7Q4F8Rr&xv6<2o-VdZKpDN1%oHmVGXql# zXG>!vb2k%L6GKBMLt|4HCnFbUS0gt=7ehms8QAn18<-kc7?=Qc8Ua<hnpheen>)I> zSh!jkI9dYZ2Bz0Duec;JFF6%vZzj-Qs9rO?daay`QWHz^i$e1Ab6_bTAS1sdzc?em zK*2fKOhF?&GcP5-yjT+yJrLizq!wkCrKY$Q<>xAZ!`CVki~T0%g!~QBn?g>Q=>r|3 z4@w+Ji3KJEOo1RKJm~{D@XV8%2h1@=z^w7aYe@nF17ohIi(^Q|tu52`dL3~PIG%1+ z{qdYj)BS{nN)a4Uzgfz@U5|{==-~Rr(X?J+hS&Y0>>I9~a|+n7!)e0@qjPDSCqysa zelqu;f#OV^&$nmJ^%d*n=n)W<QMqBXLNn7=f3xbe`~%;@s_sSHJo4k~OgVK%Rrc$T zR+%%`o}PbiUixvh#eaiq9=uWhwou#SM&C=8Uq&o5x)^q~e*7C)>7$^?RXt(u(xzEy zOPU;}B=89}ep{<6u&4Nh>w+5DRCa}Vt_$zQ-(mgo)$`M{6pJ-XGfMySzIu_fqb8xM zIo&>rjjbj2?e)nA^GjETTIn!NmEN#PGO#~*Y439ez4xkDnXXRN&Pke}eTMr4>oZ;x zKDC3Jd3;tjEd1V+bK{)Y%G$QIDJfg_xop@z_u<1l?(CE;R_hhlnjVf9c&{M6XkYI= z$N!Fd8jm^dX^2q>UEnA^L2H7Q^pY(86$;1V><mnqe;9lYxu>o-;m`U@4@9nbC@(Pk bs(gUqpHO<9rrQcmP=V&@>gTe~DWM4fDsR{! diff --git a/plugins/kimchi/ui/images/theme-default/ac24_resume_grey.png b/plugins/kimchi/ui/images/theme-default/ac24_resume_grey.png deleted file mode 100644 index 1714ba2d00294e99222f833b8cf5e33da31448f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1282 zcmeAS@N?(olHy`uVBq!ia0vp^Qa~)h!3HFsG`&3vq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FfgZOhD4M^`1)8S=jZArg4F0$<Q4#RGcefLR}>^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&iz}FXUa9%MqpnyT9Uy)d#Z>VRWpPLKv7g%+1Nl+@n8CX>phg24%>IbD3 z=a&{G1LGr28KxN+cK9s<DFnL4%D*TR7%7Q4F8Rr&xv6<2o-VdZKpDN1%oHmVGXql# zXG>!vb2k%L6GKBMLt|4HCnFbUS0gt=7ehms8QAn1xSBb;n7f#|S-2V*8oHV|I=Y#< zS~!~;n_HL~7+4y?^m^tMmn7yTr^4*b1lkMLYl2s=m2**QVo82cNPd0}ECmE)<d@_Z zXXF<sI0u_4XoP3xrR0|vYl5N&;#-&0qRg_?6t|-MTm^9WT4iFf-^84dzae^4$O$uj zpkwqwi32IIz=VJ)5X6KheIN&(c~bL$Ii?7hH7ag6?Pg$LH1c$D45_%aXWGTy76pMe z#*54EzIj}xurI?=?19(<x7iySHaBM<W7^hSeW!Y#j`idYMV)ys4*D7$JRonE*5IhM zRONpX$ECYRU+uDc`!t~V)3Qvv1uJ>(TJRk9Wv+EDZnJyEl{9T%m!aDtjZ3lzucwwy zndkU9=XRJJn_^3`-z1gDJsMmxyH<Q*>Nrw(reMu$E6&J{ZI{m9FXEiM!sA2qLEql4 zs%w7|zTdl|J2^M+!yb)}zAv@<{Ec(`CoA{--l4?RW_EbR_l}&24;eYxZZ#R+pPI&d z%xQ`#>*>!j(GTAm-0<OWJhe&0QQ7NqNc)}Uh8%(S3rsu0FXRj4E66fk{VliT+D?am zJVmW*?k+Ywy~(S-d0FN!6W0ZWZ4v(^pOtgWf7`vVwxRwd<J#Omaudp{ISm*X#7kc9 TIKK2Js8sTF^>bP0l+XkKJo~{m diff --git a/plugins/kimchi/ui/images/theme-default/arrow-down-black.png b/plugins/kimchi/ui/images/theme-default/arrow-down-black.png deleted file mode 100644 index 2c05f00498232213a081497051c94d16537daab8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2942 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 diff --git a/plugins/kimchi/ui/images/theme-default/arrow-down-disable.png b/plugins/kimchi/ui/images/theme-default/arrow-down-disable.png deleted file mode 100644 index 2d04c841780fa57153d4a73f3bee69824f6efb57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 472 zcmV;}0Vn>6P)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B00004b3#c}2nYxW zd<bNS0004xNkl<ZIE~%Wzi-W99L4e1`D&V|3LS(5xxKfOSt3TG2s0reX(TMQ_!VNZ zh#xUYy4w5!VnqmI7D4*Gx9xXeu`;OkG58Xc5{txVd6FmRyg%nW5C821>bed}RaJVu z-XEK1W@bjQKFOP^uIrRiwwF?NFD@>w`cp_<*TXo4o7h=lGtOZe`|G;?Ev(<~594T( zsU*8_bqJG5_F)J&FwyV#r}1`TV&Z3z5gcomk6{7tsw5ARJWBF0$yk!pxP+}gLS|=Y zD@@`{k_|}~lH5)*RpB8{;0~6s7Kd?pFc^G=4F-d%l(IL;xg?vCXak&2@+z$eMsNj( zunvoOf(uEWmQoJlV*92Gcz`2#-Rt!}fB!epM{yie-&A{vTWzIrd}!03$IEWF3*UoU z*c$A?b!=&`-(z*FzuPW)(d~B27vC}v%+1XOJ8-Q%hub=j+dA{(<Ky3XehPy5`T1ZQ zPT~OW;VhnaI-O<uUxJ`%8l{wtE$BX;bvm7;l{_m>(==7nG=J^?H}eT{w|+~olSG{W O0000<MNUMnLSTa0@YLi0 diff --git a/plugins/kimchi/ui/images/theme-default/arrow-down.png b/plugins/kimchi/ui/images/theme-default/arrow-down.png deleted file mode 100644 index 3f5239bbb93ad8660f47d3def443e42b8f57c6e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 537 zcmV+!0_OdRP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B00004b3#c}2nYxW zd<bNS0005dNkl<ZIE~$sze^Nw7>A$d6~#>G7g3=>Q#G^&cL#z*Q$%}FLnMWF=;0ky z&|yo<#f2xjw6^sJL}L+>rbk<lQf`6m4I+8ox1kd>!=xqXGrqjf!~62S@ZUy&d_HeP zq|VMxrlzL$3=a<v_W}piuaVE^O(~t<*x0zVwzk%>S4p8z=mPEn&wyM2ed+_?sd}|g zDEv`2GBVPo-j0Z3L|jmxbYwD_l6og14yzZ{&P*orF`Lb<HX4l`lF`x89-yE;RF9}l zbve`-b+%nN6cP8-Dsb{wNx57Obtoe4t4Gy!^@UpO$Y!%&)b|n5ubx)BBjTLem&@fE z3kwV107|7&q?E1zkJS?@?IFtQCjrLB#sGR!N;UNca6sJv-T~w4LQ3g6@CfJw)`1z| zW~<d&nVz2hdHyY<_X2sKxVf6T1Uv_ZQc9<Q@4!o-0xV5VP6BKfwPpJw;xbSN`rGAI zU|+lcHBd|`E!OMxw8`x__5A$&`oO@zVnocUXCvZxM07_)Q+=!60+uHxCbn_E{h7JB zIR*y@SJZj6S3RS?Qp*wXxmK&~V0NswHRI#sG@H$1z%}5F`k`8_wsvE7O{G$aN~QAG b{J+T$+X03p_V~Q~00000NkvXXu0mjf`lS0g diff --git a/plugins/kimchi/ui/images/theme-default/arrow-up.png b/plugins/kimchi/ui/images/theme-default/arrow-up.png deleted file mode 100644 index 40ce708941a35d8e1578e3cafb13d330fcf37c10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 510 zcmV<a0RjGrP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B00004b3#c}2nYxW zd<bNS0005CNkl<ZIE~$rJ!?~O6vlt&78gOQf)-b$iZ2KSmn<r{=pcRoKR^>nFL|-K z<P!wcpd?CfHn&cG04E2BSc>ALR0_q4C<tzXLwz0xuM%P+9mQw+bI$X7&N+YhZxw$l zw%cuhqd)?D=yW<$dy{E}EXzXDIorAIN0Jt@ESnlU6=eH_?XILNk}lfr+Foe2S`+*K zNN6^jGZAqXSOrdwgb8>L+_1gY?RIxYeKVtvMx(I@xN7?WaJqnO0H1(4;DGH5z`IhZ zv^5+KzfWAv_T^%QGm=8mhNNXlHA$}}Vf&cvySA^_>-FFM07%nxFK`XWfmt9TVjW16 zBv}KHbRM`}OccO3AO%)?z24WTR;&AgMW7iGM~Z-T;AX$ye=$07nx?00KLjoTVfzbk z2gnoK%eGs#=OiKNne7_za{MEDz1|z!4M|TW+4iBrpCyv!CC%!mp4eWr{k-4rdmL2U z@s;he?Z=XKB<+(lALVlSxb1s@BVsAf^X*B1aaAgn!;<a;2P2}E09!x<ShBq<2*Aq9 z%4gsfPy;rTJkJGe0^5VZV7HuK`Ut!&82^}l07Tsjb=)@&!~g&Q07*qoM6N<$f&;VO AtpET3 diff --git a/plugins/kimchi/ui/images/theme-default/arrow_out.png b/plugins/kimchi/ui/images/theme-default/arrow_out.png deleted file mode 100644 index f5b4b8ed7de68dc79673472aab7c9672233bc8a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3048 zcmV<E3m5c>P)<h;3K|Lk000e1NJLTq000jF003YJ1^@s6!gMIb00009a7bBm000XU z000XU0RWnu7ytkYPiaF#P*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-oy)XH-+^7Crag z^g>IBfRsybQWXdwQbLP>6p<z>Aqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uh<iVD~V z<RPMtgQJLw%KPDaqifc@_vX$1wbwr9tn;0-&j-K=43<bUQ8j=JsX`tR;Dg7+#^K~H zK!FM*Z~zbpvt%K2{UZSY_<lS*D<Z%Lz5oGu(+dayz)hRLFdT>f59&ghTmgWD0l;*T zI7<kC6aYYajzXpYKt=(8otP$50H6c_V9R4-;{Z@C0AMG7=F<Rxo%or10RUT+Ar%3j zkpLhQWr#!oXgdI`&sK^>09Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-<?i z0%4j!F2Z@488U%158(66005wo6%pWr^Zj_v4zAA5HjcIqUoGmt2LB>rV&nehQ1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_<lS*MWK+n+1cgf z<k(8YLR(?VSAG6x!e78w{cQPuJpA|d;J)G{fihizM+Erb!p!tcr5w+a34~(Y=8s4G zw+sLL9n&JjNn*KJDiq^U5^;`1nvC-@r6P$!k}1U{(*I=Q-z@tBKHoI}uxdU5dyy@u zU1J0GOD7Ombim^G008p4Z^6_k2m^p<gW=D2|L;HjN1!DDfM!XOaR2~bL?kX$%CkSm z2mk;?pn)o|K^yeJ7%adB9Ki+L!3+FgHiSYX#KJ-lLJDMn9CBbOtb#%)hRv`YDqt_v zKpix|QD}yfa1JiQRk#j4a1Z)n2%f<xynzV>LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_Ifq<Ex{*7`05XF7hP+2Hl!3BQJ=6@fL%FCo z8iYoo3(#bAF`ADSpqtQgv>H8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ<AYmRsNLWl*PS{AOARHt#5!wki2?K;t z!Y3k=s7tgax)J%r7-BLphge7~Bi0g+6E6^Zh(p9TBoc{3GAFr^0!gu?RMHaCM$&Fl zBk3%un>0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 z<uv66WtcKSRim0x-Ke2d5jBrmLam{;Qm;{ms1r1GnmNsb7D-E`t)i9F8fX`2_i3-_ zbh;7Ul^#x)&{xvS=|||7=mYe33=M`AgU5(xC>fg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vF<Q0r40Q)j6=sE4X&sBct1q<&fbi3VB2Ov6t@q*0);U*o*SAPZv|vv@2aYYnT0 zb%8a+Cb7-ge0D0knEf5Qi#@8Tp*ce{N;6lpQuCB%KL_KOarm5cP6_8Ir<e17iry6O zDdH&`rZh~sF=bq9s+O0QSgS~@QL9Jmy*94xr=6y~MY~!1fet~(N+(<=M`w@D1)b+p z*;C!83a1uLJv#NSE~;y#8=<>IcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a<fJbF^|4I#xQ~n$Dc= zKYhjYmgz5NSkDm8*fZm{6U!;YX`NG>(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-k<Mujg;0Lz*3buG=3$G&ehepthlN*$KaOySSQ^nWmo<0M+(UEUMEXRQ zMBbZcF;6+KElM>iKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BK<z=<L*0kfKU@CX*zeqbYQT4(^U>T#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot<a{81DF0~rvGr5Xr~8u`lav1h z1DNytV>2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0003KNkl<Zc-rjPy=ucS6o%nfjYQFsL4y`Up|{ngV{Xx_Z@^RUpit=64z(dod%7qP zJC1#vLWgn$#=`RR`A^nxoQQC3yWtnjA3M&uSh@$`3;3RcA~LvgsO!1|0<h8C)!+p0 zJx$Ym6ucO4Iw&zla?Z4E+iL;_10e)bN>o*)3OGCHy;lcJCTasNK943~_H9lCNZE8V zY!vV*B6lJZ2Qy3)kaK<jD&P(1)pOf>zXLkp73kOe7`uX=fM@62UW+H82493{b9)UO z<HH&_{#1K_l+q*cz61f>$r`o=?#upV35v)7-vY;_sGEaR_-|KF!-fqTHf-3iVZ(+E q|3_?f604I~oy6)SRwucp{R{vP7|{U{#BK5b0000<MNUMnLSTa7ET*pj diff --git a/plugins/kimchi/ui/images/theme-default/group.png b/plugins/kimchi/ui/images/theme-default/group.png deleted file mode 100644 index 1160bd97178375f202c3c20fef689ddf4a6dcfae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1703 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 diff --git a/plugins/kimchi/ui/images/theme-default/host-icon-sprite.png b/plugins/kimchi/ui/images/theme-default/host-icon-sprite.png deleted file mode 100644 index da1cd3f2562a5905a526446bcc8fc18bea06c734..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1034 zcmV+l1oiugP)<h;3K|Lk000e1NJLTq003?P000^Y1^@s6R_JLg00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3t>283nlSO%wnC03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00VAGL_t(&-tAexPZU8E z{`PW&1_K4^OH?eZvAftnL5(5A#KOeLoryLc6xvbn7idfrLqY*-qLqe%L|Ypgg$i36 z(dbjkBSwPpvl)`j+}`fa-u^(2muzw~^LF01^X{8@Zysm_jzUN2Fh`A~Pjc5hKFL~I z+Z}W#NVXC{Y>}KuY7;pNNspw5tO0f7IFeP8D-r4|QCJ)u*CII!fKd<0S(2@?9Y=DD z<R_9!@=PZG-V7bLl9r_@9LG4P1)Rq+9Y?Z{<af)|`7qr|9MBxV)c`acbbCfT&pQC{ z%j$mX<hUFic+YA-2XN6mak_;`9K$+|XK?mUTkTPj&CIsEF5cU<hDHKoBi7iJvbM^i z*Tus8!czN9a>$8s1<N-8RRC8_`$GnE?vb2Jz_2+0dq-p)ngI3#?S24@sTh|bQ+;d5 zH%uEL`5>TIAzA4bYua?6Ovagcnjz|Ai5Da5sM6$aQ8E^l$E3xZb^24#IlFC{{Sv!X zdPZ`HoHhZhMyRZj95%WP!xe@3m<5`5?4yL_;89M%??>JmIN;83>nfaa#_lVU`y{Vr z67H9I<>i9?7&xxqKI>29L{6meTNYI%0Emdw!G8E&QVE-1Rcq#UWYToK0q{&jHq+Sd zU}FNnI)H(=d=J2sh`dW;({;UEMO8gxC-hsZHn6+_8Cz8V%OQ7`GXQ2(brnD(BP{Cx z=6&CP5~WnH*XNDysWO?Qs#^et%pdJCfS-x(Dpi%PY)T=^F&E8^3~dd>ISl}e&Opgd z>jQ8Oz$E}@0sK%^x9UJ%4m8_i!$G%aL_`u-2dYWWvJAJ-u<F2q`TaRWw_eh}pDyEv z>yyFRKMi0z&>mIQrid&iVqA_4oV3~tBC;bQJ7_QMEcIHnC?X#LytKL>s%r052kP~D zY<0ls{5RDBFDZ*`N~hftRMj`pW7t-CT|^!ky^4A7udB@<*0kwB7vI-)nq=l_0(fe5 zkBi7gBF9Bcoc6<NF-#g4k&RAyOj^9%=3_<YamMC0fYCtLR}r}oxmAjYmj^hLTt`+1 zRCTyh@)?Dxh{Y^e+NuMpIv5&N7WDCVBl5M=0B!+z9Oa;-3`iRt9+5!hy{f(jFa_X- zh^)1x14RNBkv{-#tLjpkD=*u5$B=13xe4GPc-8~JKL<=Y@!??g0{{R307*qoM6N<$ Ef;%S0RsaA1 diff --git a/plugins/kimchi/ui/images/theme-default/icon-back.png b/plugins/kimchi/ui/images/theme-default/icon-back.png deleted file mode 100644 index eca9948ca7f0c4eaa3c36d20e4fb2d72ac79b2d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ-JULvArbCxuSRn<C<w3y#71eK zT)K72v}tTjuGj8VdL~>5@BMC(b=2TTSM%q?EFRVyo~rsxN}a;s^<!54Nr^X)q~g@x z^JN^q%lN$@{6O#y=>_6_at*5DZ*m1wnKN6b$4D%Y<YV4)Sh2y?LNY=0pS;7ws8U8N zRxu8ago~UK3wje6O$2ieNH=}5eE-k*!lQ-zA6s=>GtE7+RQk>%v4gUYTRgh7os8Nz s0?gB1y)!t(JaL}EzvtS*278#<8D&)ztBkXBf!<*7boFyt=akR{0KU{)8UO$Q diff --git a/plugins/kimchi/ui/images/theme-default/icon-camera.png b/plugins/kimchi/ui/images/theme-default/icon-camera.png deleted file mode 100644 index f181545ed44db658aa6373c28ca33724f84a3d05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4860 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 diff --git a/plugins/kimchi/ui/images/theme-default/icon-design.png b/plugins/kimchi/ui/images/theme-default/icon-design.png deleted file mode 100644 index c8931dae58e4d3d95d7a1ebba04ed0481f4b74ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4562 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 diff --git a/plugins/kimchi/ui/images/theme-default/icon-detail.png b/plugins/kimchi/ui/images/theme-default/icon-detail.png deleted file mode 100644 index 978df03ca7480d0f9ebb3b4f1a1f73226fcbe246..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3079 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 Voc;M?!D;{i002ovPDHLkV1gS<wu1lw diff --git a/plugins/kimchi/ui/images/theme-default/icon-iso.png b/plugins/kimchi/ui/images/theme-default/icon-iso.png deleted file mode 100644 index d76290427e75fd1c6ad914acde114e065760b30d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4188 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 diff --git a/plugins/kimchi/ui/images/theme-default/icon-list.png b/plugins/kimchi/ui/images/theme-default/icon-list.png deleted file mode 100644 index 7b3b595ffce5fab49dbd2588cebd113922b9dcbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2983 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 diff --git a/plugins/kimchi/ui/images/theme-default/icon-load.png b/plugins/kimchi/ui/images/theme-default/icon-load.png deleted file mode 100644 index 2ad195ca84691697a63e720003fe48b1573590f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3678 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 diff --git a/plugins/kimchi/ui/images/theme-default/icon-local.png b/plugins/kimchi/ui/images/theme-default/icon-local.png deleted file mode 100644 index 092026fbc9301b311d5e9bb8556450cd6fa93ff9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 425 zcmV;a0apHrP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004SNkl<ZSV!%a z3vt3g5QaekH~<v14oDTWC}^snNB{>oAXQKt6bFEU4h~uc@P9LR3`t0`$1CkjcIF>Q z*t`919|`SN&DO3teyag!GGNU>tY)1DHtd`Hld3fqfJmEsRc%!8`;+c3%hpx_Ji6dr zeNLr`5o9L6cj-q0VqLVZ41l1V9EcBzGKAPd&d)A55WwWD41m-PrH%9=eL5Hm1ScLz zKs-q71%w$Ok>{)QEA=H(%5{jb2W11MBXLb*rtDM(VtLT<1drSXA%U~LlyK#4<|ZQx zKtSK|rZF;-`9tBJnv7$BY{yeSU}(lm%ufOkxykSV*^VE}`TGjNJva~pDUni>;Q^NV z!FN1mI5{$xq`|G_pu{>%1^`eUcl@n_d;Y$@93}&R-4#xD_7?vNfKufiBn3yO<4teR z&<t20%)x;V1vtCbMGG5%Kal|*JiIRJuq_#g+|#gkXM(Nb#Z~_aZ_d;J)SiJoPBKc^ Ts5X1J00000NkvXXu0mjf;iIrQ diff --git a/plugins/kimchi/ui/images/theme-default/icon-power-down.png b/plugins/kimchi/ui/images/theme-default/icon-power-down.png deleted file mode 100644 index 2c653bc6af72f628cea721d618849d912c1aa186..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4372 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 O0000<MNUMnLSTY^CsYvt diff --git a/plugins/kimchi/ui/images/theme-default/icon-power-up.png b/plugins/kimchi/ui/images/theme-default/icon-power-up.png deleted file mode 100644 index a4575f90120e56d21d42dc4fbefcfc571a30ef71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4367 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 JPDHLkV1k37QX&8V diff --git a/plugins/kimchi/ui/images/theme-default/icon-qcow2.png b/plugins/kimchi/ui/images/theme-default/icon-qcow2.png deleted file mode 100644 index a5220093e8143db08887f31decf8af059d654ba7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4684 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 O0000<MNUMnLSTX?tJj49 diff --git a/plugins/kimchi/ui/images/theme-default/icon-raw.png b/plugins/kimchi/ui/images/theme-default/icon-raw.png deleted file mode 100644 index b5def8f3dddd81a3a570f3acbd3b206684275cbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4679 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 JPDHLkV1mo3<ud>P diff --git a/plugins/kimchi/ui/images/theme-default/icon-remote.png b/plugins/kimchi/ui/images/theme-default/icon-remote.png deleted file mode 100644 index e316dc0701db28b51db92b5e6e6985f3b82b25e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1005 zcmV<J0}}j+P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F8000BDNkl<ZSVxuC zkM$Ep5C?FmK&Zf@0<Z$l3WN#>6^IoWD-bF$Rv=bjr~s(IPytwh&gb4t+~2yJgn4gX z_U7i#cjw>b{=F}wr=k9R@DltW_(__-kKfP1r{Fiif86T!{tb$P{S+*?ptle(fc%)i zrZ(3A?8EYhCh&)Jd`!n~j${J3HGw`(IUuisf1V+j0pRS<bj<d*U|>$STt9S{)PJ7( zfPR;t@3<HNa2vsa_?S1Uo8B1ztR^Fe;IA_{5O;j_00jLjgG=|zJXe!R>6en;`8EBp zf7E881<<Gcl#w3B?=iuYtOrr@rFr4}E(5pvF7r(ZS^)bH>h_+b4FIL_UPB3ZDI06N zck32V>z5Dl?iGL;S~`Lqg3Y!YA<v@`lSO6YT=$!x5uHm>0646Uo!D$ySQCgdn?4Im z$nfq4e<o{J066+8SmV_U&w!lMH&FmUBby)@;aB#YzYTtyzhXWFK$rfW!ELWmA5^Rj z^$c0a*I*;8$pi$3zF<Ik|19l2KLg+pEd6Q<z%kg|_T)wy@lx{%x=(xhHO7FD`;M?b zrLWfj2q-nx?Q4Pp;_qN%!+_pl0IU@W_)8;jA;gw{09twrfB@<)ZO(`zEbyALC7(MV z=SS~Hb6*Nod(Xfq)q4Q`NsWFh?nACLY9_UndZ0#Spns`<*jZ|t@=TWiP*U?<@G-d3 z+1j_~YXIo#3qa_~z_y601klYI%%l_`y<r-FY6;j{R5OtL8{<Rpr{E8xCY%|sg*p{v zq(-W200l(JoJZ62I^=9+U~58X)cV?jDZLipi?kns7Nqa`+9NeB+ZaM>5h=y_D>d*q z0zmB)EVaFD`E6ZQnXByEB0?PK&PVBRbfYDNw%3TP+Uk>fzs6x}w1$8biyu4YK>;|# zgECxOwWGB1-;Xfa2!Q$D2U~nwtTNOzr(jvAjX1n&2y1WDdkaRep7_-1MVjvztlVzD z1b=RkLuQev4-m7FYyn99?t*UB8VKJS{|^K{H+-MEGJq6_p4JdlUERVnn;8M;pOMcz z;6~Kh??yd<wiKgGltZ>|^y)%zuWBE-xuECN&j659JO=BBQ?Ob0jP}9GWC3Z&YqW-f zuVV%Gd?#b0?&TD6LF?bqA<nfz^+rE(J&+}V?(&7S3;w^pngJ+>Zft9{UogPPIW30( z11kt{RbwevCi+9V27nRgoN#>SQ#x}Ra)Ffy_}MgV=C=T7;{bt|1Xd-gY^d)sgI~b+ b->ZKC*A4Oh7Gf$=00000NkvXXu0mjfz>VSq diff --git a/plugins/kimchi/ui/images/theme-default/icon-reset.png b/plugins/kimchi/ui/images/theme-default/icon-reset.png deleted file mode 100644 index eae8449a556d68a44c28144727f7bb3c5d2fc13c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4576 zcmV<65g+b}P)<h;3K|Lk000e1NJLTq0012T000^Y1^@s6OO{u+00009a7bBm000XU z000XU0RWnu7ytkYPiaF#P*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-oy)XH-+^7Crag z^g>IBfRsybQWXdwQbLP>6p<z>Aqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uh<iVD~V z<RPMtgQJLw%KPDaqifc@_vX$1wbwr9tn;0-&j-K=43<bUQ8j=JsX`tR;Dg7+#^K~H zK!FM*Z~zbpvt%K2{UZSY_<lS*D<Z%Lz5oGu(+dayz)hRLFdT>f59&ghTmgWD0l;*T zI7<kC6aYYajzXpYKt=(8otP$50H6c_V9R4-;{Z@C0AMG7=F<Rxo%or10RUT+Ar%3j zkpLhQWr#!oXgdI`&sK^>09Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-<?i z0%4j!F2Z@488U%158(66005wo6%pWr^Zj_v4zAA5HjcIqUoGmt2LB>rV&nehQ1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_<lS*MWK+n+1cgf z<k(8YLR(?VSAG6x!e78w{cQPuJpA|d;J)G{fihizM+Erb!p!tcr5w+a34~(Y=8s4G zw+sLL9n&JjNn*KJDiq^U5^;`1nvC-@r6P$!k}1U{(*I=Q-z@tBKHoI}uxdU5dyy@u zU1J0GOD7Ombim^G008p4Z^6_k2m^p<gW=D2|L;HjN1!DDfM!XOaR2~bL?kX$%CkSm z2mk;?pn)o|K^yeJ7%adB9Ki+L!3+FgHiSYX#KJ-lLJDMn9CBbOtb#%)hRv`YDqt_v zKpix|QD}yfa1JiQRk#j4a1Z)n2%f<xynzV>LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_Ifq<Ex{*7`05XF7hP+2Hl!3BQJ=6@fL%FCo z8iYoo3(#bAF`ADSpqtQgv>H8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ<AYmRsNLWl*PS{AOARHt#5!wki2?K;t z!Y3k=s7tgax)J%r7-BLphge7~Bi0g+6E6^Zh(p9TBoc{3GAFr^0!gu?RMHaCM$&Fl zBk3%un>0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 z<uv66WtcKSRim0x-Ke2d5jBrmLam{;Qm;{ms1r1GnmNsb7D-E`t)i9F8fX`2_i3-_ zbh;7Ul^#x)&{xvS=|||7=mYe33=M`AgU5(xC>fg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vF<Q0r40Q)j6=sE4X&sBct1q<&fbi3VB2Ov6t@q*0);U*o*SAPZv|vv@2aYYnT0 zb%8a+Cb7-ge0D0knEf5Qi#@8Tp*ce{N;6lpQuCB%KL_KOarm5cP6_8Ir<e17iry6O zDdH&`rZh~sF=bq9s+O0QSgS~@QL9Jmy*94xr=6y~MY~!1fet~(N+(<=M`w@D1)b+p z*;C!83a1uLJv#NSE~;y#8=<>IcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a<fJbF^|4I#xQ~n$Dc= zKYhjYmgz5NSkDm8*fZm{6U!;YX`NG>(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-k<Mujg;0Lz*3buG=3$G&ehepthlN*$KaOySSQ^nWmo<0M+(UEUMEXRQ zMBbZcF;6+KElM>iKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BK<z=<L*0kfKU@CX*zeqbYQT4(^U>T#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot<a{81DF0~rvGr5Xr~8u`lav1h z1DNytV>2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000LINkl<Zc-ov+X>3&275?sh%e<MfXYuofZN|oUVX*_0eGw^OnTA9$p(zqZgfvB> zs6wq8QKTXyn_onrN|D>NN|n$Cktj`xL4mL&ZNQB%0z`?cK)~2wmV%dA8PD>Td-}s; zXKV$Ea-^&GboJi(biVVQh2iOq17HATSyA1La|ZwrkzreAoP<a}tt0s<zheLt05a#2 z)01C3Nmf)p7~{gW<H>mR{%|BX1b_h8ndcLo{Xdfc<fxj<Us63|kteUHG1p%(N0OC1 z0E~#z>BR8OXz;;5hVJ$r4?eil1Hj1mrtb;Lq>8$EtBNYBcRO4;3mD_-h${jZ1Hixl zFvejSslHJE-9PvI``p{9M11gZz|s?FcL1;eki%OzV{+AuU)q-KU|;}a5E*Zbv5^A+ zT=KcS`pUvU)lAb!Ux-JBLXV?vqF5XNa`e*jy0V&CuLY)5-d@|V^g>7H1<7AjvVw@< zb~*19<oUaNo}6yRcr<O8xwa50=NyaylB`zilP1qI(#g~D@L=q5^l|_aW6Yi7%dZT~ znA7AdEZr<AT6vz={aX9m`wo13{Iq`T?4>uC&a3ZzVdb(5nnMWzEN$C1zjCcxKXl~O zx@$eRH>$GY;+z2tFj9&4yUrZj^e8k)*)%f%8UUV~S6EeCS-YkvQ2mM|Dbs1B9H8sI z_uBvT#!msL06YMk0O9}=07S-z6i+1OLq|?E{Qblif3Pg82mmBmF$em(H~r^dpME%A zC8`#vsGGaFux#o&)#;v1whhJ^7~=qA;GEt3?Y7MeRxO(!$zn!)N2*i+#&a9DHKl~~ z0b_6yfOOh8{lcQ@>vWH6cuX*p%cnT2XDxg+6bx4q32<2&0nAuDk(_+)a##JTW%E0} zONqf?aP-yCbsaY@bsR04zVIW>o%0GK0TN<)dCkoFjZKZ`$Aok1#?_v-me*HrSoi!d zIG3(u17f5U9K(s!GRv~Y-Jdyg20M1_Kz@Gy*lBHTMJ)ILx4JqH%Zi)^0Egz#j-EQR z*fcGcT^e++=lb19Z`WI9D&bXK?%AM`d<r6{vV^YdJ&Ug1ysbPlt;!tzv8kyEu~;ly z8*)oaivVC3y7g|$FzzzOsu&Rr%bF<p1k@PbQQ0$L;Ou);)WCmTAr;A_yVicDo)_ zlubG=%W~@BU~obIP-sqeq&}Z-T;$$@;_9k7OMk?<RA{6U5i^~NeVYqb2*3q^S(XJ^ z*L9et2`)+CoacZ5+ZJ#-)c)3AZE3mDd*_`KXV0(odvl93%vb;riA1t7Npt5G1*Xq= zH*Zq;m3VmIux*)|0w)N7B1>?niX0Ay+3MA+At#eb0AO5_ED*&3K$0X3426`w`wwG{ z%NKs$xP0N4nOYu8_^w^Muyg0mF;pX&ykZ*ZUYEz$=yc~c638SW03rbR`i;GNLnlt2 zpo<qTjyWMBN(o{00RZO=@!@1)G#2+nBcVsFt*t`<1~QEt`}glhXJ_X)dSk)<aAe@W zmn2yN;~ZR)6vh}h=Lp9hmF(X8yVA2~J5&ICT*I%PyZq&{Y0rEFK@bFJs{EVFr#{>_ z*#8i^uA{B34coVG&n}a3Rx|(E=E=3Q4hq{IR{}x^A#7_f8VMh^276oOty{N_&|{?0 ze(dDM!1USI1?*bR0K>4iG0po4@bH^pFvyylo1Zu*6VdQR+cLw9aXtIq7J^&0D411W zH}B1s1C@;ETR*a*qJH`Fd-6-lciZ+zU6Qc>`SrQawhZ3w>B}?+nlLc<=-`%BO<nNZ z`cED1+?6B<mTdzJC@(2Kzv0Ekql;$G?9lz*TT)9)%V<(DV_FRk9{S*#!&|UM)3kz& z!lvkx0!xVKej*-?fryBRgE5D!sD78%Ut2b9*5c^EgPXQxnx5i{az%5k5JHHu;=-%V zFE+mQ>z{3Sr@nS-hs&wm0T3A%DFAlxy}#0zU)_B6O7Fw=9GB)NB7g{jMAAqMe-R4} zTuwZS3`vUO$noV@<aqKLWQSHU(AT~GYUgK1w!FT3VKgazzjDbB&i-Ug!*Sj3xd&hn zz@rQ!m<T#L=0w|H{`TX8M^66H>Cg%!&Ot;V2r$L~%5W?MD6>IWmbg})=XmKr+rGYg z1Hr)5K&b^F3Lpl+oCq+{1ORFKtLqQ{y!oX~ZkKj0Wf){w76=TKX^|ir*}@1&n>Hj_ zs`+6<V}nD}Ff~xx4WJJ|a3bL2A|36e41jvSf3WENqo-f~rl)Uh@16UVX~XmjAymc~ zDT<uP^Lj!vYb(1Nmdrc0V)5Mb0D1uoKXL1N3}`kJDgb#X94+|jYIogmDpf9Qk;@pM zX^vQFQNgXcn#x<5oJF#R`}YPNH$^ffqGX;dYtJ<RJoU2uzX1S0-5^Y~P;dqS0000< KMNUMnLSTYcw5GuT diff --git a/plugins/kimchi/ui/images/theme-default/icon-search.png b/plugins/kimchi/ui/images/theme-default/icon-search.png deleted file mode 100644 index b38cf6cba2ae18095f990c7dd3736365d9965fe1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4197 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 diff --git a/plugins/kimchi/ui/images/theme-default/icon-sort.png b/plugins/kimchi/ui/images/theme-default/icon-sort.png deleted file mode 100644 index 78e8b3930368c9ee163ea6f28a0c5a1d631241a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3421 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 diff --git a/plugins/kimchi/ui/images/theme-default/icon-tree.png b/plugins/kimchi/ui/images/theme-default/icon-tree.png deleted file mode 100644 index 5f7ed5312dac8d3bfb26010ea6555682f5a43f3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3526 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 A0ssI2 diff --git a/plugins/kimchi/ui/images/theme-default/icon-user.png b/plugins/kimchi/ui/images/theme-default/icon-user.png deleted file mode 100644 index f4258d420b98a019332bc742e15d53497e1012cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5366 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 U)&>o#U;qFB07*qoM6N<$f|wvR(EtDd diff --git a/plugins/kimchi/ui/images/theme-default/icon-volume-default.png b/plugins/kimchi/ui/images/theme-default/icon-volume-default.png deleted file mode 100644 index ac906c7723e9c26900c347cf5e47e3192a5b2f88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4265 zcmV;a5LWMrP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T7000U_X+uL$Nkc;* zP;zf(X>4Tx0C?J+Q)g6D=@vcr-t<CCh=7z!Z&DQqAW}k$fE1A?Dj^9FN{At$*%eX2 z5k*A=8_1xD1CEY>j1^HV42lZa2jn55j)S9!ipu-pd!uXCy!YnK{<YUW=dAOcv(E>> z2n?1;Gf_2w45>mM5#WQz#Kz&|E<k|_Bya!_2(x4%bNwR$0Qi19JS!r=2fhFSc+(3A z0KiR~z%U$#{}1XynOp&YgaN>GkvK~TfD`~gdX7S-06<0ofSs5oQvjd@0AR~wV&ec% zEdXFAf9BHwfSvf6djSAjlpz%XppgI|6J>}*0BAb^tj|`8MF3bZ02F3R#5n-iEdVe{ zS7t~6u(trf&JYW-00;~KFj0twDF6g}0AR=?BX|IWnE(_<@>e|ZE3OddDgXd@nX){& zBsoQaTL>+22Uk}v9w^R97b_GtVFF>AKrX_0nHe&HG!NkO%m4tOkrff(gY*4(&JM25 z&Nhy=4qq+mzXtyzVq)X|<<F~dKmY*YbbitPEHASffI9|&ZT_Mq?gVIF3!ruPi)OM9 zK(zp%>DpKGaQJ>aJVl|9x!Kv}<mA{nwP%2$2<XTo2=SN&}Hemwm5_29nZB!Mzr zfky=R;KI!GOr;#pk_m)j+~$u*{I?7L{2kLG#7SbgSSl3bQ4(>EM4F8AGNmGkLXs)P zCDQ+7;@>R$13uq10I+I40eg`xs9j?N_Dd%aSaiVR_W%I$yKlkNC<p_9XoKO;cmMA{ z{YRiB0Dxvml5qe4UPL4=RLZkI#|QubM4*8xut6L2!5A#S1{}c!+`$X{U^aw8B*el( z5JC!MfE;pQDXfA*D2C0j9V%ci)Ic3Hz)@(1lW-0$!d18qJ#Y{DVF;eVD7=9Q1VP9M z6Ja6Rhyh}XSR;-I7nz0lA;Cxl5{o1t$%qtDB1@4qNHJ21R3KGI9r8VL0y&3VM!JzZ z$N(~e{D!<oF_eL_Q9aZQwL`h6HyVUSq6^SubTOKb7NDEZa<m#fj5eX?(5q+<+K)a% z$1uR?7zZ=NY%ngy!$Pq*ED4ii%dsM?46DW(uvV-CyNUH<`v|5`jg)2{r_GLLgxt zK}c9kSWehTs3069G!fbfHwgoTQNkx8lc-CyCb|*%#28{SF^5=4EF;zuj}tEtdx%5C zHzX2?Loz41kOE1uq*T%p(niv5QX}asshc!N8Y7d*+GK082RW21AS=j)<elWh<TK<O z<RS7~3Y}s=aisWD;wVzeYDyX95al%G24$EsK~<xgQr)PbR1r0gT0*U%wo<QAho}=Y zb(%TNgBD3krLCfs(;8?OX!mKa=ybXf-IX3rm(W+z%jrkxm*@lZcMJ`N6@$l!XDAt) z7zY?<8Fv`3m`tV_(~B9$R4_L&>zL=651DUOSSq$Ed=-((3YAKgCY2j1FI1_jrmEhm z3sv(~%T$l4UQ>OpMpZLY<EaVMmaA2&olxsj8&hYgJE(`MXQ*#fKcs$H{fP!y!%V|Z zL!?olv0vl7#vlu08MAmSA!`k*hIN58#3r%L*?e{?yO{kQyNf-lsi8STGfFd8vr_Yv zW<Lkxm~r@=bWRE9D5sb6eu~}{?<wLb8>Tc&xiMv2YpRx)mRPGut5K^*>%BIv?Wdil zy+ylO`+*KY$4Vz$Cr4+G&IO(4Q`uA9rwXSQO+7mGt}d!;r5mBUM0dY#r|y`ZzFvTy zOmC;&dA;ZQ9DOhSRQ+xGr}ak+SO&8UBnI0I&KNw!HF0k|9WTe*@liuv!$3o&VU=N* z;e?U7(LAHoMvX=fjA_PP<0Rv4#%;!<CI%)UCQD7~P41dfO}VBiraMeKOvla4&7#fL znKhd|G1oHZo9CO?o8Px!T6kJ4wy3taWl6H+TBcd<w!ChIS~*#zSXEkGvqr6*ttHmG zt-GfYr@2m(POF~QXTz}Zw#l}sw;8bI*aq9Kwr#e3VP|3&XSc<!!|s#4lYP2<jr~0b z4Tsqds~uV$esi>P6gpNq-kQ#w?mvCS^p@!_XIRe=&)75LwiC-K#A%&Vo6|>U7iYP1 zgY$@siA#dZE|)$on;XX6$i3uBboFsv;d;{botv|p!tJQrukJSPY3_&IpUgC$DV|v~ zbI`-cL*P;6(LW2Hl`w1HtbR{JPl0E(=OZs;FOgTR*RZ#xcdGYc?-xGyK60PqKI1$$ z-ZI`<U(7eax5&54Ps4AXUxnX8e<S~7|9bz?0H=T@0cQh=fkA;=0{i%Sd?CM%KRVlG z_OjXSL5!feK@~xdf~|t(!L1=^$n21<A@}E)&XLY(4uw#D=+@8&Vdi0r!+s1Wg@=V# zhChyQh*%oYF_$%W(cD9G-$eREmPFp0XE9GXuPsV7Dn6<%YCPIEx-_~!#x7=A%+*+( zSV?S4962s3t~PFLzTf=q^M~S{;tS(@7nm=|U2u7!&cgJCrxvL$5-d8FKum~EIF#@~ z5Gtq^j3x3DcO{MrdBPpSXCg1rHqnUKLtH8zPVz`9O?r~-k-Rl|B*inOEaka`C#jIU zObtxkn>wBrnsy*<GCexIF@utkka0q)Ax)FEXX<C>W_HW0Wrec-#cqqYFCLW#$!oKa ztOZ#u3bsO~=u}!L*D43HXJuDrzs-rtIhL!QE6wf9v&!3$H=OUE|LqdO65*1zrG`sa zEge|qy{u|EvOIBl+X~|q1uKSD2CO`|inc0k)laMKSC_7Sy(W51Yk^+D%7VeQ0c-0E zRSM;Wee2xU?Ojh;FInHUVfu!h8$K0@imnvf7nc=(*eKk1<r{}@%D<W1l(ea<#JOb8 zX3}Qq=H4xyTMm}0m*$raZVlPmv<=@@wC(lwMcXfz%_!TugSJDtqrW`3yk)1!&dobN zRHRh&RQgml?$X`0Vb}O>(e4|2y!JHg)!SRV_x(P}zS~s+RZZ1q)n)rh`?L2yu8FGY z_?G)^U9C=SaqY(g(gXbmBM!FLxzyDi(mhmCkJc;eM-ImyzW$x>cP$Mz4ONYt#^NJz zM0w=t_X*$k9t}F$c8q(h;Rn+nb{%IOFKR-X@|s4QQ=0o*Vq3aT%s$c9>fU<%N829{ zoHRUHc}nwC$!Xf@g42^{^3RN&m7RTlF8SPG+oHC6=VQ*_Y7cMkx)5~X(nbG^=R3SR z&Rp`ibn>#><r7!9SDLRnUv27i>OB6F(@)2{oV%K?xm;_x?s~noduI3P8=g1L-SoYA z@fQEq)t)&$-M#aAZ}-Lb_1_lVesU-M&da;mcPH+xyidGe^g!)F*+boj)jwPQ+}Q8j ze`>&Yp!3n(NB0JWgU|kv^^Xrj1&^7J%Z3ex>z+71IXU7#a{cN2r$f(V&nBK1{-XZN zt``<Be)!ev*Ur(H(V>^}my^G3e5L*B!0Q>W+s4Ai9=^$VGcjKDR{QP2cieX!@1x%j zPvm?ce<=TG`LXp=(5L&88IzO$1Ou4!{1CdwXaE2J24YJ`L;(K){{a7>y{D4^000Sa zNLh0L01FcU01FcV0GgZ_00007bV*G`2i*w^2m>lc;ERj^00reqL_t(o!|j-DY*XhI z$A8bg*VnP*B;X`KYO)m4CLKx3IzlSYsKi>8s;kt3T7jZMHKA&4wN(u5ecFd<-IpO1 zX;WXOt*h8dtFcB*Rn>PYXr%%Pkdgvxng-FZm4spkg6-JX_ujJ)wu774#SRYJhn{bK z{9HZ%bI$*N&UqgA%C5{*-o+<+8h{@FO@JS$1AM?mz%Da}IB)`ZMz(f-dRc(#i5>+U z1NL;x_YVg=da}-EjMbQWB9d?dwkujW!!u#Kp0|g`n}M}Ji)`(b+$~0)nQ2_Lh#6 zD{PC|E;XiJ=Aa3JV%&15G&FQgJ*jW+tpFARr*n5sMq}-+qx$VTdTt1K)M8-NfroDE z9w7Ae5&rh^SlOBN+(%(TPxrCrr2!mRBM@%(tL1m>JW`t%;9x@cMJg(XqA9U}M8X!1 zo{bZWJG}FsXxYhscr->VVbeDn=R(R61u_(ulV@Dh$(!P1o7$rQ#`Ye=7Q~~VZ(|!r z&Q0*0uT^0=Zdn0tTNz??V>Qd`eFT(JSv`EXvHg5Oku*Hj`)D{Rk6W(Pn1-gQt5ixv zkd*66rOv^ofU)8D=4Hdv09O5>_tt2NeIhPthpw)Pq{U<E+HPyh@^#Zve9^+MlrR%) z^*)0qzum;@#%fZou=|rSe)`^NqN(C(kv-QE<;%-Kr2r{Zy1(3BzUO*wX$a6g7@@Js z<dLQGs4x_p-#j&=&LR0!T)3}%xy|z%+|m%><)Ja|e`Sc({}>=@Io#Vkw=AhQrqs`p zL5?RKR=jwEk$5Uy<tsgyy5jUjYZd^`Ac6@;I5-jmpt;7&d+WcB?Fx_W9i9b%S7?8| zb20TkgIjlf#QrnU|Bn>sTK8at=l>Nh8@RHFB-ehpYys<AgJrFcWsP7cU=p>Q*#Rhm z0)_fQ6)G_u+k3CPp-6!gSDQ>|noPEw|3$A8P+rZQ$Q!{m^Ymi}BF^Ts2_8tgbgXU+ z_%+nzq-wcBIAP<_6(W#wTrMOXqA8cfbG%f0bUZoZMa*^?97_<6r$AGeI)p2%YOKc0 z?p2U<-1z&S#T>uRt{ZE#=MEH-#a%D-&fj;AP~4Vh?JXV6N~x;c4NcGVaeCYWLjxrQ zD?A+B*v|L&oZ|I?2oHX90SU|D_C+;pz9EQGiZ}j!k@dR=xsXa<W$OJVXCMB?RO%1v z+k0b+{ro&Mr}C|LH?%o<Rs3q#^3k|0?lkNfVytVcLp&Oia=2?zkiA_?Sld0o>w^)L zM`K6d2!B8RIS;)$#BUFcq%*Uyic{ZP$}d-hz!BDERW8$MbTZCJF1X7S>KsXDMvd<- zspF}`qdc~%k*?Mt%l^`j1t>l3r!p@2`>VafSOUN9Y+#P5^Z1Goo7(CzRayzfj&xcn z^17+k$AOLQR2v!{JC0$AprpWXXK4K9-C;JoHZ=KtOSQ?hRc1-^X3+qZQiupQ*H-Ys z**LE4=FDi*hdU*L(lvG+4|CruLo>cimvqO?g6zJ#nIC^^A-V{XS(7Q`$o|$fXsz>M zsF_t*qr^vtNszx=8KSEt$hN~H{PW`o@u+o)_X+}4Cik=i`Ps4swAcF5X`jKkUYtns zfJ9(vZ3R2mEFyWwwS02kqCXr*DYz-<<GMLs%#1T%nCY+DxRq&)2zZsEZLXKLx!!3$ zmLLcl@RZ0w$=@K0oq$v^O;@tVOaK)n0907E&>Kn2TKnw{PcUIi))5OZiv~F1x->o8 zPv;*$;3xaflpWkJ4tz%EpN`V<=YGa*mrQz7#Q@X*S652a`3#g-W4_<GED;Ko8JR|y zv<1Be%Bxf7Gw^6i0hO6FUsfbzK)qK}Z})U9x%Yh1;hIWMUSMv<8#M)hDsa!uUH{R| z^XY0067=e5B7?w6;AF86nEf729op1hXDz7oBt;;Wa?GS7M(&}7fXNhaDo+Hn|68ue z&J*WU!j@Lq+PSLOC*XQu6VQ=){>`dvHWVY7$o*cncAnuYE3^F<>K#$%^M|uQ00000 LNkvXXu0mjfnm8lp diff --git a/plugins/kimchi/ui/images/theme-default/kimchi-loading15x15.gif b/plugins/kimchi/ui/images/theme-default/kimchi-loading15x15.gif deleted file mode 100644 index aaa4f85a0560dcb59d4bb70154a9144417aae926..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1653 zcmZ?wbhEHb6krfwcz&0`fx$V3fzy*s(30KRoyj+pP0*a%B9B4Xkl)0X$H9|dJd8D} zo<ZDBSSFF7*jZT0OhTc9Q7nTgk3rREDud*7MxI>8&Ju=(ISf+93MQOdag7Y~1hic{ z8T#{u6)cohTNtM^7+W$J#50+i$>`cj=^O84k`pyFn#{1$Ur8%a&i6QjtgEuCfQhw> zh77A6gQ$gokA@_-E$2dp^>Sv?oMy2Rvbjr`S1FsTIOwZtnQE_R*m$2oUC1KhF@wT7 z#vS5TPBXdYi#jqhIC*|#&}Xr)`pY25?86wZk@$x}Azj<#4}*rAu{Vcnu(UhJUj}_& zGsWW!mvn9Irz#jqI|d0m<_4Kq$D4?%x#%8bJFV#KwS(tqvz9fdTmMyIV-~+CKU<>^ zTODbStQ;$e9OEp8kfaJrQB(IojUXN?PfLA&1ruKlE$<Ybz{O>Dnh|c+IZj3l84L_z z+ZiGkGQ_8gg)Ec{ZB|VbVu;;p8Ir+}TJcZ8St};J)7e)ugI_wAy~kUSA^Gq;v#nzB zo6<uZ9TN=&l6EuXHCx41&a>X&p6tkweNrgxtWY&KLrITauKX0wDL;*ZSPITdWuHCl z7S2#|o1wN-skGcGd-j}YNrw7v?ff;HUH7htly%83WoVk=SR=P3TA8QnVNZtdt|Td^ z4tBRT;l<gOCKJSuq^f)gOk<w3o@>%d>z1S5joVY2V;E+x4Cszxn7#dGQiZ}|@k{wq ze5<)H#@>~ixp+mvx~nC^*GqKvReGJxyd=J8Z|Hp0)LG8{Q?7j|(|J;(^S(;?X-VtX z{Ej0{$vo>WNUb@RHtpd12Emt&YTJ7ve>HRaY*WxWB$BmO<7<oVrMfE&d+u577yI7H zdv${AuTG6`J!)PD74G*(XRN&WpI$)mKewN2NU*bGfUA+70W%{51B2pE7EU3C{|q`n zHZYS2Ffee)GW_S1@z}87U^9oXR?LYF3lFyoD0|KE*tqCuBO@a=9coY=j!k!j<aB0i zc<9u4hfS*nq@!EHIP1=djf>s;v1`@Ep>^V-!(BqkNq@`*laF`Fn|H~0Zd!7(0h{Hf zM42F;^~FLc<zy?bzucZ38xtI`nPf?{Nk)rZI#dI#a%KcAJ>AR3%!JJ}Tb!mjcL>V+ z&Dl|qe5_B>QtnB`#6;Il`9QBD85<TlO;@&EX5(p~fXzf_h=~b~c^s@tPtrczcWUF8 zl$)Y)G4W`lxU|rj6$Xj!z4E$EBA!9O@K)2-%Q<1V)NzW4rQ4Q{qQ@s^Df6<iU^CYa zVJ@$f%ZvcUgKd2BZZRt+Jap&~-N|`mN5EtIK6cxtnin4*pO_@<TefG1V5)aFPwc)q zGcP6L3rdhvk&Uz{R5;QluAbJjV`8#<o~Uk<jm4+?Cwh5=mxY`NNH{%#3wux+Vs{|2 sX~(-16pJpOC{Q`pufUDnn>s|9;tWh`McC5^G?`;~3OSj#0+YEl0GD)I?EnA( diff --git a/plugins/kimchi/ui/images/theme-default/loading.gif b/plugins/kimchi/ui/images/theme-default/loading.gif deleted file mode 100644 index 60d46d2683817f81a678c5e3eef14ef35089d119..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2190 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 L$~1kj8oc@+?)_VM diff --git a/plugins/kimchi/ui/images/theme-default/user.png b/plugins/kimchi/ui/images/theme-default/user.png deleted file mode 100644 index c57a81a92757ef31c424a4e6c741f71db62a1092..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1322 zcmV+_1=aeAP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$%t=H+RCwCFS6xgTRTRGSvwt(QEW2!% zZEC<RY*%PmU|~TT(9l}brY~)zO*HkzHZ`VcV>GER{yyo84?Y{zXpHs6S4l9Y#$eJ` zmI9TeNz<hS;wC6n(*0#;*YAuwlVv;L6r^`@m^(Xj@A=NT=X~eDmCI%J$6w2=dc>kV zY@@+(9ODK4xF85;1zu=k91CHOq^hbvsYP|PR4&aWrYD(|;jiDtI5Pm<(b&U^nWnhO zZnuB!bUFte4hIuOQ3F&emDt+a8q4K!YCf0$1oO+2)4!@#0EkwQl5$ualok1!EXhHq z%gJmu8{>K206<bG6ogDB^F}6}*^Ol{S=pO6{k6PaIG$r3kLNqL+Z|Ng3M1<QNK>wD z0wClKm&?WQ4U=X0#ew+2^IHe7-h8rlfP@r~VhtmXu2yJ}XCzr-e!u_2cz2($B>?5B zi|2UO+S2;E!|Bj0HB)Q`0>S806y@n{9{~c7$%@p!ndP-YM`IIhEY=e{_Fn+RjXY4D zb{x;w(OtLDQsClyUxV+7?FS)7Fxa?e#qxE6tFbYV-gXdDdWFN`J9K{(0F)I&&kRj$ zI|#vW?8M0vpCb(|D<`nShlY!hry^t9K7x{3LJ-PdzWUnvKdl1r@A9)#r$@fP4l7&p zK#etB9o>b2g9B$ST)a@CRMeTzOi1}V@4bC5&=`2jO0Zg@ViXxFP-BUi$(LJN_Ksfp z=3D3WYuB~o(FYyT;UkCH$jA$KK}644v0lp-vto3ht%C^2h1~xbJa874jpHaz!TRjf zY@!{XyqnEtPcAMl+BGYX^P$j_DNIKpA3+{;9_VVv`tOm%b^yJ6^VZZ?maAd3z0;0@ z^8+}4h*+&yEHYHNtJz%k6}(OoDNW5J6wD))C57Iu_-s)vYB2+#M<hwQVt3em#0U9& zo&oSVtQoZgARg=c6uf^<=YBd{Y`}8a9F^U1Jl{ry%u<!a_#1N%?h2Ge@cpwW*%8Sl zF#ymAiApspWGS6aAB88zHwA!z8&qWFXDTRUy%7gEZ}J3fMsuAPv~1!2Wj+Ec3L+D2 zqQ(OhuzFCF7qC8cf8~C7W^Vd{X+O}>78M%&4WH3QB-PYQo53<|<J#h5P&Rc-l^#J? ztdGi32J7nTKEUIfrfCS5pT-%6Ny$cqM^~a*D~g8DbG5~0>&O6nb1AyN(`O36>+`;^ zE8i^Fw<;AciT(!v#fQ?cbAMMCx}7NsJl&F=7!*g?e<hVl1yaAKR6|o}Z|D*QkY09o zN@#y%ln=dSY#kHg^-=2m9;N1QW$4+`+|+aik2gd;`n?U_M)dhR4nPNiKf{Ix&_Fij z3wd5}JSG6RifhF^Mi%tOdm`1jyVF9%1!9s64=8STpq4mxa*!S{s%Us%UnHDGZax<4 zb!iSYtJOTviuu)rdkcFeCVpX4i3FROnWX~qzgZm!1kk2;v%da**4x{|>b>>js0Gj0 z79%RJ$03IxgUidyp5)ymo1dR&^T~O(w6w(16;L1%wz|4%C<yKjGVr{ij5;GUFVxVY zR|qke<XXV1A0cCv`|^h6xNTp%_8-x2w{KCTwpR&x%A<1^#8<T}S=9xRvL(nY<R)Z} gniR8!<R1YB09_*wa#VgYhyVZp07*qoM6N<$f^kM~^#A|> diff --git a/plugins/kimchi/ui/js/Makefile.am b/plugins/kimchi/ui/js/Makefile.am deleted file mode 100644 index c9d1218..0000000 --- a/plugins/kimchi/ui/js/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2013 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -EXTRA_DIST = src - -jsdir = $(datadir)/wok/plugins/kimchi/ui/js - -dist_js_DATA = kimchi.min.js $(filter-out kimchi.min.js, $(wildcard *.js)) - -kimchi.min.js: src/*.js - cat $(sort $^) > $@ - -CLEANFILES = kimchi.min.js diff --git a/plugins/kimchi/ui/js/src/kimchi.api.js b/plugins/kimchi/ui/js/src/kimchi.api.js deleted file mode 100644 index fde803a..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.api.js +++ /dev/null @@ -1,1355 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -var kimchi = { - - widget: {}, - - trackingTasks: [], - - /** - * - * Get host capabilities - * suc: callback if succeed err: callback if failed - */ - getCapabilities : function(suc, err, done) { - done = typeof done !== 'undefined' ? done: function(){}; - wok.requestJSON({ - url : "plugins/kimchi/config/capabilities", - type : "GET", - contentType : "application/json", - dataType : "json", - success: suc, - error: err, - complete: done - }); - }, - - /** - * Get the i18 strings. - */ - getI18n: function(suc, err, url, sync) { - wok.requestJSON({ - url : url ? url : 'plugins/kimchi/i18n.json', - type : 'GET', - resend: true, - dataType : 'json', - async : !sync, - success : suc, - error: err - }); - }, - - /** - * Get the host static information. - */ - getHost: function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/host', - type : 'GET', - resend: true, - contentType : 'application/json', - dataType : 'json', - success : suc, - error: err - }); - }, - - /** - * Get the dynamic host stats (usually used for monitoring). - */ - getHostStats : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/host/stats', - type : 'GET', - contentType : 'application/json', - headers: {'Wok-Robot': 'wok-robot'}, - dataType : 'json', - success : suc, - error: err - }); - }, - - /** - * Get the historic host stats. - */ - getHostStatsHistory : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/host/stats/history', - type : 'GET', - resend: true, - contentType : 'application/json', - headers: {'Wok-Robot': 'wok-robot'}, - dataType : 'json', - success : suc, - error: err - }); - }, - - /** - * - * Create a new Virtual Machine. Usage: kimchi.createVM({ name: 'MyUbuntu', - * template: '/templates/ubuntu_base' }, creationSuc, creationErr); - * - * settings: name *(optional)*: The name of the VM. Used to identify the VM - * in this API. If omitted, a name will be chosen based on the template - * used. template: The URI of a Template to use when building the VM - * storagepool *(optional)*: Assign a specific Storage Pool to the new VM - * suc: callback if succeed err: callback if failed - */ - createVM : function(settings, suc, err) { - wok.requestJSON({ - url : "plugins/kimchi/vms", - type : "POST", - contentType : "application/json", - data : JSON.stringify(settings), - dataType : "json" - }).done(suc).fail(err); - }, - - /** - * - * Create a new Template. settings name: The name of the Template. Used to - * identify the Template in this API suc: callback if succeed err: callback - * if failed - */ - createTemplate : function(settings, suc, err) { - wok.requestJSON({ - url : "plugins/kimchi/templates", - type : "POST", - contentType : "application/json", - data : JSON.stringify(settings), - dataType : "json", - success: suc, - error: err - }); - }, - - deleteTemplate : function(tem, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/templates/' + encodeURIComponent(tem), - type : 'DELETE', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - cloneTemplate : function(tem, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/templates/' + encodeURIComponent(tem) + "/clone", - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - listTemplates : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/templates', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - /** - * Retrieve the information of a template by the given name. - */ - retrieveTemplate : function(templateName, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/templates/' + encodeURIComponent(templateName), - type : 'GET', - contentType : 'application/json', - dataType : 'json' - }).done(suc); - }, - - /** - * Update a template with new information. TODO: Update me when the RESTful - * API is available. Now work it around by remove the template and then - * recreate it with new information. - */ - updateTemplate : function(name, settings, suc, err) { - $.ajax({ - url : 'plugins/kimchi/templates/' + encodeURIComponent(name), - type : 'PUT', - contentType : 'application/json', - data : JSON.stringify(settings), - dataType : 'json' - }).done(suc).fail(err); - }, - - /** - * Create a new Storage Pool. settings name: The name of the Storage Pool - * path: The path of the defined Storage Pool type: The type of the defined - * Storage Pool capacity: The total space which can be used to store volumes - * The unit is MBytes suc: callback if succeed err: callback if failed - */ - createStoragePool : function(settings, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/storagepools', - type : 'POST', - contentType : 'application/json', - data : JSON.stringify(settings), - dataType : 'json' - }).done(suc).fail(err); - }, - - updateStoragePool : function(name, content, suc, err) { - $.ajax({ - url : "plugins/kimchi/storagepools/" + encodeURIComponent(name), - type : 'PUT', - contentType : 'application/json', - dataType : 'json', - data : JSON.stringify(content) - }).done(suc).fail(err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - }); - }, - - startVM : function(vm, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/start', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - poweroffVM : function(vm, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/poweroff', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - shutdownVM : function(vm, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/shutdown', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - resetVM : function(vm, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/reset', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - suspendVM : function(vm, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/suspend', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - resumeVM : function(vm, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/resume', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - /** - * Retrieve the information of a given VM by its name. - * - * @param vm VM name - * @param suc callback for success - * @param err callback for error - */ - retrieveVM : function(vm, suc, err) { - $.ajax({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm), - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success: suc, - error: err - }); - }, - - /** - * Update a VM with new information. - */ - updateVM : function(name, settings, suc, err) { - $.ajax({ - url : "plugins/kimchi/vms/" + encodeURIComponent(name), - type : 'PUT', - contentType : 'application/json', - data : JSON.stringify(settings), - dataType : 'json', - success: suc, - error: err - }); - }, - - deleteVM : function(vm, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm), - type : 'DELETE', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - vncToVM : function(vm) { - wok.requestJSON({ - url : 'plugins/kimchi/config', - type : 'GET', - dataType : 'json' - }).done(function(data, textStatus, xhr) { - proxy_port = data['display_proxy_port']; - wok.requestJSON({ - url : "plugins/kimchi/vms/" + encodeURIComponent(vm) + "/connect", - type : "POST", - dataType : "json" - }).done(function() { - url = 'https://' + location.hostname + ':' + proxy_port; - url += "/console.html?url="; - url += encodeURIComponent("plugins/kimchi/novnc/vnc_auto.html"); - url += "&port=" + proxy_port; - /* - * From python documentation base64.urlsafe_b64encode(s) - * substitutes - instead of + and _ instead of / in the - * standard Base64 alphabet, BUT the result can still - * contain = which is not safe in a URL query component. - * So remove it when needed as base64 can work well without it. - * */ - url += "&path=?token=" + wok.urlSafeB64Encode(vm).replace(/=*$/g, ""); - url += "&wok=" + location.port; - url += '&encrypt=1'; - window.open(url); - }); - }).error(function() { - wok.message.error.code('KCHAPI6002E'); - }); - }, - - spiceToVM : function(vm) { - wok.requestJSON({ - url : 'plugins/kimchi/config', - type : 'GET', - dataType : 'json' - }).done(function(data, textStatus, xhr) { - proxy_port = data['display_proxy_port']; - wok.requestJSON({ - url : "plugins/kimchi/vms/" + encodeURIComponent(vm) + "/connect", - type : "POST", - dataType : "json" - }).done(function(data, textStatus, xhr) { - url = 'https://' + location.hostname + ':' + proxy_port; - url += "/console.html?url=plugins/kimchi/spice_auto.html"; - url += "&port=" + proxy_port + "&listen=" + location.hostname; - /* - * From python documentation base64.urlsafe_b64encode(s) - * substitutes - instead of + and _ instead of / in the - * standard Base64 alphabet, BUT the result can still - * contain = which is not safe in a URL query component. - * So remove it when needed as base64 can work well without it. - * */ - url += "&token=" + wok.urlSafeB64Encode(vm).replace(/=*$/g, ""); - url += "&wok=" + location.port; - url += '&encrypt=1'; - window.open(url); - }); - }).error(function() { - wok.message.error.code('KCHAPI6002E'); - }); - }, - - listVMs : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms', - type : 'GET', - contentType : 'application/json', - headers: {'Wok-Robot': 'wok-robot'}, - dataType : 'json', - resend: true, - success : suc, - error : err - }); - }, - - listTemplates : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/templates', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend: true, - success : suc, - error : err - }); - }, - - listStoragePools : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/storagepools', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend: true, - success : suc, - error : err - }); - }, - - listStorageVolumes : function(poolName, suc, err) { - $.ajax({ - url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - listIsos : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/storagepools/kimchi_isos/storagevolumes', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - listDistros : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/config/distros', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - stepListDeepScanIsos : function(suc, err) { - var deepScanHandler = { - stop : false - }; - var isoPool = 'iso' + new Date().getTime(); - kimchi.createStoragePool({ - name : isoPool, - type : 'kimchi-iso', - path : '/' - }, function(result) { - var taskId = result.task_id; - function monitorTask() { - if (deepScanHandler.stop) { - return; - } - kimchi.getTask(taskId, function(result) { - var status = result.status; - if (status === "finished") { - if (deepScanHandler.stop) { - return; - } - kimchi.listStorageVolumes(isoPool, function(isos) { - if (deepScanHandler.stop) { - return; - } - suc(isos, true); - }, err); - } else if (status === "running") { - if (deepScanHandler.stop) { - return; - } - kimchi.listStorageVolumes(isoPool, function(isos) { - if (deepScanHandler.stop) { - return; - } - suc(isos, false); - setTimeout(monitorTask, 2000); - }, err); - } else if (status === "failed") { - if (deepScanHandler.stop) { - return; - } - err(result.message); - } - }, err); - } - setTimeout(monitorTask, 2000); - }, err); - return deepScanHandler; - }, - - getTask : function(taskId, suc, err) { - wok.requestJSON({ - url : 'tasks/' + encodeURIComponent(taskId), - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - getTasksByFilter : function(filter, suc, err, sync) { - wok.requestJSON({ - url : 'tasks?' + filter, - type : 'GET', - contentType : 'application/json', - dataType : 'json', - async : !sync, - success : suc, - error : err - }); - }, - - deleteStoragePool : function(poolName, suc, err) { - $.ajax({ - url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName), - type : 'DELETE', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - changePoolState : function(poolName, state, suc, err) { - if (state === 'activate' || state === 'deactivate') - $.ajax({ - url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/' + state, - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - listNetworks : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/networks', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - toggleNetwork : function(name, on, suc, err) { - var action = on ? "activate" : "deactivate"; - wok.requestJSON({ - url : 'plugins/kimchi/networks/' + encodeURIComponent(name) + '/' + action, - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - createNetwork : function(network, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/networks', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - data : JSON.stringify(network), - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getInterfaces : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/interfaces', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - deleteNetwork : function(name, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/networks/' + encodeURIComponent(name), - type : 'DELETE', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - listReports : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/debugreports', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend: true, - success : suc, - error : err - }); - }, - - trackTask : function(taskID, suc, err, progress) { - var onTaskResponse = function(result) { - var taskStatus = result['status']; - switch(taskStatus) { - case 'running': - progress && progress(result); - setTimeout(function() { - kimchi.trackTask(taskID, suc, err, progress); - }, 2000); - break; - case 'finished': - suc && suc(result); - break; - case 'failed': - err && err(result); - break; - default: - break; - } - }; - - kimchi.getTask(taskID, onTaskResponse, err); - if(kimchi.trackingTasks.indexOf(taskID) < 0) - kimchi.trackingTasks.push(taskID); - }, - - createReport: function(settings, suc, err, progress) { - var onResponse = function(data) { - taskID = data['id']; - kimchi.trackTask(taskID, suc, err, progress); - }; - - wok.requestJSON({ - url : 'plugins/kimchi/debugreports', - type : "POST", - contentType : "application/json", - data : JSON.stringify(settings), - dataType : "json", - success : onResponse, - error : err - }); - }, - - renameReport : function(name, settings, suc, err) { - $.ajax({ - url : "plugins/kimchi/debugreports/" + encodeURIComponent(name), - type : 'PUT', - contentType : 'application/json', - data : JSON.stringify(settings), - dataType : 'json', - success: suc, - error: err - }); - }, - - deleteReport: function(settings, suc, err) { - var reportName = encodeURIComponent(settings['name']); - wok.requestJSON({ - url : 'plugins/kimchi/debugreports/' + reportName, - type : 'DELETE', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - downloadReport: function(settings, suc, err) { - window.open(settings['file']); - }, - - shutdown: function(settings, suc, err) { - var reboot = settings && settings['reboot'] === true; - var url = 'plugins/kimchi/host/' + (reboot ? 'reboot' : 'shutdown'); - wok.requestJSON({ - url : url, - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - listHostPartitions : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/host/partitions', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - getStorageServers: function(type, suc, err) { - var url = 'plugins/kimchi/storageservers?_target_type=' + type; - wok.requestJSON({ - url : url, - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getStorageTargets: function(server,type, suc, err) { - var url = 'plugins/kimchi/storageservers/' + server + '/storagetargets?_target_type=' + type; - wok.requestJSON({ - url : url, - type : 'GET', - contentType : 'application/json', - timeout: 2000, - dataType : 'json', - success : suc, - error : err - }); - }, - - getStoragePool: function(poolName, suc, err) { - var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName); - wok.requestJSON({ - url : url, - type : 'GET', - contentType : 'application/json', - timeout: 2000, - dataType : 'json', - success : suc, - error : err - }); - }, - - getStoragePoolVolume: function(poolName, volumeName, suc, err) { - var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName); - wok.requestJSON({ - url : url, - type : 'GET', - contentType : 'application/json', - timeout: 2000, - dataType : 'json', - success : suc, - error : err - }); - }, - - addVMStorage : function(settings, suc, err) { - var vm = encodeURIComponent(settings['vm']); - delete settings['vm']; - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + vm + '/storages', - type : 'POST', - contentType : 'application/json', - data : JSON.stringify(settings), - dataType : 'json', - success : suc, - error : err - }); - }, - - retrieveVMStorage : function(settings, suc, err) { - var vm = encodeURIComponent(settings['vm']); - var dev = encodeURIComponent(settings['dev']); - wok.requestJSON({ - url : "plugins/kimchi/vms/" + vm + '/storages/' + dev, - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success: suc, - error: err - }); - }, - - replaceVMStorage : function(settings, suc, err) { - var vm = encodeURIComponent(settings['vm']); - var dev = encodeURIComponent(settings['dev']); - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + vm + '/storages/' + dev, - type : 'PUT', - contentType : 'application/json', - data : JSON.stringify({ - path: settings['path'] - }), - dataType : 'json', - success : suc, - error : err - }); - }, - - deleteVMStorage : function(settings, suc, err) { - var vm = settings['vm']; - var dev = settings['dev']; - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + - '/storages/' + encodeURIComponent(dev), - type : 'DELETE', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - listVMStorages : function(params, suc, err) { - var vm = encodeURIComponent(params['vm']); - var type = params['storageType']; - var url = 'plugins/kimchi/vms/' + vm + '/storages'; - if(type) { - url += '?type=' + type; - } - wok.requestJSON({ - url : url, - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - listSoftwareUpdates : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/host/packagesupdate', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend: true, - success : suc, - error : err - }); - }, - - updateSoftware : function(suc, err, progress) { - var taskID = -1; - var onResponse = function(data) { - taskID = data['id']; - trackTask(); - }; - - var trackTask = function() { - kimchi.getTask(taskID, onTaskResponse, err); - }; - - var onTaskResponse = function(result) { - var taskStatus = result['status']; - switch(taskStatus) { - case 'running': - progress && progress(result); - setTimeout(function() { - trackTask(); - }, 200); - break; - case 'finished': - case 'failed': - suc(result); - break; - default: - break; - } - }; - - wok.requestJSON({ - url : 'plugins/kimchi/host/swupdate', - type : "POST", - contentType : "application/json", - dataType : "json", - success : onResponse, - error : err - }); - }, - - createRepository : function(settings, suc, err) { - wok.requestJSON({ - url : "plugins/kimchi/host/repositories", - type : "POST", - contentType : "application/json", - data : JSON.stringify(settings), - dataType : "json", - success: suc, - error: err - }); - }, - - retrieveRepository : function(repository, suc, err) { - var reposID = encodeURIComponent(repository); - wok.requestJSON({ - url : "plugins/kimchi/host/repositories/" + reposID, - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - updateRepository : function(name, settings, suc, err) { - var reposID = encodeURIComponent(name); - $.ajax({ - url : "plugins/kimchi/host/repositories/" + reposID, - type : 'PUT', - contentType : 'application/json', - data : JSON.stringify(settings), - dataType : 'json', - success : suc, - error : err - }); - }, - - enableRepository : function(name, enable, suc, err) { - var reposID = encodeURIComponent(name); - $.ajax({ - url : "plugins/kimchi/host/repositories/" + reposID + - '/' + (enable === true ? 'enable' : 'disable'), - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - deleteRepository : function(repository, suc, err) { - var reposID = encodeURIComponent(repository); - wok.requestJSON({ - url : 'plugins/kimchi/host/repositories/' + reposID, - type : 'DELETE', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - listRepositories : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/host/repositories', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend: true, - success : suc, - error : err - }); - }, - - getHostFCDevices: function(suc, err) { - var url = 'plugins/kimchi/host/devices?_cap=fc_host'; - wok.requestJSON({ - url : url, - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getGuestInterfaces: function(name, suc, err) { - var url = 'plugins/kimchi/vms/' + encodeURIComponent(name) + '/ifaces'; - wok.requestJSON({ - url : url, - type : 'GET', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err || function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - createGuestInterface : function(name, interface, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(name) + '/ifaces', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - data : JSON.stringify(interface), - success : suc, - error : err || function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - deleteGuestInterface : function(vm, mac, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/ifaces/' + encodeURIComponent(mac), - type : 'DELETE', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - updateGuestInterface : function(vm, mac, interface, suc, err) { - $.ajax({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/ifaces/' + encodeURIComponent(mac), - type : 'PUT', - contentType : 'application/json', - data : JSON.stringify(interface), - dataType : 'json', - success: suc, - error: err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getUserById : function(data, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/users?_user_id=' + data.user_id, - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - async : false, - success : suc && suc(data), - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getUsers : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/users', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getGroups : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/groups', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getHostPCIDevices : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/host/devices?_passthrough=true&_cap=pci', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getPCIDeviceCompanions : function(pcidev, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/host/devices?_passthrough_affected_by=' + pcidev, - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getISCSITargets : function(server, port, suc, err) { - server = encodeURIComponent(server); - port = port ? '&_server_port='+encodeURIComponent(port) : ''; - wok.requestJSON({ - url : 'plugins/kimchi/storageservers/' + server + '/storagetargets?_target_type=iscsi' + port, - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getPeers : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/peers', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getVMPCIDevices : function(id, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(id) + '/hostdevs', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - addVMPCIDevice : function(vm, device, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/'+ encodeURIComponent(vm) +'/hostdevs', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - data : JSON.stringify(device), - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - removeVMPCIDevice : function(vm, device, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/'+ encodeURIComponent(vm) +'/hostdevs/' + encodeURIComponent(device), - type : 'DELETE', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - /** - * Create a new volume with capacity - */ - createVolumeWithCapacity: function(poolName, settings, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes', - type : 'POST', - contentType : "application/json", - data : JSON.stringify(settings), - dataType : "json", - success : suc, - error : err - }); - }, - - /** - * Upload volume content - */ - uploadVolumeToSP: function(poolName, volumeName, settings, suc, err) { - var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName); - var fd = settings['formData']; - wok.requestJSON({ - url : url, - type : 'PUT', - data : fd, - processData : false, - contentType : false, - dataType: 'json', - success : suc, - error : err - }); - }, - - /** - * Add a volume to a given storage pool by URL. - */ - downloadVolumeToSP: function(settings, suc, err) { - var sp = encodeURIComponent(settings['sp']); - delete settings['sp']; - wok.requestJSON({ - url : 'plugins/kimchi/storagepools/' + sp + '/storagevolumes', - type : 'POST', - data : JSON.stringify(settings), - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err - }); - }, - - cloneGuest: function(vm, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + "/clone", - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - listSnapshots : function(vm, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getCurrentSnapshot : function(vm, suc, err, sync) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots/current', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - async : !sync, - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - revertSnapshot : function(vm, snapshot, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots/' + encodeURIComponent(snapshot) + '/revert', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - createSnapshot : function(vm, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots', - type : 'POST', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - deleteSnapshot : function(vm, snapshot, suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots/' + encodeURIComponent(snapshot), - type : 'DELETE', - contentType : 'application/json', - dataType : 'json', - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - }, - - getCPUInfo : function(suc, err) { - wok.requestJSON({ - url : 'plugins/kimchi/host/cpuinfo', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err ? err : function(data) { - wok.message.error(data.responseJSON.reason); - } - }); - } -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.guest_add_main.js b/plugins/kimchi/ui/js/src/kimchi.guest_add_main.js deleted file mode 100644 index 6be6f9a..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.guest_add_main.js +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.guest_add_main = function() { - var showTemplates = function() { - wok.topic('templateCreated').unsubscribe(showTemplates); - kimchi.listTemplates(function(result) { - if (result && result.length) { - $('#prompt-create-template').addClass('hidden'); - $('#prompt-choose-template').removeClass('hidden'); - var html = ''; - var tmpl = $('#tmpl-template').html(); - $.each(result, function(index, value) { - html += wok.substitute(tmpl, value); - }); - $('#templateTile').html(html); - return; - } - - $('#btn-create-template').on('click', function(event) { - wok.topic('templateCreated').subscribe(showTemplates); - - wok.window.open('plugins/kimchi/template-add.html'); - - event.preventDefault(); - }); - - $('#prompt-choose-template').addClass('hidden'); - $('#prompt-create-template').removeClass('hidden'); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }; - - function validateForm() { - if (!$('input[name=template]:checked', '#templateTile').val()) { - return false; - } - return true; - } - - $('#form-vm-add').change(function() { - if (validateForm()) { - $('#vm-doAdd').attr('disabled', false); - } - }); - - var addGuest = function(event) { - $('#vm-doAdd').attr('disabled', true); - $('#vm-doAdd').attr('style', 'display:none'); - $('#vm-doAdding').attr('style', 'display'); - var formData = $('#form-vm-add').serializeObject(); - kimchi.createVM(formData, function() { - kimchi.listVmsAuto(); - wok.window.close(); - }, function(jqXHR, textStatus, errorThrown) { - $('#vm-doAdd').attr('style', 'display'); - $('#vm-doAdding').attr('style', 'display:none'); - var reason = jqXHR && - jqXHR['responseJSON'] && - jqXHR['responseJSON']['reason']; - wok.message.error(reason); - }); - - return false; - }; - - $('#form-vm-add').on('submit', addGuest); - $('#vm-doAdd').on('click', addGuest); - - showTemplates(); -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js b/plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js deleted file mode 100644 index 7105c88..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js +++ /dev/null @@ -1,759 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.guest_edit_main = function() { - var buttonContainer = $('#action-button-container'); - $('#guest-edit-tabs').tabs({ - beforeActivate: function(event, ui) { - var display_list = null; - if(kimchi.thisVMState === "running") { - display_list = ['form-guest-edit-permission']; - } else { - display_list = ['form-guest-edit-general', 'form-guest-edit-permission']; - } - $(buttonContainer).addClass('hidden'); - var deactivated = ui['newPanel']; - if(display_list.indexOf($(deactivated).attr('id')) >= 0) { - $(buttonContainer).removeClass('hidden'); - } - } - }); - - var guestEditForm = $('#form-guest-edit-general'); - var saveButton = $('#guest-edit-button-save'); - var authType; - - var refreshCDROMs = function() { - kimchi.listVMStorages({ - vm: kimchi.selectedGuest - }, function(storages) { - var container = $('#form-guest-edit-storage .body'); - $(container).empty(); - $.each(storages, function(index, storage) { - storage['vm'] = kimchi.selectedGuest; - rowHTML = $('#' + storage['type'] + '-row-tmpl').html(); - var templated = wok.substitute(rowHTML, storage); - container.append(templated); - }); - - $('.replace', container).button({ - icons: { - primary: 'ui-icon-pencil' - }, - text: false - }); - - $('.detach', container).button({ - icons: { - primary: 'ui-icon-trash' - }, - text: false - }); - if (kimchi.thisVMState === 'running') { - $('.detach[data-type="cdrom"]', container).remove(); - } - - $('.save', container).button({ - icons: { - primary: 'ui-icon-disk' - }, - text: false - }); - - $('.cancel', container).button({ - icons: { - primary: 'ui-icon-arrowreturnthick-1-w' - }, - text: false - }); - }); - }; - - var initStorageListeners = function() { - var container = $('#form-guest-edit-storage .body'); - var toggleCDROM = function(rowNode, toEdit) { - $('button.replace,button.detach', rowNode) - [(toEdit ? 'add' : 'remove') + 'Class']('hidden'); - $('button.save,button.cancel', rowNode) - [(toEdit ? 'remove' : 'add') + 'Class']('hidden'); - var pathBox = $('.path input', rowNode) - .prop('readonly', !toEdit); - toEdit && pathBox.select(); - pathBox.val(pathBox.attr('value')); - }; - - var replaceCDROM = function(event) { - event.preventDefault(); - kimchi.selectedGuestStorage = $(this).data('dev'); - $('.item', container).each(function(i, n) { - toggleCDROM(n); - }); - var rowNode = $('#cdrom-' + kimchi.selectedGuestStorage); - toggleCDROM(rowNode, true); - }; - - $(container).on('click', 'button.replace', replaceCDROM); - - $(container).on('click', 'button.detach', function(e) { - e.preventDefault(); - var settings = { - title : i18n['KCHAPI6004M'], - content : i18n['KCHVMCD6001M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - if ($(this).data('type') == "disk") - settings['content'] = i18n['KCHVMCD6009M']; - - var dev = $(this).data('dev'); - wok.confirm(settings, function() { - kimchi.deleteVMStorage({ - vm: kimchi.selectedGuest, - dev: dev - }, function() { - wok.topic('kimchi/vmCDROMDetached').publish(); - }); - }); - }); - - $(container).on('click', 'button.save', function(event) { - event.preventDefault(); - var path = $('#cdrom-path-' + kimchi.selectedGuestStorage).val(); - var settings = { - vm: kimchi.selectedGuest, - dev: kimchi.selectedGuestStorage, - path: path - }; - - kimchi.replaceVMStorage(settings, function(result) { - wok.topic('kimchi/vmCDROMReplaced').publish({ - result: result - }); - }, function(result) { - var errText = result['reason'] || - result['responseJSON']['reason']; - wok.message.error(errText); - }); - }); - - $(container).on('click', 'button.cancel', function(event) { - event.preventDefault(); - var rowNode = $('#cdrom-' + kimchi.selectedGuestStorage); - toggleCDROM(rowNode); - }); - }; - - var setupInterface = function() { - $(".add", "#form-guest-edit-interface").button({ - icons: { primary: "ui-icon-plusthick" }, - text: false - }).click(function(evt){ - evt.preventDefault(); - addItem({ - id: -1, - mac: "", - network: "", - type: "network", - viewMode: "hide", - editMode: "" - }); - }); - var toggleEdit = function(item, on, itemId){ - $("#label-mac-" + itemId, item).toggleClass("hide", on); - $("#edit-mac-" + itemId, item).toggleClass("hide", !on); - $("#label-network-" + itemId, item).toggleClass("hide", false); - $("select", item).toggleClass("hide", true); - $(".action-area", item).toggleClass("hide"); - }; - var addItem = function(data) { - if (data.id == -1) { - data.id = $('#form-guest-edit-interface > .body').children().size() - } - var itemNode = $.parseHTML(wok.substitute($('#interface-tmpl').html(),data)); - $(".body", "#form-guest-edit-interface").append(itemNode); - $("select", itemNode).append(networkOptions); - if(data.network!==""){ - $("select", itemNode).val(data.network); - } - $(".edit", itemNode).button({ - disabled: kimchi.thisVMState === "running", - icons: { primary: "ui-icon-pencil" }, - text: false - }).click(function(evt){ - evt.preventDefault(); - toggleEdit($(this).closest('div'), true, data.id); - }); - $(".delete", itemNode).button({ - icons: { primary: "ui-icon-trash" }, - text: false - }).click(function(evt){ - evt.preventDefault(); - var item = $(this).parent().parent(); - kimchi.deleteGuestInterface(kimchi.selectedGuest, item.prop("id"), function(){ - item.remove(); - }); - }); - $(".save", itemNode).button({ - icons: { primary: "ui-icon-disk" }, - text: false - }).click(function(evt){ - evt.preventDefault(); - var item = $(this).parent().parent(); - var interface = { - network: $("select", item).val(), - type: "network", - mac: $(":text", item).val() - }; - var postUpdate = function(mac){ - $("#label-network-" + data.id, item).text(interface.network); - $("#label-mac-" + data.id, item).text(mac); - $("#edit-mac-" + data.id, item).val(mac); - toggleEdit(item, false, data.id); - }; - if(item.prop("id")==""){ - kimchi.createGuestInterface(kimchi.selectedGuest, interface, function(data){ - item.prop("id", data.mac); - postUpdate(data.mac); - }); - }else{ - if (item.prop('id') == interface.mac) { - toggleEdit(item, false, data.id); - } else { - kimchi.updateGuestInterface(kimchi.selectedGuest, item.prop('id'), - interface, function(data){ - item.prop("id", data.mac); - postUpdate(data.mac); - }); - } - } - }); - $(".cancel", itemNode).button({ - icons: { primary: "ui-icon-arrowreturnthick-1-w" }, - text: false - }).click(function(evt){ - evt.preventDefault(); - var item = $(this).parent().parent(); - $("label", item).text()==="" ? item.remove() : toggleEdit(item, false, data.id); - }); - }; - var networkOptions = ""; - kimchi.listNetworks(function(data){ - for(var i=0;i<data.length;i++){ - var isSlected = i==0 ? " selected" : ""; - networkOptions += "<option"+isSlected+">"+data[i].name+"</option>"; - } - kimchi.getGuestInterfaces(kimchi.selectedGuest, function(data){ - for(var i=0;i<data.length;i++){ - data[i].viewMode = ""; - data[i].editMode = "hide"; - data[i].id = i; - addItem(data[i]); - } - }); - }); - }; - - var setupPermission = function() { - //set up for LDAP - $(".add", "#form-guest-edit-permission").button({ - icons: { primary: "ui-icon-plusthick" }, - text: false - }).click(function(evt){ - evt.preventDefault(); - addItem({ - user: "", - freeze: false, - viewMode: "hide", - editMode: "", - checked: true - }); - }); - var addItem = function(data) { - var itemNode = $.parseHTML(wok.substitute($('#ldap-user-tmpl').html(),data)); - $(".body", "#form-guest-edit-permission .ldap").append(itemNode); - $(".delete", itemNode).button({ - icons: { primary: "ui-icon-trash" }, - text: false - }).click(function(evt){ - evt.preventDefault(); - var item = $(this).parent().parent(); - item.remove(); - }); - $("input").focusout(function() { - var item = $(this).parent().parent(); - var user= $(this).val(); - item.prop("id", user); - $("label", item).text(user); - }); - $("input").focusin(function() { - $(this).removeClass("checked"); - }); - - if (data.checked == true) { - $(".checked", itemNode).addClass("hide"); - } - }; - var toggleEdit = function(item, on){ - $("label", item).toggleClass("hide", on); - $("input", item).toggleClass("hide", !on); - $(".action-area", item).toggleClass("hide"); - }; - //set up for PAM - var userNodes = {}, groupNodes = {}; - authType = kimchi.capabilities['auth'] - if (authType == 'pam') { - $("#form-guest-edit-permission .ldap").hide(); - kimchi.retrieveVM(kimchi.selectedGuest, function(vm){ - kimchi.getUsers(function(users){ - kimchi.getGroups(function(groups){ - var subArray = function(a1, a2){ //a1-a2 - for(var i=0; i<a2.length; i++){ - for(var j=0; j<a1.length; j++){ - if(a2[i] == a1[j]){ - a1.splice(j, 1); - break; - } - } - } - }; - subArray(users, vm.users); subArray(groups, vm.groups); - init(users, groups, vm.users, vm.groups); - }); - }); - }); - } else if (authType == 'ldap') { - $("#form-guest-edit-permission .pam").hide(); - kimchi.retrieveVM(kimchi.selectedGuest, function(vm){ - for (var i=0; i<vm.users.length; i++) { - addItem({ - user: vm.users[i], - viewMode: "", - freeze: true, - editMode: "hide", - checked: true}); - } - }); - } - var sortNodes = function(container, isUser){ - nodes = container.children(); - var keys = []; - nodes.each(function(){ - keys.push($("label", this).text()); - }); - keys.sort(); - container.empty(); - for(var i=0; i<keys.length; i++){ - var itemNode = isUser ? userNodes[keys[i]] : groupNodes[keys[i]]; - $(itemNode).click(function(){ - $(this).toggleClass("item-picked"); - }); - container.append(itemNode); - } - }; - var init = function(availUsers, availGroups, selUsers, selGroups){ - var initNode = function(key, isUserNode){ - var nodeGroups = isUserNode ? userNodes : groupNodes; - nodeGroups[key] = $.parseHTML(wok.substitute($('#permission-item-pam').html(), { - val: key, - class: isUserNode? "user-icon" : "group-icon" - })); - }; - for(var i=0; i<availUsers.length; i++){ - initNode(availUsers[i], true); - $("#permission-avail-users").append(userNodes[availUsers[i]]); - sortNodes($("#permission-avail-users"), true); - } - for(var i=0; i<selUsers.length; i++){ - initNode(selUsers[i], true); - $("#permission-sel-users").append(userNodes[selUsers[i]]); - sortNodes($("#permission-sel-users"), true); - } - for(var i=0; i<availGroups.length; i++){ - initNode(availGroups[i], false); - $("#permission-avail-groups").append(groupNodes[availGroups[i]]); - sortNodes($("#permission-avail-groups"), false); - } - for(var i=0; i<selGroups.length; i++){ - initNode(selGroups[i], false); - $("#permission-sel-groups").append(groupNodes[selGroups[i]]); - sortNodes($("#permission-sel-groups"), false); - } - }; - var filterNodes = function(key, container){ - container.children().each(function(){ - $(this).css("display", $("label", this).text().indexOf(key)==-1 ? "none" : ""); - }); - } - $("#permission-avail-searchBox").on("keyup", function() { - var key = $(this).val(); - filterNodes(key, $("#permission-avail-users")); - filterNodes(key, $("#permission-avail-groups")); - }); - $("#permission-sel-searchBox").on("keyup", function() { - var key = $(this).val(); - filterNodes(key, $("#permission-sel-users")); - filterNodes(key, $("#permission-sel-groups")); - }); - $('#permissionGo').button().click(function(evt) { - evt.preventDefault(); - $("#permission-avail-users").children(".item-picked").appendTo("#permission-sel-users").removeClass("item-picked"); - sortNodes($("#permission-sel-users"), true); - $("#permission-avail-groups").children(".item-picked").appendTo("#permission-sel-groups").removeClass("item-picked"); - sortNodes($("#permission-sel-groups"), false); - $("#permission-sel-searchBox").val(""); - filterNodes("", $("#permission-sel-users")); - filterNodes("", $("#permission-sel-groups")); - }); - $('#permissionBack').button().click(function(evt) { - evt.preventDefault(); - $("#permission-sel-users").children(".item-picked").appendTo("#permission-avail-users").removeClass("item-picked"); - sortNodes($("#permission-avail-users"), true); - $("#permission-sel-groups").children(".item-picked").appendTo("#permission-avail-groups").removeClass("item-picked"); - sortNodes($("#permission-avail-groups"), false); - $("#permission-avail-searchBox").val(""); - filterNodes("", $("#permission-avail-users")); - filterNodes("", $("#permission-avail-groups")); - }); - } - var setupPCIDevice = function(){ - kimchi.getHostPCIDevices(function(hostPCIs){ - kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs){ - var pciEnabled = kimchi.capabilities.kernel_vfio; - for(var i=0; i<hostPCIs.length; i++){ - var itemNode = $.parseHTML(wok.substitute($('#pci-tmpl').html(),{ - name: hostPCIs[i].name, - product: hostPCIs[i].product.description, - vendor: hostPCIs[i].vendor.description - })); - $(".body", "#form-guest-edit-pci").append(itemNode); - var iconClass = "ui-icon-plus"; - for(var j=0; j<vmPCIs.length; j++){ - if(hostPCIs[i].name==vmPCIs[j].name){ - iconClass = "ui-icon-minus"; - break; - } - } - pciEnabled || $("button", itemNode).remove(); - $("button", itemNode).button({ - icons: { primary: iconClass }, - text: false - }).click(function(){ - var obj = $(this); - if(obj.button("option", "icons").primary == "ui-icon-minus"){ - kimchi.removeVMPCIDevice(kimchi.selectedGuest, obj.parent().prop("id"), function(){ - kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs1){ - for(var k=0; k<hostPCIs.length; k++) { - $("button", "#" + hostPCIs[k].name).button("option", "icons", {primary: "ui-icon-plus"}); - } - for(var k=0; k<vmPCIs1.length; k++) { - $("button", "#" + vmPCIs1[k].name).button("option", "icons", {primary: "ui-icon-minus"}); - } - }); - filterNodes($("select", "#form-guest-edit-pci").val(), $("input", "#form-guest-edit-pci").val()); - }); - } else { - kimchi.addVMPCIDevice(kimchi.selectedGuest, { name: obj.parent().prop("id") }, function(){ - kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs1){ - for(var k=0; k<vmPCIs1.length; k++) { - $("button", "#" + vmPCIs1[k].name).button("option", "icons", {primary: "ui-icon-minus"}); - } - }); - filterNodes($("select", "#form-guest-edit-pci").val(), $("input", "#form-guest-edit-pci").val()); - }); - } - }); - kimchi.getPCIDeviceCompanions(hostPCIs[i].name, function(infoData) { - var pciTitle = i18n["KCHVMED6007M"] + "\n"; - var haveCompanions = false; - for(var p=0; p<infoData.length; p++) { - if(infoData[p].device_type === "net") { - haveCompanions = true; - pciTitle += " " + infoData[p].name + "\n"; - pciTitle += " " + i18n["KCHVMED6001M"] + " " + infoData[p].interface; - pciTitle += ", " + i18n["KCHVMED6002M"] + " " + infoData[p].address; - pciTitle += ", " + i18n["KCHVMED6003M"] + " " + infoData[p].link_type + "\n"; - } else if(infoData[p].device_type === "storage") { - haveCompanions = true; - pciTitle += " " + infoData[p].name + "\n"; - pciTitle += " " + i18n["KCHVMED6004M"] + " " + infoData[p].block; - pciTitle += ", " + i18n["KCHVMED6005M"] + " " + infoData[p].drive_type; - pciTitle += ", " + i18n["KCHVMED6006M"] + " " + infoData[p].model + "\n"; - } - } - for(var q=0; q<infoData.length; q++) { - haveCompanions && $(".name", "#" + infoData[q].parent).attr("title", pciTitle); - haveCompanions && $(".product", "#" + infoData[q].parent).attr("title", pciTitle); - haveCompanions && $(".vendor", "#" + infoData[q].parent).attr("title", pciTitle); - } - }); - } - }); - }); - var filterNodes = function(group, text){ - text = text.toLowerCase(); - $(".body", "#form-guest-edit-pci").children().each(function(){ - var textFilter = $(".name", this).text().toLowerCase().indexOf(text)!=-1; - textFilter = textFilter || $(".product", this).text().toLowerCase().indexOf(text)!=-1; - textFilter = textFilter || $(".vendor", this).text().toLowerCase().indexOf(text)!=-1; - var display = "none"; - var itemGroup = $("button", this).button("option", "icons").primary; - if(textFilter){ - if(group == "all"){ - display = ""; - }else if(group=="toAdd" && itemGroup=="ui-icon-plus"){ - display = "" - }else if(group == "added" && itemGroup=="ui-icon-minus"){ - display = "" - } - } - $(this).css("display", display); - }); - }; - $("select", "#form-guest-edit-pci").change(function(){ - filterNodes($(this).val(), $("input", "#form-guest-edit-pci").val()); - }); - $("input", "#form-guest-edit-pci").on("keyup", function() { - filterNodes($("select", "#form-guest-edit-pci").val(), $(this).val()); - }); - }; - - var setupSnapshot = function() { - var currentSnapshot; - var setCurrentSnapshot = function(aSnapshot){ - if(!aSnapshot) - kimchi.getCurrentSnapshot(kimchi.selectedGuest, function(snapshot){ - if(snapshot&&snapshot.name) aSnapshot = snapshot.name; - }, null, true); - if(aSnapshot){ - if(currentSnapshot) $(".ui-icon-check", "#"+currentSnapshot).addClass("hide"); - $(".ui-icon-check", "#"+aSnapshot).removeClass("hide"); - currentSnapshot = aSnapshot; - } - }; - var addItem = function(data, container) { - var itemNode = $.parseHTML(wok.substitute($('#snapshot-tmpl').html(),data)); - $("."+container, "#form-guest-edit-snapshot").append(itemNode); - $(".delete", itemNode).button({ - icons: { primary: "ui-icon-trash" }, - text: false - }).click(function(evt){ - evt.preventDefault(); - var item = $(this).parent().parent(); - $("button", "#form-guest-edit-snapshot").button("disable"); - kimchi.deleteSnapshot(kimchi.selectedGuest, item.prop("id"), function(){ - item.remove(); - setCurrentSnapshot(); - $("button", "#form-guest-edit-snapshot").button("enable"); - }, function(data){ - wok.message.error(data.responseJSON.reason); - $("button", "#form-guest-edit-snapshot").button("enable"); - }); - }); - $(".revert", itemNode).button({ - icons: { primary: "ui-icon-arrowthick-1-ne" }, - text: false - }).click(function(evt){ - evt.preventDefault(); - var item = $(this).parent().parent(); - $(".ui-icon-check", item).addClass("hide"); - $(".icon", item).removeClass("hide"); - $("button", "#form-guest-edit-snapshot").button("disable"); - kimchi.revertSnapshot(kimchi.selectedGuest, item.prop("id"), function(){ - $(".icon", item).addClass("hide"); - $("button", "#form-guest-edit-snapshot").button("enable"); - setCurrentSnapshot(item.prop("id")); - kimchi.listVmsAuto(); - wok.window.close(); - }, function(data){ - wok.message.error(data.responseJSON.reason); - $(".icon", item).addClass("hide"); - $("button", "#form-guest-edit-snapshot").button("enable"); - }); - }); - }; - var addOngoingItem = function(task){ - var uri = task.target_uri; - addItem({ - name: uri.substring(uri.lastIndexOf('/')+1, uri.length), - created: "", - listMode: "hide", - createMode: "" - }, 'task'); - if(kimchi.trackingTasks.indexOf(task.id)==-1) - kimchi.trackTask(task.id, function(task){ - listGeneratingSnapshots(); - $("button", "#form-guest-edit-snapshot").button("enable"); - }, function(err){ - wok.message.error(err.message); - listGeneratingSnapshots(); - $("button", "#form-guest-edit-snapshot").button("enable"); - }); - }; - var listGeneratingSnapshots = function(){ - kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/plugins/kimchi/snapshots/*'), function(tasks) { - $(".task", "#form-guest-edit-snapshot").empty(); - for(var i=0;i<tasks.length;i++){ - addOngoingItem(tasks[i]); - } - if(tasks.length==0) listSnapshots(); - }); - }; - var listSnapshots = function(){ - kimchi.listSnapshots(kimchi.selectedGuest, function(data){ - $(".body", "#form-guest-edit-snapshot").empty(); - for(var i=0;i<data.length;i++){ - data[i].created = new Date(data[i].created*1000).toLocaleString(); - data[i].createMode = "hide"; - data[i].listMode = ""; - addItem(data[i], 'body'); - } - setCurrentSnapshot(); - }); - }; - listGeneratingSnapshots(); - $(".add", "#form-guest-edit-snapshot").button({ - icons: { primary: "ui-icon-plusthick" }, - text: false - }).click(function(evt){ - evt.preventDefault(); - kimchi.createSnapshot(kimchi.selectedGuest, function(task){ - $("button", "#form-guest-edit-snapshot").button("disable"); - addOngoingItem(task); - }); - }); - if(kimchi.thisVMState=="running") $("button", "#form-guest-edit-snapshot").remove(); - }; - - var initContent = function(guest) { - guest['icon'] = guest['icon'] || 'plugins/kimchi/images/icon-vm.png'; - $('#form-guest-edit-general').fillWithObject(guest); - kimchi.thisVMState = guest['state']; - refreshCDROMs(); - $('#guest-edit-attach-cdrom-button').button({ - icons: { - primary: "ui-icon-plusthick" - }, - text: false - }).click(function(event) { - event.preventDefault(); - wok.window.open("plugins/kimchi/guest-storage-add.html"); - }); - if(kimchi.thisVMState === "running") { - $("#form-guest-edit-general input").prop("disabled", true); - } else { - $("#action-button-container").removeClass("hidden"); - } - - var onAttached = function(params) { - refreshCDROMs(); - }; - var onReplaced = function(params) { - refreshCDROMs(); - }; - var onDetached = function(params) { - refreshCDROMs(); - }; - - initStorageListeners(); - setupInterface(); - setupPermission(); - setupPCIDevice(); - setupSnapshot(); - - wok.topic('kimchi/vmCDROMAttached').subscribe(onAttached); - wok.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced); - wok.topic('kimchi/vmCDROMDetached').subscribe(onDetached); - - kimchi.clearGuestEdit = function() { - wok.topic('kimchi/vmCDROMAttached').unsubscribe(onAttached); - wok.topic('kimchi/vmCDROMReplaced').unsubscribe(onReplaced); - wok.topic('kimchi/vmCDROMDetached').unsubscribe(onDetached); - }; - }; - - kimchi.retrieveVM(kimchi.selectedGuest, initContent); - - var generalSubmit = function(event) { - $(saveButton).prop('disabled', true); - var data=$('#form-guest-edit-general').serializeObject(); - if(data['memory']!=undefined) { - data['memory'] = Number(data['memory']); - } - if(data['cpus']!=undefined) { - data['cpus'] = Number(data['cpus']); - } - - kimchi.updateVM(kimchi.selectedGuest, data, function() { - kimchi.listVmsAuto(); - wok.window.close(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - $(saveButton).prop('disabled', false); - }); - } - - var permissionSubmit = function(event) { - var content = { users: [], groups: [] }; - authType = kimchi.capabilities['auth'] - if (authType == 'pam') { - $("#permission-sel-users").children().each(function(){ - content.users.push($("label", this).text()); - }); - $("#permission-sel-groups").children().each(function(){ - content.groups.push($("label", this).text()); - }); - kimchi.updateVM(kimchi.selectedGuest, content, function(){ - wok.window.close(); - }); - } else if (authType == 'ldap') { - $(saveButton).prop('disabled', true); - var errors = 0; - - $(".body", "#form-guest-edit-permission .ldap").children().each(function () { - var elem = $(this); - content.users.push(elem.attr("id")); - - if (!$('input', elem).hasClass('hide')) { - var user = {'user_id': $(this).attr("id")}; - kimchi.getUserById(user, null, function (data) { - errors += 1; - $("input", elem).addClass("checked"); - }); - } - }); - if (errors == 0) { - kimchi.updateVM(kimchi.selectedGuest, content, function(){ - wok.window.close(); - }); - } else { - $(saveButton).prop('disabled', false); - } - } - } - - // tap map, "general": 0, "storage": 1, "interface": 2, "permission": 3, "password": 4 - var submit_map = {0: generalSubmit, 3:permissionSubmit}; - var submitForm = function(event) { - var current = $('#guest-edit-tabs').tabs( "option", "active" ); - var submitFun = submit_map[current]; - submitFun && submitFun(event); - event.preventDefault(); - }; - - $(guestEditForm).on('submit', submitForm); - $(saveButton).on('click', submitForm); -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.guest_main.js b/plugins/kimchi/ui/js/src/kimchi.guest_main.js deleted file mode 100644 index 7dd5d84..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.guest_main.js +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -kimchi.sampleGuestObject = { - "name": "", - "uuid": "", - "state": "shutoff", - "persistent": true, - "icon": null, - "cpus": 0, - "memory": 0, - "stats": { - "net_throughput": 0, - "io_throughput_peak": 100, - "cpu_utilization": 0, - "io_throughput": 0, - "net_throughput_peak": 100 - }, - "screenshot": null, - "graphics": { - "passwd": null, - "passwdValidTo": null, - "type": "vnc", - "port": null, - "listen": "127.0.0.1" - }, - "users": [], - "groups": [], - "access": "full" -}; - -kimchi.vmstart = function(event) { - var button=$(this); - if (!button.hasClass('loading')) { - button.addClass('loading'); - var vm=$(this).closest('li[name=guest]'); - var vm_id=vm.attr("id"); - kimchi.startVM(vm_id, function(result) { - button.removeClass('loading'); - kimchi.listVmsAuto(); - }, function(err) { - button.removeClass('loading'); - wok.message.error(err.responseJSON.reason); - } - ); - } else { - event.preventDefault(); - event.stopPropagation(); - return; - } -}; - -kimchi.vmsuspend = function(event) { - var button=$(this); - if (!button.hasClass('pause-gray')) { - button.addClass('pause-gray'); - var vm=$(this).closest('li[name=guest]'); - var vm_id=vm.attr("id"); - kimchi.suspendVM(vm_id, function(result) { - button.removeClass('pause-gray'); - kimchi.listVmsAuto(); - }, function(err) { - button.removeClass('pause-gray'); - wok.message.error(err.responseJSON.reason); - } - ); - } else { - event.preventDefault(); - event.stopPropagation(); - return; - } -}; - -kimchi.vmresume = function(event) { - var button=$(this); - if (!button.hasClass('resume-gray')) { - button.addClass('resume-gray'); - var vm=$(this).closest('li[name=guest]'); - var vm_id=vm.attr("id"); - kimchi.resumeVM(vm_id, function(result) { - button.removeClass('resume-gray'); - kimchi.listVmsAuto(); - }, function(err) { - button.removeClass('resume-gray'); - wok.message.error(err.responseJSON.reason); - } - ); - } else { - event.preventDefault(); - event.stopPropagation(); - return; - } -}; - -kimchi.vmpoweroff = function(event) { - var button=$(this); - if (!button.hasClass('loading')) { - button.addClass('loading'); - var vm=button.closest('li[name=guest]'); - var vm_id=vm.attr("id"); - var vmObject=vm.data(); - var vm_persistent=vmObject.persistent == true; - var content_msg = vm_persistent ? i18n['KCHVM6003M'] : - i18n['KCHVM6009M']; - var settings = { - title : i18n['KCHVM6002M'], - content : content_msg, - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - wok.confirm(settings, function() { - kimchi.poweroffVM(vm_id, function(result) { - button.removeClass('loading'); - kimchi.listVmsAuto(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }, function() { - }); - } else { - event.preventDefault(); - event.stopPropagation(); - } -}; - -kimchi.vmshutdown = function(event){ - var vm=$(this).closest('li[name=guest]'); - var vm_id=vm.attr("id"); - var settings = { - title : i18n['KCHVM6006M'], - content : i18n['KCHVM6007M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - wok.confirm(settings, function() { - kimchi.shutdownVM(vm_id, function(result) { - kimchi.listVmsAuto(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - } - ); - }, function() { - }); -}; - -kimchi.vmreset = function(event){ - var vm=$(this).closest('li[name=guest]'); - var vm_id=vm.attr("id"); - var settings = { - title : i18n['KCHVM6004M'], - content : i18n['KCHVM6005M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - wok.confirm(settings, function() { - kimchi.resetVM(vm_id, function(result) { - kimchi.listVmsAuto(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - } - ); - }, function() { - }); -}; - -kimchi.vmdelete = function(event) { - var vm = $(this).closest('li[name=guest]'); - var vm_id=vm.attr("id"); - var settings = { - title : i18n['KCHVM6008M'], - content : i18n['KCHVM6001M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - wok.confirm(settings, function() { - kimchi.deleteVM(vm_id, function(result) { - kimchi.listVmsAuto(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }, function() { - }); -}; - -kimchi.vmedit = function(event) { - var vm = $(this).closest('li[name=guest]'); - var vm_id=vm.attr("id"); - kimchi.selectedGuest = vm_id; - wok.window.open({ - url: 'plugins/kimchi/guest-edit.html', - close: function() { - kimchi.clearGuestEdit(); - } - }); -}; - -kimchi.openVmConsole = function(event) { - var vm=$(this).closest('li[name=guest]'); - var vmObject=vm.data(); - if (vmObject.graphics['type'] == 'vnc') { - kimchi.vncToVM(vm.attr('id')); - } - else if (vmObject.graphics['type'] == 'spice') { - kimchi.spiceToVM(vm.attr('id')); - } - -}; - -kimchi.getVmsCurrentConsoleImgs = function() { - var res = new Object(); - $('#guestList').children().each(function() { - res[$(this).attr('id')] = $(this).find('img.imgactive').attr('src'); - }) - return res; -}; - -kimchi.getOpenMenuVmId = function() { - var result; - var openMenu = $('#guestList div[name="actionmenu"] .popover:visible'); - if(openMenu) { - var li_element=openMenu.closest('li'); - result=li_element.attr('id'); - } - return result; -}; - -kimchi.listVmsAuto = function() { - if (kimchi.vmTimeout) { - clearTimeout(kimchi.vmTimeout); - } - var getCreatingGuests = function(){ - var guests = []; - kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/plugins/kimchi/vms/[^/]+$'), function(tasks) { - for(var i=0;i<tasks.length;i++){ - var guestUri = tasks[i].target_uri; - var guestName = guestUri.split('/')[2] - guests.push($.extend({}, kimchi.sampleGuestObject, {name: guestName, isCreating: true})); - if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1) - kimchi.trackTask(tasks[i].id, null, function(err){ - wok.message.error(err.message); - }, null); - } - }, null, true); - return guests; - }; - var getCloningGuests = function(){ - var guests = []; - kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/plugins/kimchi/vms/.+/clone'), function(tasks) { - for(var i=0;i<tasks.length;i++){ - var guestUri = tasks[i].target_uri; - var guestName = guestUri.split('/')[2] - guests.push($.extend({}, kimchi.sampleGuestObject, {name: guestName, isCloning: true})); - if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1) - kimchi.trackTask(tasks[i].id, null, function(err){ - wok.message.error(err.message); - }, null); - } - }, null, true); - return guests; - }; - kimchi.listVMs(function(result, textStatus, jqXHR) { - if (result && textStatus=="success") { - result = getCloningGuests().concat(result); - result = getCreatingGuests().concat(result); - if(result.length) { - var listHtml = ''; - var guestTemplate = kimchi.guestTemplate; - var currentConsoleImages = kimchi.getVmsCurrentConsoleImgs(); - var openMenuGuest = kimchi.getOpenMenuVmId(); - $('#guestList').empty(); - $('#guestListField').show(); - $('#noGuests').hide(); - - $.each(result, function(index, vm) { - var guestLI = kimchi.createGuestLi(vm, currentConsoleImages[vm.name], vm.name==openMenuGuest); - $('#guestList').append(guestLI); - }); - } else { - $('#guestListField').hide(); - $('#noGuests').show(); - } - } - - kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); - }, function(errorResponse, textStatus, errorThrown) { - if(errorResponse.responseJSON && errorResponse.responseJSON.reason) { - wok.message.error(errorResponse.responseJSON.reason); - } - kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); - }); -}; - -kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { - var result=kimchi.guestElem.clone(); - - //Setup the VM list entry - var vmRunningBool=(vmObject.state=="running"); - var vmSuspendedBool = (vmObject.state=="paused"); - var vmPoweredOffBool = (vmObject.state=="shutoff"); - var vmPersistent = (vmObject.persistent == true); - result.attr('id',vmObject.name); - result.data(vmObject); - - //Add the Name - var guestTitle=result.find('.title').attr('title',vmObject.name); - guestTitle.html(vmObject.name); - - //Setup the VM console thumbnail display - var curImg = vmObject.icon; - if (vmObject.screenshot) { - curImg = vmObject.screenshot.replace(/^\//,''); - } - var load_src = curImg || 'plugins/kimchi/images/icon-vm.png'; - var tile_src = prevScreenImage || vmObject['load-src']; - var liveTile=result.find('div[name=guest-tile] > .tile'); - liveTile.addClass(vmObject.state); - liveTile.find('.imgactive').attr('src',tile_src); - var imgLoad=liveTile.find('.imgload'); - imgLoad.on('load', function() { - var oldImg=$(this).parent().find('.imgactive'); - oldImg.removeClass("imgactive").addClass("imgload"); - oldImg.attr("src",""); - $(this).addClass("imgactive").removeClass("imgload"); - $(this).off('load'); - }); - imgLoad.attr('src',load_src); - - //Link the stopped tile to the start action, the running tile to open the console, and the paused tile to resume - if(!(vmObject.isCloning || vmObject.isCreating)){ - if (vmPoweredOffBool) { - liveTile.off("click", kimchi.openVmConsole); - liveTile.off("click", kimchi.vmresume); - liveTile.on("click", kimchi.vmstart); - liveTile.hover(function(event){$(this).find('.overlay').show()}, function(event){$(this).find('.overlay').hide()}); - } else if (vmSuspendedBool) { - liveTile.off("click", kimchi.vmstart); - liveTile.off("click", kimchi.openVmConsole); - liveTile.on("click", kimchi.vmresume); - if(vmObject.state="paused") { - liveTile.find('.overlay').attr('src',"plugins/kimchi/images/theme-default/ac24_resume.png"); - liveTile.find('.overlay').attr('alt',"Resume"); - } - liveTile.hover(function(event){$(this).find('.overlay').show()}, function(event){$(this).find('.overlay').hide()}); - } else { - liveTile.off("click", kimchi.vmstart); - liveTile.off("click", kimchi.vmresume); - liveTile.on("click", kimchi.openVmConsole); - } - } - - //Setup the gauges - var stats=vmObject.stats; - var gaugeValue=0; - gaugeValue=parseInt(stats.net_throughput); - kimchi.circleGaugeInit(result, "net_throughput",gaugeValue,(gaugeValue*100/stats.net_throughput_peak)); - gaugeValue=parseInt(stats.io_throughput); - kimchi.circleGaugeInit(result, "io_throughput",gaugeValue,(gaugeValue*100/stats.io_throughput_peak)); - gaugeValue=parseInt(stats.cpu_utilization); - kimchi.circleGaugeInit(result, "cpu_utilization",gaugeValue+"%",gaugeValue); - - //Setup the VM Actions - var guestActions=result.find("div[name=guest-actions]"); - guestActions.find(".shutoff-disabled").prop("disabled", !vmRunningBool); - guestActions.find(".running-disabled").prop("disabled", vmRunningBool); - guestActions.find(".non-persistent-disabled").prop("disabled", !vmPersistent); - guestActions.find(".reset-disabled").prop("disabled", vmPoweredOffBool || !vmPersistent); - guestActions.find(".pause-disabled").prop("disabled", vmPoweredOffBool || !vmPersistent); - - if (vmSuspendedBool) { //VM is paused - //Hide Start - guestActions.find(".running-hidden").hide(); - //Hide Pause button and menu - guestActions.find(".pause-disabled").hide(); - guestActions.find(".pause-hidden").hide(); - } - - if (vmRunningBool) { //VM IS running - //Hide Start - guestActions.find(".running-hidden").hide(); - //Hide Resume - guestActions.find(".resume-hidden").hide(); - } - - if (vmPoweredOffBool) { //VM is powered off - //Hide PowerOff - guestActions.find(".shutoff-hidden").hide(); - //Hide Pause - guestActions.find(".pause-hidden").hide(); - //Hide Resume - guestActions.find(".resume-hidden").hide(); - } - - var consoleActions=guestActions.find("[name=vm-console]"); - - if ((vmObject.graphics['type'] == 'vnc') || (vmObject.graphics['type'] == 'spice')) { - consoleActions.on("click", kimchi.openVmConsole); - consoleActions.show(); - } else { //we don't recognize the VMs supported graphics, so hide the menu choice - consoleActions.hide(); - consoleActions.off("click",kimchi.openVmConsole); - } - - //Setup action event handlers - if(!(vmObject.isCloning || vmObject.isCreating)){ - guestActions.find("[name=vm-start]").on({click : kimchi.vmstart}); - guestActions.find("[name=vm-poweroff]").on({click : kimchi.vmpoweroff}); - if ((vmRunningBool) || (vmSuspendedBool)) { - //If the guest is not running, do not enable reset; otherwise, reset is enabled (when running or paused) - guestActions.find("[name=vm-reset]").on({click : kimchi.vmreset}); - - //If the guest is not running, do not enable shutdown;otherwise, shutdown is enabled (when running or paused) - guestActions.find("[name=vm-shutdown]").on({click : kimchi.vmshutdown}); - } - - if (vmSuspendedBool) { - guestActions.find("[name=vm-resume]").on({click : kimchi.vmresume}); - } - - if (vmRunningBool) { - guestActions.find("[name=vm-pause]").on({click : kimchi.vmsuspend}); - } - - guestActions.find("[name=vm-edit]").on({click : kimchi.vmedit}); - guestActions.find("[name=vm-delete]").on({click : kimchi.vmdelete}); - guestActions.find("[name=vm-clone]").click(function(){ - var guest = $(this).closest('li[name=guest]').attr("id"); - wok.confirm({ - title : i18n['KCHAPI6006M'], - content : i18n['KCHVM6010M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }, function() { - kimchi.cloneGuest(guest, function(data){ - kimchi.listVmsAuto(); - }); - }, null); - }); - - //Maintain menu open state - var actionMenu=guestActions.find("div[name=actionmenu]"); - if (openMenu) { - $('.popover', actionMenu).toggle(); - } - - }else{ - guestActions.find('.btn').attr('disabled', true); - $('.popover', guestActions.find("div[name=actionmenu]")).remove(); - - result.find('.guest-pending').removeClass('hide-content'); - pendingText = result.find('.guest-pending .text') - if(vmObject.isCloning) - pendingText.text(i18n['KCHAPI6009M']); - else - pendingText.text(i18n['KCHAPI6008M']); - } - - return result; -}; - -kimchi.circleGaugeInit = function(topElement, divName, display, percentage){ - var gauge=topElement.find('div[name="' + divName + '"] .circleGauge'); - if(gauge) { - var data=Object(); - data.percentage = percentage; - data.display = display; - gauge.data(data); - } - gauge.circleGauge(); - return(gauge); -}; - -kimchi.guestSetRequestHeader = function(xhr) { - xhr.setRequestHeader('Accept', 'text/html'); -}; - -kimchi.guest_main = function() { - if(wok.tabMode['guests'] === 'admin') { - $('.tools').attr('style','display'); - $("#vm-add").on("click", function(event) { - wok.window.open('plugins/kimchi/guest-add.html'); - }); - } - kimchi.guestTemplate = $('#guest-tmpl').html(); - kimchi.guestElem=$('<div/>').html(kimchi.guestTemplate).find('li'); - $('#guests-root-container').on('remove', function() { - kimchi.vmTimeout && clearTimeout(kimchi.vmTimeout); - }); - kimchi.listVmsAuto() -}; - -kimchi.editTemplate = function(guestTemplate, oldPopStat) { - if (oldPopStat) { - return guestTemplate.replace("vm-action", "vm-action open"); - } - return guestTemplate; -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.guest_media_main.js b/plugins/kimchi/ui/js/src/kimchi.guest_media_main.js deleted file mode 100644 index b920527..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.guest_media_main.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.guest_media_main = function() { - - var refreshCDROMs = function() { - kimchi.listVMStorages({ - vm: kimchi.selectedGuest, - storageType: 'cdrom' - }, function(storages) { - var rowHTML = $('#cdrom-row-tmpl').html(); - var container = $('#guest-edit-cdrom-row-container'); - $(container).empty(); - - $.each(storages, function(index, storage) { - storage['vm'] = kimchi.selectedGuest; - var templated = wok.substitute(rowHTML, storage); - container.append(templated); - }); - - var replaceCDROM = function(event) { - event.preventDefault(); - kimchi.selectedGuestStorage = $(this).data('dev'); - wok.window.open("plugins/kimchi/guest-cdrom-edit.html"); - }; - - $('input[type="text"][name="cdrom"]', container).on('click', replaceCDROM); - $('.replace', container).on('click', replaceCDROM); - }); - }; - - refreshCDROMs(); - - var onReplaced = function(params) { - refreshCDROMs(); - }; - wok.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced); - - kimchi.clearGuestMedia = function() { - wok.topic('kimchi/vmCDROMReplaced').unsubscribe(onReplaced); - }; -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.guest_storage_add.main.js b/plugins/kimchi/ui/js/src/kimchi.guest_storage_add.main.js deleted file mode 100644 index bc162e8..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.guest_storage_add.main.js +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.guest_storage_add_main = function() { - var types = [{ - label: 'cdrom', - value: 'cdrom', - }, - { - label: 'disk', - value: 'disk', - }]; - var typesRunning = [{ - label: 'disk', - value: 'disk' - }]; - - var storageAddForm = $('#form-guest-storage-add'); - var submitButton = $('#guest-storage-button-add'); - var typeTextbox = $('input[name="type"]', storageAddForm); - var pathTextbox = $('input[name="path"]', storageAddForm); - var poolTextbox = $('input[name="pool"]', storageAddForm); - var volTextbox = $('input[name="vol"]', storageAddForm); - - typeTextbox.change(function() { - var pathObject = {'cdrom': ".path-section", 'disk': '.volume-section'} - selectType = $(this).val(); - $.each(pathObject, function(type, value) { - if(selectType == type){ - $(value).removeClass('hidden'); - } else { - $(value).addClass('hidden'); - } - }); - - if ($(".path-section").hasClass('hidden')) { - $(poolTextbox).val('default'); - $(poolTextbox).change(); - $(pathTextbox).val(""); - } - else { - $(poolTextbox).val(""); - $(volTextbox).val(""); - } - }); - - kimchi.listStoragePools(function(result) { - var options = []; - if (result && result.length) { - $.each(result, function(index, storagePool) { - if ((storagePool.state=="active") && (storagePool.type !== 'kimchi-iso')) { - options.push({ - label: storagePool.name, - value: storagePool.name - }); - } - }); - wok.select('guest-add-storage-pool-list', options); - } - }); - - poolTextbox.change(function() { - var options = []; - kimchi.listStorageVolumes($(this).val(), function(result) { - var validVolType = { cdrom: /iso/, disk: /^(raw|qcow|qcow2|bochs|qed|vmdk)$/}; - $('#guest-disk').selectMenu(); - if (result.length) { - $.each(result, function(index, value) { - // Only unused volume can be attached - if (value.used_by.length == 0 && (value.type != 'file' || validVolType[selectType].test(value.format))) { - options.push({ - label: value.name, - value: value.name - }); - } - }); - if (options.length) { - $(volTextbox).val(options[0].value); - $(volTextbox).change(); - } - } - $('#guest-disk').selectMenu("setData", options); - }); - }); - - - typeTextbox.change(function() { - var pathObject = {'cdrom': ".path-section", 'disk': '.volume-section'} - var selectType = $(this).val(); - $.each(pathObject, function(type, value) { - if(selectType == type){ - $(value).removeClass('hidden'); - } else { - $(value).addClass('hidden'); - } - }); - }); - - if (kimchi.thisVMState === 'running') { - types =typesRunning; - $(typeTextbox).val('disk'); - typeTextbox.change(); - poolTextbox.change(); - } - var selectType = $(typeTextbox).val(); - wok.select('guest-storage-type-list', types); - - var validateCDROM = function(settings) { - if (/^((https|http|ftp|ftps|tftp|\/).*)+$/.test(settings['path'])) - return true; - else { - wok.message.error.code('KCHVMSTOR0001E'); - return false; - } - } - - var validateDisk = function(settings) { - if (settings['pool'] && settings['vol']) - return true; - else { - wok.message.error.code('KCHVMSTOR0002E'); - return false; - } - } - - validator = {cdrom: validateCDROM, disk: validateDisk}; - var submitForm = function(event) { - if (submitButton.prop('disabled')) { - return false; - } - - var formData = storageAddForm.serializeObject(); - var settings = { - vm: kimchi.selectedGuest, - type: typeTextbox.val(), - }; - - $(submitButton).prop('disabled', true); - $.each([pathTextbox, poolTextbox, volTextbox], function(i, c) { - $(c).prop('disabled', true); - val = $(c).val() - if (val && val != '') { - settings[$(c).attr('name')] = $(c).val(); - } - }); - // Validate form for cdrom and disk - validateSpecifiedForm = validator[settings['type']]; - if (!validateSpecifiedForm(settings)) { - $(submitButton).prop('disabled', false); - $.each([submitButton, pathTextbox, poolTextbox, volTextbox], function(i, c) { - $(c).prop('disabled', false); - }); - return false; - } - $(submitButton).addClass('loading').text(i18n['KCHVMCD6003M']); - - kimchi.addVMStorage(settings, function(result) { - wok.window.close(); - wok.topic('kimchi/vmCDROMAttached').publish({ - result: result - }); - }, function(result) { - var errText = result['reason'] || - result['responseJSON']['reason']; - wok.message.error(errText); - - $.each([submitButton, pathTextbox, poolTextbox, volTextbox], function(i, c) { - $(c).prop('disabled', false); - }); - $(submitButton).removeClass('loading').text(i18n['KCHVMCD6002M']); - }); - - event.preventDefault(); - }; - - storageAddForm.on('submit', submitForm); - submitButton.on('click', submitForm); - pathTextbox.on('change input propertychange', function(event) { - $(submitButton).prop('disabled', $(this).val() === ''); - }); - volTextbox.on('change propertychange', function (event) { - $(submitButton).prop('disabled', $(this).val() === ''); - }); - -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.host.js b/plugins/kimchi/ui/js/src/kimchi.host.js deleted file mode 100644 index e2d2511..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.host.js +++ /dev/null @@ -1,858 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.host={}; - -kimchi.host_main = function() { - var expand = function(header, toExpand) { - var controlledNode = $(header).attr('aria-controls'); - $('#' + controlledNode)[toExpand ? 'removeClass' : 'addClass']('hidden'); - $(header).attr('aria-expanded', toExpand ? 'true' : 'false'); - }; - - var repositoriesGrid = null; - var initRepositoriesGrid = function(repo_type) { - var gridFields=[]; - if (repo_type == "yum") { - gridFields=[{ - name: 'repo_id', - label: i18n['KCHREPO6004M'], - 'class': 'repository-id' - }, { - name: 'config[repo_name]', - label: i18n['KCHREPO6005M'], - 'class': 'repository-name' - }, { - name: 'enabled', - label: i18n['KCHREPO6009M'], - 'class': 'repository-enabled' - }]; - } - else if (repo_type == "deb") { - gridFields=[{ - name: 'baseurl', - label: i18n['KCHREPO6006M'], - makeTitle: true, - 'class': 'repository-baseurl deb' - }, { - name: 'enabled', - label: i18n['KCHREPO6009M'], - 'class': 'repository-enabled deb' - }, { - name: 'config[dist]', - label: "dist", - 'class': 'repository-gpgcheck deb' - }, { - name: 'config[comps]', - label: "comps", - 'class': 'repository-gpgcheck deb' - }]; - } - else { - gridFields=[{ - name: 'repo_id', - label: i18n['KCHREPO6004M'], - 'class': 'repository-id' - }, { - name: 'enabled', - label: i18n['KCHREPO6009M'], - 'class': 'repository-enabled' - }, { - name: 'baseurl', - label: i18n['KCHREPO6006M'], - makeTitle: true, - 'class': 'repository-baseurl' - }]; - } - repositoriesGrid = new wok.widget.Grid({ - container: 'repositories-grid-container', - id: 'repositories-grid', - title: i18n['KCHREPO6003M'], - toolbarButtons: [{ - id: 'repositories-grid-add-button', - label: i18n['KCHREPO6012M'], - onClick: function(event) { - wok.window.open({url:'plugins/kimchi/repository-add.html', - class: repo_type}); - } - }, { - id: 'repositories-grid-enable-button', - label: i18n['KCHREPO6016M'], - disabled: true, - onClick: function(event) { - var repository = repositoriesGrid.getSelected(); - if(!repository) { - return; - } - var name = repository['repo_id']; - var enable = !repository['enabled']; - $(this).prop('disabled', true); - kimchi.enableRepository(name, enable, function() { - wok.topic('kimchi/repositoryUpdated').publish(); - }); - } - }, { - id: 'repositories-grid-edit-button', - label: i18n['KCHREPO6013M'], - disabled: true, - onClick: function(event) { - var repository = repositoriesGrid.getSelected(); - if(!repository) { - return; - } - kimchi.selectedRepository = repository['repo_id']; - wok.window.open({url:'plugins/kimchi/repository-edit.html', - class: repo_type}); - } - }, { - id: 'repositories-grid-remove-button', - label: i18n['KCHREPO6014M'], - disabled: true, - onClick: function(event) { - var repository = repositoriesGrid.getSelected(); - if(!repository) { - return; - } - - var settings = { - title : i18n['KCHREPO6001M'], - content : i18n['KCHREPO6002M'], - confirm : i18n['KCHAPI6004M'], - cancel : i18n['KCHAPI6003M'] - }; - - wok.confirm(settings, function() { - kimchi.deleteRepository( - repository['repo_id'], - function(result) { - wok.topic('kimchi/repositoryDeleted').publish(result); - }, function(error) { - } - ); - }); - } - }], - onRowSelected: function(row) { - var repository = repositoriesGrid.getSelected(); - if(!repository) { - return; - } - $('#repositories-grid-remove-button').prop('disabled', false); - $('#repositories-grid-edit-button').prop('disabled', false); - var enabled = repository['enabled']; - $('#repositories-grid-enable-button') - .text(i18n[enabled ? 'KCHREPO6017M' : 'KCHREPO6016M']) - .prop('disabled', false); - }, - frozenFields: [], - fields: gridFields, - data: listRepositories - }); - }; - - var listRepositories = function(gridCallback) { - kimchi.listRepositories(function(repositories) { - if($.isFunction(gridCallback)) { - gridCallback(repositories); - } - else { - if(repositoriesGrid) { - repositoriesGrid.setData(repositories); - } - else { - initRepositoriesGrid(); - repositoriesGrid.setData(repositories); - } - } - }, - function(error) { - var message = error && error['responseJSON'] && error['responseJSON']['reason']; - - if($.isFunction(gridCallback)) { - gridCallback([]); - } - repositoriesGrid && - repositoriesGrid.showMessage(message || i18n['KCHUPD6008M']); - }); - - $('#repositories-grid-remove-button').prop('disabled', true); - $('#repositories-grid-edit-button').prop('disabled', true); - $('#repositories-grid-enable-button').prop('disabled', true); - }; - - var softwareUpdatesGridID = 'software-updates-grid'; - var softwareUpdatesGrid = null; - var progressAreaID = 'software-updates-progress-textarea'; - var reloadProgressArea = function(result) { - var progressArea = $('#' + progressAreaID)[0]; - $(progressArea).text(result['message']); - var scrollTop = $(progressArea).prop('scrollHeight'); - $(progressArea).prop('scrollTop', scrollTop); - }; - - var initSoftwareUpdatesGrid = function(softwareUpdates) { - softwareUpdatesGrid = new wok.widget.Grid({ - container: 'software-updates-grid-container', - id: softwareUpdatesGridID, - title: i18n['KCHUPD6001M'], - rowSelection: 'disabled', - toolbarButtons: [{ - id: softwareUpdatesGridID + '-update-button', - label: i18n['KCHUPD6006M'], - disabled: true, - onClick: function(event) { - var updateButton = $(this); - var progressArea = $('#' + progressAreaID)[0]; - $('#software-updates-progress-container').removeClass('hidden'); - $(progressArea).text(''); - !wok.isElementInViewport(progressArea) && - progressArea.scrollIntoView(); - $(updateButton).text(i18n['KCHUPD6007M']).prop('disabled', true); - - kimchi.updateSoftware(function(result) { - reloadProgressArea(result); - $(updateButton).text(i18n['KCHUPD6006M']).prop('disabled', false); - wok.topic('kimchi/softwareUpdated').publish({ - result: result - }); - }, function(error) { - var message = error && error['responseJSON'] && error['responseJSON']['reason']; - wok.message.error(message || i18n['KCHUPD6009M']); - $(updateButton).text(i18n['KCHUPD6006M']).prop('disabled', false); - }, reloadProgressArea); - } - }], - frozenFields: [], - fields: [{ - name: 'package_name', - label: i18n['KCHUPD6002M'], - 'class': 'software-update-name' - }, { - name: 'version', - label: i18n['KCHUPD6003M'], - 'class': 'software-update-version' - }, { - name: 'arch', - label: i18n['KCHUPD6004M'], - 'class': 'software-update-arch' - }, { - name: 'repository', - label: i18n['KCHUPD6005M'], - 'class': 'software-update-repos' - }], - data: listSoftwareUpdates - }); - }; - - var listSoftwareUpdates = function(gridCallback) { - kimchi.listSoftwareUpdates(function(softwareUpdates) { - if($.isFunction(gridCallback)) { - gridCallback(softwareUpdates); - } - else { - if(softwareUpdatesGrid) { - softwareUpdatesGrid.setData(softwareUpdates); - } - else { - initSoftwareUpdatesGrid(softwareUpdates); - } - } - - var updateButton = $('#' + softwareUpdatesGridID + '-update-button'); - $(updateButton).prop('disabled', softwareUpdates.length === 0); - }, function(error) { - var message = error && error['responseJSON'] && error['responseJSON']['reason']; - if($.isFunction(gridCallback)) { - gridCallback([]); - } - softwareUpdatesGrid && - softwareUpdatesGrid.showMessage(message || i18n['KCHUPD6008M']); - }); - }; - - var reportGridID = 'available-reports-grid'; - var reportGrid = null; - var enableReportButtons = function(toEnable) { - var buttonID = '#{grid}-{btn}-button'; - $.each(['rename', 'remove', 'download'], function(i, n) { - $(wok.substitute(buttonID, { - grid: reportGridID, - btn: n - })).prop('disabled', !toEnable); - }); - }; - var initReportGrid = function(reports) { - reportGrid = new wok.widget.Grid({ - container: 'available-reports-grid-container', - id: reportGridID, - title: i18n['KCHDR6002M'], - toolbarButtons: [{ - id: reportGridID + '-generate-button', - label: i18n['KCHDR6006M'], - onClick: function(event) { - wok.window.open('plugins/kimchi/report-add.html'); - } - }, { - id: reportGridID + '-rename-button', - label: i18n['KCHDR6008M'], - disabled: true, - onClick: function(event) { - var report = reportGrid.getSelected(); - if(!report) { - return; - } - - kimchi.selectedReport = report['name']; - wok.window.open('plugins/kimchi/report-rename.html'); - } - }, { - id: reportGridID + '-remove-button', - label: i18n['KCHDR6009M'], - disabled: true, - onClick: function(event) { - var report = reportGrid.getSelected(); - if(!report) { - return; - } - - var settings = { - title : i18n['KCHAPI6004M'], - content : i18n['KCHDR6001M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - - wok.confirm(settings, function() { - kimchi.deleteReport({ - name: report['name'] - }, function(result) { - listDebugReports(); - }, function(error) { - wok.message.error(error.responseJSON.reason); - }); - }); - } - }, { - id: reportGridID + '-download-button', - label: i18n['KCHDR6010M'], - disabled: true, - onClick: function(event) { - var report = reportGrid.getSelected(); - if(!report) { - return; - } - - kimchi.downloadReport({ - file: report['uri'] - }); - } - }], - onRowSelected: function(row) { - var report = reportGrid.getSelected(); - // Only enable report buttons if the selected line is not a - // pending report - if (report['time'] == i18n['KCHDR6007M']) { - var gridElement = $('#'+ reportGridID); - var row = $('tr:contains(' + report['name'] + ')', gridElement); - enableReportButtons(false); - row.attr('class', ''); - } - else { - enableReportButtons(true); - } - }, - frozenFields: [], - fields: [{ - name: 'name', - label: i18n['KCHDR6003M'], - 'class': 'debug-report-name' - }, { - name: 'time', - label: i18n['KCHDR6005M'], - 'class': 'debug-report-time' - }], - data: reports - }); - }; - - var getPendingReports = function() { - var reports = [] - var filter = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/debugreports/*') - - kimchi.getTasksByFilter(filter, function(tasks) { - for(var i = 0; i < tasks.length; i++) { - reportName = tasks[i].target_uri.replace(/^\/plugins\/kimchi\/debugreports\//, '') || i18n['KCHDR6012M']; - reports.push({'name': reportName, 'time': i18n['KCHDR6007M']}) - - if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) { - continue; - } - - kimchi.trackTask(tasks[i].id, function(result) { - wok.topic('kimchi/debugReportAdded').publish(); - }, function(result) { - // Error message from Async Task status - if (result['message']) { - var errText = result['message']; - } - // Error message from standard kimchi exception - else { - var errText = result['responseJSON']['reason']; - } - result && wok.message.error(errText); - wok.topic('kimchi/debugReportAdded').publish(); - }, null); - } - }, null, true); - - return reports; - }; - - var listDebugReports = function() { - kimchi.listReports(function(reports) { - pendingReports = getPendingReports(); - allReports = pendingReports.concat(reports); - $('#debug-report-section').removeClass('hidden'); - - // Row selection will be cleared so disable buttons here - enableReportButtons(false); - - if(reportGrid) { - reportGrid.setData(allReports); - } - else { - initReportGrid(allReports); - } - - // Set id-debug-img to pending reports - // It will display a loading icon - var gridElement = $('#' + reportGridID); - $.each($('td:contains(' + i18n['KCHDR6007M'] + ')', gridElement), function(index, row) { - $(row).parent().addClass('no-hover'); - $(row).attr('id', 'id-debug-img'); - }); - }, function(error) { - if(error['status'] == 403) { - $('#debug-report-section').addClass('hidden'); - return; - } - $('#debug-report-section').removeClass('hidden'); - }); - }; - - var shutdownButtonID = '#host-button-shutdown'; - var restartButtonID = '#host-button-restart'; - var shutdownHost = function(params) { - var settings = { - title : i18n['KCHAPI6004M'], - content : i18n['KCHHOST6008M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - - wok.confirm(settings, function() { - kimchi.shutdown(params); - $(shutdownButtonID).prop('disabled', true); - $(restartButtonID).prop('disabled', true); - // Check if there is any VM is running. - kimchi.listVMs(function(vms) { - for(var i = 0; i < vms.length; i++) { - if(vms[i]['state'] === 'running') { - wok.message.error.code('KCHHOST6001E'); - $(shutdownButtonID).prop('disabled', false); - $(restartButtonID).prop('disabled', false); - return; - } - } - - }); - }, function() { - }); - }; - - var initPage = function() { - $('#host-info-container .section-header').each(function(i, header) { - $('<span class="arrow"></span>').prependTo(header); - var toExpand = $(header).attr('aria-expanded') !== 'false'; - expand(header, toExpand); - }); - - $('#host-info-container').on('click', '.section-header', function(event) { - var toExpand = $(this).attr('aria-expanded') === 'false'; - expand(this, toExpand); - }); - - $('#host-button-shutdown').on('click', function(event) { - shutdownHost(null); - }); - - $('#host-button-restart').on('click', function(event) { - shutdownHost({ - reboot: true - }); - }); - - var setupUI = function() { - if (kimchi.capabilities == undefined) { - setTimeout(setupUI, 2000); - return; - } - - if((kimchi.capabilities['repo_mngt_tool']) && (kimchi.capabilities['repo_mngt_tool']!="None")) { - initRepositoriesGrid(kimchi.capabilities['repo_mngt_tool']); - $('#repositories-section').switchClass('hidden', kimchi.capabilities['repo_mngt_tool']); - wok.topic('kimchi/repositoryAdded') - .subscribe(listRepositories); - wok.topic('kimchi/repositoryUpdated') - .subscribe(listRepositories); - wok.topic('kimchi/repositoryDeleted') - .subscribe(listRepositories); - } - - if(kimchi.capabilities['update_tool']) { - $('#software-update-section').removeClass('hidden'); - initSoftwareUpdatesGrid(); - wok.topic('kimchi/softwareUpdated') - .subscribe(listSoftwareUpdates); - $('#software-updates-progress-container').accordion({ - collapsible: true - }); - } - - if(kimchi.capabilities['system_report_tool']) { - listDebugReports(); - wok.topic('kimchi/debugReportAdded') - .subscribe(listDebugReports); - wok.topic('kimchi/debugReportRenamed') - .subscribe(listDebugReports); - } - }; - setupUI(); - }; - - kimchi.getHost(function(data) { - var htmlTmpl = $('#host-tmpl').html(); - data['logo'] = data['logo'] || ''; - data['memory'] = wok.formatMeasurement(data['memory'], { - fixed: 2 - }); - var templated = wok.substitute(htmlTmpl, data); - $('#host-content-container').html(templated); - - initPage(); - initTracker(); - }); - - var StatsMgr = function() { - var statsArray = { - cpu: { - u: { - type: 'percent', - legend: i18n['KCHHOST6002M'], - points: [] - } - }, - memory: { - u: { - type: 'value', - base: 2, - fixed: 2, - legend: i18n['KCHHOST6003M'], - points: [] - } - }, - diskIO: { - r: { - type: 'value', - base: 2, - fixed: 2, - unit: 'B/s', - legend: i18n['KCHHOST6004M'], - points: [] - }, - w: { - type: 'value', - base: 2, - fixed: 2, - unit: 'B/s', - legend: i18n['KCHHOST6005M'], - 'class': 'disk-write', - points: [] - } - }, - networkIO: { - r: { - type: 'value', - base: 2, - fixed: 2, - unit: 'B/s', - legend: i18n['KCHHOST6006M'], - points: [] - }, - s: { - type: 'value', - base: 2, - fixed: 2, - unit: 'B/s', - legend: i18n['KCHHOST6007M'], - 'class': 'network-sent', - points: [] - } - } - }; - var SIZE = 20; - var cursor = SIZE; - - var add = function(stats) { - for(var key in stats) { - var item = stats[key]; - for(var metrics in item) { - var value = item[metrics]['v']; - var max = item[metrics]['max']; - var unifiedMetrics = statsArray[key][metrics]; - var ps = unifiedMetrics['points']; - if(!Array.isArray(value)){ - ps.push(value); - if(ps.length > SIZE + 1) { - ps.shift(); - } - } - else{ - ps=ps.concat(value); - ps.splice(0, ps.length-SIZE-1); - unifiedMetrics['points']=ps; - } - if(max !== undefined) { - unifiedMetrics['max'] = max; - } - else { - if(unifiedMetrics['type'] !== 'value') { - continue; - } - max = -Infinity; - $.each(ps, function(i, value) { - if(value > max) { - max = value; - } - }); - if(max === 0) { - ++max; - } - max *= 1.1; - unifiedMetrics['max'] = max; - } - } - } - cursor++; - }; - - var get = function(which) { - var stats = statsArray[which]; - var lines = []; - for(var k in stats) { - var obj = stats[k]; - var line = { - type: obj['type'], - base: obj['base'], - unit: obj['unit'], - fixed: obj['fixed'], - legend: obj['legend'] - }; - if(obj['max']) { - line['max'] = obj['max']; - } - if(obj['class']) { - line['class'] = obj['class']; - } - var ps = obj['points']; - var numStats = ps.length; - var unifiedPoints = []; - $.each(ps, function(i, value) { - unifiedPoints.push({ - x: cursor - numStats + i, - y: value - }); - }); - line['points'] = unifiedPoints; - lines.push(line); - } - return lines; - }; - - return { - add: add, - get: get - }; - }; - - var Tracker = function(charts) { - var charts = charts; - var timer = null; - var statsPool = new StatsMgr(); - var setCharts = function(newCharts) { - charts = newCharts; - for(var key in charts) { - var chart = charts[key]; - chart.updateUI(statsPool.get(key)); - } - }; - - var self = this; - - var UnifyStats = function(stats) { - var result= { - cpu: { - u: { - v: stats['cpu_utilization'] - } - }, - memory: { - u: { - } - }, - diskIO: { - r: { - v: stats['disk_read_rate'] - }, - w: { - v: stats['disk_write_rate'] - } - }, - networkIO: { - r: { - v: stats['net_recv_rate'] - }, - s: { - v: stats['net_sent_rate'] - } - } - }; - if(Array.isArray(stats['memory'])){ - result.memory.u['v']=[]; - result.memory.u['max']=-Infinity; - for(var i=0;i<stats['memory'].length;i++){ - result.memory.u['v'].push(stats['memory'][i]['avail']); - result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']); - } - } - else { - result.memory.u['v']=stats['memory']['avail'], - result.memory.u['max']=stats['memory']['total'] - } - return(result); - }; - - - var statsCallback = function(stats) { - var unifiedStats = UnifyStats(stats); - statsPool.add(unifiedStats); - for(var key in charts) { - var chart = charts[key]; - chart.updateUI(statsPool.get(key)); - } - timer = setTimeout(function() { - continueTrack(); - }, 1000); - }; - - var track = function() { - kimchi.getHostStatsHistory(statsCallback, - function() { - continueTrack(); - }); - }; - - var continueTrack = function() { - kimchi.getHostStats(statsCallback, - function() { - continueTrack(); - }); - }; - - var destroy = function() { - timer && clearTimeout(timer); - timer = null; - }; - - return { - setCharts: setCharts, - start: track, - stop: destroy - }; - }; - - var initTracker = function() { - // TODO: Extend tabs with onUnload event to unregister timers. - if(kimchi.hostTimer) { - kimchi.hostTimer.stop(); - delete kimchi.hostTimer; - } - - var trackedCharts = { - cpu: new wok.widget.LineChart({ - id: 'chart-cpu', - node: 'container-chart-cpu', - type: 'percent' - }), - memory: new wok.widget.LineChart({ - id: 'chart-memory', - node: 'container-chart-memory', - type: 'value' - }), - diskIO: new wok.widget.LineChart({ - id: 'chart-disk-io', - node: 'container-chart-disk-io', - type: 'value' - }), - networkIO: new wok.widget.LineChart({ - id: 'chart-network-io', - node: 'container-chart-network-io', - type: 'value' - }) - }; - - if(kimchi.hostTimer) { - kimchi.hostTimer.setCharts(trackedCharts); - } - else { - kimchi.hostTimer = new Tracker(trackedCharts); - kimchi.hostTimer.start(); - } - }; - - $('#host-root-container').on('remove', function() { - if(kimchi.hostTimer) { - kimchi.hostTimer.stop(); - delete kimchi.hostTimer; - } - - repositoriesGrid && repositoriesGrid.destroy(); - wok.topic('kimchi/repositoryAdded') - .unsubscribe(listRepositories); - wok.topic('kimchi/repositoryUpdated') - .unsubscribe(listRepositories); - wok.topic('kimchi/repositoryDeleted') - .unsubscribe(listRepositories); - - softwareUpdatesGrid && softwareUpdatesGrid.destroy(); - wok.topic('kimchi/softwareUpdated').unsubscribe(listSoftwareUpdates); - - reportGrid && reportGrid.destroy(); - wok.topic('kimchi/debugReportAdded').unsubscribe(listDebugReports); - wok.topic('kimchi/debugReportRenamed').unsubscribe(listDebugReports); - }); -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.main.js b/plugins/kimchi/ui/js/src/kimchi.main.js deleted file mode 100644 index 2fdeb85..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.main.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.capabilities = undefined; -kimchi.getCapabilities(function(result) { - kimchi.capabilities = result; - - if(kimchi.capabilities.federation=="on") - $('#peers').removeClass('hide-content'); -}, function() { - kimchi.capabilities = {}; -}); diff --git a/plugins/kimchi/ui/js/src/kimchi.network.js b/plugins/kimchi/ui/js/src/kimchi.network.js deleted file mode 100644 index c43b59a..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.network.js +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -kimchi.NETWORK_TYPE_BRIDGE = "bridged"; - -kimchi.initNetwork = function() { - if(wok.tabMode['network'] === 'admin') { - $('.tools').attr('style','display'); - $('#network-content .header span:last-child').attr('style','display'); - kimchi.initNetworkCreation(); - } - kimchi.initNetworkListView(); - kimchi.initNetworkDialog(); - kimchi.initNetworkCleanup(); -}; - -kimchi.initNetworkListView = function() { - kimchi.listNetworks(function(data) { - for (var i = 0; i < data.length; i++) { - var network = { - name : data[i].name, - in_use : data[i].in_use, - state : data[i].state === "active" ? "up" : "down" - }; - if (data[i].connection === "bridge") { - network.type = kimchi.NETWORK_TYPE_BRIDGE; - } else { - network.type = data[i].connection; - } - network.interface = data[i].interface ? data[i].interface : null; - network.addrSpace = data[i].subnet ? data[i].subnet : null; - network.persistent = data[i].persistent; - kimchi.addNetworkItem(network); - } - $('#networkGrid').grid({enableSorting: false}); - $('input', $('.grid-control', '#network-content')).on('keyup', function(){ - $('#networkGrid').grid('filter', $(this).val()); - }); - }); -}; - -kimchi.addNetworkItem = function(network) { - var itemNode = $.parseHTML(kimchi.getNetworkItemHtml(network)); - $("#networkBody").append(itemNode); - if(wok.tabMode["network"] === "admin") { - $(".column-action").attr("style","display"); - } else { - $(".column-space").addClass('column-space-no-border-right'); - } - kimchi.addNetworkActions(network); - return itemNode; -}; - -kimchi.getNetworkItemHtml = function(network) { - if(!network.interface) { - network.interface = i18n["KCHNET6001M"]; - } - if(!network.addrSpace) { - network.addrSpace = i18n["KCHNET6001M"]; - } - if(i18n["network_type_" + network.type]) { - network.type = i18n["network_type_" + network.type]; - } - - var disable_in_use = network.in_use ? "ui-state-disabled" : ""; - var networkItem = wok.substitute($('#networkItem').html(), { - name : network.name, - state : network.state, - type : network.type, - interface: network.interface, - addrSpace : network.addrSpace, - startClass : network.state === "up" ? "hide-action-item" : "", - stopClass : network.state === "down" ? "hide-action-item" : disable_in_use, - stopDisabled : network.in_use ? "disabled" : "", - deleteClass : network.state === "up" || network.in_use ? "ui-state-disabled" : "", - deleteDisabled: network.state === "up" || network.in_use ? "disabled" : "" - }); - return networkItem; -}; - -kimchi.stopNetwork = function(network,menu) { - $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("up", "nw-loading"); - $("[nwAct='stop']", menu).addClass("ui-state-disabled"); - kimchi.toggleNetwork(network.name, false, function() { - $("[nwAct='start']", menu).removeClass("hide-action-item"); - $("[nwAct='stop']", menu).addClass("hide-action-item"); - $("[nwAct='stop']", menu).removeClass("ui-state-disabled"); - if (!network.in_use) { - $("[nwAct='delete']", menu).removeClass("ui-state-disabled"); - $(":first-child", $("[nwAct='delete']", menu)).removeAttr("disabled"); - } - $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("nw-loading", "down"); - }, function(err) { - $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("nw-loading", "up"); - if (!network.in_use) { - $("[nwAct='stop']", menu).removeClass("ui-state-disabled"); - } - wok.message.error(err.responseJSON.reason); - }); -} - -kimchi.addNetworkActions = function(network) { - $(".menu-container", "#" + wok.escapeStr(network.name)).menu(); - - $('#' + wok.escapeStr(network.name)).on('click', '.menu-container li', function(evt) { - var menu = $(evt.currentTarget).parent(); - if ($(evt.currentTarget).attr("nwAct") === "start") { - $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("down", "nw-loading"); - $("[nwAct='start']", menu).addClass("ui-state-disabled"); - $("[nwAct='delete']", menu).addClass("ui-state-disabled"); - $(":first-child", $("[nwAct='delete']", menu)).attr("disabled", true); - kimchi.toggleNetwork(network.name, true, function() { - $("[nwAct='start']", menu).addClass("hide-action-item"); - $("[nwAct='start']", menu).removeClass("ui-state-disabled"); - $("[nwAct='stop']", menu).removeClass("hide-action-item"); - network.state = "up"; - if (network.in_use) { - $("[nwAct='stop']", menu).addClass("ui-state-disabled"); - } - $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("nw-loading", "up"); - }, function(err) { - $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("nw-loading","down"); - $("[nwAct='start']", menu).removeClass("ui-state-disabled"); - if (!network.in_use) { - $("[nwAct='delete']", menu).removeClass("ui-state-disabled"); - } - $(":first-child", $("[nwAct='delete']", menu)).removeAttr("disabled"); - wok.message.error(err.responseJSON.reason); - }); - } else if ($(evt.currentTarget).attr("nwAct") === "stop") { - if (network.in_use) { - return false; - } - if (!network.persistent) { - var settings = { - title : i18n['KCHAPI6001M'], - content : i18n['KCHNET6004M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - wok.confirm(settings, function() { - kimchi.stopNetwork(network, menu); - $('#networkGrid').grid('deleteRow', $(evt.currentTarget).parents(".row")); - }, null); - } - else { - kimchi.stopNetwork(network, menu); - network.state = "down"; - } - } else if ($(evt.currentTarget).attr("nwAct") === "delete") { - if (network.state === "up" || network.in_use) { - return false; - } - wok.confirm({ - title : i18n['KCHAPI6006M'], - content : i18n['KCHNET6002M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }, function() { - kimchi.deleteNetwork(network.name, function() { - $('#networkGrid').grid('deleteRow', $(evt.currentTarget).parents(".row")); - }); - }, null); - } - }); - - $("#networkBody .column-action .popable").button({ - icons : { - secondary : "action-button-icon" - } - }); - -}; - -kimchi.initNetworkCreation = function() { - $("#networkAdd").on("click", function() { - kimchi.openNetworkDialog(function() { - var errorCallback = function(){ - $("#networkFormOk").button("enable"); - $("#networkName").removeAttr("readonly"); - $("#networkFormOk span").text(i18n.KCHAPI6005M); - }; - var network = kimchi.getNetworkDialogValues(); - var data = { - name : network.name, - connection: network.type - }; - if (network.type === kimchi.NETWORK_TYPE_BRIDGE) { - data.connection = "bridge"; - data.interface = network.interface; - if ($("#enableVlan").prop("checked")) { - data.vlan_id = network.vlan_id; - if (!(data.vlan_id >=1 && data.vlan_id <= 4094)) { - wok.message.error.code('KCHNET6001E'); - errorCallback(); - return; - } - } - } - kimchi.createNetwork(data, function(result) { - network.state = result.state === "active" ? "up" : "down"; - network.interface = result.interface ? result.interface : i18n["KCHNET6001M"]; - network.addrSpace = result.subnet ? result.subnet : i18n["KCHNET6001M"]; - network.persistent = result.persistent; - $('#networkGrid').grid('addRow', kimchi.addNetworkItem(network)); - $("#networkConfig").dialog("close"); - }, function(data) { - wok.message.error(data.responseJSON.reason); - errorCallback(); - }); - }); - }); -}; - -kimchi.initNetworkDialog = function() { - buttonsObj= {}; - buttonsObj['id'] = "networkFormOk"; - buttonsObj['text'] = i18n.KCHAPI6005M; - buttonsObj['class'] = "btn-normal"; - buttonsObj['disabled'] = true; - buttonsObj['click'] = function() { }; - buttonsObjCancel= {}; - buttonsObjCancel['id'] = "networkFormCancel"; - buttonsObjCancel['text'] = i18n.KCHAPI6003M; - buttonsObjCancel['class'] = "btn-normal"; - buttonsObjCancel['disabled'] = false; - buttonsObjCancel['click'] = function() { - $(this).dialog("close"); - }; - $("#networkConfig").dialog({ - autoOpen : false, - modal : true, - width : 600, - draggable : false, - resizable : false, - closeText: "X", - dialogClass : "network-ui-dialog remove-when-logged-off", - open : function(){ - $(".ui-dialog-titlebar-close", $("#networkConfig").parent()).removeAttr("title"); - $(".ui-widget-overlay").css({ - "background": "#FFFFFF", - "opacity": "0.5" - }); - }, - beforeClose : function() { - kimchi.cleanNetworkDialog(); - }, - buttons : [buttonsObj, buttonsObjCancel] - }); - $("#networkConfig").parent().css({ - "background": "#FFFFFF", - "border-radius": 0, - "border": "2px solid #999999" - }); - $(".ui-dialog-titlebar button", $("#networkConfig").parent()).remove(); - $(".ui-dialog-titlebar span", $("#networkConfig").parent()).css({ - "font-weight": "lighter", - "height": "48px", - "line-height": "48px", - "margin": "0 30px", - "color": "#444444", - "font-size": "22px" - }); - $(".ui-dialog-titlebar", $("#networkConfig").parent()).css({ - "box-shadow": "none", - "padding": "0", - }); - $(".ui-dialog-buttonpane", $("#networkConfig").parent()).css({ - "background": "#008ABF" - }); - $(".ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset").css({ - "padding": "0 10px", - "float": "left" - }); - $(".ui-dialog-buttonpane .ui-dialog-buttonset button").removeClass("ui-corner-all"); - $(".ui-dialog-buttonpane .ui-dialog-buttonset button").css({ - "background": "#FFFFFF", - "color": "#444444", - "font-size": "13px", - "border-radius": "0", - "opacity": "1" - }); - kimchi.setupNetworkFormEvent(); -}; - -kimchi.openNetworkDialog = function(okCallback) { - kimchi.getInterfaces(function(result) { - var options = []; - $('#networkDestinationID').selectMenu(); - var nics = {}; - for (var i = 0; i < result.length; i++) { - options.push({label:result[i].name,value:result[i].name}); - nics[result[i].name] = result[i]; - } - result.length>0 && $("#networkDestinationID").selectMenu("setData", options); - onChange = function() { - $("#networkDestinationLabel").text($("#networkDestinationID li:first-child").text()); - $("#networkDestinationID li:first-child").addClass("active"); - if (result.length>0 && nics[$("#networkDestinationLabel").text()].type === "bridge") { - $("#enableVlan").prop("checked", false); - $("#enableVlan").prop("disabled", true); - $("#networkVlanID").val(""); - $("#networkVlanID").toggle(false); - $("#labelNetworkVlanID").toggle(false); - } else { - $("#enableVlan").prop("disabled",false); - } - }; - $("#networkDestinationLabel").on("change", onChange); - kimchi.setDefaultNetworkType(result.length!==0); - onChange(); - }); - $("#networkConfig").dialog({ - title : i18n.KCHNET6003M - }); - $("#networkFormOk").on("click", function() { - $("#networkFormOk").button("disable"); - $("#networkName").prop("readonly", "readonly"); - $("#networkFormOk span").text(i18n.KCHAPI6008M); - okCallback(); - }); - $("#enableVlan").on("click", function() { - $("#networkVlanID").prop("disabled", !this.checked); - if (!this.checked) { - $("#networkVlanID").slideUp(100); - $("#labelNetworkVlanID").slideUp(100); - $("#networkVlanID").val(""); - } - else { - $("#networkVlanID").slideDown(100); - $("#labelNetworkVlanID").slideDown(100); - } - }); - $("#networkConfig").dialog("open"); -}; - -kimchi.enableBridgeOptions = function(enable) { - if (!enable) { - $("#enableVlan").prop("checked", false); - $("#networkVlanID").toggle(false); - $("#labelNetworkVlanID").toggle(false); - $("#networkVlanID").val(""); - $("#networkDestinationLabel").text(""); - $("#bridgeOptions").slideUp(100); - } else if (!$("#networkDestinationLabel").text()){ - $("#networkDestinationLabel").text($("#networkDestinationID li:first-child").text()); - $("#bridgeOptions").slideDown(100); - $("#networkVlanID").toggle(false); - $("#labelNetworkVlanID").toggle(false); - } -}; - - -kimchi.setDefaultNetworkType = function(isInterfaceAvail) { - $("#networkTypeBri").prop("checked", isInterfaceAvail); - $("#networkTypeBri").prop("disabled", !isInterfaceAvail); - $("#networkTypeNat").prop("checked", !isInterfaceAvail); - if (!isInterfaceAvail) { - kimchi.enableBridgeOptions(false); - $("#networkBriDisabledLabel").show(); - } else { - if (kimchi.capabilities && kimchi.capabilities.nm_running) { - wok.message.warn(i18n['KCHNET6001W']); - } - $("#bridgeOptions").slideDown(100); - $("#networkVlanID").toggle(false); - $("#labelNetworkVlanID").toggle(false); - $("#networkBriDisabledLabel").hide(); - } -}; - -kimchi.getNetworkDialogValues = function() { - var network = { - name : $("#networkName").val(), - type : $("input:radio[name=networkType]:checked").val() - }; - if (network.type === kimchi.NETWORK_TYPE_BRIDGE) { - network.interface = $("#networkDestinationLabel").text(); - network.vlan_id = parseInt($("#networkVlanID").val()); - } - return network; -}; - -kimchi.cleanNetworkDialog = function() { - $("input:text", "#networkConfig").val(null).removeClass("invalid-field"); - $("#networkTypeIso").prop("checked", false); - $("#networkTypeNat").prop("checked", false); - $("#networkTypeBri").prop("checked", false); - $("#networkDestinationLabel").text($("#networkDestinationID li:first-child").text()); - $("#networkFormOk").off("click"); - $("#networkFormOk").button("disable"); - $("#networkFormOk span").text(i18n.KCHAPI6005M); - $("#networkName").removeAttr("readonly"); - $("#networkVlanID").toggle(false); - $("#labelNetworkVlanID").toggle(false); - $("#enableVlan").prop("checked", false); - -}; -kimchi.setupNetworkFormEvent = function() { - $("#networkName").on("keyup", function(event) { - $("#networkName").toggleClass("invalid-field", !$("#networkName").val().match(/^[^\"\/]+$/)); - kimchi.updateNetworkFormButton(); - }); - $("#networkTypeIso").on("click", function(event) { - kimchi.enableBridgeOptions(false); - }); - $("#networkTypeNat").on("click", function(event) { - kimchi.enableBridgeOptions(false); - }); - $("#networkTypeBri").on("click", function(event) { - kimchi.enableBridgeOptions(true); - }); -}; - -kimchi.updateNetworkFormButton = function() { - if($("#networkName").hasClass("invalid-field")){ - $("#networkFormOk").button("disable"); - }else{ - $("#networkFormOk").button("enable"); - } -}; - -kimchi.initNetworkCleanup = function() { - $("#network-content").on("remove", function() { - $("#networkConfig").dialog("destroy"); - }); -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.report_add_main.js b/plugins/kimchi/ui/js/src/kimchi.report_add_main.js deleted file mode 100644 index 5f098d3..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.report_add_main.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.report_add_main = function() { - var reportGridID = 'available-reports-grid'; - var addReportForm = $('#form-report-add'); - var submitButton = $('#button-report-add'); - var nameTextbox = $('input[name="name"]', addReportForm); - nameTextbox.select(); - - var submitForm = function(event) { - if(submitButton.prop('disabled')) { - return false; - } - var reportName = nameTextbox.val(); - var validator = RegExp("^[_A-Za-z0-9-]*$"); - if (!validator.test(reportName)) { - wok.message.error.code('KCHDR6011M'); - return false; - } - var formData = addReportForm.serializeObject(); - var taskAccepted = false; - var onTaskAccepted = function() { - if(taskAccepted) { - return; - } - taskAccepted = true; - wok.window.close(); - wok.topic('kimchi/debugReportAdded').publish(); - }; - - kimchi.createReport(formData, function(result) { - onTaskAccepted(); - wok.topic('kimchi/debugReportAdded').publish(); - }, function(result) { - // Error message from Async Task status - if (result['message']) { - var errText = result['message']; - } - // Error message from standard kimchi exception - else { - var errText = result['responseJSON']['reason']; - } - result && wok.message.error(errText); - - taskAccepted && - $('.grid-body-view table tr:first-child', - '#' + reportGridID).remove(); - submitButton.prop('disabled', false); - nameTextbox.select(); - }, onTaskAccepted); - - event.preventDefault(); - }; - - addReportForm.on('submit', submitForm); - submitButton.on('click', submitForm); -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js b/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js deleted file mode 100644 index 1bdb8d9..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.report_rename_main = function() { - var renameReportForm = $('#form-report-rename'); - var submitButton = $('#button-report-rename'); - var nameTextbox = $('input[name="name"]', renameReportForm); - var submitForm = function(event) { - if(submitButton.prop('disabled')) { - return false; - } - var reportName = nameTextbox.val(); - - // if the user hasn't changed the report's name, - // nothing should be done. - if (reportName == kimchi.selectedReport) { - wok.message.error.code('KCHDR6013M'); - return false; - } - - var validator = RegExp("^[A-Za-z0-9-]*$"); - if (!validator.test(reportName)) { - wok.message.error.code('KCHDR6011M'); - return false; - } - var formData = renameReportForm.serializeObject(); - submitButton.prop('disabled', true); - nameTextbox.prop('disabled', true); - kimchi.renameReport(kimchi.selectedReport, formData, function(result) { - submitButton.prop('disabled', false); - nameTextbox.prop('disabled', false); - wok.window.close(); - wok.topic('kimchi/debugReportRenamed').publish({ - result: result - }); - }, function(result) { - var errText = result && - result['responseJSON'] && - result['responseJSON']['reason']; - wok.message.error(errText); - submitButton.prop('disabled', false); - nameTextbox.prop('disabled', false).focus(); - }); - - event.preventDefault(); - }; - - renameReportForm.on('submit', submitForm); - submitButton.on('click', submitForm); - - nameTextbox.val(kimchi.selectedReport).select(); -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js b/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js deleted file mode 100644 index 656306b..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.repository_add_main = function() { - - var addForm = $('#form-repository-add'); - var addButton = $('#button-repository-add'); - - var validateField = function(event) { - var valid=($(this).val()!==''); - $(addButton).prop('disabled', !valid); - return(valid); - }; - - var validateForm = function(event) { - var valid=false; - addForm.find('input.required').each( function() { - valid=($(this).val()!==''); - return(!valid); - }); - return(valid); - } - - addForm.find('input.required').on('input propertychange', validateField); - - var weedObject = function(obj) { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - if((typeof(obj[key])==="object") && !Array.isArray(obj[key])) { - weedObject(obj[key]); - } - else if(obj[key] == '') { - delete obj[key]; - } - } - } - } - - var addRepository = function(event) { - var valid = validateForm(); - if(!valid) { - return false; - } - - var formData = $(addForm).serializeObject(); - - if (formData && formData.isMirror!=undefined) { - formData.isMirror=(String(formData.isMirror).toLowerCase() === 'true'); - } - if(formData.isMirror) { - if(formData.config==undefined) { - formData.config=new Object(); - } - formData.config.mirrorlist=formData.baseurl; - delete formData.baseurl; - delete formData.isMirror; - } - weedObject(formData); - if(formData.config && formData.config.comps) { - formData.config.comps=formData.config.comps.split(/[,\s]/); - for(var i=0; i>formData.config.comps.length; i++) { - formData.config.comps[i]=formData.config.comps[i].trim(); - } - for (var j=formData.config.comps.indexOf(""); j!=-1; j=formData.config.comps.indexOf("")) { - formData.config.comps.splice(j, 1); - } - } - - kimchi.createRepository(formData, function() { - wok.topic('kimchi/repositoryAdded').publish(); - wok.window.close(); - }, function(jqXHR, textStatus, errorThrown) { - var reason = jqXHR && - jqXHR['responseJSON'] && - jqXHR['responseJSON']['reason']; - wok.message.error(reason); - }); - return false; - }; - - $(addForm).on('submit', addRepository); -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js b/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js deleted file mode 100644 index 5bfc51e..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.repository_edit_main = function() { - - var editForm = $('#form-repository-edit'); - - var saveButton = $('#repository-edit-button-save'); - - if(kimchi.capabilities['repo_mngt_tool']=="yum") { - editForm.find('input.deb').prop('disabled', true); - } - else if(kimchi.capabilities['repo_mngt_tool']=="deb") { - editForm.find('input.yum').prop('disabled', true); - } - - kimchi.retrieveRepository(kimchi.selectedRepository, function(repository) { - editForm.fillWithObject(repository); - - $('input', editForm).on('input propertychange', function(event) { - if($(this).val() !== '') { - $(saveButton).prop('disabled', false); - } - }); - }); - - - var editRepository = function(event) { - var formData = $(editForm).serializeObject(); - - if (formData && formData.config) { - formData.config.gpgcheck=(String(formData.config.gpgcheck).toLowerCase() === 'true'); - } - - if(formData.config && formData.config.comps) { - formData.config.comps=formData.config.comps.split(/[,\s]/); - for(var i=0; i>formData.config.comps.length; i++) { - formData.config.comps[i]=formData.config.comps[i].trim(); - } - for (var j=formData.config.comps.indexOf(""); j!=-1; j=formData.config.comps.indexOf("")) { - formData.config.comps.splice(j, 1); - } - } - - kimchi.updateRepository(kimchi.selectedRepository, formData, function() { - wok.topic('kimchi/repositoryUpdated').publish(); - wok.window.close(); - }, function(jqXHR, textStatus, errorThrown) { - var reason = jqXHR && - jqXHR['responseJSON'] && - jqXHR['responseJSON']['reason']; - wok.message.error(reason); - }); - - return false; - }; - - $(editForm).on('submit', editRepository); - $(saveButton).on('click', editRepository); -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.storage_main.js b/plugins/kimchi/ui/js/src/kimchi.storage_main.js deleted file mode 100644 index 40a43f6..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.storage_main.js +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the 'License'); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.doListStoragePools = function() { - kimchi.listStoragePools(function(result) { - var storageHtml = $('#storageTmpl').html(); - if (result && result.length) { - var listHtml = ''; - $.each(result, function(index, value) { - value.usage = Math.round(value.allocated / value.capacity * 100) || 0; - value.capacity = wok.changetoProperUnit(value.capacity,1); - value.allocated = wok.changetoProperUnit(value.allocated,1); - value.enableExt = value.type==="logical" ? "" : "hide-content"; - if ('kimchi-iso' !== value.type) { - listHtml += wok.substitute(storageHtml, value); - } - }); - if($('#storageGrid').hasClass('grid')) - $('#storageGrid').grid('destroy'); - $('#storagepoolsList').html(listHtml); - if(wok.tabMode['storage'] === 'admin') { - $('.storage-button').attr('style','display'); - } else { - $('.storage-allocate').addClass('storage-allocate-padding-user'); - } - $('#storageGrid').grid({enableSorting: false}); - $('input', $('.grid-control', '.storage')).on('keyup', function(){ - $('#storageGrid').grid('filter', $(this).val()); - }); - kimchi.storageBindClick(); - } else { - $('#storagepoolsList').html(''); - } - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); -} - -kimchi.storageBindClick = function() { - - $('.inactive').each(function(index) { - if ('active' === $(this).data('state')) { - $(this).hide(); - } else { - $(this).show(); - } - }); - - $('.list-storage .storage-state .active').each(function(index) { - if ('active' === $(this).data('state')) { - $(this).show(); - } else { - $(this).hide(); - } - }); - - $('.pool-activate').each(function(index) { - if ('active' === $(this).data('stat')) { - $(this).hide(); - } else { - $(this).show(); - } - }); - - $('.pool-deactivate').each(function(index) { - if ('active' === $(this).data('stat')) { - $(this).show(); - } else { - $(this).hide(); - } - }); - - $('.pool-add-volume').each(function(index) { - var canAddVolume = - $(this).data('stat') === 'active' && - $(this).data('type') !== 'iscsi' && - $(this).data('type') !== 'scsi'; - if(canAddVolume) { - $(this).show(); - } - else { - $(this).hide(); - } - }); - - if(wok.tabMode['storage'] === 'admin') { - $('.pool-delete').on('click', function(event) { - var $pool = $(this); - var settings = { - title : i18n['KCHAPI6001M'], - content : i18n['KCHPOOL6001M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - wok.confirm(settings, function() { - var poolName = $pool.data('name'); - kimchi.deleteStoragePool(poolName, function() { - kimchi.doListStoragePools(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }); - }); - - $('.pool-activate').on('click', function(event) { - var poolName = $(this).data('name'); - kimchi.changePoolState(poolName, 'activate', function() { - kimchi.doListStoragePools(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }); - - $('.pool-deactivate').on('click', function(event) { - var poolName = $(this).data('name'); - var settings = { - title : i18n['KCHAPI6001M'], - content : i18n['KCHPOOL6012M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - if (!$(this).data('persistent')) { - wok.confirm(settings, function() { - kimchi.changePoolState(poolName, 'deactivate', function() { - kimchi.doListStoragePools(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }, function() { - return false; - }); - } - else { - kimchi.changePoolState(poolName, 'deactivate', function() { - kimchi.doListStoragePools(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - } - }); - - $('.pool-add-volume').on('click', function(event) { - var poolName = $(this).data('name'); - kimchi.selectedSP = poolName; - wok.window.open('plugins/kimchi/storagepool-add-volume.html'); - }); - - $('.storage-action').on('click', function() { - var storage_action = $(this); - var deleteButton = storage_action.find('.pool-delete'); - if ('active' === deleteButton.data('stat')) { - deleteButton.attr('disabled', 'disabled'); - } else { - deleteButton.removeAttr('disabled'); - } - }); - - $('.pool-extend').on('click', function() { - $("#logicalPoolExtend").dialog("option", "poolName", $(this).data('name')); - $("#logicalPoolExtend").dialog("open"); - }); - } - - $('.row').on('click', function(event) { - if (!$(event.target).parents().hasClass('bottom')) { - if ($(this).data('stat') === 'active') { - var that = $(this); - var volumeDiv = $('#volume' + that.data('name')); - var slide = $('.volumes', this); - if (that.hasClass('in')) { - that.css('height','auto'); - kimchi.doListVolumes(that); - } else { - slide.slideUp('slow', function(){ - that.css('height',''); - }); - that.addClass('in'); - kimchi.changeArrow($('.arrow-up', this)); - } - } - } - }); -} - -kimchi._generateVolumeHTML = function(volume) { - if(volume['type'] === 'kimchi-iso') { - return ''; - } - var volumeHtml = $('#volumeTmpl').html(); - volume.capacity = wok.changetoProperUnit(volume.capacity,1); - volume.allocation = wok.changetoProperUnit(volume.allocation,1); - return wok.substitute(volumeHtml, volume); -}; - -kimchi.doListVolumes = function(poolObj) { - var poolName = poolObj.data('name') - - var getOngoingVolumes = function() { - var result = {} - var filter = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/storagepools/' + poolName + '/*') - kimchi.getTasksByFilter(filter, function(tasks) { - for(var i = 0; i < tasks.length; i++) { - var volumeName = tasks[i].target_uri.split('/').pop(); - result[volumeName] = tasks[i]; - - if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) { - continue; - } - - kimchi.trackTask(tasks[i].id, function(result) { - wok.topic('kimchi/volumeTransferFinished').publish(result); - }, function(result) { - wok.topic('kimchi/volumeTransferError').publish(result); - }, function(result) { - wok.topic('kimchi/volumeTransferProgress').publish(result); - }); - } - }, null, true); - return result; - }; - - var volumeDiv = $('#volume' + poolName); - $(volumeDiv).empty(); - var slide = $('.volumes', poolObj); - var handleArrow = $('.arrow-down', poolObj); - - kimchi.listStorageVolumes(poolName, function(result) { - var listHtml = ''; - var ongoingVolumes = []; - var ongoingVolumesMap = getOngoingVolumes(); - $.each(ongoingVolumesMap, function(volumeName, task) { - ongoingVolumes.push(volumeName) - var volume = { - poolName: poolName, - used_by: [], - capacity: 0, - name: volumeName, - format: '', - bootable: null, - os_distro: '', - allocation: 0, - os_version: '', - path: '', - type: 'file' - }; - listHtml += kimchi._generateVolumeHTML(volume); - }); - - $.each(result, function(index, value) { - if (ongoingVolumes.indexOf(value.name) == -1) { - value.poolname = poolName; - listHtml += kimchi._generateVolumeHTML(value); - } - }); - - if (listHtml.length > 0) { - volumeDiv.html(listHtml); - } else { - volumeDiv.html("<div class='pool-empty'>" + i18n['KCHPOOL6002M'] + "</div>"); - } - - $.each(ongoingVolumesMap, function(volumeName, task) { - wok.topic('kimchi/volumeTransferProgress').publish(task); - }); - - poolObj.removeClass('in'); - kimchi.changeArrow(handleArrow); - slide.slideDown('slow'); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); -} - -kimchi.initLogicalPoolExtend = function() { - $("#logicalPoolExtend").dialog({ - autoOpen : false, - modal : true, - width : 600, - resizable : false, - closeText: "X", - open : function(){ - $('#loading-info', '#logicalPoolExtend').removeClass('hidden'); - $(".ui-dialog-titlebar-close", $("#logicalPoolExtend").parent()).removeAttr("title"); - kimchi.listHostPartitions(function(data) { - $('#loading-info', '#logicalPoolExtend').addClass('hidden'); - if (data.length > 0) { - for(var i=0;i<data.length;i++){ - if (data[i].type === 'part' || data[i].type === 'disk') { - $('.host-partition', '#logicalPoolExtend').append(wok.substitute($('#logicalPoolExtendTmpl').html(), data[i])); - } - } - } else { - $('.host-partition').html(i18n['KCHPOOL6011M']); - $('.host-partition').addClass('text-help'); - } - }, function(err) { - $('#loading-info', '#logicalPoolExtend').addClass('hidden'); - $('.host-partition').html(i18n['KCHPOOL6013M'] + '<br/>(' + err.responseJSON.reason + ')'); - $('.host-partition').addClass('text-help'); - }); - }, - beforeClose : function() { $('.host-partition', '#logicalPoolExtend').empty(); }, - buttons : [{ - class: "ui-button-primary", - text: i18n.KCHAPI6007M, - click: function(){ - var devicePaths = []; - $("input[type='checkbox']:checked", "#logicalPoolExtend").each(function(){ - devicePaths.push($(this).prop('value')); - }) - kimchi.updateStoragePool($("#logicalPoolExtend").dialog("option", "poolName"),{disks: devicePaths},function(data){ - var item = $("#"+$("#logicalPoolExtend").dialog("option", "poolName")); - $(".usage", $(".storage-name", item)).text((Math.round(data.allocated/data.capacity*100)||0)+"%"); - $(".storage-text", $(".storage-capacity", item)).text(wok.changetoProperUnit(data.capacity,1)); - $(".storage-text", $(".storage-allocate", item)).text(wok.changetoProperUnit(data.allocated,1)); - }); - $(this).dialog("close"); - } - }] - }); -} - -kimchi.storage_main = function() { - if(wok.tabMode['storage'] === 'admin') { - $('.tools').attr('style','display'); - $('#storage-pool-add').on('click', function() { - wok.window.open('plugins/kimchi/storagepool-add.html'); - }); - $('.list-title .title-actions').attr('style','display'); - } - kimchi.doListStoragePools(); - kimchi.initLogicalPoolExtend(); - - wok.topic('kimchi/storageVolumeAdded').subscribe(function() { - pool = kimchi.selectedSP; - var poolNode = $('.storage-li[data-name="' + pool + '"]'); - kimchi.doListVolumes(poolNode); - }); - - wok.topic('kimchi/volumeTransferProgress').subscribe(function(result) { - var extractProgressData = function(data) { - var sizeArray = /(\d+)\/(\d+)/g.exec(data) || [0, 0, 0]; - var downloaded = sizeArray[1]; - var percent = 0; - if(downloaded) { - var total = sizeArray[2]; - if(!isNaN(total)) { - percent = downloaded / total * 100; - } - } - var formatted = wok.formatMeasurement(downloaded); - var size = (1.0 * formatted['v']).toFixed(1) + formatted['s']; - return { - size: size, - percent: percent - }; - }; - - var uriElements = result.target_uri.split('/'); - var poolName = uriElements[2]; - var volumeName = uriElements.pop(); - var progress = extractProgressData(result['message']); - var size = progress['size']; - var percent = progress['percent']; - - volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]'); - $('.progress-bar-inner', volumeBox).css({ - width: percent + '%' - }); - $('.progress-transferred', volumeBox).text(size); - $('.volume-progress', volumeBox).removeClass('hidden'); - $('.progress-status', volumeBox).text(i18n['KCHPOOL6014M']); - }); - - wok.topic('kimchi/volumeTransferFinished').subscribe(function(result) { - var uriElements = result.target_uri.split('/'); - var poolName = uriElements[2]; - var volumeName = uriElements.pop(); - var volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]'); - $('.volume-progress', volumeBox).addClass('hidden'); - kimchi.getStoragePoolVolume(poolName, volumeName, function(volume) { - var html = kimchi._generateVolumeHTML(volume); - $(volumeBox).replaceWith(html); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }); - - wok.topic('kimchi/volumeTransferError').subscribe(function(result) { - // Error message from Async Task status - if (result['message']) { - var errText = result['message']; - } - // Error message from standard kimchi exception - else { - var errText = result['responseJSON']['reason']; - } - result && wok.message.error(errText); - - var uriElements = result.target_uri.split('/'); - var poolName = uriElements[2]; - var volumeName = uriElements.pop(); - volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]'); - $('.progress-status', volumeBox).text(i18n['KCHPOOL6015M']); - }); -}; - -kimchi.changeArrow = function(obj) { - if ($(obj).hasClass('arrow-down')) { - $(obj).removeClass('arrow-down').addClass('arrow-up'); - } else { - $(obj).removeClass('arrow-up').addClass('arrow-down'); - } -} diff --git a/plugins/kimchi/ui/js/src/kimchi.storagepool_add_main.js b/plugins/kimchi/ui/js/src/kimchi.storagepool_add_main.js deleted file mode 100644 index 8c27539..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.storagepool_add_main.js +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -kimchi.storagepool_add_main = function() { - kimchi.initStorageAddPage(); - $('#form-pool-add').on('submit', kimchi.addPool); - $('#pool-doAdd').on('click', kimchi.addPool); - // 'pool-doAdd' button starts as disabled. - $("#pool-doAdd").attr("disabled", true); - // Make any change in the form fields enables the - // 'pool-doAdd' button if all the visible form - // fields are filled, disables it otherwise. - $('#form-pool-add').on('input change propertychange', function() { - if (!kimchi.inputsNotBlank()) - $("#pool-doAdd").attr("disabled", true); - else - $("#pool-doAdd").attr("disabled", false); - }); -}; - -kimchi.storageFilterSelect = function(id, isUpdate) { - var input = $('input', '#'+id); - var options = $(".option", '#'+id); - var filter = function(container, key){ - container.children().each(function(){ - $(this).css("display", $(this).text().indexOf(key)==-1 ? "none" : ""); - }); - }; - if(!isUpdate){ - input.on("keyup", function(){ - filter(options, input.val()); - }); - } - options.children().each(function(){ - $(this).click(function(){ - options.children().removeClass("active"); - input.val($(this).text()); - input.trigger("change"); - $(this).addClass("active"); - filter(options, ""); - }); - }); -}; - -kimchi.setupISCSI = function(){ - var loadTargets = function(server, port, callback){ - var isUpdate = $(".option", "#iSCSITarget").children().length > 0; - $(".option", "#iSCSITarget").empty(); - $('input', "#iSCSITarget").attr("placeholder", i18n['KCHPOOL6006M']); - kimchi.getISCSITargets(server, port, function(data){ - if(data.length==0){ - $('input', "#iSCSITarget").attr("placeholder", i18n['KCHPOOL6007M']); - }else{ - for(var i=0; i<data.length; i++){ - var itemNode = $.parseHTML("<li>"+data[i].target+"</li>"); - $(".option", "#iSCSITarget").append(itemNode); - } - $('input', "#iSCSITarget").attr("placeholder", ""); - $(".popover", "#iSCSITarget").css("display", "block"); - } - kimchi.storageFilterSelect('iSCSITarget', isUpdate); - $('input', "#iSCSITarget").trigger("focus"); - callback(); - }, function(data){ - $('input', "#iSCSITarget").attr("placeholder", i18n['KCHPOOL6008M']); - callback(); - wok.message.error(data.responseJSON.reason); - }); - }; - var triggerLoadTarget = function(){ - $('input', "#iSCSITarget").val(""); - var server = $("#iscsiserverId").val().trim(); - var port = $("#iscsiportId").val().trim(); - if(server!="" && !$("#iscsiserverId").hasClass("invalid-field") && !$("#iscsiportId").hasClass("invalid-field")){ - $("#iscsiserverId").attr("disabled", true); - $("#iscsiportId").attr("disabled", true); - loadTargets(server, port, function(){ - $("#iscsiserverId").attr("disabled", false); - $("#iscsiportId").attr("disabled", false); - }); - } - }; - $("#iscsiserverId").change(function(){ - $('input', "#iSCSITarget").off('focus', triggerLoadTarget); - $('input', "#iSCSITarget").one('focus', triggerLoadTarget); - }); - $("#iscsiportId").change(function(){ - $('input', "#iSCSITarget").off('focus', triggerLoadTarget); - $('input', "#iSCSITarget").one('focus', triggerLoadTarget); - }); - var initISCSIServers = function(){ - kimchi.getStorageServers("iscsi", function(data){ - for(var i=0;i<data.length;i++){ - var itemNode = $.parseHTML("<li>"+data[i].host+"</li>"); - $(".option", "#iSCSIServer").append(itemNode); - $(itemNode).click(function(){ - $("#iscsiportId").val($(this).prop("port")); - $("#iscsiserverId").val($(this).text()); - triggerLoadTarget(); - }).prop("port", data[i].port); - } - kimchi.storageFilterSelect('iSCSIServer', false); - }); - }; - initISCSIServers(); -}; - -kimchi.initStorageAddPage = function() { - kimchi.listHostPartitions(function(data) { - if (data.length > 0) { - var deviceHtml = $('#partitionTmpl').html(); - var listHtml = ''; - valid_types = ['part', 'disk', 'mpath']; - $.each(data, function(index, value) { - if (valid_types.indexOf(value.type) != -1) { - listHtml += wok.substitute(deviceHtml, value); - } - }); - $('.host-partition', '#form-pool-add').html(listHtml); - } else { - $('.host-partition').html(i18n['KCHPOOL6011M']); - $('.host-partition').addClass('text-help'); - } - }, function(err) { - $('.host-partition').html(i18n['KCHPOOL6013M'] + '<br/>(' + err.responseJSON.reason + ')'); - $('.host-partition').addClass('text-help'); - }); - - kimchi.getHostFCDevices(function(data){ - if(data.length>0){ - for(var i=0;i<data.length;i++){ - data[i].label = data[i].name; - data[i].value = data[i].name; - } - $('#scsiAdapter').selectMenu(); - $("input", "#scsiAdapter").val(data[0].name); - $('#scsiAdapter').selectMenu("setData", data); - } else { - $('#scsiAdapter').html(i18n['KCHPOOL6005M']); - $('#scsiAdapter').addClass('text-help'); - } - }); - - $('#poolTypeId').selectMenu(); - $('#serverComboboxId').combobox(); - $('#targetFilterSelectId').filterselect(); - var options = [ { - label : "DIR", - value : "dir" - }, { - label : "NFS", - value : "netfs" - }, { - label : "iSCSI", - value : "iscsi" - }, { - label : "LOGICAL", - value : "logical" - }, { - label : i18n.KCHPOOL6004M, - value : "scsi" - } ]; - $('#poolTypeId').selectMenu("setData", options); - - kimchi.getStorageServers('netfs', function(data) { - var serverContent = []; - if (data.length > 0) { - $.each(data, function(index, value) { - serverContent.push({ - label : value.host, - value : value.host - }); - }); - } - $('#serverComboboxId').combobox("setData", serverContent); - $('input[name=nfsServerType]').change(function() { - if ($(this).val() === 'input') { - $('#nfsServerInputDiv').removeClass('tmpl-html'); - $('#nfsServerChooseDiv').addClass('tmpl-html'); - } else { - $('#nfsServerInputDiv').addClass('tmpl-html'); - $('#nfsServerChooseDiv').removeClass('tmpl-html'); - } - }); - $('#nfsserverId').on("change keyup",function() { - if ($(this).val() !== '' && wok.isServer($(this).val())) { - $('#nfspathId').prop('disabled',false); - $(this).removeClass("invalid-field"); - } else { - $(this).addClass("invalid-field"); - $('#nfspathId').prop( "disabled",true); - } - $('#targetFilterSelectId').filterselect('clear'); - }); - $('#nfspathId').focus(function() { - var targetContent = []; - kimchi.getStorageTargets($('#nfsserverId').val(), 'netfs', function(data) { - if (data.length > 0) { - $.each(data, function(index, value) { - targetContent.push({ - label : value.target, - value : value.target - }); - }); - } - $('#targetFilterSelectId').filterselect("setData", targetContent); - }); - }); - }); - - $('#poolTypeInputId').change(function() { - var poolObject = {'dir': ".path-section", 'netfs': '.nfs-section', - 'iscsi': '.iscsi-section', 'scsi': '.scsi-section', - 'logical': '.logical-section'} - var selectType = $(this).val(); - $.each(poolObject, function(type, value) { - if(selectType == type){ - $(value).removeClass('tmpl-html'); - } else { - $(value).addClass('tmpl-html'); - } - }); - }); - $('#authId').click(function() { - if ($(this).prop("checked")) { - $('.authenticationfield').removeClass('tmpl-html'); - } else { - $('.authenticationfield').addClass('tmpl-html'); - } - }); - $('#iscsiportId').keyup(function(event) { - $(this).toggleClass("invalid-field",!/^[0-9]*$/.test($(this).val())); - }); - $('#iscsiserverId').keyup(function(event) { - $(this).toggleClass("invalid-field",!wok.isServer($(this).val().trim())); - }).change(function(event) { - $(this).toggleClass("invalid-field",!wok.isServer($(this).val().trim())); - }); - kimchi.setupISCSI(); -}; - -/* Returns 'true' if all form fields were filled, 'false' if - * any field is left blank. The function takes into account - * the current poolType selected. - * - * Any 'field is blank' verification that were done in other - * validate functions were deleted, since we're doing it here - * already. - */ -kimchi.inputsNotBlank = function() { - if (!$('#poolId').val()) return false; - var poolType = $("#poolTypeInputId").val(); - if (poolType === "dir") { - if (!$('#pathId').val()) return false; - } else if (poolType === "netfs") { - if (!$('#nfspathId').val()) return false; - if (!$('#nfsserverId').val()) return false; - } else if (poolType === "iscsi") { - if (!$('#iscsiserverId').val()) return false; - if (!$('#iscsiTargetId').val()) return false; - } else if (poolType === "logical") { - if ($("input[name=devices]:checked").length === 0) - return false; - } - return true; -}; - -kimchi.validateForm = function() { - var poolType = $("#poolTypeInputId").val(); - if (poolType === "dir") { - return kimchi.validateDirForm(); - } else if (poolType === "netfs") { - return kimchi.validateNfsForm(); - } else if (poolType === "iscsi") { - return kimchi.validateIscsiForm(); - } else if (poolType === "logical") { - return kimchi.validateLogicalForm(); - } else { - return true; - } -}; - -kimchi.validateDirForm = function () { - var path = $('#pathId').val(); - if (!/(^\/.*)$/.test(path)) { - wok.message.error.code('KCHAPI6003E'); - return false; - } - return true; -}; - -kimchi.validateNfsForm = function () { - var nfspath = $('#nfspathId').val(); - var nfsserver = $('#nfsserverId').val(); - if (!kimchi.validateServer(nfsserver)) { - return false; - } - if (!/((\/([0-9a-zA-Z-_\.]+)))$/.test(nfspath)) { - wok.message.error.code('KCHPOOL6005E'); - return false; - } - $('#nfs-mount-loading').removeClass('hidden'); - return true; -}; - -kimchi.validateIscsiForm = function() { - var iscsiServer = $('#iscsiserverId').val(); - var iscsiTarget = $('#iscsiTargetId').val(); - if (!kimchi.validateServer(iscsiServer)) { - return false; - } - return true; -}; - -kimchi.validateServer = function(serverField) { - if(!wok.isServer(serverField)) { - wok.message.error.code('KCHPOOL6009E'); - return false; - } - return true; -}; - -kimchi.validateLogicalForm = function () { - if ($("input[name=devices]:checked").length === 0) { - wok.message.error.code('KCHPOOL6006E'); - return false; - } else { - return true; - } -}; - -kimchi.addPool = function(event) { - if (kimchi.validateForm()) { - var formData = $('#form-pool-add').serializeObject(); - delete formData.authname; - var poolType = $('#poolTypeId').selectMenu('value'); - if (poolType === 'dir') { - formData.path = $('#pathId').val(); - } else if (poolType === 'logical') { - var source = {}; - if (!$.isArray(formData.devices)) { - var deviceObj = []; - deviceObj[0] = formData.devices; - source.devices = deviceObj; - } else { - source.devices = formData.devices; - } - delete formData.devices; - formData.source = source; - } else if (poolType === 'netfs'){ - var source = {}; - source.path = $('#nfspathId').val(); - source.host = $('#nfsserverId').val(); - formData.source = source; - } else if (poolType === 'iscsi') { - var source = {}; - source.target = $('#iscsiTargetId').val(); - source.host = $('#iscsiserverId').val(); - $('#iscsiportId').val() !== '' ? source.port = parseInt($('#iscsiportId').val()): null; - if ($('#authId').prop("checked")) { - source.auth = { - "username" : $('#usernameId').val(), - "password" : $('#passwordId').val() - }; - } - formData.source = source; - } else if (poolType === 'scsi'){ - formData.source = { adapter_name: $('#scsiAdapter').selectMenu('value') }; - } - var storagePoolAddingFunc = function() { - $('input', '#form-pool-add').attr('disabled','disabled'); - $('#pool-doAdd').hide(); - $('#pool-loading').show(); - kimchi.createStoragePool(formData, function() { - kimchi.doListStoragePools(); - wok.window.close(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - $('input', '#form-pool-add').removeAttr('disabled'); - $('#pool-loading').hide(); - $('#pool-doAdd').show(); - }); - }; - if (poolType === 'logical') { - var settings = { - title : i18n['KCHAPI6001M'], - content : i18n['KCHPOOL6003M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - wok.confirm(settings, function() { - storagePoolAddingFunc(); - }, function() { - }); - } else { - storagePoolAddingFunc(); - } - } -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.storagepool_add_volume_main.js b/plugins/kimchi/ui/js/src/kimchi.storagepool_add_volume_main.js deleted file mode 100644 index 8479ab2..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.storagepool_add_volume_main.js +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014-2015 - * - * Licensed under the Apache License, Version 2.0 (the 'License'); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.sp_add_volume_main = function() { - // download from remote server or upload from local file - var type = 'download'; - - var addButton = $('#sp-add-volume-button'); - var remoteURLBox = $('#volume-remote-url'); - var localFileBox = $('#volume-input-file'); - var typeRadios = $('input.volume-type'); - - var isValidURL = function() { - var url = $(remoteURLBox).val(); - return kimchi.template_check_url(url); - }; - - var isValidFile = function() { - var fileName = $(localFileBox).val(); - return fileName.length > 0; - }; - - $(typeRadios).change(function(event) { - $('.volume-input').prop('disabled', true); - $('.volume-input.' + this.value).prop('disabled', false); - type = this.value; - if(type == 'download') { - $(addButton).prop('disabled', !isValidURL()); - } - else { - $(addButton).prop('disabled', !isValidFile()); - } - }); - - $(remoteURLBox).on('input propertychange', function(event) { - $(addButton).prop('disabled', !isValidURL()); - }); - - $(localFileBox).on('change', function(event) { - $(addButton).prop('disabled', !isValidFile()); - }); - - var onError = function(result) { - $(this).prop('disabled', false); - $(typeRadios).prop('disabled', false); - if(!result) { - return; - } - var msg = result['message'] || ( - result['responseJSON'] && result['responseJSON']['reason'] - ); - wok.message.error(msg); - }; - - var fetchRemoteFile = function() { - var volumeURL = remoteURLBox.val(); - var volumeName = volumeURL.split(/(\\|\/)/g).pop(); - kimchi.downloadVolumeToSP({ - sp: kimchi.selectedSP, - url: volumeURL - }, function(result) { - wok.window.close(); - wok.topic('kimchi/storageVolumeAdded').publish(); - }, onError); - }; - - var uploadFile = function() { - var chunkSize = 8 * 1024 * 1024; // 8MB - var uploaded = 0; - - var blobFile = $(localFileBox)[0].files[0]; - - var createUploadVol = function() { - kimchi.createVolumeWithCapacity(kimchi.selectedSP, { - name: blobFile.name, - format: '', - capacity: blobFile.size, - upload: true - }, function(result) { - wok.window.close(); - trackVolCreation(result.id); - }, onError); - }; - - var uploadRequest = function(blob) { - var fd = new FormData(); - fd.append('chunk', blob); - fd.append('chunk_size', blob.size); - - kimchi.uploadVolumeToSP(kimchi.selectedSP, blobFile.name, { - formData: fd - }, function(result) { - if (uploaded < blobFile.size) - setTimeout(doUpload, 500); - }, onError); - - uploaded += blob.size - }; - - // Check file exists and has read permission - try { - var blob = blobFile.slice(0, 20); - var reader = new FileReader(); - reader.onloadend = function(e) { - if (e.loaded == 0) - wok.message.error.code('KCHAPI6008E'); - else - createUploadVol(); - }; - - reader.readAsBinaryString(blob); - } catch (err) { - wok.message.error.code('KCHAPI6008E'); - return; - } - - var doUpload = function() { - try { - var blob = blobFile.slice(uploaded, uploaded + chunkSize); - var reader = new FileReader(); - reader.onloadend = function(e) { - if (e.loaded == 0) - wok.message.error.code('KCHAPI6009E'); - else - uploadRequest(blob); - }; - - reader.readAsBinaryString(blob); - } catch (err) { - wok.message.error.code('KCHAPI6009E'); - return; - } - } - - var trackVolCreation = function(taskid) { - var onTaskResponse = function(result) { - var taskStatus = result['status']; - var taskMsg = result['message']; - if (taskStatus == 'running') { - if (taskMsg != 'ready for upload') { - setTimeout(function() { - trackVolCreation(taskid); - }, 2000); - } else { - wok.topic('kimchi/storageVolumeAdded').publish(); - doUpload(); - } - } - }; - kimchi.getTask(taskid, onTaskResponse, onError); - }; - }; - - $(addButton).on('click', function(event) { - $(this).prop('disabled', true); - $(typeRadios).prop('disabled', true); - if(type === 'download') { - fetchRemoteFile(); - } - else { - uploadFile(); - } - event.preventDefault(); - }); -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.template_add_main.js b/plugins/kimchi/ui/js/src/kimchi.template_add_main.js deleted file mode 100644 index 01a47c2..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.template_add_main.js +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.switchPage = function(fromPageId, toPageId, direction) { - direction = direction || 'left'; - var toLeftBegin; - var fromLeftEnd; - if('left' === direction) { - toLeftBegin = '100%'; - fromLeftEnd = '-100%'; - } else if('right' === direction) { - toLeftBegin = '-100%'; - fromLeftEnd = '100%'; - } - var formPage = $('#'+fromPageId); - var toPage = $('#'+toPageId); - toPage.css({ - left: toLeftBegin - }); - formPage.animate({ - left: fromLeftEnd, - opacity: 0.1 - }, 400); - toPage.animate({ - left: '0', - opacity: 1 - }, 400); -}; - -kimchi.template_add_main = function() { - kimchi.deepScanHandler = null; - // 1-1 local iso - $('#iso-local').click(function() { - kimchi.switchPage('iso-type-box', 'iso-local-box'); - initLocalIsoField(); - initIsoFileField(); - kimchi.listIsos(function(isos) { - if (isos && isos.length) { - showLocalIsoField(isos); - $('#iso-more').show(); - } else { - $('#iso-search').show(); - } - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }); - - $('#iso-local-box-back').click(function() { - if (kimchi.deepScanHandler) { - kimchi.deepScanHandler.stop = true; - } - kimchi.switchPage('iso-local-box', 'iso-type-box', 'right'); - }); - - $('#iso-search').click(function() { - var settings = { - content : i18n['KCHTMPL6002M'] - }; - wok.confirm(settings, function() { - $('#iso-search').hide(); - $('#iso-search-loading').show(); - deepScan('#iso-search'); - }); - }); - - $('#iso-more').click(function() { - var settings = { - content : i18n['KCHTMPL6002M'] - }; - wok.confirm(settings, function() { - $('#iso-more').hide(); - $('#iso-more-loading').show(); - deepScan('#iso-more'); - }); - }); - - $('#iso-search-loading').click(function() { - $('#iso-search-loading').hide(); - $('#iso-search').show(); - if (kimchi.deepScanHandler) { - kimchi.deepScanHandler.stop = true; - } - }); - - $('#iso-more-loading').click(function() { - $('#iso-more-loading').hide(); - $('#iso-more').show(); - if (kimchi.deepScanHandler) { - kimchi.deepScanHandler.stop = true; - } - }); - - var deepScan = function(button) { - kimchi.deepScanHandler = kimchi.stepListDeepScanIsos(function(isos, isFinished) { - if (isos && isos.length) { - if(button === '#iso-search') { - $(button + '-loading').hide(); - button = '#iso-more'; - $(button + '-loading').show(); - } - showLocalIsoField(isos); - } else { - if (isFinished) { - wok.message.warn(i18n['KCHTMPL6001W']); - } - } - if (isFinished) { - $(button + '-loading').hide(); - $(button).show(); - } - }, function(err) { - wok.message.error(err.responseJSON.reason); - $(button + '-loading').hide(); - $(button).show(); - }); - }; - - //1-1-1 local iso list - var initLocalIsoField = function() { - kimchi.isoInfo = {}; - $('#local-iso-field').hide(); - $('#select-all-local-iso').prop('checked', false); - $('#btn-template-local-iso-create').attr('disabled', 'disabled'); - $('#iso-search').hide(); - $('#iso-more').hide(); - $('#iso-search-loading').hide(); - $('#iso-more-loading').hide(); - $('#list-local-iso').empty(); - }; - - var showLocalIsoField = function(isos) { - var html = ''; - var template = $('#tmpl-list-local-iso').html(); - $.each(isos, function(index, volume) { - var isoId = volume.os_distro + '*' + volume.name + '*' + volume.os_version; - if (!kimchi.isoInfo[isoId]) { - volume.isoId = isoId; - volume.capacity = wok.changetoProperUnit(volume.capacity, 1); - kimchi.isoInfo[isoId] = volume; - html += wok.substitute(template, volume); - } - }); - $('#list-local-iso').append(html); - $('#local-iso-field').show(); - }; - - $('#select-all-local-iso').click(function() { - $('#list-local-iso [type="checkbox"]').prop('checked', $(this).prop('checked')); - if ($(this).prop('checked')) { - $('#btn-template-local-iso-create').removeAttr('disabled'); - } else { - $('#btn-template-local-iso-create').attr('disabled', 'disabled'); - } - }); - - $('#list-local-iso').on('click', '[type="checkbox"]', function() { - var checkedLength = $('#list-local-iso [type="checkbox"]:checked').length; - if (checkedLength) { - $('#btn-template-local-iso-create').removeAttr('disabled'); - var length = $('#list-local-iso [type="checkbox"]').length; - $('#select-all-local-iso').prop('checked', length == checkedLength); - } else { - $('#select-all-local-iso').prop('checked', false); - $('#btn-template-local-iso-create').attr('disabled', 'disabled'); - } - }); - - $('#btn-template-local-iso-create').click(function() { - submitIso('form-local-iso'); - }); - - //1-1-2 local iso file - var initIsoFileField = function() { - $('#iso-file-check').prop('checked', false); - $('#iso-file-box').hide(); - $('#iso-file').val(''); - $('#btn-template-file-create').attr('disabled', 'disabled'); - }; - - $('#iso-file-check').click(function() { - if ($(this).prop('checked')) { - $('#iso-file-box').slideDown(); - } else { - $('#iso-file-box').slideUp(); - } - }); - - $('#iso-file').on('input propertychange', function() { - if ($('#iso-file').val()) { - $('#btn-template-file-create').removeAttr('disabled'); - } else { - $('#btn-template-file-create').attr('disabled', 'disabled'); - } - }); - - $('#btn-template-file-create').click(function() { - var isoFile = $('#iso-file').val(); - if (!kimchi.template_check_path(isoFile)) { - wok.message.error.code('KCHAPI6003E'); - return; - } - var data = { - "cdrom" : isoFile - }; - addTemplate(data); - }); - - //1-2 remote iso - $('#iso-remote').css('opacity', 0.3).css('cursor', 'not-allowed'); - - var enabledRemoteIso = function() { - if (kimchi.capabilities == undefined) { - setTimeout(enabledRemoteIso, 2000); - return; - } - - if (kimchi.capabilities.qemu_stream != true) { - return; - } - - $('#iso-remote').css('opacity', 1).css('cursor', 'pointer'); - $('#iso-remote').click(function() { - kimchi.switchPage('iso-type-box', 'iso-remote-box'); - initRemoteIsoField(); - initIsoUrlField(); - kimchi.listDistros(function(isos) { - showRemoteIsoField(isos); - }, function() { - }); - }); - }; - enabledRemoteIso(); - - $('#iso-remote-box-back').click(function() { - kimchi.switchPage('iso-remote-box', 'iso-type-box', 'right'); - }); - - //1-2-1 remote iso list - var initRemoteIsoField = function() { - $('#load-remote-iso').show(); - $('#remote-iso-field').hide(); - $('#iso-url-field').hide(); - $('#select-all-remote-iso').prop('checked', false); - $('#btn-template-remote-iso-create').attr('disabled', 'disabled'); - }; - - var showRemoteIsoField = function(isos) { - if (isos && isos.length) { - kimchi.isoInfo = {}; - var html = ''; - var template = $('#tmpl-list-remote-iso').html(); - $.each(isos, function(index, volume) { - var isoId = volume.os_distro + '*' + volume.name + '*' + volume.os_version; - if (!kimchi.isoInfo[isoId]) { - volume.isoId = isoId; - kimchi.isoInfo[isoId] = volume; - html += wok.substitute(template, volume); - } - }); - $('#list-remote-iso').html(html); - $('#load-remote-iso').hide() - $('#remote-iso-field').show(); - $('#iso-url-field').show(); - } else { - $('#load-remote-iso').hide() - $('#iso-url-field').show(); - wok.message.warn(i18n['KCHTMPL6001W']); - } - }; - - $('#select-all-remote-iso').click(function() { - $('#list-remote-iso [type="checkbox"]').prop('checked', $(this).prop('checked')); - if ($(this).prop('checked')) { - $('#btn-template-remote-iso-create').removeAttr('disabled'); - } else { - $('#btn-template-remote-iso-create').attr('disabled', 'disabled'); - } - }); - - $('#list-remote-iso').on('click', '[type="checkbox"]', function() { - var checkedLength = $('#list-remote-iso [type="checkbox"]:checked').length; - if (checkedLength) { - $('#btn-template-remote-iso-create').removeAttr('disabled'); - var length = $('#list-remote-iso [type="checkbox"]').length; - $('#select-all-remote-iso').prop('checked', length == checkedLength); - } else { - $('#select-all-remote-iso').prop('checked', false); - $('#btn-template-remote-iso-create').attr('disabled', 'disabled'); - } - }); - - $('#btn-template-remote-iso-create').click(function() { - submitIso('form-remote-iso'); - }); - - //1-2-2 remote iso url - var initIsoUrlField = function() { - $('#iso-url-check').prop('checked', false); - $('#iso-url-box').hide(); - $('#iso-url').val(''); - $('#btn-template-url-create').attr('disabled', 'disabled'); - } - - $('#iso-url-check').click(function() { - if ($(this).prop('checked')) { - $('#iso-url-box').slideDown(); - } else { - $('#iso-url-box').slideUp(); - } - }); - - $('#iso-url').on('input propertychange', function() { - if ($('#iso-url').val()) { - $('#btn-template-url-create').removeAttr('disabled'); - } else { - $('#btn-template-url-create').attr('disabled', 'disabled'); - } - }); - - $('#vm-image-local').click(function(){ - kimchi.switchPage('iso-type-box', 'vm-image-local-box'); - }); - $('#vm-image-local-box-back').click(function(){ - kimchi.switchPage('vm-image-local-box', 'iso-type-box', 'right'); - }); - $('input', '#vm-image-local-box').on('keyup cut paste', function(){ - setTimeout(function(){ - var isValid = kimchi.template_check_path($('input', '#vm-image-local-box').val()); - $('input', '#vm-image-local-box').toggleClass('invalid-field', !isValid); - $('button', $('.body', '#vm-image-local-box')).button(isValid ? "enable" : "disable"); - }, 0); - }); - $('button', $('.body', '#vm-image-local-box')).button({ - disabled: true - }).click(function(){ - $('input', '#vm-image-local-box').prop('disabled', true); - $(this).button('option', { - label: i18n['KCHAPI6008M'], - disabled: true - }); - addTemplate({disks:[{base:$('input', '#vm-image-local-box').val()}]}, function(){ - $('input', '#vm-image-local-box').prop('disabled', false); - $('button', $('.body', '#vm-image-local-box')).button('option', { - label: i18n['KCHAPI6005M'], - disabled: false - }); - }); - }); - - $('#btn-template-url-create').click(function() { - var isoUrl = $('#iso-url').val(); - if (!kimchi.template_check_url(isoUrl)) { - wok.message.error.code('KCHAPI6004E'); - return; - } - var data = { - "cdrom" : isoUrl - }; - addTemplate(data); - }); - - //do create - var addTemplate = function(data, callback) { - kimchi.createTemplate(data, function() { - if(callback) callback(); - kimchi.doListTemplates(); - wok.window.close(); - wok.topic('templateCreated').publish(); - }, function(err) { - if(callback) callback(); - wok.message.error(err.responseJSON.reason); - }); - }; - - var submitIso = function(formId) { - var formData = $('#' + formId).serializeObject(); - if (formData.iso) { - var length = 0; - var successNum = 0; - var addTemplate = function(isoInfo) { - var data = { - "os_distro" : isoInfo.os_distro, - "os_version" : isoInfo.os_version, - "cdrom" : isoInfo.path - }; - kimchi.createTemplate(data, function() { - successNum++; - $('input[value="' + isoInfo.isoId + '"]').prop('checked', false); - $('.check-all>input').prop('checked', false); - kimchi.doListTemplates(); - wok.topic('templateCreated').publish(data); - if (successNum === length) { - wok.window.close(); - } - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }; - if (formData.iso instanceof Array) { - length = formData.iso.length; - $.each(formData.iso, function(index, value) { - addTemplate(kimchi.isoInfo[value]); - }); - } else { - length = 1; - addTemplate(kimchi.isoInfo[formData.iso]); - } - } - }; -}; - -kimchi.template_check_url = function(url) { - var reg = /(https|http|ftp|ftps|tftp):\/\//; - if (url.constructor === String) { - return reg.test(url); - } - return false; -}; - -kimchi.template_check_path = function(filePath) { - var reg = /((\/([0-9a-zA-Z-_ \.]+))+)$/; - if (filePath.constructor === String) { - return reg.test(filePath); - } - return false; -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js b/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js deleted file mode 100644 index d40b6c7..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.template_edit_main = function() { - var templateEditMain = $('#edit-template-tabs'); - var origDisks; - var origPool; - var origNetworks; - var templateDiskSize; - $('#template-name', templateEditMain).val(kimchi.selectedTemplate); - templateEditMain.tabs(); - - var initTemplate = function(template) { - origDisks = template.disks; - origPool = template.storagepool; - origNetworks = template.networks; - for(var i=0;i<template.disks.length;i++){ - if(template.disks[i].base){ - template["vm-image"] = template.disks[i].base; - $('.templ-edit-cdrom').addClass('hide'); - $('.templ-edit-vm-image').removeClass('hide'); - break; - } - } - for ( var prop in template) { - var value = template[prop]; - if (prop == 'graphics') { - value = value["type"]; - } - $('input[name="' + prop + '"]', templateEditMain).val(value); - } - - var vncOpt = [{label: 'VNC', value: 'vnc'}]; - $('#template-edit-graphics').append('<option selected>VNC</option>'); - $('#template-edit-graphics').append('<option>Spice</option>'); - wok.select('template-edit-graphics-list', vncOpt); - var enableSpice = function() { - if (kimchi.capabilities == undefined) { - setTimeout(enableSpice, 2000); - return; - } - if (kimchi.capabilities.qemu_spice == true) { - spiceOpt = [{label: 'Spice', value: 'spice'}] - wok.select('template-edit-graphics-list', spiceOpt); - } - }; - enableSpice(); - var initStorage = function(result) { - var scsipools = {}; - var addStorageItem = function(storageData) { - var thisName = storageData.storageName; - var nodeStorage = $.parseHTML(wok.substitute($('#template-storage-pool-tmpl').html(), storageData)); - $('.template-tab-body', '#form-template-storage').append(nodeStorage); - var storageOptions = ''; - var scsiOptions = ''; - $('#selectStorageName').find('option').remove(); - $.each(result, function(index, storageEntities) { - if((storageEntities.state === 'active') && (storageEntities.type != 'kimchi-iso')) { - if(storageEntities.type === 'iscsi' || storageEntities.type === 'scsi') { - kimchi.listStorageVolumes(storageEntities.name, function(currentVolume) { - $.each(currentVolume, function(indexSCSI, scsiEntities) { - var tmpPath = storageEntities.name + '/' + scsiEntities.name; - var isSlected = tmpPath === thisName ? ' selected' : ''; - scsiOptions += '<option' + isSlected + '>' + tmpPath + '</option>'; - }); - $('#selectStorageName').append(scsiOptions); - }, function() {}); - } else { - var isSlected = storageEntities.name === thisName ? ' selected' : ''; - storageOptions += '<option' + isSlected + '>' + storageEntities.name + '</option>'; - } - } - }); - $('#selectStorageName').append(storageOptions); - - // Set disk format - $('#diskFormat').val(storageData.storageDiskFormat); - $('#diskFormat').on('change', function() { - $('.template-storage-disk-format').val($(this).val()); - }); - - $('#selectStorageName').change(function() { - var selectedItem = $(this).parent().parent(); - var tempStorageNameFull = $(this).val(); - var tempName = tempStorageNameFull.split('/'); - var tempStorageName = tempName[0]; - $('.template-storage-name').val(tempStorageNameFull); - kimchi.getStoragePool(tempStorageName, function(info) { - tempType = info.type; - selectedItem.find('.template-storage-type').val(tempType); - if (tempType === 'iscsi' || tempType === 'scsi') { - kimchi.getStoragePoolVolume(tempStorageName, tempName[tempName.length-1], function(info) { - volSize = info.capacity / Math.pow(1024, 3); - $('.template-storage-disk', selectedItem).attr('readonly', true).val(volSize); - $('#diskFormat').val('raw'); - $('#diskFormat').prop('disabled', true).change(); - }); - } else if (tempType === 'logical') { - $('.template-storage-disk', selectedItem).attr('readonly', false); - $('#diskFormat').val('raw'); - $('#diskFormat').prop('disabled', true).change(); - } else { - $('.template-storage-disk', selectedItem).attr('readonly', false); - if ($('#diskFormat').prop('disabled') == true) { - $('#diskFormat').val('qcow2'); - $('#diskFormat').prop('disabled', false).change(); - } - } - }); - }); - }; - - if ((origDisks && origDisks.length) && (origPool && origPool.length)) { - splitPool = origPool.split('/'); - var defaultPool = splitPool[splitPool.length-1]; - var defaultType; - - kimchi.getStoragePool(defaultPool, function(info) { - defaultType = info.type; - $.each(origDisks, function(index, diskEntities) { - var storageNodeData = { - viewMode : '', - editMode : 'hide', - storageName : defaultPool, - storageType : defaultType, - storageDisk : diskEntities.size, - storageDiskFormat : diskEntities.format ? diskEntities.format : 'qcow2' - } - - if (diskEntities.volume) { - kimchi.getStoragePoolVolume(defaultPool, diskEntities.volume, function(info) { - var volSize = info.capacity / Math.pow(1024, 3); - var nodeData = storageNodeData - nodeData.storageName = defaultPool + '/' + diskEntities.volume; - nodeData.storageDisk = volSize; - addStorageItem(nodeData); - $('.template-storage-disk').attr('readonly', true); - $('#diskFormat').val('raw'); - $('#diskFormat').prop('disabled', true).change(); - }); - } else if (defaultType === 'logical') { - addStorageItem(storageNodeData); - $('#diskFormat').val('raw'); - $('#diskFormat').prop('disabled', true).change(); - } else { - addStorageItem(storageNodeData); - } - }); - }); - } - - $('#template-edit-storage-add-button').button({ - icons: { - primary: "ui-icon-plusthick" - }, - text: false, - disabled: true - }).click(function(event) { - event.preventDefault(); - var storageNodeData = { - viewMode : 'hide', - editMode : '', - storageName : 'null', - storageType : 'dir', - storageDisk : '10' - } - addStorageItem(storageNodeData); - }); - }; - var initInterface = function(result) { - var networkItemNum = 0; - var addInterfaceItem = function(networkData) { - var networkName = networkData.networkV; - var nodeInterface = $.parseHTML(wok.substitute($('#template-interface-tmpl').html(), networkData)); - $('.template-tab-body', '#form-template-interface').append(nodeInterface); - $('.delete', '#form-template-interface').button({ - icons : {primary : 'ui-icon-trash'}, - text : false - }).click(function(evt) { - evt.preventDefault(); - $(this).parent().parent().remove(); - }); - var networkOptions = ''; - for(var i=0;i<result.length;i++){ - if(result[i].state === "active") { - var isSlected = networkName===result[i].name ? ' selected' : ''; - networkOptions += '<option' + isSlected + '>' + result[i].name + '</option>'; - } - } - $('select', '#form-template-interface #networkID' + networkItemNum).append(networkOptions); - networkItemNum += 1; - }; - if(result && result.length > 0) { - for(var i=0;i<origNetworks.length;i++) { - addInterfaceItem({ - networkID : 'networkID' + networkItemNum, - networkV : origNetworks[i], - type : 'network' - }); - } - } - $('#template-edit-interface-add-button').button({ - icons: { - primary: 'ui-icon-plusthick' - }, - text: false - }).click(function(evt) { - evt.preventDefault(); - addInterfaceItem({ - networkID : 'networkID' + networkItemNum, - networkV : 'default', - type : 'network' - }); - }); - }; - var initProcessor = function(){ - var setCPUValue = function(){ - if(!$('#cores').hasClass("invalid-field")&&$('#cores').val()!=""){ - $("#cpus").val(parseInt($("#cores").val())*parseInt($("#threads").val())); - }else{ - $("#cpus").val(''); - } - }; - $("input:text", "#form-template-processor").on('keyup', function(){ - $(this).toggleClass("invalid-field", !$(this).val().match('^[0-9]*$')); - if($(this).prop('id')=='cores') setCPUValue(); - }); - $("input:checkbox", "#form-template-processor").click(function(){ - $(".topology", "#form-template-processor").toggleClass("hide", !$(this).prop("checked")); - $("#cpus").attr("disabled", $(this).prop("checked")); - setCPUValue(); - }); - $('select', '#form-template-processor').change(function(){ - setCPUValue(); - }); - kimchi.getCPUInfo(function(data){ - var options = ""; - for(var i=0;Math.pow(2,i)<=data.threads_per_core;i++){ - var lastOne = Math.pow(2,i+1)>data.threads_per_core?" selected":""; - options += "<option"+lastOne+">"+Math.pow(2,i)+"</option>"; - } - $('select', '#form-template-processor').append(options); - if(template.cpus) $("#cpus").val(template.cpus); - var topo = template.cpu_info.topology; - if(topo&&topo.cores) $("#cores").val(topo.cores); - if(topo&&topo.threads){ - $('select', '#form-template-processor').val(topo.threads); - $("input:checkbox", "#form-template-processor").trigger('click'); - } - }); - }; - kimchi.listNetworks(initInterface); - kimchi.listStoragePools(initStorage); - initProcessor(); - }; - kimchi.retrieveTemplate(kimchi.selectedTemplate, initTemplate); - - - $('#tmpl-edit-button-save').on('click', function() { - var editableFields = [ 'name', 'memory', 'disks', 'graphics']; - var data = {}; - //Fix me: Only support one storage pool now - var storages = $('.template-tab-body .item', '#form-template-storage'); - var tempName = $('.template-storage-name', storages).val(); - var tmpItem = $('#form-template-storage .item'); - tempName = tempName.split('/'); - var tempNameHead = tempName[0]; - var tempNameTail = tempNameHead; - if($('.template-storage-type', tmpItem).val() === 'iscsi' || $('.template-storage-type', tmpItem).val() == 'scsi') { - tempNameTail = tempName[tempName.length-1]; - } - tempName = '/plugins/kimchi/storagepools/' + tempNameHead; - data['storagepool'] = tempName; - $.each(editableFields, function(i, field) { - /* Support only 1 disk at this moment */ - if (field == 'disks') { - if($('.template-storage-type', tmpItem).val() === 'iscsi' || $('.template-storage-type', tmpItem).val() == 'scsi') { - origDisks[0]['size'] && delete origDisks[0]['size']; - origDisks[0]['volume'] = tempNameTail; - } else { - origDisks[0]['volume'] && delete origDisks[0]['volume']; - origDisks[0].size = Number($('.template-storage-disk', tmpItem).val()); - } - origDisks[0].format = $('.template-storage-disk-format', tmpItem).val(); - data[field] = origDisks; - } - else if (field == 'graphics') { - var type = $('#form-template-general [name="' + field + '"]').val(); - data[field] = {'type': type}; - } - else { - data[field] = $('#form-template-general [name="' + field + '"]').val(); - } - }); - data['memory'] = Number(data['memory']); - data['cpus'] = parseInt($('#cpus').val()); - if($("input:checkbox", "#form-template-processor").prop("checked")){ - data['cpu_info'] = { - topology: { - sockets: 1, - cores: parseInt($("#cores").val()), - threads: parseInt($("#threads").val()) - } - }; - }else{ - data['cpu_info'] = {}; - } - var networks = $('.template-tab-body .item', '#form-template-interface'); - var networkForUpdate = new Array(); - $.each(networks, function(index, networkEntities) { - var thisValue = $('select', networkEntities).val(); - networkForUpdate.push(thisValue); - }); - if (networkForUpdate instanceof Array) { - data.networks = networkForUpdate; - } else if (networkForUpdate != null) { - data.networks = [networkForUpdate]; - } else { - data.networks = []; - } - - kimchi.updateTemplate($('#template-name').val(), data, function() { - kimchi.doListTemplates(); - wok.window.close(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }); -}; diff --git a/plugins/kimchi/ui/js/src/kimchi.template_main.js b/plugins/kimchi/ui/js/src/kimchi.template_main.js deleted file mode 100644 index b09fe12..0000000 --- a/plugins/kimchi/ui/js/src/kimchi.template_main.js +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -kimchi.doListTemplates = function() { - kimchi.listTemplates(function(result) { - if (result && result.length) { - $('#noTemplates').hide(); - var listHtml = ''; - var templateHtml = $('#templateTmpl').html(); - $.each(result, function(index, value) { - var isLocal; - if(value.cdrom){ - isLocal = /^\//.test(value['cdrom']); - }else{ - for(var i=0;i<value.disks.length;i++){ - if(value.disks[i].base){ - isLocal = /^\//.test(value.disks[i].base); - break; - } - } - } - if(isLocal){ - value.location = "plugins/kimchi/images/theme-default/icon-local.png"; - }else{ - value.location = "plugins/kimchi/images/theme-default/icon-remote.png"; - } - listHtml += wok.substitute(templateHtml, value); - }); - $('#templateList').html(listHtml); - kimchi.templateBindClick(); - } else { - $('#templateList').html(''); - $('#noTemplates').show(); - } - $('html').removeClass('processing'); - }, function(err) { - wok.message.error(err.responseJSON.reason); - $('html').removeClass('processing'); - }); -}; - -kimchi.templateBindClick = function() { - $('.template-edit').on('click', function(event) { - var templateName = $(this).data('template'); - kimchi.selectedTemplate = templateName; - wok.window.open("plugins/kimchi/template-edit.html"); - }); - $('.template-clone').on('click', function(event) { - kimchi.selectedTemplate = $(this).data('template'); - $('html').addClass('processing'); - kimchi.cloneTemplate(kimchi.selectedTemplate, function() { - kimchi.doListTemplates(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - kimchi.doListTemplates(); - }); - }); - $('.template-delete').on('click', function(event) { - var $template = $(this); - var settings = { - title : i18n['KCHAPI6001M'], - content : i18n['KCHTMPL6003M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - wok.confirm(settings, function() { - var templateName = $template.data('template'); - kimchi.deleteTemplate(templateName, function() { - kimchi.doListTemplates(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }, function() { - }); - }); -} -kimchi.hideTitle = function() { - $('#tempTitle').hide(); -}; - -kimchi.template_main = function() { - if(wok.tabMode['templates'] === 'admin') { - $('.tools').attr('style','display'); - $("#template-add").on("click", function(event) { - wok.window.open({ - url: 'plugins/kimchi/template-add.html', - close: function() { - if (kimchi.deepScanHandler) { - kimchi.deepScanHandler.stop = true; - } - } - }); - }); - } - - kimchi.doListTemplates(); -}; diff --git a/plugins/kimchi/ui/pages/Makefile.am b/plugins/kimchi/ui/pages/Makefile.am deleted file mode 100644 index 56288e3..0000000 --- a/plugins/kimchi/ui/pages/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2013 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -SUBDIRS = help - -htmldir = $(datadir)/wok/plugins/kimchi/ui/pages - -dist_html_DATA = $(wildcard *.tmpl) $(NULL) diff --git a/plugins/kimchi/ui/pages/guest-add.html.tmpl b/plugins/kimchi/ui/pages/guest-add.html.tmpl deleted file mode 100644 index 3770d96..0000000 --- a/plugins/kimchi/ui/pages/guest-add.html.tmpl +++ /dev/null @@ -1,98 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<!DOCTYPE html> -<html> -<body> -<div class="window" style="width: 900px;height: 580px;"> - <header> - <h1 class="title h1 grey">$_("Create a New Virtual Machine")</h1> - </header> - <div class="content"> - <form id="form-vm-add"> - <section class="form-section"> - <h2>1. $_("Virtual Machine Name")</h2> - <div class="field"> - <input type="text" class="text" style="width: 300px" name="name"><br> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("The name used to identify the virtual machine. If omitted, a name will be chosen based on the template used.") - </p> - </div> - </section> - <section class="form-section"> - <h2>2. $_("Template")</h2> - <div class="field"> - <div class="text-help"> - <div id="prompt-create-template" class="hidden"> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <div class="text-help help-inline">$_("Please create a template first.")</div> - <a id="btn-create-template" class="btn-normal" href="templates.html"> - <span class="text">$_("Create a Template")</span> - </a> - </div> - <div id="prompt-choose-template" class="hidden"> - <span class="icon-info-circled light-grey c1"></span> - <span class="text-help">$_("Please choose a template.")</span> - </div> - </div> - <ul id="templateTile" class="tile-check tile-template"> - </ul> - <script type="html/text" id="tmpl-template" class="tmpl-html"> - <li> - <label> - <input type="radio" name="template" value="/plugins/kimchi/templates/{name}"> - <div class="info"> - <div class="summary os-icon"> - <img src="{icon}"> - <span class="title">{name}</span> - </div> - <ul class="list-info"> - <li><label>$_("OS")</label><span>{os_distro}</span></li> - <li><label>$_("OS Version")</label><span>{os_version}</span></li> - <li><label>$_("CPUS")</label><span>{cpus}</span></li> - <li><label>$_("Memory")</label><span>{memory}M</span></li> - </ul> - </div> - </label> - </li> - </script> - </div> - </section> - </form> - </div> - <footer> - <div class="btn-group"> - <button id="vm-doAdd" class="btn-normal" disabled="disabled" href="javascript:void(0);"><span class="text">$_("Create")</span></button> - <button id="vm-doAdding" class="btn-normal" disabled="disabled" style="display:none" href="javascript:void(0);"><span class="text">$_("Creating...")</span></button> - <button id="vm-add=cancel" class="btn-normal close" type="button"> - <span class="text">$_("Cancel")</span> - </button> - </div> - </footer> -</div> -<script> - kimchi.guest_add_main(); -</script> -</body> -</html> diff --git a/plugins/kimchi/ui/pages/guest-edit.html.tmpl b/plugins/kimchi/ui/pages/guest-edit.html.tmpl deleted file mode 100644 index c5acf04..0000000 --- a/plugins/kimchi/ui/pages/guest-edit.html.tmpl +++ /dev/null @@ -1,311 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext - -<div id="guest-edit-window" class="window"> - <header> - <h1 class="title h1 grey">$_("Edit Guest")</h1> - </header> - <div class="content"> - <div id="guest-edit-tabs"> - <ul> - <li> - <a href="#form-guest-edit-general">$_("General")</a> - </li> - <li> - <a href="#form-guest-edit-storage">$_("Storage")</a> - </li> - <li> - <a href="#form-guest-edit-interface">$_("Interface")</a> - </li> - <li> - <a href="#form-guest-edit-permission">$_("Permission")</a> - </li> - <li> - <a href="#form-guest-edit-pci">$_("Host PCI Device")</a> - </li> - <li> - <a href="#form-guest-edit-snapshot">$_("Snapshot")</a> - </li> - </ul> - <form id="form-guest-edit-general"> - <fieldset class="guest-edit-fieldset"> - <div class="edit-general-inline"> - <div class="guest-edit-wrapper-label"> - <label for="guest-edit-id-textbox"> - $_("Name") - </label> - </div> - <div class="guest-edit-wrapper-label"> - <label for="guest-edit-cores-textbox"> - $_("CPUs") - </label> - </div> - <div class="guest-edit-wrapper-label"> - <label for="guest-edit-memory-textbox"> - $_("Memory (MB)") - </label> - </div> - <div class="guest-edit-wrapper-label"> - <label for="guest-edit-icon-textbox"> - $_("Icon") - </label> - </div> - </div> - <div class="edit-general-inline"> - <div class="guest-edit-wrapper-controls"> - <input id="guest-edit-id-textbox" - name="name" type="text" /> - </div> - <div class="guest-edit-wrapper-controls"> - <input - id="guest-edit-cores-textbox" - name="cpus" - type="text" /> - </div> - <div class="guest-edit-wrapper-controls"> - <input id="guest-edit-memory-textbox" - name="memory" - type="text" /> - </div> - <div class="guest-edit-wrapper-controls"> - <input - id="guest-edit-icon-textbox" - name="icon" - type="text" - disabled="disabled" /> - </div> - </div> - </fieldset> - </form> - <form id="form-guest-edit-storage"> - <div class="header"> - <span class="cell">$_("Device")</span> - <span class="cell">$_("Path")</span> - <button type="button" id="guest-edit-attach-cdrom-button" class="action-area attach"></button> - </div> - <div class="body"></div> - </form> - <form id="form-guest-edit-interface" class="guest-edit-interface"> - <div class="header"> - <span class="cell">$_("Network")</span> - <span class="cell">$_("Type")</span> - <span class="cell">$_("MAC Address")</span> - <button class="add action-area"></button> - </div> - <div class="body"></div> - </form> - <form id="form-guest-edit-permission" class="guest-edit-permission"> - <div class="pam"> - <div class="column avail"> - <div class="title">$_("Available system users and groups")</div> - <input type="text" id="permission-avail-searchBox"> - <div class="body"> - <div class="head"> - <div class="column column-user"><div class="item">Users</div></div> - <div class="column column-group"><div class="item">Groups</div></div> - </div> - <div id="permission-avail-users" class="column column-user"></div> - <div id="permission-avail-groups" class="column column-group"></div> - </div> - </div> - <div class="column control"> - <button id="permissionGo"> > </button> - <button id="permissionBack"> < </button> - </div> - <div class="column selected"> - <div class="title">$_("Selected system users and groups")</div> - <input type="text" id="permission-sel-searchBox"> - <div class="body"> - <div class="head"> - <div class="column column-user"><div class="item">Users</div></div> - <div class="column column-group"><div class="item">Groups</div></div> - </div> - <div id="permission-sel-users" class="column column-user"></div> - <div id="permission-sel-groups" class="column column-group"></div> - </div> - </div> - </div> - <div class="ldap"> - <div class="header"> - <span class="cell">$_("User")</span> - <button type="button" id="guest-edit-add-user-button" class="action-area add"></button> - </div> - <div class="body"></div> - </div> - </form> - <form id="form-guest-edit-pci" class="guest-edit-pci"> - <div class="guest-scroll-indent"> - <div class="filter"> - <span class="group"> - <select class="control"> - <option value="all">$_("All")</option> - <option value="toAdd">$_("To Add")</option> - <option value="added">$_("Added")</option> - </select><input type="text" class="control" placeholder="$_("filter")"> - </span> - </div> - <div class="header"> - <span class="cell name">$_("Name")</span> - <span class="cell product">$_("Product")</span> - <span class="cell vendor">$_("Vendor")</span> - </div> - <div class="body"></div> - </div> - </form> - <form id="form-guest-edit-snapshot" class="guest-edit-snapshot"> - <div class="header"> - <span class="cell sel"></span> - <span class="cell name">$_("Name")</span> - <span class="cell created">$_("Created")</span> - <button class="add action-area"></button> - </div> - <div class="task"></div> - <div class="body"></div> - </form> - </div> - </div> - <footer> - <div id="action-button-container" class="btn-group hidden"> - <button id="guest-edit-button-save" class="btn-normal"> - <span class="text">$_("Save")</span> - </button> - </div> - <button id="guest-edit-button-cancel" class="btn-normal close"> - <span class="text">$_("Cancel")</span> - </button> - </footer> -</div> -<script id="cdrom-row-tmpl" type="text/html"> - <div class="item view" id="cdrom-{dev}"> - <span class="cell dev"> - <input type="text" readonly="readonly" - id="cdrom-dev-{dev}" name="cdrom-dev-{dev}" value="{dev}" /> - </span> - <span class="cell path"> - <input id="cdrom-path-{dev}" name="cdrom" type="text" - data-vm="{vm}" data-dev="{dev}" - value="{path}" readonly="readonly" /> - </span> - <span class="action-area"> - <button type="button" class="guest-edit-cdrom-button replace" - data-vm="{vm}" data-dev="{dev}" - title='$_("Replace")'> - </button> - <button type="button" class="guest-edit-cdrom-button detach" - data-vm="{vm}" data-dev="{dev}" data-type="{type}" - title='$_("Detach")'> - </button> - <button type="button" class="guest-edit-cdrom-button save hidden" - data-vm="{vm}" data-dev="{dev}" - title='$_("Save")'> - </button> - <button type="button" class="guest-edit-cdrom-button cancel hidden" - data-vm="{vm}" data-dev="{dev}" - title='$_("Cancel")'> - </button> - </span> - </div> -</script> -<script id="interface-tmpl" type="text/html"> - <div class="item" id="{mac}"> - <span class="cell"> - <label id="label-network-{id}" class="{viewMode}">{network}</label> - <select class="{editMode}"></select> - </span> - <span class="cell"> - <span>{type}</span> - </span> - <span class="cell"> - <label id="label-mac-{id}" class="{viewMode}">{mac}</label> - <input class="{editMode}" type="text" - id="edit-mac-{id}" name="{mac}" value="{mac}" /> - </span> - <span class="action-area {editMode}"> - <button class="save"></button><button class="cancel"></button> - </span> - <span class="action-area {viewMode}"> - <button class="edit"></button><button class="delete"></button> - </span> - <div> -</script> -<script id="ldap-user-tmpl" type="text/html"> - <div class="item" id="{user}"> - <span class="cell"> - <label class="{viewMode}">{user}</label> - <input type="text" placeholder="LDAP User ID,e.g.foo@foo.com" class="{editMode}"/> - </span> - <span class="action-area"> - <button class="delete"></button> - </span> - <div> -</script> -<script id="disk-row-tmpl" type="text/html"> - <div class="item" id="cdrom-{dev}"> - <span class="cell dev"> - <input type="text" readonly="readonly" - id="disk-dev-{dev}" name="disk-dev-{dev}" value="{dev}" /> - </span> - <span class="cell path"> - <input id="disk-path-{dev}" name="path-{dev}" type="text" - data-vm="{vm}" data-dev="{dev}" - value="{path}" readonly="readonly" /> - </span> - <span class="action-area"> - <button type="button" class="guest-edit-cdrom-button detach" - data-vm="{vm}" data-dev="{dev}" data-type="{type}" - title="$_("Detach")"> - </button> - </span> - </div> -</script> -<script id="permission-item-pam" type="text/html"> -<div class="item"> - <span class="icon {class}"></span> - <label>{val}</label> -</div> -</script> -<script id="pci-tmpl" type="text/html"> -<div class="item" id="{name}"> - <span class="cell name" title="{name}">{name}</span> - <span class="cell product" title="{product}">{product}</span> - <span class="cell vendor" title="{vendor}">{vendor}</span> - <button></button> -</div> -</script> -<script id="snapshot-tmpl" type="text/html"> - <div class="item" id="{name}"> - <span class="cell sel"> - <span class="icon {createMode}"></span> - <span class="ui-icon ui-icon-check hide"></span> - </span> - <span class="cell name">{name}</span> - <span class="cell created">{created}</span> - <span class="action-area"> - <button class="revert {listMode}" title="$_("revert")"></button> - <button class="delete {listMode}"></button> - </span> - <div> -</script> -<script type="text/javascript"> - kimchi.guest_edit_main(); -</script> diff --git a/plugins/kimchi/ui/pages/guest-storage-add.html.tmpl b/plugins/kimchi/ui/pages/guest-storage-add.html.tmpl deleted file mode 100644 index a26e0f9..0000000 --- a/plugins/kimchi/ui/pages/guest-storage-add.html.tmpl +++ /dev/null @@ -1,103 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<div id="guest-storage-add-window" class="window"> - <header> - <h1 class="title">$_("Add a Storage Device to VM")</h1> - <div class="close">X</div> - </header> - <div class="content"> - <form id="form-guest-storage-add"> - <section class="form-section"> - <h2>1. $_("Device Type")</h2> - <div class="field"> - <p class="text-help"> - $_("The device type. Currently, \"cdrom\" and \"disk\" are supported.") - </p> - <div class="btn dropdown popable"> - <input id="guest-storage-type" name="type" value="cdrom" type="hidden" /> - <span class="text" id="guest-storage-type-label"></span> - <span class="arrow"></span> - <div class="popover"> - <ul class="select-list" id="guest-storage-type-list" data-target="guest-storage-type" data-label="guest-storage-type-label"></ul> - </div> - </div> - </div> - </section> - <div class="volume-section hidden"> - <section class="form-section"> - <h2>2. $_("Storage Pool")</h2> - <div class="field storage-field"> - <p class="text-help"> - $_("Storage pool which volume located in") - </p> - <div class="btn dropdown popable"> - <input value="default" id="guest-disk-pool" name="pool" type="hidden"/> - <span class="text" id="guest-disk-pool-label">default</span><span class="arrow"></span> - <div class="popover" style="width: 100%"> - <ul class="select-list" id="guest-add-storage-pool-list" data-target="guest-disk-pool" data-label="guest-disk-pool-label"></ul> - </div> - </div> - </div> - </section> - <section class="form-section"> - <h2>3. $_("Storage Volume")</h2> - <div class="field storage-field"> - <p class="text-help"> - $_("Storage volume to be attached") - </p> - <div class="btn dropdown popable" id="guest-disk"> - <input id="guest-disk-vol" name="vol" type="hidden"> - <span class="text" id="guest-disk-vol-label"></span><span class="arrow"></span> - <div class="popover" style="width: 100%"> - <ul class="select-list" id="guest-add-storage-pool-list" data-target="guest-disk-vol" data-label="guest-disk-vol-label"></ul> - </div> - </div> - </div> - </section> - </div> - <div class="path-section"> - <section class="form-section"> - <h2>2. $_("File Path")</h2> - <div class="field"> - <p class="text-help"> - $_("The ISO file path in the server for CDROM.") - </p> - <input type="text" class="text" name="path" /> - </div> - </section> - </div> - </fieldset> - </form> - </div> - <footer> - <div class="btn-group"> - <button id="guest-storage-button-add" class="btn-normal" disabled="disabled"> - <span class="text">$_("Attach")</span> - </button> - </div> - </footer> -</div> -<script type="text/javascript"> - kimchi.guest_storage_add_main(); -</script> diff --git a/plugins/kimchi/ui/pages/guest.html.tmpl b/plugins/kimchi/ui/pages/guest.html.tmpl deleted file mode 100644 index 78e9161..0000000 --- a/plugins/kimchi/ui/pages/guest.html.tmpl +++ /dev/null @@ -1,77 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext - <li name="guest" class="guest"> - <div class="sortable guest-type"> - <div class="guest-general"> - <h2 class="title" title="{name}">{name}</h2> - </div> - <div class="guest-pending hide-content"> - <span class="icon"></span><span class="text"></span> - </div> - </div> - <div name="cpu_utilization" class="sortable"> - <div class="circleGauge"></div> - </div> - <div name="io_throughput" class="sortable"> - <div class="circleGauge"></div> - <div class="subtitle">KB/s</div> - </div> - <div name="net_throughput" class="sortable"> - <div class="circleGauge"></div> - <div class="subtitle">KB/s</div> - </div> - <div name="guest-tile" class="sortable guest-tile"> - <div class="tile "> - <img class="imgactive" alt="" src=""> - <img class="imgload" alt="" src=""> - <img class="overlay shutoff-hidden" alt="$_("Start")" src="plugins/kimchi/images/theme-default/icon-power-down.png" > - </div> - </div> - <div class="sortable guest-actions" name="guest-actions"> - <div class="top"> - <button class="btn reset-disabled" name="vm-reset" href="javascript:void(0);" title="$_("Reset")"><span class="icon reset"></span></button> - <button class="btn pause-disabled" name="vm-pause" href="javascript:void(0);" title="$_("Pause")"><span class="icon pause"></span></button> - <button class="btn resume-hidden" name="vm-resume" href="javascript:void(0);" title="$_("Resume")"><span class="icon resume"></span></button> - <button class="btn running-hidden" name="vm-start" href="javascript:void(0);" title="$_("Start")"><span class="icon power-down"></span></button> - <button class="btn shutoff-hidden" name="vm-poweroff" href="javascript:void(0);" title="$_("Power Off")"><span class="icon power-up"></span></button> - </div> - <div class="bottom"> - <div name="actionmenu" class="btn dropdown popable vm-action" style="width: 126px"> - <span class="text">$_("Actions")</span><span class="arrow"></span> - <div class="popover actionsheet right-side" style="width: 250px"> - <button class="button-big shutoff-disabled" name="vm-console" ><span class="text">$_("Connect")</span></button> - <button class="button-big running-disabled" name="vm-clone"><span class="text">$_("Clone")</span></button> - <button class="button-big" name="vm-edit"><span class="text">$_("Edit")</span></button> - <button class="button-big shutoff-hidden non-persistent-disabled" name="vm-reset"><span class="text">$_("Reset")</span></button> - <button class="button-big pause-hidden non-persistent-disabled" name="vm-pause"><span class="text">$_("Pause")</span></button> - <button class="button-big resume-hidden" name="vm-resume"><span class="text">$_("Resume")</span></button> - <button class="button-big shutoff-hidden" name="vm-shutdown"><span class="text">$_("Shut Down")</span></button> - <button class="button-big running-hidden" name="vm-start"><span class="text">$_("Start")</span></button> - <button class="button-big shutoff-hidden" name="vm-poweroff"><span class="text">$_("Power Off")</span></button> - <button class="button-big red non-persistent-disabled" name="vm-delete">$_("Delete")</button> - </div> - </div> - </div> - </div> - </li> diff --git a/plugins/kimchi/ui/pages/guests.html.tmpl b/plugins/kimchi/ui/pages/guests.html.tmpl deleted file mode 100644 index b8a1259..0000000 --- a/plugins/kimchi/ui/pages/guests.html.tmpl +++ /dev/null @@ -1,65 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# - -#unicode UTF-8 -#import gettext -#from Cheetah.Template import Template -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext - -#silent ht = Template - -<!DOCTYPE html> -<html> -<head> -<link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> -<script src="plugins/kimchi/js/kimchi.min.js"></script> -</head> -<body> -<div id="guests-root-container"> - <div class="toolbar"> - <div class="tools" style="display:none"> - <a id="vm-add" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> - </div> - </div> - <div id="guestListField" style="display: none"> - <ul class="list-title"> - <li class="guest-type">$_("Name")</li> - <li class="guest-cpu">$_("CPU")</li> - <li class="guest-storage">$_("Disk I/O")</li> - <li class="guest-network">$_("Network I/O")</li> - <li class="guest-tile">$_("Livetile")</li> - <li class="guest-actions">$_("Actions")</li> - </ul> - <ul id="guestList" class="list-vm empty-when-logged-off"> - </ul> - </div> - <div id="noGuests" class="list-no-result" style="display: none;"> - $_("No guests found.") - </div> - <script id="guest-tmpl" type="kimchi/template"> - $ht(file=$data.ui_dir + "/pages/guest.html.tmpl", searchList=[self, {'lang':$lang}]) - </script> - <script type="text/javascript"> - kimchi.guest_main(); - </script> -</div> -</body> -</html> diff --git a/plugins/kimchi/ui/pages/help/Makefile.am b/plugins/kimchi/ui/pages/help/Makefile.am deleted file mode 100644 index a4ee361..0000000 --- a/plugins/kimchi/ui/pages/help/Makefile.am +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -SUBDIRS = zh_CN it_IT en_US zh_TW pt_BR ja_JP ru_RU ko_KR fr_FR de_DE es_ES - -DITA_HTML_FILES = $(patsubst %.dita,%.html,$(wildcard */*.dita)) -HTML_FILES = $(if $(DITA_HTML_FILES), $(DITA_HTML_FILES), $(wildcard */*.html)) -DITA_XSL_FILE = dita-help.xsl - -EXTRA_DIST = $(DITA_XSL_FILE) - -helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help - -dist_help_DATA = kimchi.css - -all: $(HTML_FILES) $(wildcard */*.dita) - -%.html: %.dita $(DITA_XSL_FILE) - xsltproc -o $@ $(DITA_XSL_FILE) $< - -CLEANFILES = $(HTML_FILES) diff --git a/plugins/kimchi/ui/pages/help/de_DE/Makefile.am b/plugins/kimchi/ui/pages/help/de_DE/Makefile.am deleted file mode 100644 index 3d99aae..0000000 --- a/plugins/kimchi/ui/pages/help/de_DE/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -de_DE_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/de_DE - -dist_de_DE_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/de_DE/guests.dita b/plugins/kimchi/ui/pages/help/de_DE/guests.dita deleted file mode 100644 index 1d64469..0000000 --- a/plugins/kimchi/ui/pages/help/de_DE/guests.dita +++ /dev/null @@ -1,127 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="de-de"> -<title>G��ste</title> -<shortdesc>Auf der Seite <wintitle>G��ste</wintitle> sind die definierten virtuellen -Maschinen von KVM aufgelistet.</shortdesc> -<csbody> -<p>F��r jeden Gast werden die folgenden Informationen angezeigt:<dl><dlentry> -<dt>Name</dt> -<dd>Name der virtuellen Maschine.</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>Prozentsatz der Prozessorauslastung in der virtuellen Maschine.</dd> -</dlentry><dlentry> -<dt>Netz-E/A</dt> -<dd>Netz-E/A-��bertragungsrate in KB pro Sekunde.</dd> -</dlentry><dlentry> -<dt>Platten-E/A</dt> -<dd>Platten-E/A-��bertragungsrate in KB pro Sekunde.</dd> -</dlentry><dlentry> -<dt>Live Tile</dt> -<dd>Status der Konsole f��r das Gastbetriebssystem oder ein Symbol, das die -<tm tmtype="tm" trademark="Linux">Linux</tm>-Verteilung darstellt, wenn -der Gast nicht aktiv ist.</dd> -</dlentry></dl></p> -<p>Die folgenden Aktionssymbole werden f��r jeden Gast angezeigt:<dl> -<dlentry> -<dt>Zur��cksetzen</dt> -<dd>Klicken Sie hier, um den Gast zur��ckzusetzen. </dd> -</dlentry><dlentry> -<dt>Power (Starten oder Stoppen)</dt> -<dd>Klicken Sie hier, um den Gast ein- bzw. auszuschalten. Wenn das Symbol rot ist, -ist er ausgeschaltet. Wenn das Symbol gr��n ist, ist er eingeschaltet.</dd> -</dlentry></dl> </p> -<p>Die folgenden Aktionen k��nnen f��r jeden Gast ausgew��hlt werden:<ul> -<li>W��hlen Sie <uicontrol>Verbinden</uicontrol> aus, um eine Verbindung zur fernen Konsole -f��r das Gastbetriebssystem herzustellen.</li> -<li>W��hlen Sie <uicontrol>Medien verwalten</uicontrol> aus, um den Pfad zu den -Installationsmedien zu ��ndern.</li> -<li>W��hlen Sie <uicontrol>Zur��cksetzen</uicontrol> aus, um den Gast zur��ckzusetzen.</li> -<li>W��hlen Sie <uicontrol>Bearbeiten</uicontrol> aus, um die Eigenschaften eines -bestehenden Gastes zu bearbeiten. G��ste k��nnen nur bearbeitet werden, wenn sie gestoppt sind.</li> -<li>W��hlen Sie <uicontrol>L��schen</uicontrol> aus, um den Gast zu l��schen.</li> -</ul>Um einen Gast bzw. eine virtuelle Maschine zu erstellen, klicken Sie auf das <uicontrol>Plus (+)</uicontrol>-Symbol oben rechts auf der Seite.</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="de-de"> -<title>Virtuelle Maschine erstellen</title> -<shortdesc>Erstellen Sie eine virtuelle Maschine mithilfe einer bestehenden Vorlage.</shortdesc> -<csbody> -<p> <ol> -<li>Geben Sie den Namen ein, mit dem die virtuelle Maschine gekennzeichnet wird.</li> -<li rev="rev1">W��hlen Sie eine Vorlage aus. <ul> -<li>Wenn Vorlagen vorhanden sind, w��hlen Sie eine aus den angezeigten Vorlagen aus.</li> -<li>Wenn keine Vorlagen vorhanden sind, klicken Sie auf <uicontrol>Vorlage erstellen</uicontrol>, um eine Vorlage zu erstellen.</li> -</ul></li> -<li>Klicken Sie auf <uicontrol>Erstellen</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="de-de"> -<title>Gast bearbeiten</title> -<shortdesc>Bearbeiten Sie die Eigenschaften einer bestehenden virtuellen Maschine. Einige Eigenschaften k��nnen nur bearbeitet werden, solange der Gast gestoppt ist. Andere Eigenschaften treten beim n��chsten Booten in Kraft. </shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>F��r jeden Gast werden die folgenden Informationen auf der Registerkarte <wintitle>Allgemein</wintitle> angezeigt:<dl> -<dlentry> -<dt>Name</dt> -<dd>Name der virtuellen Maschine. (Kann nur bearbeitet werden, solange der Gast gestoppt ist.)</dd> -</dlentry><dlentry> -<dt>CPUs</dt> -<dd>Anzahl der Prozessoren. (Wenn der Gast aktiv ist, tritt die neue Menge beim n��chsten Booten in Kraft.) -</dd> -</dlentry><dlentry> -<dt>Speicher</dt> -<dd>Speicherkapazit��t in MB. (Wenn der Gast aktiv ist, tritt die neue Menge beim n��chsten Booten in Kraft.) -</dd> -</dlentry><dlentry> -<dt>Symbol</dt> -<dd>Grafikbild, das die Linux-Verteilung darstellt und anstelle des aktuellen Status (Live Tile) angezeigt werden soll, wenn der Gast nicht aktiv ist.</dd> -</dlentry></dl></p> -<p>Die folgenden Informationen werden auf der Registerkarte <wintitle>Speicher</wintitle> angezeigt.</p> -<dl><dlentry> -<dt>Speicher</dt> -<dd>Zeigt die Position der ISO-Datei an, die f��r die Installation verwendet wird.</dd> -</dlentry></dl> -<p> Felder, die nicht inaktiviert sind, k��nnen bearbeitet werden. Nachdem Sie ein Feld bearbeitet haben, klicken Sie auf <uicontrol>Speichern</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="de-de"> -<title>Speichereinheit hinzuf��gen, ersetzen oder abh��ngen</title> -<shortdesc rev="rev1">Sie k��nnen eine Speichereinheit zu Ihrer virtuellen Maschine hinzuf��gen oder diese ersetzen oder abh��ngen. Die einzige unterst��tzte Einheit ist CD-ROM. F��hren Sie die folgenden Schritte aus, um Ihre Speichereinheiten zu bearbeiten:</shortdesc> -<csbody> -<ol> -<li>W��hlen Sie im Fenster <wintitle>Gast bearbeiten</wintitle> die Option <wintitle>Speicher</wintitle> aus.</li> -<li>Um eine Speichereinheit zu ersetzen, klicken Sie auf das erste Symbol mit dem <uicontrol>orangefarbenen Schr��gstrich (/)</uicontrol>. Geben Sie den ISO-Dateipfad ein und klicken Sie auf <uicontrol>Ersetzen</uicontrol>.</li> -<li>Um eine Speichereinheit abzuh��ngen, klicken Sie auf das zweite Symbol mit dem <uicontrol>roten Gedankenstrich (-)</uicontrol>. Best��tigen Sie den L��schvorgang und klicken Sie auf <uicontrol>OK</uicontrol>.</li> -<li>Um eine Speichereinheit hinzuzuf��gen, klicken Sie auf das dritte Symbol mit dem gr��nen <uicontrol>Pluszeichen (+)</uicontrol>. Geben Sie einen Einheitennamen und einen ISO-Dateipfad ein und klicken Sie auf <uicontrol>Anh��ngen</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="de-de"> -<title>CD-ROM f��r VM ersetzen</title> -<shortdesc rev="rev1">Sie k��nnen den Inhalt der CD-ROM f��r eine virtuelle Maschine nach Abschluss der Installation ersetzen.</shortdesc> -<csbody> -<ol> -<li>Stellen Sie sicher, dass die virtuelle Maschine gestartet ist.</li> -<li>W��hlen Sie aus dem Aktionsmen�� die Option <uicontrol>Medien verwalten</uicontrol> aus.</li> -<li>Um das zu ��ndern, was aktuell in der CD-ROM geladen ist, klicken Sie auf das Symbol mit dem <uicontrol>orangefarbenen Schr��gstrich (/)</uicontrol> neben dem hdc-Feld.</li> -<li>Geben Sie auf der Seite <wintitle>CD-ROM f��r VM ersetzen</wintitle> den ISO-Dateipfad ein. Die anderen beiden Felder sind schreibgesch��tzt.</li> -<li>Klicken Sie auf <uicontrol>Ersetzen</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 231 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/de_DE/host.dita b/plugins/kimchi/ui/pages/help/de_DE/host.dita deleted file mode 100644 index 33a40e3..0000000 --- a/plugins/kimchi/ui/pages/help/de_DE/host.dita +++ /dev/null @@ -1,49 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="de-de"> -<title>Host</title> -<shortdesc>Die Seite <wintitle>Host</wintitle> zeigt Informationen zum Hostsystem an und erm��glicht Ihnen, den Host herunterzufahren, erneut zu starten und eine Verbindung zu ihm herzustellen.</shortdesc> -<csbody> -<p>Sie k��nnen die folgenden Aktionen am Host durchf��hren:<ul> -<li>W��hlen Sie <uicontrol>Herunterfahren</uicontrol> aus, um das Hostsystem herunterzufahren.</li> -<li>W��hlen Sie <uicontrol>Erneut starten</uicontrol> aus, um das Hostsystem erneut zu starten.</li> -<li>W��hlen Sie <uicontrol>Verbinden</uicontrol> aus, um eine VNC-Verbindung zum Hostsystem herzustellen, wenn noch keine Verbindung besteht.</li> -</ul></p> -<p>Klicken Sie auf die folgenden Abschnitte, um Informationen zum Host anzuzeigen:<dl> -<dlentry> -<dt>Basisinformationen</dt> -<dd>Dieser Abschnitt zeigt die Verteilung, die Version und den Codenamen des Hostbetriebssystems sowie den Prozessortyp und die Speicherkapazit��t in GB an.</dd> -</dlentry><dlentry> -<dt>Systemstatistik</dt> -<dd>Dieser Abschnitt zeigt mithilfe von Grafiken Statistiken f��r CPU, Speicher, Platten-E/A und Netz-E/A f��r den Host an. W��hlen Sie <uicontrol>Daten werden nach dem Verlassen dieser Seite gesammelt</uicontrol> aus, um mit der Sammlung von Daten fortzufahren, wenn die Host-Registerkarte nicht angezeigt wird.</dd> -</dlentry><dlentry> -<dt>Software-Updates</dt> -<dd>Dieser Abschnitt zeigt Informationen f��r alle Pakete an, bei denen Aktualisierungen verf��gbar sind, einschlie��lich Paketname, Version, Architektur und Repository. Sie k��nnen alle aufgelisteten Pakete aktualisieren, indem Sie <uicontrol>Alle aktualisieren</uicontrol> ausw��hlen. Sie k��nnen nicht einzelne Pakete zur Aktualisierung ausw��hlen.</dd> -</dlentry><dlentry> -<dt>Repositorys</dt> -<dd>Dieser Abschnitt zeigt Repositorys an, die dem Hostsystem zugeordnet sind. Sie k��nnen Repositorys hinzuf��gen, aktivieren, bearbeiten oder entfernen. Beim Hinzuf��gen wird ein Repository dem Hostsystem zugeordnet. Das Aktivieren eines Repositorys dagegen erm��glicht dem Host den Zugriff auf das Repository. Wenn Ihr System Red Hat Enterprise -Linux oder Fedora ist, k��nnen Sie <filepath>yum</filepath>-Repositorys hinzuf��gen. -Wenn Ihr System Ubuntu oder Debian ist, f��gen Sie <filepath>deb</filepath>-Repositorys hinzu.<p>Wenn Sie mit yum-Repositorys arbeiten, k��nnen Sie eine GPG-Pr��fung hinzuf��gen, um sicherzustellen, dass ein Paket aus diesem Repository nicht besch��digt wurde. -W��hlen Sie ein Repository und dann <uicontrol>Bearbeiten</uicontrol> aus. W��hlen Sie <uicontrol>Ja</uicontrol> aus, um die GPG-Pr��fung zu aktivieren, und geben Sie dann ein URL zur GPG-Schl��sseldatei f��r das Repository ein.</p></dd> -</dlentry><dlentry> -<dt>Debugberichte</dt> -<dd>Dieser Abschnitt zeigt Debugberichte, einschlie��lich Name und Dateipfad, an. -Sie haben die M��glichkeit, einen neuen Bericht zu erstellen oder einen bestehenden Bericht umzubenennen, zu entfernen oder herunterzuladen.<p>Der Debugbericht wird w��hrend des Befehls <cmdname>sosreport</cmdname> generiert. Er ist verf��gbar f��r Red Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>-, Fedora- -und Ubuntu-Verteilungen. Der Befehl generiert eine .tar-Datei, die Konfigurations- und Diagnoseinformationen enth��lt, wie zum Beispiel Kernelversion, geladene Module sowie System- und Servicekonfigurationdateien. -Der Befehl f��hrt zudem externe Programme aus, um weitere Informationen zu sammeln, und speichert diese Ausgabe im resultierenden Archiv.</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 232 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/de_DE/network.dita b/plugins/kimchi/ui/pages/help/de_DE/network.dita deleted file mode 100644 index 49a2935..0000000 --- a/plugins/kimchi/ui/pages/help/de_DE/network.dita +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="de-de"> -<title>Netz</title> -<shortdesc>Die Seite <wintitle>Netz</wintitle> zeigt Informationen zur Netzverbindung an.</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>Netzname</dt> -<dd>Name des Netzes oder <uicontrol>Standard</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Status</dt> -<dd>Status des Netzes, aktiv (gr��n) oder inaktiv (rot). </dd> -</dlentry><dlentry> -<dt>Netztyp</dt> -<dd>Netztyp, zum Beispiel <uicontrol>NAT</uicontrol> (Network -Address Translation, Netzadressumsetzung).</dd> -</dlentry><dlentry> -<dt>Schnittstelle</dt> -<dd>Netzschnittstelle, zum Beispiel <uicontrol>virbr0</uicontrol> (Standard).</dd> -</dlentry><dlentry> -<dt>Adressraum</dt> -<dd>IP-Adresse.</dd> -</dlentry></dl></p> -<p>Die folgenden Aktionen k��nnen ausgew��hlt werden:<ul> -<li rev="rev1">W��hlen Sie <uicontrol>Starten</uicontrol> aus, um die Netzverbindung herzustellen.</li> -<li>W��hlen Sie <uicontrol>Stoppen</uicontrol> aus, um die Netzverbindung zu beenden.</li> -<li>W��hlen Sie <uicontrol>L��schen</uicontrol> aus, um die Verbindungsinformationen zu l��schen.</li> -</ul>Um ein Netz zu erstellen, klicken Sie auf das Symbol <uicontrol>Plus (+)</uicontrol> oben rechts in der Anzeige.</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="de-de"> -<title>Netz erstellen</title> -<shortdesc>Erstellen Sie ein Netz.</shortdesc> -<csbody> -<p> <ol> -<li>Geben Sie den Namen des Netzes ein.</li> -<li>Klicken Sie hier, um den Netztyp auszuw��hlen. <dl rev="rev1"><dlentry> -<dt><uicontrol>Isoliert</uicontrol></dt> -<dd>Isolierter Modus. G��ste k��nnen keine Kommunikation an externe Systeme senden oder von ihnen empfangen.</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>Network Address Translation-Modus. Bei der Kommunikation von G��sten mit externen Systemen wird die Host-IP-Adresse verwendet. Externe Systeme k��nnen keine Kommunikation mit G��sten initiieren.</dd> -</dlentry><dlentry> -<dt><uicontrol>��berbr��ckt</uicontrol></dt> -<dd>��berbr��ckt-Modus. G��ste k��nnen mit externen Systemen kommunizieren und von externen Systemen kontaktiert werden, als ob sie physische Systeme im Netz w��ren. F��r den ��berbr��ckt-Modus m��ssen Sie zus��tzliche Ziel- und VLAN-Informationen angeben.</dd> -</dlentry></dl></li> -<li>Klicken Sie auf <uicontrol>Erstellen</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 230 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/de_DE/storage.dita b/plugins/kimchi/ui/pages/help/de_DE/storage.dita deleted file mode 100644 index 7f89603..0000000 --- a/plugins/kimchi/ui/pages/help/de_DE/storage.dita +++ /dev/null @@ -1,86 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="de-de"> -<title>Speicher</title> -<shortdesc>Auf der Seite <wintitle>Speicher</wintitle> werden die verf��gbaren Speicherpools aufgelistet, einschlie��lich der sofort einsatzf��higen Speicherpools 'default' und 'ISO'. Wenn Sie ein eigenes ISO-Image verwenden m��chten, f��gen Sie es zum Speicherpoolpfad 'ISO' hinzu.</shortdesc> -<csbody> -<p>F��r jeden Speicherpool werden die folgenden Informationen angezeigt:<dl> -<dlentry> -<dt>Name</dt> -<dd>Name des Speicherpools und genutzter Prozentsatz.</dd> -</dlentry><dlentry> -<dt>Status</dt> -<dd>Status des Speicherpools, aktiv (gr��n) oder inaktiv (rot). </dd> -</dlentry><dlentry> -<dt>Position</dt> -<dd>Dateipfad zur Position des Speicherpools.</dd> -</dlentry><dlentry> -<dt>Typ</dt> -<dd>Typ des Speicherpools, zum Beispiel <uicontrol>dir</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Kapazit��t</dt> -<dd>Speicherkapazit��t im Speicherpool.</dd> -</dlentry><dlentry> -<dt>Zugeordnet</dt> -<dd>Speicherplatz, der bereits im Speicherpool zugeordnet ist.</dd> -</dlentry></dl></p> -<p>Die folgenden Aktionen k��nnen f��r jeden Speicherpool ausgew��hlt werden:<ul> -<li>W��hlen Sie <uicontrol>Aktivieren</uicontrol> aus, um den Speicherpool zu aktivieren, damit er genutzt werden kann.</li> -<li>W��hlen Sie <uicontrol>Inaktivieren</uicontrol> aus, um einen aktiven Speicherpool zu inaktivieren.</li> -<li>W��hlen Sie <uicontrol>Definition aufheben</uicontrol>, um einen inaktiven Speicherpool zu entfernen.</li> -</ul></p> -<p>Um Details zum Speicherdatentr��ger anzuzeigen, klicken Sie auf den Pfeil auf der rechten Seite der Speicherpoolzeile. Zu den Details geh��ren folgende Informationen:<dl><dlentry> -<dt>Typ</dt> -<dd>Typ des Datentr��gers, zum Beispiel <uicontrol>file</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Format</dt> -<dd>Das Format, variiert abh��ngig vom Typ.</dd> -</dlentry><dlentry> -<dt>Kapazit��t</dt> -<dd>Gr����e des Speicherdatentr��gers.</dd> -</dlentry><dlentry> -<dt>Zuordnung</dt> -<dd>Speicherplatz, der bereits im Speicherpool zugeordnet ist.</dd> -</dlentry></dl>Um einen Speicherpool zu definieren, klicken Sie auf das Symbol <uicontrol>Plus (+)</uicontrol> oben rechts in der Anzeige.</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="de-de"> -<title>Speicherpool definieren</title> -<shortdesc> Definieren Sie einen Speicherpool.</shortdesc> -<csbody> -<p> <ol> -<li>Geben Sie im Feld <uicontrol>Speicherpoolname</uicontrol> den Namen ein, mit dem der Speicherpool gekennzeichnet werden soll.</li> -<li>W��hlen Sie aus der Liste <uicontrol>Speicherpooltyp</uicontrol> den Typ aus: <dl><dlentry> -<dt><uicontrol>DIR</uicontrol></dt> -<dd>Gibt einen Verzeichnispool an. Wenn Sie <uicontrol>DIR</uicontrol> ausw��hlen, geben Sie den <uicontrol>Speicherpfad</uicontrol> ein (Dateipfad zum Speicherpool).</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>Gibt einen Netzdateisystempool an. Wenn Sie <uicontrol>NFS</uicontrol> ausw��hlen, -geben Sie <uicontrol>NFS-Server-IP</uicontrol> und <uicontrol>NFS-Pfad</uicontrol> an (Pfad des exportierten Verzeichnisses).</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>Gibt einen Pool an, der auf einem Ziel basiert, der auf einem iSCSI-Server zugeordnet ist. -Wenn Sie <uicontrol>iSCSI</uicontrol> ausw��hlen, geben Sie die IP-Adresse vom <uicontrol>iSCSI-Server</uicontrol> und das <uicontrol>Ziel</uicontrol> auf dem iSCSI-Server an. Sie k��nnen optional iSCSI-Authentifizierung hinzuf��gen.</dd> -</dlentry><dlentry> -<dt><uicontrol>Logisch</uicontrol></dt> -<dd>Gibt einen Speicherpool aus logischen Datentr��gern an. W��hlen Sie die Position zur Einheit im <uicontrol>Einheitenpfad</uicontrol> aus.</dd> -</dlentry><dlentry> -<dt><uicontrol>SCSI-Fibre Channel</uicontrol></dt> -<dd>Gibt einen Pool an, der auf einem SCSI-Fibre Channel basiert. W��hlen Sie aus, welcher Adapter verwendet werden soll.</dd> -</dlentry></dl></li> -<li>Klicken Sie auf <uicontrol>Erstellen</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 233 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/de_DE/templates.dita b/plugins/kimchi/ui/pages/help/de_DE/templates.dita deleted file mode 100644 index 5063930..0000000 --- a/plugins/kimchi/ui/pages/help/de_DE/templates.dita +++ /dev/null @@ -1,112 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="de-de"> -<title>Vorlagen</title> -<shortdesc>Die Seite <wintitle>Vorlagen</wintitle> zeigt die definierten Vorlagen der virtuellen Maschine an, die zum Erstellen von KVM-G��sten verwendet werden k��nnen.</shortdesc> -<csbody> -<p>F��r jede Vorlage werden die folgenden Informationen angezeigt:<dl> -<dlentry> -<dt>BS</dt> -<dd>Name des Betriebssystems oder der Verteilung.</dd> -</dlentry><dlentry> -<dt>Version</dt> -<dd>Version des Betriebssystems oder der Verteilung.</dd> -</dlentry><dlentry> -<dt>CPUs</dt> -<dd>Anzahl der Prozessoren, die f��r die Vorlage definiert sind.</dd> -</dlentry><dlentry> -<dt>Speicher</dt> -<dd>Gr����e des zuzuordnenden Arbeitsspeichers in MB.</dd> -</dlentry></dl></p> -<p>Die folgenden Aktionen k��nnen f��r jede Vorlage ausgew��hlt werden:<ul> -<li>W��hlen Sie <uicontrol>Bearbeiten</uicontrol> aus, um die Vorlage zu bearbeiten.</li> -<li>W��hlen Sie <uicontrol>L��schen</uicontrol> aus, um die Vorlage zu l��schen.</li> -</ul>Um eine Vorlage hinzuzuf��gen, klicken Sie auf das Symbol <uicontrol>Plus (+)</uicontrol> oben rechts in der Anzeige.</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="de-de"> -<title>Vorlage bearbeiten</title> -<shortdesc>Bearbeiten Sie eine bestehende Vorlage.</shortdesc> -<csbody> -<p>F��r jede Vorlage werden die folgenden Informationen angezeigt: <dl> -<dlentry> -<dt>Name</dt> -<dd>Name der Vorlage.</dd> -</dlentry><dlentry> -<dt>Anbieter</dt> -<dd>Der Name des Unternehmens, das das Betriebssystem oder die Verteilung erstellt hat, f��r die die Vorlage konfiguriert ist.</dd> -</dlentry><dlentry> -<dt>Version</dt> -<dd>Die Version des Betriebssystems oder der Verteilung, f��r die die Vorlage konfiguriert ist.</dd> -</dlentry><dlentry> -<dt>CPU-Anzahl</dt> -<dd>Anzahl der Prozessoren, die f��r die Vorlage definiert sind.</dd> -</dlentry><dlentry> -<dt>Speicher</dt> -<dd>Speicherkapazit��t in MB, die der virtuellen Maschine zugeordnet werden soll.</dd> -</dlentry><dlentry> -<dt>Platte</dt> -<dd>Plattengr����e in GB.</dd> -</dlentry><dlentry> -<dt>CD-ROM</dt> -<dd>Dateipfad zur Position der ISO-Datei an, die f��r die Installation des KVM-Gastes verwendet wird.</dd> -</dlentry><dlentry> -<dt>Speicherpool</dt> -<dd>Bestimmter Speicherpool oder der Standardspeicherpool.</dd> -</dlentry><dlentry> -<dt>Netz</dt> -<dd>Standardnetzschnittstelle, die f��r den KVM-Gast verf��gbar ist. Sie k��nnen mehrere Netze ausw��hlen.</dd> -</dlentry></dl> Felder, die nicht inaktiviert sind, k��nnen bearbeitet werden. Nachdem Sie ein Feld bearbeitet haben, klicken Sie auf <uicontrol>Speichern</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>Vorlage hinzuf��gen</title> -<shortdesc>F��gen Sie eine Vorlage vom Quellendatentr��ger hinzu. Sie k��nnen f��r eine nachfolgende Erkennung Ihr eigenes ISO-Image zum Speicherpool 'ISO' hinzuf��gen.</shortdesc> -<csbody> -<p>W��hlen Sie die Position des Quellendatentr��gers aus den folgenden Optionen aus:<dl> -<dlentry> -<dt>Lokales ISO-Image</dt> -<dd>W��hlen Sie diese Option aus, um Speicherpools nach Installations-ISO-Images zu durchsuchen, die im System verf��gbar sind.</dd> -</dlentry><dlentry> -<dt>Fernes ISO-Image</dt> -<dd>W��hlen Sie diese Option aus, um eine ferne Position f��r ein Installations-ISO-Image anzugeben.</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>Vorlage hinzuf��gen - lokales ISO-Image</title> -<shortdesc>F��gen Sie eine Vorlage aus einem lokalen ISO-Image hinzu.</shortdesc> -<csbody> -<p>Die im System verf��gbaren ISO-Images werden angezeigt.<dl><dlentry> -<dt>BS</dt> -<dd>Name des Betriebssystems oder der Verteilung.</dd> -</dlentry><dlentry> -<dt>Version</dt> -<dd>Version des Betriebssystems oder der Verteilung.</dd> -</dlentry><dlentry> -<dt>Gr����e</dt> -<dd>Gr����e des ISO-Image.</dd> -</dlentry></dl></p> -<p>Um eine Vorlage aus einem ISO-Image zu erstellen, w��hlen Sie aus den folgenden -Optionen aus:<ul> -<li>W��hlen Sie ein ISO-Image aus, aus dem Sie eine Vorlage erstellen m��chten, und klicken Sie dann auf <uicontrol>Vorlagen aus ausgew��hltem ISO erstellen</uicontrol>.</li> -<li>W��hlen Sie <uicontrol>Alle</uicontrol> aus, um eine Vorlage aus jedem aufgelisteten ISO-Image zu erstellen, und klicken Sie dann auf <uicontrol>Vorlagen aus ausgew��hltem ISO erstellen</uicontrol>.</li> -<li>Wenn das ISO-Image, das Sie verwenden m��chten, nicht in den Suchergebnissen angezeigt wird, k��nnen Sie aus den folgenden Optionen ausw��hlen:<ul> -<li>W��hlen Sie <uicontrol>Ich m��chte eine bestimmte ISO-Datei verwenden</uicontrol> aus, um einen Pfad zum ISO-Image anzugeben.</li> -<li>Klicken Sie auf <uicontrol>Weitere ISOs suchen</uicontrol>, um weitere ISO-Images zu suchen.</li> -</ul></li> -</ul></p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 229 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/dita-help.xsl b/plugins/kimchi/ui/pages/help/dita-help.xsl deleted file mode 100644 index 45f0a3b..0000000 --- a/plugins/kimchi/ui/pages/help/dita-help.xsl +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<xsl:stylesheet version="1.0" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - xmlns="http://www.w3.org/1999/xhtml"> - <xsl:output method="xml" indent="yes" encoding="UTF-8" /> - - <xsl:template match="/"> - <html> - <head> - <title><xsl:value-of select="/cshelp/title" /></title> - <meta charset="UTF-8" /> - <link rel="shortcut icon" href="images/logo.ico" /> - <link rel="stylesheet" type="text/css" href="../kimchi.css" /> - </head> - <body> - <xsl:apply-templates select="//cshelp" /> - </body> - </html> - </xsl:template> - - <xsl:template match="cshelp"> - <h1><xsl:value-of select="title" /></h1> - <p class="shortdesc"><xsl:value-of select="shortdesc" /></p> - <p class="csbody"><xsl:copy-of select="csbody/node()" /></p> - </xsl:template> -</xsl:stylesheet> diff --git a/plugins/kimchi/ui/pages/help/en_US/Makefile.am b/plugins/kimchi/ui/pages/help/en_US/Makefile.am deleted file mode 100644 index d37f03a..0000000 --- a/plugins/kimchi/ui/pages/help/en_US/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -en_US_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/en_US - -dist_en_US_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/en_US/guests.dita b/plugins/kimchi/ui/pages/help/en_US/guests.dita deleted file mode 100644 index 1bb437a..0000000 --- a/plugins/kimchi/ui/pages/help/en_US/guests.dita +++ /dev/null @@ -1,136 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> -<?Pub Sty _display FontColor="red"?> -<?Pub Inc?> -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="en-us"> -<title>Guests</title> -<shortdesc>The <wintitle>Guests</wintitle> page lists the defined -KVM virtual machines.</shortdesc> -<csbody> -<p>For each guest, the following information is displayed:<dl><dlentry> -<dt>Name</dt> -<dd>Name of the virtual machine.</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>Percentage of processor utilization in the virtual machine.</dd> -</dlentry><dlentry> -<dt>Network I/O</dt> -<dd>Network input/output transmission rate in KB per seconds.</dd> -</dlentry><dlentry> -<dt>Disk I/O</dt> -<dd>Disk input/output transmission rate in KB per seconds.</dd> -</dlentry><dlentry> -<dt>Livetile</dt> -<dd>State of guest operating system console, or an icon that represents -the <tm tmtype="tm" trademark="Linux">Linux</tm> distribution if the -guest is not active.</dd> -</dlentry></dl></p> -<p>The following actions icons are displayed for each guest:<dl> -<dlentry> -<dt>Reset</dt> -<dd>Click to reset the guest. </dd> -</dlentry><dlentry> -<dt>Power (Start or Stop)</dt> -<dd>Click to power on or power off the guest. If the icon is red, -the power is off; if the icon is green, the power is on.</dd> -</dlentry></dl> </p> -<p>The following actions can be selected for each guest:<ul> -<li>Select <uicontrol>Connect</uicontrol> to connect to the remote -console for the guest operating system.</li> -<li>Select <uicontrol>Manage media</uicontrol> to change the path -to the installation media.</li> -<li>Select <uicontrol>Reset</uicontrol> to reset the guest.</li> -<li>Select <uicontrol>Edit</uicontrol> to edit the properties of an -existing guest. Guests can be edited only while stopped.</li> -<li>Select <uicontrol>Delete</uicontrol> to delete the guest.</li> -</ul>To create a guest, or virtual machine, click the <uicontrol>plus -(+)</uicontrol> icon in the upper right of the page.</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="en-us"> -<title>Create virtual machine</title> -<shortdesc>Create a virtual machine by using an existing template.</shortdesc> -<csbody> -<p> <ol> -<li>Type the name to be used to identify the virtual machine.</li> -<li rev="rev1">Select a template. <ul> -<li>If templates exist, select from displayed templates.</li> -<li>If no templates exist, click <uicontrol>Create a template</uicontrol> to -create a template.</li> -</ul></li> -<li>Click <uicontrol>Create</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="en-us"> -<title>Edit guest</title> -<shortdesc>Edit the properties of an existing virtual machine. Some properties -can be edited only while guest is stopped. Others will take effect in next boot.</shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>For each guest, the following information is displayed on the <wintitle>General</wintitle> tab:<dl> -<dlentry> -<dt>Name</dt> -<dd>Name of the virtual machine. (can only be edited while guest is stopped)</dd> -</dlentry><dlentry> -<dt>CPUs</dt> -<dd>Number of processors. (if guest is running, new amount will take effect -in next boot)</dd> -</dlentry><dlentry> -<dt>Memory</dt> -<dd>Amount of memory in MB. (if guest is running, new amount will take effect -in next boot)</dd> -</dlentry><dlentry> -<dt>Icon</dt> -<dd>Graphic image representing the Linux distribution to be displayed -in place of current status (Livetile) when the guest is not active.</dd> -</dlentry></dl></p> -<p>The following information is displayed on the <wintitle>Storage</wintitle> tab.</p> -<dl><dlentry> -<dt>Storage</dt> -<dd>Displays the location of the ISO file used for installation.</dd> -</dlentry></dl><?Pub Caret -2?> -<p> Fields that are not disabled can be edited. After you edit a field, -click <uicontrol>Save</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="en-us"> -<title>Add, replace, or detach a storage device</title> -<shortdesc rev="rev1">You can add, replace, or detach a storage device -to your virtual machine. The only supported device is CDROM. To edit -your storage devices, follow these steps:</shortdesc> -<csbody> -<ol> -<li>On the <wintitle>Edit Guest</wintitle> window, select <wintitle>Storage</wintitle>.</li> -<li>To replace a storage device, click the first icon with the <uicontrol>orange -slash (/)</uicontrol>. Enter the ISO file path and click <uicontrol>Replace</uicontrol>.</li> -<li>To detach a storage device, click the second icon with the <uicontrol>red -dash (-)</uicontrol>. Confirm the deletion and click <uicontrol>OK</uicontrol>.</li> -<li>To add a storage device, click the third icon with the green <uicontrol>plus -sign (+)</uicontrol>. Enter a device name and ISO file path and click <uicontrol>Attach</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="en-us"> -<title>Replace a CDROM of VM</title> -<shortdesc rev="rev1">You can replace the contents of the CDROM for -a virtual machine after the installation is complete.</shortdesc> -<csbody> -<ol> -<li>Ensure that the virtual machine is started.</li> -<li>From the Actions menu, select <uicontrol>Manage Media</uicontrol>.</li> -<li>To change what is currently loaded in the CDROM, click the <uicontrol>orange -slash (/)</uicontrol> icon next to the hdc field.</li> -<li>On the <wintitle>Replace a CDROM of VM</wintitle> page, enter -the ISO file path. The other two fields are read-only.</li> -<li>Click <uicontrol>Replace</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> -<?Pub *0000005541?> diff --git a/plugins/kimchi/ui/pages/help/en_US/host.dita b/plugins/kimchi/ui/pages/help/en_US/host.dita deleted file mode 100644 index 0dcb670..0000000 --- a/plugins/kimchi/ui/pages/help/en_US/host.dita +++ /dev/null @@ -1,70 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> -<?Pub Sty _display FontColor="red"?> -<?Pub Inc?> -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="en-us"> -<title>Host</title> -<shortdesc>The <wintitle>Host</wintitle> page shows information about -the host system, and allows you to shut down, restart, and connect -to the host.</shortdesc> -<csbody> -<p>You can perform the following actions on the host:<ul> -<li>Select <uicontrol>Shut down</uicontrol> to shut down the host -system.</li> -<li>Select <uicontrol>Restart</uicontrol> to restart the host system.</li> -<li>Select <uicontrol>Connect</uicontrol> to open a VNC connection -to the host system, if it is not already connected.</li> -</ul></p> -<p>Click the following sections to display information about the host:<dl> -<dlentry> -<dt>Basic information</dt> -<dd>This section displays the host operating system distribution, -version, and code name, as well as the processor type, the number of -online CPUs and amount of memory in GB.</dd> -</dlentry><dlentry> -<dt>System statistics</dt> -<dd>This section displays graphs to show statistics for CPU, memory, -disk I/O, and network I/O for the host. Select <uicontrol>Collecting -data after leaving this page</uicontrol> to continue collecting data -when the host tab is out of view.</dd> -</dlentry><dlentry> -<dt>Software Updates</dt> -<dd>This section displays information for all of the packages that -have updates available, including package name, version, architecture, -and repository. You can update all of the packages listed by selecting <uicontrol>Update -All</uicontrol>. You cannot select individual packages for updates.</dd> -</dlentry><dlentry> -<dt>Repositories</dt> -<dd>This section displays repositories that are associated with the -host system. You can add, enable, edit, or remove repositories. Adding -a repository associates it with the host system while enabling a repository -allows the host to access it. If your system is Red Hat Enterprise -Linux or Fedora, you can add <filepath>yum</filepath> repositories. -If your system is Ubuntu or Debian, then add <filepath>deb</filepath> repositories.<p>If -you are working with yum repositories, you can add a GPG check to -verify that a package from this repository have not been corrupted. -Select a repository and then <uicontrol>Edit</uicontrol>. Select <uicontrol>Yes</uicontrol> to -enable GPG Check and then enter a URL to the GPG key file for the -repository.</p><?Pub Caret 156?></dd> -</dlentry><dlentry> -<dt>Debug reports</dt> -<dd>This section displays debug reports, including name and file path. -You can select from options to generate a new report, or rename, remove, -or download an existing report.<p>The debug report is generated using -the <cmdname>sosreport</cmdname> command. It is available for Red -Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora, -and Ubuntu distributions. The command generates a .tar file that contains -configuration and diagnostic information, such as the running kernel -version, loaded modules, and system and service configuration files. -The command also runs external programs to collect further information -and stores this output in the resulting archive.</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> -<?Pub *0000003492?> diff --git a/plugins/kimchi/ui/pages/help/en_US/network.dita b/plugins/kimchi/ui/pages/help/en_US/network.dita deleted file mode 100644 index 25c05ff..0000000 --- a/plugins/kimchi/ui/pages/help/en_US/network.dita +++ /dev/null @@ -1,68 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> -<?Pub Sty _display FontColor="red"?> -<?Pub Inc?> -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="en-us"> -<title>Network</title> -<shortdesc>The <wintitle>Network</wintitle> page displays information -about the network connection.</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>Network Name</dt> -<dd>Name of the network, or <uicontrol>default</uicontrol>.</dd> -</dlentry><dlentry> -<dt>State</dt> -<dd>State of the network, active (green) or inactive (red). </dd> -</dlentry><dlentry> -<dt>Network type</dt> -<dd>Network type, for example, <uicontrol>NAT</uicontrol> (network -address translation).</dd> -</dlentry><dlentry> -<dt>Interface</dt> -<dd>Network interface, for example, <uicontrol>virbr0</uicontrol> (default).</dd> -</dlentry><dlentry> -<dt>Address space</dt> -<dd>IP address.</dd> -</dlentry></dl></p> -<p>The following actions can be selected:<ul> -<li rev="rev1">Select <uicontrol>Start</uicontrol> to begin the network -connection.</li> -<li>Select <uicontrol>Stop</uicontrol> to end the network connection.</li> -<li>Select <uicontrol>Delete</uicontrol> to delete the connection -information.</li> -</ul>To create a network, click the <uicontrol>plus (+)</uicontrol> icon -in the upper right of the display.</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="en-us"> -<title>Create a network</title> -<shortdesc>Create a network.</shortdesc> -<csbody> -<p> <ol> -<li>Type the name of the network.</li> -<li>Click to select the network type. <dl rev="rev1"><dlentry> -<dt><uicontrol>Isolated</uicontrol></dt> -<dd>Isolated mode. Guests cannot send or receive communication to -or from external systems.</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>Network Address Translation mode. Communication from guests to -external systems uses the host IP address. External systems cannot -initiate communication to guests.</dd> -</dlentry><dlentry> -<dt><uicontrol>Bridged</uicontrol></dt> -<dd>Bridged mode. Guests can communicate with external systems and -be contacted by external systems as if they were physical systems -on the network. For bridged mode, you must specify additional destination -and VLAN information.</dd> -</dlentry></dl><?Pub Caret 224?></li> -<li>Click <uicontrol>Create</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> -<?Pub *0000002571?> diff --git a/plugins/kimchi/ui/pages/help/en_US/storage.dita b/plugins/kimchi/ui/pages/help/en_US/storage.dita deleted file mode 100644 index d9a32f9..0000000 --- a/plugins/kimchi/ui/pages/help/en_US/storage.dita +++ /dev/null @@ -1,99 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> -<?Pub Sty _display FontColor="red"?> -<?Pub Inc?> -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="en-us"> -<title>Storage</title> -<shortdesc>The <wintitle>Storage</wintitle> page lists the available -storage pools, including the out of box 'default' and 'ISO' storage pool. -If you want to use your own ISO, please add it to 'ISO' storage pool path.</shortdesc> -<csbody> -<p>For each storage pool, the following information is displayed:<dl> -<dlentry> -<dt>Name</dt> -<dd>Name of the storage pool and percentage used.</dd> -</dlentry><dlentry> -<dt>State</dt> -<dd>State of the storage pool, active (green) or inactive (red). </dd> -</dlentry><dlentry> -<dt>Location</dt> -<dd>File path to the location of the storage pool.</dd> -</dlentry><dlentry> -<dt>Type</dt> -<dd>Type of storage pool, for example, <uicontrol>dir</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Capacity</dt> -<dd>Amount of space in the storage pool.</dd> -</dlentry><dlentry> -<dt>Allocated</dt> -<dd>Amount of space that is already allocated in the storage pool.</dd> -</dlentry></dl></p> -<p>The following actions can be selected for each storage pool:<ul> -<li>Select <uicontrol>Activate</uicontrol> to activate the storage -pool so that it can be used.</li> -<li>Select <uicontrol>Deactivate</uicontrol> to deactivate an active -storage pool.</li> -<li>Select <uicontrol>Undefine</uicontrol> to remove an inactive storage -pool.</li> -</ul></p> -<p>To display storage volume details for a storage pool, click the -arrow on the right side of the storage pool row. Details include -the following:<dl><dlentry> -<dt>Type</dt> -<dd>The type of volume, for example, <uicontrol>file</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Format</dt> -<dd>The format, varying dependent on the type.</dd> -</dlentry><dlentry> -<dt>Capacity</dt> -<dd>Size of the storage volume.</dd> -</dlentry><dlentry> -<dt>Allocation</dt> -<dd>Amount of space that is already allocated in the storage pool.</dd> -</dlentry></dl>To define a storage pool, click the <uicontrol>plus -(+)</uicontrol> icon in the upper right of the display.</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="en-us"> -<title>Define a storage pool</title> -<shortdesc> Define a storage pool.</shortdesc> -<csbody> -<p> <ol> -<li>In the <uicontrol>Storage pool name</uicontrol> field, type the -name to be used to identify the storage pool.</li> -<li>In the <uicontrol>Storage pool type</uicontrol> list, select the -type: <dl><dlentry> -<dt><uicontrol>DIR</uicontrol></dt> -<dd>Specifies a directory pool. When selecting <uicontrol>DIR</uicontrol>, -type the <uicontrol>Storage path</uicontrol> (file path to the storage -pool).</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>Specifies a network filesystem pool. When selecting <uicontrol>NFS</uicontrol>, -type the <uicontrol>NFS server IP</uicontrol> address and <uicontrol>NFS -path</uicontrol> (path of the exported directory).</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>Specifies a pool based on a target allocated on an iSCSI server. -When selecting <uicontrol>iSCSI</uicontrol>, type the <uicontrol>iSCSI -server</uicontrol> IP address and <uicontrol>Target</uicontrol> on -the iSCSI server. You can optionally select to add iSCSI authentication.</dd> -</dlentry><dlentry> -<dt><uicontrol>Logical</uicontrol></dt> -<dd>Specifies a logical volume storage pool. Select the location to -the device in <uicontrol>Device path</uicontrol>.</dd> -</dlentry><dlentry> -<dt><uicontrol>SCSI Fibre Channel</uicontrol></dt> -<dd>Specifies a pool based on an SCSI Fibre Channel. Select which -SCSI adapter to use.</dd> -</dlentry></dl><?Pub Caret 0?></li> -<li>Click <uicontrol>Create</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> -<?Pub *0000003914?> diff --git a/plugins/kimchi/ui/pages/help/en_US/templates.dita b/plugins/kimchi/ui/pages/help/en_US/templates.dita deleted file mode 100644 index 57ee9b5..0000000 --- a/plugins/kimchi/ui/pages/help/en_US/templates.dita +++ /dev/null @@ -1,123 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> -<?Pub Sty _display FontColor="red"?> -<?Pub Inc?> -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="en-us"> -<title>Templates</title> -<shortdesc>The <wintitle>Templates</wintitle> page shows the defined -virtual machine templates that can be used to create KVM guests.</shortdesc> -<csbody> -<p>For each template, the following information is displayed:<dl> -<dlentry> -<dt>OS</dt> -<dd>Name of the operating system or distribution.</dd> -</dlentry><dlentry> -<dt>Version</dt> -<dd>Version of the operating system or distribution.</dd> -</dlentry><dlentry> -<dt>CPUs</dt> -<dd>Number of processors that are defined for the template.</dd> -</dlentry><dlentry> -<dt>Memory</dt> -<dd>Amount of random access memory to be allocated, in MB.</dd> -</dlentry></dl></p> -<p>The following actions can be selected for each template:<ul> -<li>Select <uicontrol>Edit</uicontrol> to edit the template.</li> -<li>Select <uicontrol>Delete</uicontrol> to delete the template.</li> -</ul>To add a template, click the <uicontrol>plus (+)</uicontrol> icon -in the upper right of the display.</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="en-us"> -<title>Edit template</title> -<shortdesc>Edit an existing template.</shortdesc> -<csbody> -<p>For each template, the following information is displayed: <dl> -<dlentry> -<dt>Name</dt> -<dd>Name of the template.</dd> -</dlentry><dlentry> -<dt>Vendor</dt> -<dd>The name of the company that created the operating system or distribution -that the template is configured to use.</dd> -</dlentry><dlentry> -<dt>Version</dt> -<dd>The version of the operating system or distribution that the template -is configured to use.</dd> -</dlentry><dlentry> -<dt>CPU number</dt> -<dd>Number of processors that are defined for the template.</dd> -</dlentry><dlentry> -<dt>Memory</dt> -<dd>Amount of memory in MB to be allocated to the virtual machine.</dd> -</dlentry><dlentry> -<dt>Disk</dt> -<dd>Disk size in GB.</dd> -</dlentry><dlentry> -<dt>CDROM</dt> -<dd>File path to the location of the ISO file used to install the -KVM guest.</dd> -</dlentry><dlentry> -<dt>Storage pool</dt> -<dd>Specific storage pool or the default storage pool.</dd> -</dlentry><dlentry> -<dt>Network</dt> -<dd>Default network interfaces available to the KVM guest. You can -select multiple networks.</dd> -</dlentry></dl> Fields that are not disabled can be edited. After -you edit a field, click <uicontrol>Save</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>Add template</title> -<shortdesc>Add a template from source media. -You can add your own ISO image to 'ISO' storage pool for following discovery.</shortdesc> -<csbody> -<p>Select the location of the source media from the following options:<dl> -<dlentry> -<dt>Local ISO image</dt> -<dd>Select to scan storage pools for installation ISO images available -on the system.</dd> -</dlentry><dlentry> -<dt>Remote ISO image</dt> -<dd>Select to specify a remote location for an installation ISO image.</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>Add template - local ISO image</title> -<shortdesc>Add a template from a local ISO image.</shortdesc> -<csbody> -<p>The ISO images available on the system are displayed.<dl><dlentry> -<dt>OS</dt> -<dd>Name of the operating system or distribution.</dd> -</dlentry><dlentry> -<dt>Version</dt> -<dd>Version of the operating system or distribution.</dd> -</dlentry><dlentry> -<dt>Size</dt> -<dd>Size of the ISO image.</dd> -</dlentry></dl></p> -<p>To create a template from an ISO image, choose from the following -options:<ul> -<li>Select an ISO image from which to create a template, then click <uicontrol>Create -Templates from Selected ISO</uicontrol>.</li> -<li>Select <uicontrol>All</uicontrol> to create a template from each - listed ISO image, then click <uicontrol>Create Templates from Selected -ISO</uicontrol>.</li> -<li>If the ISO image that you want to use does not appear in the scan -results, you can select from the following options:<ul> -<li>Select <uicontrol>I want to use a specific ISO file</uicontrol> to -specify a path to the ISO image.</li> -<li>Click <uicontrol>Search more ISOs</uicontrol> to search for more -ISO images.</li> -</ul></li><?Pub Caret 0?> -</ul></p> -</csbody> -</cshelp> -</cshelp> -<?Pub *0000004433?> diff --git a/plugins/kimchi/ui/pages/help/es_ES/Makefile.am b/plugins/kimchi/ui/pages/help/es_ES/Makefile.am deleted file mode 100644 index 29c596f..0000000 --- a/plugins/kimchi/ui/pages/help/es_ES/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -es_ES_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/es_ES - -dist_es_ES_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/es_ES/guests.dita b/plugins/kimchi/ui/pages/help/es_ES/guests.dita deleted file mode 100644 index 88e77e0..0000000 --- a/plugins/kimchi/ui/pages/help/es_ES/guests.dita +++ /dev/null @@ -1,120 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="es-es"> -<title>Invitados</title> -<shortdesc>La p��gina <wintitle>Invitados</wintitle> lista las m��quinas virtuales KVM definidas.</shortdesc> -<csbody> -<p>Se visualiza la siguiente informaci��n para cada invitado:<dl><dlentry> -<dt>Nombre</dt> -<dd>Nombre de la m��quina virtual.</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>Porcentaje de utilizaci��n de procesador en la m��quina virtual.</dd> -</dlentry><dlentry> -<dt>E/S de red</dt> -<dd>Velocidad de transmisi��n de entrada/salida de red en KB por segundos.</dd> -</dlentry><dlentry> -<dt>E/S de disco</dt> -<dd>Velocidad de transmisi��n de entrada/salida de disco en KB por segundos.</dd> -</dlentry><dlentry> -<dt>Livetile</dt> -<dd>Estado de la consola del sistema operativo invitado, o un icono que representa la distribuci��n de <tm tmtype="tm" trademark="Linux">Linux</tm> si el invitado no est�� activo.</dd> -</dlentry></dl></p> -<p>Se visualizan los siguientes iconos de acciones para cada invitado:<dl> -<dlentry> -<dt>Restablecer</dt> -<dd>Pulse aqu�� para restablecer el invitado. </dd> -</dlentry><dlentry> -<dt>Alimentaci��n (Iniciar o Detener)</dt> -<dd>Pulse aqu�� para encender o apagar el invitado. Si el icono es de color rojo, la alimentaci��n est�� apagada; si el icono es de color verde, la alimentaci��n est�� encendida.</dd> -</dlentry></dl> </p> -<p>Se pueden seleccionar las siguientes acciones para cada invitado:<ul> -<li>Seleccione <uicontrol>Conectar</uicontrol> para conectarse a la consola remota para el sistema operativo invitado.</li> -<li>Seleccione <uicontrol>Gestionar soporte</uicontrol> para cambiar la v��a de acceso al soporte de instalaci��n.</li> -<li>Seleccione <uicontrol>Restablecer</uicontrol> para restablecer el invitado.</li> -<li>Seleccione <uicontrol>Editar</uicontrol> para editar las propiedades de un invitado existente. Los invitados s��lo pueden editarse mientras est��n detenidos.</li> -<li>Seleccione <uicontrol>Suprimir</uicontrol> para suprimir el invitado.</li> -</ul>Para crear un invitado o m��quina virtual, pulse el icono <uicontrol>m��s (+)</uicontrol> en la esquina superior derecha de la p��gina.</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="es-es"> -<title>Crear m��quina virtual</title> -<shortdesc>Crear una m��quina virtual utilizando una plantilla existente.</shortdesc> -<csbody> -<p> <ol> -<li>Escriba el nombre a utilizar para identificar la m��quina virtual.</li> -<li rev="rev1">Seleccione una plantilla. <ul> -<li>Si existen plantillas, seleccione entre las plantillas mostradas.</li> -<li>Si no existen plantillas, pulse <uicontrol>Crear una plantilla</uicontrol> para crear una plantilla.</li> -</ul></li> -<li>Pulse <uicontrol>Crear</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="es-es"> -<title>Editar invitado</title> -<shortdesc>Editar las propiedades de una m��quina virtual existente. Algunas propiedades pueden editarse s��lo cuando el invitado se ha detenido. Otras surtir��n efecto en el arranque siguiente.</shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>Se visualiza la siguiente informaci��n para cada invitado en la pesta��a <wintitle>General</wintitle>:<dl> -<dlentry> -<dt>Nombre</dt> -<dd>Nombre de la m��quina virtual.(s��lo puede editarse cuando el invitado se ha detenido)</dd> -</dlentry><dlentry> -<dt>CPUs</dt> -<dd>N��mero de procesadores.(si el invitado est�� en ejecuci��n, la nueva cantidad surtir�� efecto en el siguiente arranque) -</dd> -</dlentry><dlentry> -<dt>Memoria</dt> -<dd>Cantidad de memoria en MB.(si el invitado est�� en ejecuci��n, la nueva cantidad surtir�� efecto en el siguiente arranque) -</dd> -</dlentry><dlentry> -<dt>Icono</dt> -<dd>Imagen gr��fica que representa la distribuci��n de Linux a visualizar en lugar del estado actual (Livetile) cuando el invitado no est�� activo.</dd> -</dlentry></dl></p> -<p>Se visualiza la siguiente informaci��n en la pesta��a <wintitle>Almacenamiento</wintitle>.</p> -<dl><dlentry> -<dt>Almacenamiento</dt> -<dd>Muestra la ubicaci��n del archivo ISO utilizado para la instalaci��n.</dd> -</dlentry></dl> -<p> Los campos que no est��n inhabilitados pueden editarse. Despu��s de editar un campo, pulse <uicontrol>Guardar</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="es-es"> -<title>A��adir, sustituir o desconectar un dispositivo de almacenamiento</title> -<shortdesc rev="rev1">Puede a��adir, sustituir o desconectar un dispositivo de almacenamiento a la m��quina virtual. El ��nico dispositivo soportado es CDROM. Para editar los dispositivos de almacenamiento, siga estos pasos:</shortdesc> -<csbody> -<ol> -<li>En la ventana <wintitle>Editar invitado</wintitle>, seleccione <wintitle>Almacenamiento</wintitle>.</li> -<li>Para sustituir un dispositivo de almacenamiento, pulse el primer icono con la <uicontrol>barra inclinada naranja (/)</uicontrol>. Especifique la v��a de acceso del archivo ISO y pulse <uicontrol>Sustituir</uicontrol>.</li> -<li>Para desconectar un dispositivo de almacenamiento, pulse el segundo icono con el <uicontrol>gui��n rojo (-)</uicontrol>. Confirme la supresi��n y pulse <uicontrol>Aceptar</uicontrol>.</li> -<li>Para a��adir un dispositivo de almacenamiento, pulse el tercer icono con el <uicontrol>signo m��s (+)</uicontrol> verde. Especifique un nombre de dispositivo y la v��a de acceso del archivo ISO y pulse <uicontrol>Conectar</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="es-es"> -<title>Sustituir un CDROM de m��quina virtual</title> -<shortdesc rev="rev1">Puede sustituir el contenido del CDROM para una m��quina virtual despu��s de completarse la instalaci��n.</shortdesc> -<csbody> -<ol> -<li>Aseg��rese de que la m��quina virtual se ha iniciado.</li> -<li>En el men�� Acciones, seleccione <uicontrol>Gestionar soporte</uicontrol>.</li> -<li>Para cambiar lo que est�� cargado actualmente en el CDROM, pulse el icono <uicontrol>barra inclinada naranja (/)</uicontrol> junto al campo hdc.</li> -<li>En la p��gina <wintitle>Sustituir un CDROM de m��quina virtual</wintitle>, especifique la v��a de acceso del archivo ISO. Los otros dos campos son de s��lo lectura.</li> -<li>Pulse <uicontrol>Sustituir</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 231 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/es_ES/host.dita b/plugins/kimchi/ui/pages/help/es_ES/host.dita deleted file mode 100644 index 7734244..0000000 --- a/plugins/kimchi/ui/pages/help/es_ES/host.dita +++ /dev/null @@ -1,49 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="es-es"> -<title>Host</title> -<shortdesc>La p��gina <wintitle>Host</wintitle> muestra informaci��n sobre el sistema host y le permite concluir, reiniciar y conectar con el sistema principal.</shortdesc> -<csbody> -<p>Puede realizar las acciones siguientes en el host:<ul> -<li>Seleccione <uicontrol>Concluir</uicontrol> para concluir el sistema host.</li> -<li>Seleccione <uicontrol>Reiniciar</uicontrol> para reiniciar el sistema host.</li> -<li>Seleccione <uicontrol>Conectar</uicontrol> para abrir una conexi��n VNC al sistema host, si no est�� conectado a��n.</li> -</ul></p> -<p>Pulse en las secciones siguientes para visualizar informaci��n acerca del host:<dl> -<dlentry> -<dt>Informaci��n b��sica</dt> -<dd>Esta secci��n muestra la distribuci��n del sistema operativo de host, la versi��n y el nombre de c��digo, as�� como el tipo de procesador y la cantidad de memoria en GB.</dd> -</dlentry><dlentry> -<dt>Estad��sticas del sistema</dt> -<dd>Esta secci��n muestra gr��ficos para mostrar estad��sticas para CPU, memoria, E/S de disco y E/S de red para el host. Seleccione <uicontrol>Recoger datos despu��s de salir de esta p��gina</uicontrol> para continuar la recogida de datos cuando la pesta��a principal ya no est�� a la vista.</dd> -</dlentry><dlentry> -<dt>Actualizaciones de software</dt> -<dd>En esta secci��n se muestra informaci��n para todos los paquetes que tienen actualizaciones disponibles, incluido el nombre de paquete, versi��n, arquitectura y repositorio. Puede actualizar todos los paquetes listados seleccionando <uicontrol>Actualizar todo</uicontrol>. No puede seleccionar paquetes individuales para las actualizaciones.</dd> -</dlentry><dlentry> -<dt>Repositorios</dt> -<dd>En esta secci��n se muestran los repositorios que est��n asociados con el sistema host. Puede a��adir, habilitar, editar o eliminar repositorios. A��adir un repositorio lo asocia con el sistema host mientras que habilitar un repositorio permite que el host acceda a ��l. Si el sistema es Red Hat Enterprise -Linux o Fedora, puede a��adir repositorios <filepath>yum</filepath>. -Si el sistema es Ubuntu o Debian, a��ada repositorios <filepath>deb</filepath>.<p>Si est�� trabajando con repositorios yum, puede a��adir una comprobaci��n GPG para verificar que un paquete de este repositorio no ha resultado da��ado. -Seleccione un repositorio y, a continuaci��n, <uicontrol>Editar</uicontrol>. Seleccione <uicontrol>S��</uicontrol> para habilitar la comprobaci��n GPG y, a continuaci��n, especifique un URL al archivo de claves GPG para el repositorio.</p></dd> -</dlentry><dlentry> -<dt>Informes de depuraci��n</dt> -<dd>En esta secci��n se muestran informes de depuraci��n, incluido el nombre y la ruta de archivo. -Puede seleccionar entre opciones para generar un informe nuevo, o bien redenominar, eliminar o descargar un informe existente.<p>El informe de depuraci��n se genera utilizando el mandato <cmdname>sosreport</cmdname>. Est�� disponible para distribuciones de Red -Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora y Ubuntu. El mandato genera un archivo .tar que contiene la informaci��n de configuraci��n y de diagn��stico, como la versi��n de kernel en ejecuci��n, los m��dulos de carga y los archivos de configuraci��n del sistema y servicio. -El mandato tambi��n ejecuta programas externos para recopilar informaci��n adicional y almacena esta salida en el archivo resultante.</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 232 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/es_ES/network.dita b/plugins/kimchi/ui/pages/help/es_ES/network.dita deleted file mode 100644 index 3654531..0000000 --- a/plugins/kimchi/ui/pages/help/es_ES/network.dita +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="es-es"> -<title>Red</title> -<shortdesc>La p��gina <wintitle>Red</wintitle> muestra informaci��n sobre la conexi��n de red.</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>Nombre de red</dt> -<dd>Nombre de la red, o <uicontrol>predeterminado</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Estado</dt> -<dd>Estado de la red, activa (verde) o inactiva (rojo). </dd> -</dlentry><dlentry> -<dt>Tipo de red</dt> -<dd>Tipo de red, por ejemplo, <uicontrol>NAT</uicontrol> (conversi��n de direcciones de red).</dd> -</dlentry><dlentry> -<dt>Interfaz</dt> -<dd>La interfaz de red, por ejemplo, <uicontrol>virbr0</uicontrol> (predeterminada).</dd> -</dlentry><dlentry> -<dt>Espacio de direcciones</dt> -<dd>Direcci��n IP.</dd> -</dlentry></dl></p> -<p>Se pueden seleccionar las siguientes acciones:<ul> -<li rev="rev1">Seleccione <uicontrol>Iniciar</uicontrol> para iniciar la conexi��n de red.</li> -<li>Seleccione <uicontrol>Detener</uicontrol> para finalizar la conexi��n de red.</li> -<li>Seleccione <uicontrol>Suprimir</uicontrol> para suprimir la informaci��n de conexi��n.</li> -</ul>Para crear una red, pulse en el icono <uicontrol>m��s (+)</uicontrol> en la esquina superior derecha de la pantalla.</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="es-es"> -<title>Crear una red</title> -<shortdesc>Crear una red.</shortdesc> -<csbody> -<p> <ol> -<li>Escriba el nombre de la red.</li> -<li>Pulse para seleccionar el tipo de red. <dl rev="rev1"><dlentry> -<dt><uicontrol>Aislada</uicontrol></dt> -<dd>Modalidad aislada. Los invitados no pueden enviar ni recibir comunicaci��n a sistemas externos o desde ellos.</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>Modalidad de Conversi��n de direcciones de red. La comunicaci��n de invitados a sistemas externos utiliza la direcci��n IP del host. Los sistemas externos no pueden iniciar la comunicaci��n con los invitados.</dd> -</dlentry><dlentry> -<dt><uicontrol>Puenteada</uicontrol></dt> -<dd>Modalidad puenteada. Los invitados pueden comunicarse con sistemas externos y ser contactados por sistemas externos como si fueran sistemas f��sicos en la red. Para la modalidad puenteada, debe especificar informaci��n de destino y VLAN adicional.</dd> -</dlentry></dl></li> -<li>Pulse <uicontrol>Crear</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 230 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/es_ES/storage.dita b/plugins/kimchi/ui/pages/help/es_ES/storage.dita deleted file mode 100644 index 0c68951..0000000 --- a/plugins/kimchi/ui/pages/help/es_ES/storage.dita +++ /dev/null @@ -1,86 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="es-es"> -<title>Almacenamiento</title> -<shortdesc>La p��gina <wintitle>Almacenamiento</wintitle> lista las agrupaciones de almacenamiento disponibles, incluyendo la agrupaci��n de almacenamiento predefinida 'default' e 'ISO'. -Si desea utilizar su propia ISO, a����dala a la v��a de acceso de la agrupaci��n de almacenamiento 'ISO'.</shortdesc> -<csbody> -<p>Se visualiza la siguiente informaci��n para cada agrupaci��n de almacenamiento:<dl> -<dlentry> -<dt>Nombre</dt> -<dd>Nombre de la agrupaci��n de almacenamiento y el porcentaje utilizado.</dd> -</dlentry><dlentry> -<dt>Estado</dt> -<dd>Estado de la agrupaci��n de almacenamiento, activa (verde) o inactiva (rojo). </dd> -</dlentry><dlentry> -<dt>Ubicaci��n</dt> -<dd>V��a de acceso de archivo a la ubicaci��n de la agrupaci��n de almacenamiento.</dd> -</dlentry><dlentry> -<dt>Tipo</dt> -<dd>Tipo de agrupaci��n de almacenamiento, por ejemplo, <uicontrol>dir</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Capacidad</dt> -<dd>Cantidad de espacio en la agrupaci��n de almacenamiento.</dd> -</dlentry><dlentry> -<dt>Asignado</dt> -<dd>Cantidad de espacio que ya est�� asignado en la agrupaci��n de almacenamiento.</dd> -</dlentry></dl></p> -<p>Se pueden seleccionar las siguientes acciones para cada agrupaci��n de almacenamiento:<ul> -<li>Seleccione <uicontrol>Activar</uicontrol> para activar la agrupaci��n de almacenamiento para que pueda utilizarse.</li> -<li>Seleccione <uicontrol>Desactivar</uicontrol> para desactivar una agrupaci��n de almacenamiento activa.</li> -<li>Seleccione <uicontrol>No definir</uicontrol> para eliminar una agrupaci��n de almacenamiento inactiva.</li> -</ul></p> -<p>Para visualizar detalles de volumen de almacenamiento para una agrupaci��n de almacenamiento, pulse la flecha situada en el lado derecho de la fila de agrupaci��n de almacenamiento. Los detalles incluyen lo siguiente:<dl><dlentry> -<dt>Tipo</dt> -<dd>El tipo de volumen, por ejemplo, <uicontrol>archivo</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Formato</dt> -<dd>El formato, variable dependiendo del tipo.</dd> -</dlentry><dlentry> -<dt>Capacidad</dt> -<dd>Tama��o del volumen de almacenamiento.</dd> -</dlentry><dlentry> -<dt>Asignaci��n</dt> -<dd>Cantidad de espacio que ya est�� asignado en la agrupaci��n de almacenamiento.</dd> -</dlentry></dl>Para definir una agrupaci��n de almacenamiento, pulse en el icono <uicontrol>m��s (+)</uicontrol> en la esquina superior derecha de la pantalla.</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="es-es"> -<title>Definir una agrupaci��n de almacenamiento</title> -<shortdesc> Definir una agrupaci��n de almacenamiento.</shortdesc> -<csbody> -<p> <ol> -<li>En el campo <uicontrol>Nombre de agrupaci��n de almacenamiento</uicontrol>, escriba el nombre que se utilizar�� para identificar la agrupaci��n de almacenamiento.</li> -<li>En la lista <uicontrol>Tipo de agrupaci��n almacenamiento</uicontrol>, seleccione el tipo: <dl><dlentry> -<dt><uicontrol>DIR</uicontrol></dt> -<dd>Especifica una agrupaci��n de directorio. Al seleccionar <uicontrol>DIR</uicontrol>, escriba la <uicontrol>V��a de acceso de almacenamiento</uicontrol> (v��a de acceso de archivo a la agrupaci��n de almacenamiento).</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>Especifica una agrupaci��n de sistema de archivos de red. Al seleccionar <uicontrol>NFS</uicontrol>, escriba la direcci��n <uicontrol>IP de servidor NFS</uicontrol> y <uicontrol>v��a de acceso de NFS</uicontrol> (v��a de acceso del directorio exportado).</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>Especifica una agrupaci��n basada en un destino asignado en un servidor iSCSI. -Al seleccionar <uicontrol>iSCSI</uicontrol>, escriba la direcci��n IP del <uicontrol>Servidor iSCSI</uicontrol> y el <uicontrol>Destino</uicontrol> en el servidor iSCSI. Opcionalmente puede seleccionar a��adir autenticaci��n iSCSI.</dd> -</dlentry><dlentry> -<dt><uicontrol>L��gico</uicontrol></dt> -<dd>Especifica una agrupaci��n de almacenamiento de volumen l��gico. Seleccione la ubicaci��n al dispositivo en <uicontrol>V��a de acceso de dispositivo</uicontrol>.</dd> -</dlentry><dlentry> -<dt><uicontrol>Canal de fibra de SCSI</uicontrol></dt> -<dd>Especifica una agrupaci��n basada en un Canal de fibra SCSI. Seleccione qu�� adaptador SCSI se utilizar��.</dd> -</dlentry></dl></li> -<li>Pulse <uicontrol>Crear</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 233 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/es_ES/templates.dita b/plugins/kimchi/ui/pages/help/es_ES/templates.dita deleted file mode 100644 index 8cceee7..0000000 --- a/plugins/kimchi/ui/pages/help/es_ES/templates.dita +++ /dev/null @@ -1,111 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="es-es"> -<title>Plantillas</title> -<shortdesc>La p��gina <wintitle>Plantillas</wintitle> muestra las plantillas de m��quina virtual definidas que se pueden utilizar para crear invitados KVM.</shortdesc> -<csbody> -<p>Se visualiza la siguiente informaci��n para cada plantilla:<dl> -<dlentry> -<dt>SO</dt> -<dd>Nombre del sistema operativo o distribuci��n.</dd> -</dlentry><dlentry> -<dt>Versi��n</dt> -<dd>Versi��n del sistema operativo o distribuci��n.</dd> -</dlentry><dlentry> -<dt>CPUs</dt> -<dd>N��mero de procesadores que est��n definidos para la plantilla.</dd> -</dlentry><dlentry> -<dt>Memoria</dt> -<dd>Cantidad de memoria de acceso aleatorio a asignar, en MB.</dd> -</dlentry></dl></p> -<p>Se pueden seleccionar las siguientes acciones para cada plantilla:<ul> -<li>Seleccione <uicontrol>Editar</uicontrol> para editar la plantilla.</li> -<li>Seleccione <uicontrol>Suprimir</uicontrol> para suprimir la plantilla.</li> -</ul>Para a��adir una plantilla, pulse en el icono <uicontrol>m��s (+)</uicontrol> en la esquina superior derecha de la pantalla.</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="es-es"> -<title>Editar plantilla</title> -<shortdesc>Editar una plantilla existente.</shortdesc> -<csbody> -<p>Se visualiza la siguiente informaci��n para cada plantilla: <dl> -<dlentry> -<dt>Nombre</dt> -<dd>Nombre de la plantilla.</dd> -</dlentry><dlentry> -<dt>Proveedor</dt> -<dd>El nombre de la empresa que cre�� el sistema operativo o distribuci��n que la plantilla est�� configurada para utilizar.</dd> -</dlentry><dlentry> -<dt>Versi��n</dt> -<dd>La versi��n del sistema operativo o distribuci��n que la plantilla est�� configurada para utilizar.</dd> -</dlentry><dlentry> -<dt>N��mero de CPU</dt> -<dd>N��mero de procesadores que est��n definidos para la plantilla.</dd> -</dlentry><dlentry> -<dt>Memoria</dt> -<dd>Cantidad de memoria en MB a asignar a la m��quina virtual.</dd> -</dlentry><dlentry> -<dt>Disco</dt> -<dd>Tama��o de disco en GB.</dd> -</dlentry><dlentry> -<dt>CDROM</dt> -<dd>V��a de acceso de archivo a la ubicaci��n del archivo ISO utilizado para instalar el invitado KVM.</dd> -</dlentry><dlentry> -<dt>Agrupaci��n de almacenamiento</dt> -<dd>Agrupaci��n de almacenamiento espec��fica o la agrupaci��n de almacenamiento predeterminada.</dd> -</dlentry><dlentry> -<dt>Red</dt> -<dd>Interfaces de red predeterminadas disponibles para el invitado KVM. Puede seleccionar varias redes.</dd> -</dlentry></dl> Los campos que no est��n inhabilitados pueden editarse. Despu��s de editar un campo, pulse <uicontrol>Guardar</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>A��adir plantilla</title> -<shortdesc>A��adir una plantilla desde el soporte de origen. Puede a��adir su propia imagen ISO a la agrupaci��n de almacenamiento 'ISO' para el siguiente descubrimiento.</shortdesc> -<csbody> -<p>Seleccione la ubicaci��n del soporte de origen entre una de las opciones siguientes:<dl> -<dlentry> -<dt>Imagen ISO local</dt> -<dd>Seleccione esta opci��n para explorar las agrupaciones de almacenamiento en busca de im��genes ISO de instalaci��n disponibles en el sistema.</dd> -</dlentry><dlentry> -<dt>Imagen ISO remota</dt> -<dd>Seleccione esta opci��n para especificar una ubicaci��n remota para una imagen ISO de instalaci��n.</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>A��adir plantilla ��� imagen ISO local</title> -<shortdesc>A��adir una plantilla desde una imagen ISO local.</shortdesc> -<csbody> -<p>Se visualizan las im��genes ISO disponibles en el sistema.<dl><dlentry> -<dt>SO</dt> -<dd>Nombre del sistema operativo o distribuci��n.</dd> -</dlentry><dlentry> -<dt>Versi��n</dt> -<dd>Versi��n del sistema operativo o distribuci��n.</dd> -</dlentry><dlentry> -<dt>Tama��o</dt> -<dd>Tama��o de la imagen ISO.</dd> -</dlentry></dl></p> -<p>Para crear una plantilla a partir de una imagen ISO, elija entre las opciones siguientes:<ul> -<li>Seleccione una imagen ISO desde la que desea crear una plantilla y, a continuaci��n, pulse <uicontrol>Crear plantillas desde ISO seleccionada</uicontrol>.</li> -<li>Seleccione <uicontrol>Todo</uicontrol> para crear una plantilla desde cada imagen ISO en la lista y, a continuaci��n, pulse <uicontrol>Crear plantillas desde ISO seleccionada</uicontrol>.</li> -<li>Si la imagen ISO que desea utilizar no aparece en los resultados de la exploraci��n, puede seleccionar entre las opciones siguientes:<ul> -<li>Seleccione <uicontrol>Deseo utilizar un archivo ISO espec��fico</uicontrol> para especificar una v��a de acceso a la imagen ISO.</li> -<li>Pulse <uicontrol>Buscar m��s ISO</uicontrol> para buscar m��s im��genes ISO.</li> -</ul></li> -</ul></p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 229 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/fr_FR/Makefile.am b/plugins/kimchi/ui/pages/help/fr_FR/Makefile.am deleted file mode 100644 index 11ce394..0000000 --- a/plugins/kimchi/ui/pages/help/fr_FR/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -fr_FR_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/fr_FR - -dist_fr_FR_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/fr_FR/guests.dita b/plugins/kimchi/ui/pages/help/fr_FR/guests.dita deleted file mode 100644 index ad5b4e4..0000000 --- a/plugins/kimchi/ui/pages/help/fr_FR/guests.dita +++ /dev/null @@ -1,130 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="fr-fr"> -<title>Invit��s</title> -<shortdesc>La page <wintitle>Invit��s</wintitle> r��pertorie les machines virtuelles KVM d��finies.</shortdesc> -<csbody> -<p>Pour chaque invit��, les informations suivantes sont affich��es :<dl><dlentry> -<dt>Nom</dt> -<dd>Nom de la machine virtuelle.</dd> -</dlentry><dlentry> -<dt>UC</dt> -<dd>Pourcentage d'utilisation du processeur sur la machine virtuelle.</dd> -</dlentry><dlentry> -<dt>E-S r��seau</dt> -<dd>Vitesse de transmission d'entr��e-sortie du r��seau, exprim��e en ko par seconde.</dd> -</dlentry><dlentry> -<dt>E-S disque</dt> -<dd>Vitesse de transmission d'entr��e-sortie du disque, exprim��e en ko par seconde.</dd> -</dlentry><dlentry> -<dt>Livetile</dt> -<dd>Etat de la console du syst��me d'exploitation de l'h��te, ou -ic��ne repr��sentant la distribution <tm tmtype="tm" trademark="Linux">Linux</tm> -si l'invit�� n'est pas actif.</dd> -</dlentry></dl></p> -<p>Les ic��nes d'action suivantes sont affich��es pour chaque invit�� :<dl> -<dlentry> -<dt>R��initialiser</dt> -<dd>Cliquez pour r��initialiser l'invit��. </dd> -</dlentry><dlentry> -<dt>Alimentation (D��marrer ou Arr��ter)</dt> -<dd>Cliquez pour mettre sous ou hors tension l'invit��. Si l'ic��ne est rouge, -l'alimentation est d��marr��e ; si l'ic��ne est verte, l'alimentation est arr��t��e.</dd> -</dlentry></dl> </p> -<p>Les actions suivantes peuvent ��tre s��lectionn��es pour chaque invit�� :<ul> -<li>S��lectionnez <uicontrol>Connexion</uicontrol> pour vous connecter �� la console -distante du syst��me d'exploitation invit��.</li> -<li>S��lectionnez <uicontrol>G��rer le support</uicontrol> pour modifier le chemin -d'acc��s au support d'installation.</li> -<li>S��lectionnez <uicontrol>R��initialiser</uicontrol> pour r��initialiser l'invit��.</li> -<li>S��lectionnez <uicontrol>Editer</uicontrol> pour ��diter les propri��t��s d'un invit�� existant. Les invit��s peuvent ��tre ��dit��s uniquement lorsqu'ils sont �� l'arr��t.</li> -<li>S��lectionnez <uicontrol>Supprimer</uicontrol> pour supprimer l'invit��.</li> -</ul>Pour cr��er un invit��, cliquez sur l'ic��ne <uicontrol>plus (+)</uicontrol> -dans le coin sup��rieur droit de la page.</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="fr-fr"> -<title>Cr��er une machine virtuelle</title> -<shortdesc>Cr��ez une machine virtuelle en utilisant un mod��le existant.</shortdesc> -<csbody> -<p> <ol> -<li>Entrez le nom �� utiliser pour identifier la machine virtuelle.</li> -<li rev="rev1">S��lectionnez un mod��le. <ul> -<li>Si des mod��les existent, faites un choix parmi les mod��les affich��s.</li> -<li>Si aucun mod��le n'existe, cliquez sur <uicontrol>Cr��er un mod��le</uicontrol> pour cr��er un mod��le.</li> -</ul></li> -<li>Cliquez sur <uicontrol>Cr��er</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="fr-fr"> -<title>Editer l'invit��</title> -<shortdesc>Editez les propri��t��s d'une machine virtuelle existante. Certaines propri��t��s -peuvent ��tre ��dit��es uniquement lorsque l'invit�� est arr��t��. D'autres seront appliqu��es �� l'amor��age suivant.</shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>Pour chaque invit��, les informations suivantes sont affich��es dans l'onglet <wintitle>G��n��ral</wintitle> :<dl> -<dlentry> -<dt>Nom</dt> -<dd>Nom de la machine virtuelle. (Ne peut ��tre ��dit�� que lorsque l'invit�� est arr��t��)</dd> -</dlentry><dlentry> -<dt>UC</dt> -<dd>Nombre de processeurs. (Si l'invit�� est en cours d'ex��cution, la nouvelle quantit�� sera appliqu��e �� l'amor��age suivant)</dd> -</dlentry><dlentry> -<dt>M��moire</dt> -<dd>Quantit�� de m��moire en Mo. (Si l'invit�� est en cours d'ex��cution, la nouvelle quantit�� sera appliqu��e �� l'amor��age suivant)</dd> -</dlentry><dlentry> -<dt>Ic��ne</dt> -<dd>Image graphique repr��sentant la distribution Linux �� afficher �� la place -du statut en cours (Livetile) lorsque l'invit�� n'est pas actif.</dd> -</dlentry></dl></p> -<p>Les informations suivantes sont affich��es dans l'onglet <wintitle>Stockage</wintitle>.</p> -<dl><dlentry> -<dt>Stockage</dt> -<dd>Affiche l'emplacement du fichier ISO utilis�� pour l'installation.</dd> -</dlentry></dl> -<p> Les zones qui ne sont pas d��sactiv��es peuvent ��tre ��dit��es. Apr��s que vous avez ��dit�� une zone, cliquez sur <uicontrol>Sauvegarder</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="fr-fr"> -<title>Ajoutez, remplacez ou d��tachez une unit�� de stockage</title> -<shortdesc rev="rev1">Vous pouvez ajouter, remplacer ou d��tacher une unit�� de stockage -pour votre machine virtuelle. Seule une unit�� CD-ROM est prise en charge. Pour ��diter vos unit��s de stockage, proc��dez comme suit :</shortdesc> -<csbody> -<ol> -<li>Dans la fen��tre <wintitle>Editer l'invit��</wintitle>, s��lectionnez <wintitle>Stockage</wintitle>.</li> -<li>Pour remplacer une unit�� de stockage, cliquez sur la premi��re ic��ne avec la <uicontrol>barre oblique (/) orange</uicontrol>. Entrez le chemin d'acc��s au fichier ISO et cliquez sur <uicontrol>Remplacer</uicontrol>.</li> -<li>Pour d��tacher une unit�� de stockage, cliquez sur la deuxi��me ic��ne avec le <uicontrol>tiret (-) rouge</uicontrol>. Confirmer la suppression et cliquez sur <uicontrol>OK</uicontrol>.</li> -<li>Pour ajouter une unit�� de stockage, cliquez sur la troisi��me ic��ne avec le <uicontrol>signe plus (+) vert</uicontrol>. Entrez un nom d'unit�� et un chemin d'acc��s au fichier ISO puis cliquez sur <uicontrol>Attacher</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="fr-fr"> -<title>Remplacer l'unit�� CD-ROM d'une machine virtuelle</title> -<shortdesc rev="rev1">Vous pouvez remplacer le contenu du CD-ROM pour -une machine virtuelle une fois l'installation termin��e.</shortdesc> -<csbody> -<ol> -<li>V��rifiez que la machine virtuelle est d��marr��e.</li> -<li>Dans le menu Actions, s��lectionnez <uicontrol>G��rer le support</uicontrol>.</li> -<li>Pour modifier les donn��es actuellement charg��es dans l'unit�� de CD-ROM, cliquez sur l'ic��ne -<uicontrol>barre oblique (/) orange</uicontrol> en regard de la zone hdc.</li> -<li>Sur la page <wintitle>Remplacer une unit�� CD-ROM d'une machine virtuelle</wintitle>, -entrez le chemin d'acc��s au fichier ISO. Les deux autres zones sont en lecture seule.</li> -<li>Cliquez sur <uicontrol>Remplacer</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 231 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/fr_FR/host.dita b/plugins/kimchi/ui/pages/help/fr_FR/host.dita deleted file mode 100644 index f4c330b..0000000 --- a/plugins/kimchi/ui/pages/help/fr_FR/host.dita +++ /dev/null @@ -1,68 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="fr-fr"> -<title>H��te</title> -<shortdesc>La page <wintitle>H��te</wintitle> affiche des informations -sur le syst��me h��te et vous permet d'arr��ter, de red��marrer et de vous -connecter �� l'h��te.</shortdesc> -<csbody> -<p>Vous pouvez effectuer les actions suivantes sur l'h��te :<ul> -<li>S��lectionnez <uicontrol>Arr��ter</uicontrol> pour arr��ter le syst��me h��te.</li> -<li>S��lectionnez <uicontrol>Red��marrer</uicontrol> pour red��marrer le syst��me h��te.</li> -<li>S��lectionnez <uicontrol>Connexion</uicontrol> pour ouvrir une connexion VNC -au syst��me h��te, si celui-ci n'est pas d��j�� connect��.</li> -</ul></p> -<p>Cliquez sur les sections suivantes pour afficher des informations sur l'h��te :<dl> -<dlentry> -<dt>Informations de base</dt> -<dd>Cette section affiche la distribution, la version et le nom de code -du syst��me d'exploitation h��te, ainsi que le type de processeur et la quantit�� -de m��moire en Go.</dd> -</dlentry><dlentry> -<dt>Statistiques syst��me</dt> -<dd>Cette section affiche les graphiques des statistiques pour l'UC, m��moire, ainsi que -les E-S disque et E-S r��seau pour l'h��te. S��lectionnez <uicontrol>Collecte des donn��es une fois la page quitt��e</uicontrol> -pour continuer la collecte de donn��es lorsque l'onglet h��te n'est plus visible.</dd> -</dlentry><dlentry> -<dt>Mises �� jour logicielles</dt> -<dd>Cette section affiche des informations pour tous les modules qui -disposent de mises �� jour disponibles, y compris le nom de module, la version, l'architecture -et le r��f��rentiel. Vous pouvez mettre �� jour toutes les modules r��pertori��s en s��lectionnant <uicontrol>Tout -mettre �� jour</uicontrol>. Vous ne pouvez pas s��lectionner des modules individuels pour les mises �� jour.</dd> -</dlentry><dlentry> -<dt>R��f��rentiels</dt> -<dd>Cette section affiche les r��f��rentiels associ��s au syst��me h��te. Vous pouvez ajouter, activer, ��diter ou retirer des r��f��rentiels. L'ajout d'un r��f��rentiel associe celui-ci au syst��me h��te, -tandis que l'activation d'un r��f��rentiel permet �� l'h��te d'y acc��der. Si votre syst��me est Red Hat Enterprise Linux ou Fedora, -vous pouvez ajouter des r��f��rentiels <filepath>yum</filepath>. -Si votre syst��me est de type Ubuntu ou Debian, ajoutez des r��f��rentiels -<filepath>deb</filepath>.<p>Si vous travaillez avec des r��f��rentiels yum, vous pouvez ajouter un contr��le GPG -afin de v��rifier qu'un module provenant de ce r��f��rentiel n'a pas ��t�� endommag��. -S��lectionnez un r��f��rentiel puis cliquez sur <uicontrol>Editer</uicontrol>. S��lectionnez <uicontrol>Oui</uicontrol> pour activer le contr��le GPG, -puis entrez une URL pour le fichier de cl��s GPG du r��f��rentiel.</p></dd> -</dlentry><dlentry> -<dt>Rapports de d��bogage</dt> -<dd>Cette section affiche les rapports de d��bogage, y compris le nom et le chemin du fichier. -Vous pouvez faire un choix parmi les options afin de g��n��rer un nouveau rapport, ou renommer, supprimer, -ou t��l��charger un rapport existant.<p>Le rapport de d��bogage est g��n��r�� �� -l'aide de la commande <cmdname>sosreport</cmdname>. Cette option est disponible pour les distributions -Red Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora et Ubuntu. La commande g��n��re un fichier .tar contenant la configuration et des informations de diagnostic, -telles que la version du noyau d'ex��cution, les modules charg��s, ainsi que les fichiers de configuration -du syst��me et de la maintenance. -La commande ex��cute ��galement des programmes externes pour collecter des informations -suppl��mentaires et stocke cette sortie dans l'archive r��sultante.</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 232 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/fr_FR/network.dita b/plugins/kimchi/ui/pages/help/fr_FR/network.dita deleted file mode 100644 index 5c2e9dd..0000000 --- a/plugins/kimchi/ui/pages/help/fr_FR/network.dita +++ /dev/null @@ -1,67 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="fr-fr"> -<title>R��seau</title> -<shortdesc>La page <wintitle>R��seau</wintitle> affiche des informations sur la connexion r��seau.</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>Nom du r��seau</dt> -<dd>Nom du r��seau, ou <uicontrol>par d��faut</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Etat</dt> -<dd>Etat du r��seau, actif (vert) ou inactif (rouge). </dd> -</dlentry><dlentry> -<dt>Type de r��seau</dt> -<dd>Type du r��seau, par exemple <uicontrol>NAT</uicontrol> (conversion d'adresses r��seau).</dd> -</dlentry><dlentry> -<dt>Interface</dt> -<dd>Interface r��seau, par exemple <uicontrol>virbr0</uicontrol> (par d��faut).</dd> -</dlentry><dlentry> -<dt>Espace adresse</dt> -<dd>Adresse IP.</dd> -</dlentry></dl></p> -<p>Les actions suivantes peuvent ��tre s��lectionn��es :<ul> -<li rev="rev1">S��lectionnez <uicontrol>D��marrer</uicontrol> pour d��marrer la connexion au r��seau.</li> -<li>S��lectionnez <uicontrol>Arr��ter</uicontrol> pour mettre fin �� la connexion au r��seau.</li> -<li>S��lectionnez <uicontrol>Supprimer</uicontrol> pour supprimer les informations de connexion.</li> -</ul>Pour cr��er un r��seau, cliquez sur l'ic��ne <uicontrol>plus (+)</uicontrol> -dans le coin sup��rieur droit de l'��cran.</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="fr-fr"> -<title>Cr��er un r��seau</title> -<shortdesc>Cr��ez un r��seau.</shortdesc> -<csbody> -<p> <ol> -<li>Entrez le nom du r��seau.</li> -<li>Cliquez pour s��lectionner le type de r��seau. <dl rev="rev1"><dlentry> -<dt><uicontrol>Isol��</uicontrol></dt> -<dd>Mode isol��. Les invit��s ne peuvent pas envoyer ni recevoir de communication avec des syst��mes externes.</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>Mode de conversion d'adresses r��seau. La communication �� partir d'invit��s -vers des syst��mes externes utilise l'adresse IP h��te. Les syst��mes externes ne -peuvent pas initier de communication vers les invit��s.</dd> -</dlentry><dlentry> -<dt><uicontrol>Rout��</uicontrol></dt> -<dd>Mode rout��. Les invit��s peuvent communiquer avec des syst��mes externes et -��tre contact��s par des syst��mes externes comme s'il s'agissait de syst��mes physiques -sur le r��seau. Pour le mode rout��, vous devez sp��cifier des informations suppl��mentaires -sur la destination et le r��seau local virtuel.</dd> -</dlentry></dl></li> -<li>Cliquez sur <uicontrol>Cr��er</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 230 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/fr_FR/storage.dita b/plugins/kimchi/ui/pages/help/fr_FR/storage.dita deleted file mode 100644 index eebf2bb..0000000 --- a/plugins/kimchi/ui/pages/help/fr_FR/storage.dita +++ /dev/null @@ -1,93 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="fr-fr"> -<title>Stockage</title> -<shortdesc>La page <wintitle>Stockage</wintitle> r��pertorie les pools de stockage disponibles, -y compris les pools de stockage 'default' et 'ISO' pr��ts �� l'emploi. -Si vous souhaitez utiliser votre propre pool de stockage ISO, ajoutez-le dans le chemin du pool de stockage 'ISO'.</shortdesc> -<csbody> -<p>Pour chaque pool de stockage, les informations suivantes sont affich��es :<dl> -<dlentry> -<dt>Nom</dt> -<dd>Nom du pool de stockage et pourcentage d'utilisation.</dd> -</dlentry><dlentry> -<dt>Etat</dt> -<dd>Etat du pool de stockage, actif (vert) ou inactif (rouge). </dd> -</dlentry><dlentry> -<dt>Emplacement</dt> -<dd>chemin d'acc��s au fichier pour l'emplacement du pool de stockage.</dd> -</dlentry><dlentry> -<dt>Type</dt> -<dd>Type de pool de stockage, par exemple <uicontrol>dir</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Capacit��</dt> -<dd>Quantit�� d'espace dans le pool de stockage.</dd> -</dlentry><dlentry> -<dt>Allou��</dt> -<dd>Quantit�� d'espace d��j�� allou��e dans le pool de stockage.</dd> -</dlentry></dl></p> -<p>Les actions suivantes peuvent ��tre s��lectionn��es pour chaque pool de stockage :<ul> -<li>S��lectionnez <uicontrol>Activer</uicontrol> pour activer le pool de stockage pour utilisation.</li> -<li>S��lectionnez <uicontrol>D��sactiver</uicontrol> pour d��sactiver un pool de stockage actif.</li> -<li>S��lectionnez <uicontrol>Annuler d��finition</uicontrol> pour retirer un pool de stockage inactif.</li> -</ul></p> -<p>Pour afficher les d��tails de volume de stockage pour un pool de stockage, cliquez sur la -fl��che situ��e �� droite de la ligne du pool de stockage. D��tails inclus :<dl><dlentry> -<dt>Type</dt> -<dd>Type de volume, par exemple <uicontrol>file</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Format</dt> -<dd>Format, variable selon le type.</dd> -</dlentry><dlentry> -<dt>Capacit��</dt> -<dd>Taille du volume de stockage.</dd> -</dlentry><dlentry> -<dt>Allocation</dt> -<dd>Quantit�� d'espace d��j�� allou��e dans le pool de stockage.</dd> -</dlentry></dl>Pour d��finir un pool de stockage, cliquez sur l'ic��ne <uicontrol>plus (+)</uicontrol> -dans le coin sup��rieur droit de l'��cran.</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="fr-fr"> -<title>D��finir un pool de stockage</title> -<shortdesc> D��finissez un pool de stockage.</shortdesc> -<csbody> -<p> <ol> -<li>Dans la zone <uicontrol>Nom du pool de stockage</uicontrol>, entrez le nom �� utiliser pour identifier le pool de stockage.</li> -<li>Dans la zone <uicontrol>Type de pool de stockage</uicontrol>, s��lectionnez le type : <dl><dlentry> -<dt><uicontrol>DIR</uicontrol></dt> -<dd>Indique un pool de r��pertoires. Lorsque vous s��lectionnez <uicontrol>DIR</uicontrol>, -indiquez le <uicontrol>Chemin de stockage</uicontrol> (chemin d'acc��s au fichier -du pool de stockage).</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>indique un pool de syst��mes de fichiers r��seau. Lorsque vous s��lectionnez <uicontrol>NFS</uicontrol>, -indiquez l'adresse <uicontrol>IP du serveur NFS</uicontrol> et le <uicontrol>Chemin NFS</uicontrol> (chemin d'acc��s au r��pertoire d'exportation).</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>Indique un pool bas�� sur une cible allou��e sur un serveur iSCSI. -Lorsque vous s��lectionnez <uicontrol>iSCSI</uicontrol>, indiquez l'adresse IP du <uicontrol>Serveur iSCSI</uicontrol> -et la <uicontrol>Cible</uicontrol> sur le serveur iSCSI. Vous avez la possibilit�� d'ajouter l'authentification iSCSI.</dd> -</dlentry><dlentry> -<dt><uicontrol>Logique</uicontrol></dt> -<dd>Indique un pool de stockage de volumes logiques. S��lectionnez l'emplacement de l'unit�� dans <uicontrol>Chemin d'unit��</uicontrol>.</dd> -</dlentry><dlentry> -<dt><uicontrol>Fibre Channel SCSI</uicontrol></dt> -<dd>Indique un pool bas��e sur une connexion Fibre Channel SCSI. S��lectionnez l'adaptateur SCSI �� utiliser.</dd> -</dlentry></dl></li> -<li>Cliquez sur <uicontrol>Cr��er</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 233 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/fr_FR/templates.dita b/plugins/kimchi/ui/pages/help/fr_FR/templates.dita deleted file mode 100644 index a517e33..0000000 --- a/plugins/kimchi/ui/pages/help/fr_FR/templates.dita +++ /dev/null @@ -1,120 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="fr-fr"> -<title>Mod��les</title> -<shortdesc>La page <wintitle>Mod��les</wintitle> affiche les mod��les de machine virtuelle d��finis -pouvant ��tre utilis��s pour cr��er des h��tes KVM.</shortdesc> -<csbody> -<p>Pour chaque mod��le, les informations suivantes sont affich��es :<dl> -<dlentry> -<dt>SE</dt> -<dd>Nom du syst��me d'exploitation ou de la distribution.</dd> -</dlentry><dlentry> -<dt>Version</dt> -<dd>Version du syst��me d'exploitation ou de la distribution.</dd> -</dlentry><dlentry> -<dt>UC</dt> -<dd>Nombre de processeurs d��finis pour le mod��le.</dd> -</dlentry><dlentry> -<dt>M��moire</dt> -<dd>Quantit�� de m��moire vive �� allouer, en Mo.</dd> -</dlentry></dl></p> -<p>Les actions suivantes peuvent ��tre s��lectionn��es pour chaque mod��le :<ul> -<li>S��lectionnez <uicontrol>Editer</uicontrol> pour ��diter le mod��le.</li> -<li>S��lectionnez <uicontrol>Supprimer</uicontrol> pour supprimer le mod��le.</li> -</ul>Pour ajouter un mod��le, cliquez sur l'ic��ne <uicontrol>plus (+)</uicontrol> -dans le coin sup��rieur droit de l'��cran.</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="fr-fr"> -<title>Editer un mod��le</title> -<shortdesc>Editez un mod��le existant.</shortdesc> -<csbody> -<p>Pour chaque mod��le, les informations suivantes sont affich��es : <dl> -<dlentry> -<dt>Nom</dt> -<dd>Nom du mod��le.</dd> -</dlentry><dlentry> -<dt>Fournisseur</dt> -<dd>Nom de la soci��t�� qui a cr���� le syst��me d'exploitation ou la distribution -pour lequel/laquelle le mod��le est configur��.</dd> -</dlentry><dlentry> -<dt>Version</dt> -<dd>Version du syst��me d'exploitation ou de la distribution -pour lequel/laquelle le mod��le est configur��.</dd> -</dlentry><dlentry> -<dt>Nombre d'UC</dt> -<dd>Nombre de processeurs d��finis pour le mod��le.</dd> -</dlentry><dlentry> -<dt>M��moire</dt> -<dd>Quantit�� de m��moire en Mo �� allouer �� la machine virtuelle.</dd> -</dlentry><dlentry> -<dt>Disque</dt> -<dd>Taille du disque en Go.</dd> -</dlentry><dlentry> -<dt>CD-ROM</dt> -<dd>chemin d'acc��s au fichier pour l'emplacement du fichier ISO utilis�� pour l'installation de l'invit�� KVM.</dd> -</dlentry><dlentry> -<dt>Pool de stockage</dt> -<dd>Pool de stockage sp��cifique ou pool de stockage par d��faut.</dd> -</dlentry><dlentry> -<dt>R��seau</dt> -<dd>Interfaces r��seau par d��faut disponibles pour l'invit�� KVM. Vous pouvez -s��lectionner plusieurs r��seaux.</dd> -</dlentry></dl> Les zones qui ne sont pas d��sactiv��es peuvent ��tre ��dit��es. Apr��s que vous avez ��dit�� une zone, cliquez sur <uicontrol>Sauvegarder</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>Ajouter un mod��le</title> -<shortdesc>Ajoutez un mod��le �� partir du support source. -Vous pouvez ajouter votre propre image ISO au pool de stockage 'ISO' pour la reconnaissance suivante.</shortdesc> -<csbody> -<p>S��lectionnez l'emplacement du support source �� partir des options suivantes :<dl> -<dlentry> -<dt>Image ISO locale</dt> -<dd>S��lectionnez cette option pour rechercher dans les pools de stockage l'image d'installation ISO disponible sur le syst��me.</dd> -</dlentry><dlentry> -<dt>Image ISO distante</dt> -<dd>S��lectionnez cette option pour indiquer un emplacement distant pour une image d'installation ISO.</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>Ajouter un mod��le - Image ISO locale</title> -<shortdesc>Ajoutez un mod��le �� partir d'une image ISO locale.</shortdesc> -<csbody> -<p>Les images ISO disponibles sur le syst��me sont affich��es.<dl><dlentry> -<dt>SE</dt> -<dd>Nom du syst��me d'exploitation ou de la distribution.</dd> -</dlentry><dlentry> -<dt>Version</dt> -<dd>Version du syst��me d'exploitation ou de la distribution.</dd> -</dlentry><dlentry> -<dt>Taille</dt> -<dd>Taille de l'image ISO.</dd> -</dlentry></dl></p> -<p>Pour cr��er un mod��le �� partir d'une image ISO, choisissez parmi les options suivantes :<ul> -<li>S��lectionnez une image ISO �� partir de laquelle cr��er un mod��le, puis cliquez sur <uicontrol>Cr��er des mod��les �� partir de l'ISO s��lectionn�� </uicontrol>.</li> -<li>S��lectionnez <uicontrol>Tout</uicontrol> pour cr��er un mod��le �� partir de chaque -image ISO r��pertori��e, puis cliquez sur <uicontrol>Cr��er des mod��les �� partir de l'ISO s��lectionn��</uicontrol>.</li> -<li>Si l'image ISO que vous souhaitez utiliser ne figure pas dans les r��sultats -d'analyse, vous pouvez faire un choix parmi les options suivantes :<ul> -<li>S��lectionnez <uicontrol>Je souhaite utiliser un fichier ISO sp��cifique</uicontrol> pour -sp��cifier un chemin d'acc��s �� l'image ISO.</li> -<li>Cliquez sur <uicontrol>Rechercher d'autres images ISO</uicontrol> pour rechercher des images ISO suppl��mentaires.</li> -</ul></li> -</ul></p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 229 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/it_IT/Makefile.am b/plugins/kimchi/ui/pages/help/it_IT/Makefile.am deleted file mode 100644 index 62e2f29..0000000 --- a/plugins/kimchi/ui/pages/help/it_IT/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -it_IT_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/it_IT - -dist_it_IT_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/it_IT/guests.dita b/plugins/kimchi/ui/pages/help/it_IT/guests.dita deleted file mode 100644 index e05db7e..0000000 --- a/plugins/kimchi/ui/pages/help/it_IT/guests.dita +++ /dev/null @@ -1,123 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="it-it"> -<title>Guest</title> -<shortdesc>La pagina <wintitle>Guest</wintitle> elenca le macchine virtuali -KVM definite.</shortdesc> -<csbody> -<p>Per ciascuna macchina guest vengono visualizzate le seguenti informazioni:<dl><dlentry> -<dt>Nome</dt> -<dd>Il nome della macchina virtuale.</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>La percentuale di utilizzo del processore nella macchina virtuale.</dd> -</dlentry><dlentry> -<dt>I/O di rete</dt> -<dd>La velocit�� di trasmissione dell'input/output di rete in KB al secondo.</dd> -</dlentry><dlentry> -<dt>I/O disco</dt> -<dd>La velocit�� di trasmissione dell'input/output disco in KB al secondo.</dd> -</dlentry><dlentry> -<dt>Riquadro animato</dt> -<dd>Lo stato della console del sistema operativo della macchina guest o un'icona che rappresenta la distribuzione <tm tmtype="tm" trademark="Linux">Linux</tm> se la macchina guest non �� attiva.</dd> -</dlentry></dl></p> -<p>Per ciascuna macchina guest vengono visualizzate le icone di azioni indicate di seguito:<dl> -<dlentry> -<dt>Reimposta</dt> -<dd>Fare clic qui per reimpostare la macchina guest. </dd> -</dlentry><dlentry> -<dt>Alimentazione (Avvia o Arresta)</dt> -<dd>Fare clic qui per accendere o spegnere la macchina guest. Se l'icona �� rossa, la macchina �� spenta, se �� verde �� accesa.</dd> -</dlentry></dl> </p> -<p>Per ciascuna macchina guest �� possibile selezionare le azioni indicate di seguito:<ul> -<li>Selezionare <uicontrol>Connetti</uicontrol> per effettuare la connessione alla console remota per il sistema operativo della macchina guest.</li> -<li>Selezionare <uicontrol>Gestisci supporti</uicontrol> per modificare il percorso al supporto di installazione.</li> -<li>Selezionare <uicontrol>Reimposta</uicontrol> per reimpostare la macchina guest.</li> -<li>Selezionare <uicontrol>Modifica</uicontrol> per modificare le propriet����di una macchina guest esistente. �� possibile modificare le macchine guest solo se sono arrestate.</li> -<li>Selezionare <uicontrol>Elimina</uicontrol> per eliminare la macchina guest.</li> -</ul>Per creare una macchina guest, o macchina virtuale, fare clic sull'icona <uicontrol>pi�� -(+)</uicontrol> nella parte in alto a destra della pagina.</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="it-it"> -<title>Creare una macchina virtuale</title> -<shortdesc>Creare una macchina virtuale utilizzando un modello esistente.</shortdesc> -<csbody> -<p> <ol> -<li>Immettere il nome da utilizzare per identificare la macchina virtuale.</li> -<li rev="rev1">Selezionare un modello. <ul> -<li>Se il modello esiste, selezionarlo dai modelli visualizzati.</li> -<li>Se non esiste alcun modello, fare clic su <uicontrol>Crea un modello</uicontrol> per crearne uno.</li> -</ul></li> -<li>Fare clic su <uicontrol>Crea</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="it-it"> -<title>Modifica macchina guest</title> -<shortdesc>Modificare le propriet�� di una macchina virtuale esistente. Alcune propriet�� possono essere -modificate solo mentre la macchina guest �� arrestata. Altre diventeranno effettive al prossimo avvio.</shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>Per ciascuna macchina guest vengono visualizzate le seguenti informazioni sulla scheda <wintitle>Generale</wintitle>:<dl> -<dlentry> -<dt>Nome</dt> -<dd>Il nome della macchina virtuale. (Pu�� essere modificato solo mentre la macchina guest �� arrestata)</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>Il numero di processori. (Se la macchina guest �� in esecuzione, la nuova quantit�� diventer�� effettiva -al prossimo avvio)</dd> -</dlentry><dlentry> -<dt>Memoria</dt> -<dd>La quantit�� di memoria in MB. (Se la macchina guest �� in esecuzione, la nuova quantit�� diventer�� effettiva -al prossimo avvio)</dd> -</dlentry><dlentry> -<dt>Icona</dt> -<dd>L'immagine grafica che rappresenta la distribuzione Linux da visualizzare al posto dello stato corrente (Riquadro animato) quando la macchina guest non �� attiva.</dd> -</dlentry></dl></p> -<p>Sulla scheda <wintitle>Memoria</wintitle> vengono visualizzate le seguenti informazioni.</p> -<dl><dlentry> -<dt>Memoria</dt> -<dd>Visualizza l'ubicazione del file ISO utilizzato per l'installazione.</dd> -</dlentry></dl> -<p> I campi non disabilitati possono essere modificati. Dopo aver modificato un campo, fare clic su <uicontrol>Salva</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="it-it"> -<title>Aggiungere, sostituire o scollegare un dispositivo di memoria.</title> -<shortdesc rev="rev1">�� possibile aggiungere, sostituire o scollegare un dispositivo di memoria per la macchina virtuale. L'unico dispositivo supportato �� CDROM. Per modificare i dispositivi di memoria, attenersi alla seguente procedura:</shortdesc> -<csbody> -<ol> -<li>Nella finestra <wintitle>Modifica macchina guest</wintitle>, selezionare <wintitle>Memoria</wintitle>.</li> -<li>Per sostituire un dispositivo di memoria, fare clic sulla prima icona con la <uicontrol>barra (/) arancione</uicontrol>. Immettere il percorso del file ISO e fare clic su <uicontrol>Sostituisci</uicontrol>.</li> -<li>Per scollegare un dispositivo di memoria, fare clic sulla seconda icona con il <uicontrol>trattino (-) rosso</uicontrol>. Confermare l'eliminazione facendo clic su <uicontrol>OK</uicontrol>.</li> -<li>Per aggiungere un dispositivo di memoria, fare clic sulla terza icona con il <uicontrol>segno pi�� (+)</uicontrol> verde. Immettere un nome dispositivo e percorso file ISO e fare clic su <uicontrol>Collega</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="it-it"> -<title>Sostituisci un CDROM della macchina virtuale</title> -<shortdesc rev="rev1">�� possibile sostituire il contenuto del CDROM per una macchina virtuale dopo il completamento dell'installazione.</shortdesc> -<csbody> -<ol> -<li>Assicurarsi che la macchina virtuale sia avviata.</li> -<li>Dal menu Azioni, selezionare <uicontrol>Gestisci supporti</uicontrol>.</li> -<li>Per modificare il contenuto correntemente caricato sul CDROM, fare clic sull'icona della <uicontrol>barra (/) arancione</uicontrol> accanto al campo hdc.</li> -<li>Sulla pagina <wintitle>Sostituisci un CDROM della macchina virtuale</wintitle>, immettere il percorso del file ISO. Gli altri due campi sono di sola lettura.</li> -<li>Fare clic su <uicontrol>Sostituisci</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 231 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/it_IT/host.dita b/plugins/kimchi/ui/pages/help/it_IT/host.dita deleted file mode 100644 index 63d3367..0000000 --- a/plugins/kimchi/ui/pages/help/it_IT/host.dita +++ /dev/null @@ -1,51 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="it-it"> -<title>Host</title> -<shortdesc>La pagina <wintitle>Host</wintitle> visualizza le informazioni sul sistema host e consente di arrestarlo, riavviarlo e connettersi ad esso.</shortdesc> -<csbody> -<p>�� possibile effettuare le seguenti operazioni sull'host:<ul> -<li>Selezionare <uicontrol>Arresta</uicontrol> per arrestare il sistema host.</li> -<li>Selezionare <uicontrol>Riavvia</uicontrol> per riavviare il sistema host.</li> -<li>Selezionare <uicontrol>Connetti</uicontrol> per aprire una connessione VNC al sistema host, se non �� gi�� connesso.</li> -</ul></p> -<p>Fare clic sulle seguenti sezioni per visualizzare le informazioni sull'host:<dl> -<dlentry> -<dt>Informazioni di base</dt> -<dd>Questa sezione visualizza il nome codice, la versione e la distribuzione del sistema operativo, come pure il tipo di processore e la quantit�� di memoria in GB.</dd> -</dlentry><dlentry> -<dt>Statistiche di sistema</dt> -<dd>Questa sezione visualizza i grafici che mostrano le statistiche per la CPU, la memoria, l'I/O disco e di rete per l'host. Selezionare <uicontrol>Raccolta dati all'uscita dalla pagina</uicontrol> per continuare la raccolta dei dati quando la scheda host non �� pi�� visibile.</dd> -</dlentry><dlentry> -<dt>Aggiornamenti del software</dt> -<dd>Questa sezione visualizza le informazioni per tutti i pacchetti per cui sono disponibili gli aggiornamenti, incluso il nome, la versione, l'architettura e il repository del pacchetto. �� possibile aggiornare tutti i pacchetti elencati, selezionando <uicontrol>Aggiorna tutto</uicontrol>. Non �� possibile selezionare singoli pacchetti per gli aggiornamenti.</dd> -</dlentry><dlentry> -<dt>Repository</dt> -<dd>Questa sezione visualizza i repository associati al sistema host. �� possibile aggiungere, abilitare, modificare o rimuovere i repository. L'aggiunta di un repository lo associa al sistema host, mentre l'abilitazione di un repository -consente all'host di accedervi. Se il sistema �� Red Hat Enterprise -Linux o Fedora, �� possibile aggiungere i repository <filepath>yum</filepath>. -Se il sistema �� Ubuntu o Debian, aggiungere i repository <filepath>deb</filepath>.<p>Se si stanno utilizzando i repository yum, �� possibile aggiungere un controllo GPG per verificare che un pacchetto da questo repository non sia stato corrotto. -Selezionare un repository, quindi <uicontrol>Modifica</uicontrol>. Selezionare <uicontrol>S��</uicontrol> per abilitare il controllo GPG, quindi immettere un URL al file di chiavi GPG per il -repository.</p></dd> -</dlentry><dlentry> -<dt>Report di debug</dt> -<dd>Questa sezione visualizza i report di debug, incluso il nome e il percorso file. -Le opzioni disponibili consentono di generare un nuovo report oppure ridenominare, rimuovere o scaricare un report esistente.<p>Il report di debug viene generato utilizzando il comando <cmdname>sosreport</cmdname>. �� disponibile per le distribuzioni Red -Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora e Ubuntu. Il comando genera un file .tar che contiene informazioni di diagnostica e configurazione, come la versione del kernel in esecuzione, i moduli caricati e i file di configurazione del servizio e del sistema. -Il comando esegue anche programmi esterni per raccogliere ulteriori informazioni e memorizza l'output nell'archivio risultante.</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 232 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/it_IT/network.dita b/plugins/kimchi/ui/pages/help/it_IT/network.dita deleted file mode 100644 index a396d58..0000000 --- a/plugins/kimchi/ui/pages/help/it_IT/network.dita +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="it-it"> -<title>Rete</title> -<shortdesc>La pagina <wintitle>Rete</wintitle> visualizza le informazioni sulla connessione di rete.</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>Nome rete</dt> -<dd>Il nome della rete o il <uicontrol>valore predefinito</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Stato</dt> -<dd>Lo stato della rete, attivo (verde) o non attivo (rosso). </dd> -</dlentry><dlentry> -<dt>Tipo di rete</dt> -<dd>I tipo di rete, ad esempio, <uicontrol>NAT</uicontrol> (network -address translation).</dd> -</dlentry><dlentry> -<dt>Interfaccia</dt> -<dd>L'interfaccia di rete, ad esempio, <uicontrol>virbr0</uicontrol> (valore predefinito).</dd> -</dlentry><dlentry> -<dt>Spazio indirizzo</dt> -<dd>L'indirizzo IP.</dd> -</dlentry></dl></p> -<p>�� possibile selezionare le seguenti azioni:<ul> -<li rev="rev1">Selezionare <uicontrol>Avvia</uicontrol> per iniziare la connessione di rete.</li> -<li>Selezionare <uicontrol>Arresta</uicontrol> per terminare la connessione di rete.</li> -<li>Selezionare <uicontrol>Elimina</uicontrol> per eliminare le informazioni di connessione.</li> -</ul>Per creare una rete fare clic sull'icona <uicontrol>pi�� -(+)</uicontrol> nella parte in alto a destra del pannello.</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="it-it"> -<title>Crea una rete</title> -<shortdesc>Creare una rete.</shortdesc> -<csbody> -<p> <ol> -<li>Immettere il nome della rete.</li> -<li>Fare clic per selezionare il tipo di rete. <dl rev="rev1"><dlentry> -<dt><uicontrol>Isolata</uicontrol></dt> -<dd>La modalit�� isolata. Le macchine guest non possono inviare o ricevere comunicazioni verso o da i sistemi esterni.</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>La modalit�� NAT (Network Address Translation). La comunicazione dalle macchine guest ai sistemi esterni utilizza l'indirizzo IP host. I sistemi esterni non possono iniziare la comunicazione con le macchine guest.</dd> -</dlentry><dlentry> -<dt><uicontrol>Con bridge</uicontrol></dt> -<dd>La modalit�� con bridge. Le macchine guest possono comunicare con i sistemi esterni ed essere contattate dai sistemi esterni come se fossero sistemi fisici sulla rete. Per la modalit�� con bridge, �� necessario specificare informazioni aggiuntive su destinazione e VLAN.</dd> -</dlentry></dl></li> -<li>Fare clic su <uicontrol>Crea</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 230 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/it_IT/storage.dita b/plugins/kimchi/ui/pages/help/it_IT/storage.dita deleted file mode 100644 index 5a9bc25..0000000 --- a/plugins/kimchi/ui/pages/help/it_IT/storage.dita +++ /dev/null @@ -1,91 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="it-it"> -<title>Memoria</title> -<shortdesc>La pagina <wintitle>Memoria</wintitle> elenca i pool di memoria -disponibili, compresi i pool di memoria pronti per l'uso 'default' e 'ISO'. -Se si desidera utilizzare un proprio ISO, aggiungerlo al percorso del pool di memoria 'ISO'.</shortdesc> -<csbody> -<p>Per ciascun pool di memoria vengono visualizzate le seguenti informazioni:<dl> -<dlentry> -<dt>Nome</dt> -<dd>Il nome del pool di memoria e la percentuale utilizzata.</dd> -</dlentry><dlentry> -<dt>Stato</dt> -<dd>Lo stato del pool di memoria, attivo (verde) o non attivo (rosso). </dd> -</dlentry><dlentry> -<dt>Ubicazione</dt> -<dd>Il percorso file all'ubicazione del pool di memoria.</dd> -</dlentry><dlentry> -<dt>Tipo</dt> -<dd>Il tipo di pool di memoria, ad esempio, <uicontrol>dir</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Capacit��</dt> -<dd>La quantit�� di spazio nel pool di memoria.</dd> -</dlentry><dlentry> -<dt>Assegnato</dt> -<dd>La quantit�� di spazio gi�� assegnato nel pool di memoria.</dd> -</dlentry></dl></p> -<p>Per ciascun pool di memoria �� possibile selezionare le azioni indicate di seguito:<ul> -<li>Selezionare <uicontrol>Attiva</uicontrol> per attivare il pool di memoria in modo da poterlo utilizzare.</li> -<li>Selezionare <uicontrol>Disattiva</uicontrol> per disattivare un pool di memoria attivo.</li> -<li>Selezionare <uicontrol>Rimuovi definizione</uicontrol> per rimuovere un pool di memoria non attivo.</li> -</ul></p> -<p>Per visualizzare i dettagli del volume di memoria per un pool di memoria, fare clic sulla freccia sul lato destro della riga del pool di memoria. I dettagli includono:<dl><dlentry> -<dt>Tipo</dt> -<dd>Il tipo di volume, ad esempio, <uicontrol>file</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Formato</dt> -<dd>Il formato, che varia in base al tipo.</dd> -</dlentry><dlentry> -<dt>Capacit��</dt> -<dd>La dimensione del volume di memoria.</dd> -</dlentry><dlentry> -<dt>Assegnazione</dt> -<dd>La quantit�� di spazio gi�� assegnato nel pool di memoria.</dd> -</dlentry></dl>Per definire un pool di memoria fare clic sull'icona <uicontrol>pi�� -(+)</uicontrol> nella parte in alto a destra del pannello.</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="it-it"> -<title>Definire un pool di memoria</title> -<shortdesc> Definire un pool di memoria.</shortdesc> -<csbody> -<p> <ol> -<li>Nel campo <uicontrol>Nome pool di memoria</uicontrol>, immettere i l nome da utilizzare per definire il pool di memoria.</li> -<li>Nell'elenco <uicontrol>Tipo pool di memoria</uicontrol>, selezionare il tipo: <dl><dlentry> -<dt><uicontrol>DIR</uicontrol></dt> -<dd>Specifica un pool directory. Quando si seleziona <uicontrol>DIR</uicontrol>, -immettere il <uicontrol>Percorso di memoria</uicontrol> (percorso file al pool di memoria).</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>Specifica un pool NFS (Network File System). Quando si seleziona <uicontrol>NFS</uicontrol>, -immettere l'indirizzo <uicontrol>IP del server NFS</uicontrol> e il <uicontrol>Percorso NFS</uicontrol> (percorso alla directory esportata).</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>Specifica un pool basato su una destinazione assegnata su un server iSCSI. -Quando si seleziona <uicontrol>iSCSI</uicontrol>, immettere l'indirizzo IP del <uicontrol>Server iSCSI</uicontrol> e la <uicontrol>Destinazione</uicontrol> sul server iSCSI. �� possibile, facoltativamente, selezionare di aggiungere l'autenticazione iSCSI.</dd> -</dlentry><dlentry> -<dt><uicontrol>Logico</uicontrol></dt> -<dd>Specifica un pool di memoria di tipo volume logico. Selezionare l'ubicazione del dispositivo in <uicontrol>Percorso dispositivo</uicontrol>.</dd> -</dlentry><dlentry> -<dt><uicontrol>Canale a fibre ottiche SCSI</uicontrol></dt> -<dd>Specifica un pool basato su un canale a fibre ottiche SCSI. Selezionare quale adattatore -SCSI utilizzare.</dd> -</dlentry></dl></li> -<li>Fare clic su <uicontrol>Crea</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 233 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/it_IT/templates.dita b/plugins/kimchi/ui/pages/help/it_IT/templates.dita deleted file mode 100644 index 9b84b16..0000000 --- a/plugins/kimchi/ui/pages/help/it_IT/templates.dita +++ /dev/null @@ -1,115 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="it-it"> -<title>Modelli</title> -<shortdesc>La pagina <wintitle>Modelli</wintitle> visualizza i modelli di macchina virtuale definiti che �� possibile utilizzare per creare macchine guest KVM.</shortdesc> -<csbody> -<p>Per ciascun modello vengono visualizzate le seguenti informazioni:<dl> -<dlentry> -<dt>SO</dt> -<dd>Il nome del sistema operativo o della distribuzione.</dd> -</dlentry><dlentry> -<dt>Versione</dt> -<dd>La versione del sistema operativo o della distribuzione.</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>Il numero di processori definiti per il modello.</dd> -</dlentry><dlentry> -<dt>Memoria</dt> -<dd>La quantit�� di memoria ad accesso casuale da assegnare, in MB.</dd> -</dlentry></dl></p> -<p>Per ciascun modello �� possibile selezionare le azioni indicate di seguito:<ul> -<li>Selezionare <uicontrol>Modifica</uicontrol> per modificare il modello.</li> -<li>Selezionare <uicontrol>Elimina</uicontrol> per eliminare il modello.</li> -</ul>Per aggiungere un modello fare clic sull'icona <uicontrol>pi�� -(+)</uicontrol> nella parte in alto a destra del pannello.</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="it-it"> -<title>Modifica modello</title> -<shortdesc>Modificare un modello esistente.</shortdesc> -<csbody> -<p>Per ciascun modello vengono visualizzate le seguenti informazioni: <dl> -<dlentry> -<dt>Nome</dt> -<dd>Il nome del modello.</dd> -</dlentry><dlentry> -<dt>Fornitore</dt> -<dd>Il nome della societ�� che ha creato il sistema operativo o la distribuzione per il cui utilizzo �� configurato il modello.</dd> -</dlentry><dlentry> -<dt>Versione</dt> -<dd>La versione del sistema operativo o della distribuzione per il cui utilizzo �� configurato il modello.</dd> -</dlentry><dlentry> -<dt>Numero CPU</dt> -<dd>Il numero di processori definiti per il modello.</dd> -</dlentry><dlentry> -<dt>Memoria</dt> -<dd>La quantit�� di memoria in MB da assegnare alla macchina virtuale.</dd> -</dlentry><dlentry> -<dt>Disco</dt> -<dd>La dimensione del disco in GB.</dd> -</dlentry><dlentry> -<dt>CDROM</dt> -<dd>Il percorso file all'ubicazione del file ISO utilizzato per installare la macchina guest -KVM.</dd> -</dlentry><dlentry> -<dt>Pool di memoria</dt> -<dd>Un pool di memoria specifico o quello predefinito.</dd> -</dlentry><dlentry> -<dt>Rete</dt> -<dd>Le interfacce di rete predefinite disponibili per la macchina guest KVM. �� possibile selezionare pi�� reti.</dd> -</dlentry></dl> I campi non disabilitati possono essere modificati. Dopo aver modificato un campo, fare clic su <uicontrol>Salva</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>Aggiungi modello</title> -<shortdesc>Aggiungere un modello dal supporto di origine. -�� possibile aggiungere una propria immagine ISO al pool di memoria 'ISO' per la seguente individuazione.</shortdesc> -<csbody> -<p>Selezionare l'ubicazione del supporto di origine dalle seguenti opzioni:<dl> -<dlentry> -<dt>Immagine ISO locale</dt> -<dd>Selezionare questa opzione per eseguire la scansione dei pool di memoria alla ricerca di immagini ISO di installazione disponibili sul sistema.</dd> -</dlentry><dlentry> -<dt>Immagine ISO remota</dt> -<dd>Selezionare questa opzione per specificare un'ubicazione remota per un'immagine ISO di installazione.</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>Aggiungi modello - Immagine ISO locale</title> -<shortdesc>Aggiungere un modello da un'immagine ISO locale.</shortdesc> -<csbody> -<p>Vengono visualizzate le immagini ISO disponibili sul sistema.<dl><dlentry> -<dt>SO</dt> -<dd>Il nome del sistema operativo o della distribuzione.</dd> -</dlentry><dlentry> -<dt>Versione</dt> -<dd>La versione del sistema operativo o della distribuzione.</dd> -</dlentry><dlentry> -<dt>Dimensione</dt> -<dd>La dimensione dell'immagine ISO.</dd> -</dlentry></dl></p> -<p>Per creare un modello da un'immagine ISO scegliere tra le seguenti opzioni:<ul> -<li>Selezionare un'immagine ISO da cui creare un modello, quindi fare clic su <uicontrol>Crea modelli da ISO selezionato</uicontrol>.</li> -<li>Selezionare <uicontrol>Tutti</uicontrol> per creare un modello da ciascuna immagine ISO elencata, quindi fare clic su <uicontrol>Crea modelli da ISO selezionato</uicontrol>.</li> -<li>Se nei risultati della scansione non viene visualizzata l'immagine ISO che si desidera utilizzare, �� possibile selezionare dalle seguenti opzioni:<ul> -<li>Selezionare <uicontrol>Utilizzare un file ISO specifico</uicontrol> per specificare un percorso all'immagine ISO.</li> -<li>Fare clic su <uicontrol>Ricerca pi�� ISO</uicontrol> per ricercare pi�� immagini -ISO.</li> -</ul></li> -</ul></p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 229 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/ja_JP/Makefile.am b/plugins/kimchi/ui/pages/help/ja_JP/Makefile.am deleted file mode 100644 index f9c2f33..0000000 --- a/plugins/kimchi/ui/pages/help/ja_JP/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -ja_JP_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/ja_JP - -dist_ja_JP_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/ja_JP/guests.dita b/plugins/kimchi/ui/pages/help/ja_JP/guests.dita deleted file mode 100644 index 5dade49..0000000 --- a/plugins/kimchi/ui/pages/help/ja_JP/guests.dita +++ /dev/null @@ -1,172 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="ja-jp"> -<title>���������</title> -<shortdesc><wintitle>���������������</wintitle>������������������������������ KVM ������������������������������������������ -</shortdesc> -<csbody> -<p>������������������������������������������������������������ -<dl><dlentry> -<dt>������</dt> -<dd>��������������������������� -</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>��������������������������������������������������������� -</dd> -</dlentry><dlentry> -<dt>���������������������������</dt> -<dd>������������������������������������ (KB/���)��� -</dd> -</dlentry><dlentry> -<dt>���������������������</dt> -<dd>������������������������������ (KB/���)��� -</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>������������������������������������������������������������������������������������������������������������������������������������������<tm tmtype="tm" trademark="Linux">Linux</tm> -��������������������������������������������������������� -</dd> -</dlentry></dl></p> -<p>������������������������������������������������������������������������������������ -<dl> -<dlentry> -<dt>������������</dt> -<dd>������������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt>������ (���������������������)</dt> -<dd>��������������������������������������������������������������������������� -������������������������������������������������������������������������������������������������������������������������ -</dd> -</dlentry></dl> </p> -<p>��������������������������������������������������������������������� -<ul> -<li>������������������������������������������������������������������������������������������������������������<uicontrol>������������</uicontrol>��������������������� -</li> -<li>������������������������������������������������������������������<uicontrol>���������������������������</uicontrol>��������������������� -</li> -<li>������������������������������������<uicontrol>������������������</uicontrol>��������������������� -</li> -<li>���������������������������������������������������������������<uicontrol>������������</uicontrol>��������������������� -��������������������������������������������������������������� -</li> -<li>������������������������������<uicontrol>������������</uicontrol>��������������������� -</li> -</ul>��������� (���������������) ���������������������������������������������������<uicontrol>��������� (+)</uicontrol> ������������������������������������������������ -</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="ja-jp"> -<title>������������������������</title> -<shortdesc>��������������������������������������������������������������������������������������������������� -</shortdesc> -<csbody> -<p> <ol> -<li>������������������������������������������������������������������ -</li> -<li rev="rev1">��������������������������������������� -<ul> -<li>������������������������������������������������������������������������������������������������������������ -</li> -<li>������������������������������������������������<uicontrol>���������������������������������</uicontrol>������������������������������������������������������������ -</li> -</ul></li> -<li><uicontrol>������������</uicontrol>������������������������������������ -</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="ja-jp"> -<title>������������������</title> -<shortdesc>������������������������������������������������������������������ -������������������������������������������������������������������������������������������������ -������������������������������������������������������������������������������������������</shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>���������������������������������������<wintitle>������������</wintitle>������������������������������ -<dl> -<dlentry> -<dt>������</dt> -<dd>��������������������������� -(������������������������������������������������������)</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>��������������������������� -(���������������������������������������������������������������������������������������)</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������������ (MB ������)��� -(���������������������������������������������������������������������������������������)</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>��������������������������������������������������������������� (������������������) ���������������������������Linux ������������������������������������������������������������������������������ -</dd> -</dlentry></dl></p> -<p>���������������<wintitle>���������������������</wintitle>������������������������������ -</p> -<dl><dlentry> -<dt>���������������</dt> -<dd>������������������������������������ ISO ������������������������������������������������������ -</dd> -</dlentry></dl> -<p> ������������������������������������������������������������������������ -������������������������������������<uicontrol>������������</uicontrol>������������������������������������ -</p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="ja-jp"> -<title>������������������������������������������������������������������������</title> -<shortdesc rev="rev1">������������������������������������������������������������������������������������������������������������������������������������������������������ -������������������������������������������ CDROM ��������������� -������������������������������������������������������������������������������������������������ -</shortdesc> -<csbody> -<ol> -<li><wintitle>������������������������</wintitle>������������������<wintitle>���������������������</wintitle>��������������������� -</li> -<li>������������������������������������������������������<uicontrol>������������������������������ (/)</uicontrol> ��������������������������������������������������������������������� -ISO ������������������������������������<uicontrol>������������</uicontrol>��������������������������� -</li> -<li>������������������������������������������������������<uicontrol>������������������ (-)</uicontrol> ������������ 2 ��������������������������������������������������������� -���������������������<uicontrol>���OK���</uicontrol>��������������������������� -</li> -<li>������������������������������������������������������<uicontrol>��������������� (+)</uicontrol> ������������ 3 ��������������������������������������������������������� -������������������ ISO ������������������������������������<uicontrol>������������</uicontrol>��������������������������� -</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="ja-jp"> -<title>VM ��� CDROM ���������</title> -<shortdesc rev="rev1">������������������������������������������������������������ CDROM ������������������������������������������������ -</shortdesc> -<csbody> -<ol> -<li>��������������������������������������������������������������� -</li> -<li>���������������������������������������<uicontrol>���������������������������</uicontrol>��������������������� -</li> -<li>CDROM ���������������������������������������������������������hdc ������������������������������<uicontrol>������������������������������ (/)</uicontrol> ��������������������������������������� -</li> -<li><wintitle>���VM ��� CDROM ������������</wintitle>���������������ISO ������������������������������������������ -��������������� 2 ��������������������������������������������������� -</li> -<li><uicontrol>������������</uicontrol>������������������������������������ -</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 231 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/ja_JP/host.dita b/plugins/kimchi/ui/pages/help/ja_JP/host.dita deleted file mode 100644 index 3a0141c..0000000 --- a/plugins/kimchi/ui/pages/help/ja_JP/host.dita +++ /dev/null @@ -1,70 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="ja-jp"> -<title>���������</title> -<shortdesc><wintitle>���������������</wintitle>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ -</shortdesc> -<csbody> -<p>��������������������������������������������������������������������� -<ul> -<li>������������������������������������������������������������<uicontrol>���������������������������</uicontrol>��������������������� -</li> -<li>������������������������������������������������<uicontrol>���������������</uicontrol>��������������������� -</li> -<li>������������������������������ VNC ��������� (���������������������������������������) ���������������������������<uicontrol>������������</uicontrol>��������������������� -</li> -</ul></p> -<p>������������������������������������������������������������������������������������������������������������ -<dl> -<dlentry> -<dt>������������</dt> -<dd>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ (GB ������) ������������������������ -</dd> -</dlentry><dlentry> -<dt>������������������������</dt> -<dd>������������������������������������������ CPU��������������������������������������������������������������������������������������������������������������������������������������� -���������������������������������������������������������������������������������<uicontrol>���������������������������������������������������������������</uicontrol>������������������������������ -</dd> -</dlentry><dlentry> -<dt>������������������������</dt> -<dd>��������������������������������������������������������������������������������������������� -(������������������������������������������������������������������������������������������) ������������������������ -<uicontrol>���������������������</uicontrol>��������������������������������������������������������������������������������������������� -��������������������������������������������������������������������������������������������� -</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>������������������������������������������������������������������������������������������������������������������������������ -������������������������������������������������������������������������������������������������������������������ -������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ -��������������� Red Hat Enterprise Linux ��������� Fedora ���������������<filepath>yum</filepath> ������������������������������������������ -��������������� Ubuntu ��������� Debian ���������������<filepath>deb</filepath> ������������������������������������������������ -<p>yum ������������������������������������������������������������������������������������������������������������������������������������������������������������GPG ������������������������������������ -���������������������������������<uicontrol>������������</uicontrol>������������������������������������ -<uicontrol>������������</uicontrol>��������������� GPG ������������������������������������������������������������������ GPG ������������������ URL ������������������������������ -</p></dd> -</dlentry><dlentry> -<dt>���������������������������</dt> -<dd>��������������������������������������������������������� (������������������������������������) ������������������������ -������������������������������������������������������������������������������������������������������������������������������������������������������������������ -<p>���������������������������������<cmdname>sosreport</cmdname> ������������������������������������ -������������Red Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>���Fedora������������ Ubuntu ��������������������������������������������������������������� -��������������������������������������������������� (������������������������������������������������������������������������������������������������������������������������������������������������) ������������ .tar ��������������������������������� -������������������������������������������������������������������������������������������������������������������������������������������������������������ -</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 227 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/ja_JP/network.dita b/plugins/kimchi/ui/pages/help/ja_JP/network.dita deleted file mode 100644 index 5d9ce05..0000000 --- a/plugins/kimchi/ui/pages/help/ja_JP/network.dita +++ /dev/null @@ -1,83 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="ja-jp"> -<title> ������������������</title> -<shortdesc><wintitle>������������������������</wintitle>������������������������������������������������������������������������������������ -</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>���������������������</dt> -<dd>��������������������������� (��������� <uicontrol>default</uicontrol>) ��������� -</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������������������ (���) ��������������������������� (���) ��������� -</dd> -</dlentry><dlentry> -<dt>������������������������������</dt> -<dd>��������������������������������������������� <uicontrol>NAT</uicontrol> (���������������������������������������) ��������� -</dd> -</dlentry><dlentry> -<dt>������������������������</dt> -<dd>������������������������������������������������������������ <uicontrol>virbr0</uicontrol> (���������������) ��������� -</dd> -</dlentry><dlentry> -<dt>���������������������������</dt> -<dd>IP ���������������</dd> -</dlentry></dl></p> -<p>������������������������������������������������ -<ul> -<li rev="rev1">���������������������������������������������<uicontrol>������������</uicontrol>��������������������� -</li> -<li>���������������������������������������������<uicontrol>������������</uicontrol>��������������������� -</li> -<li>���������������������������������<uicontrol>������������</uicontrol>��������������������� -</li> -</ul>������������������������������������������������������������������<uicontrol>��������� (+)</uicontrol> ������������������������������������������������ -</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="ja-jp"> -<title>���������������������������</title> -<shortdesc>��������������������������������������� -</shortdesc> -<csbody> -<p> <ol> -<li>������������������������������������������������ -</li> -<li>��������������������������������������������������������������������� -<dl rev="rev1"><dlentry> -<dt><uicontrol>������</uicontrol></dt> -<dd>������������������ -��������������������������������������������������������������������������������������� -</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>��������������������������������������������������� -������������������������������������������������������������ IP ������������������������������������ -������������������������������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt><uicontrol>������������</uicontrol></dt> -<dd>��������������������������� -������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ -������������������������������������������������ VLAN ������������������������������������������������������ -</dd> -</dlentry></dl></li> -<li><uicontrol>������������</uicontrol>������������������������������������ -</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 230 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/ja_JP/storage.dita b/plugins/kimchi/ui/pages/help/ja_JP/storage.dita deleted file mode 100644 index f975e7a..0000000 --- a/plugins/kimchi/ui/pages/help/ja_JP/storage.dita +++ /dev/null @@ -1,120 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="ja-jp"> -<title>���������������</title> -<shortdesc><wintitle>���������������������</wintitle>��������������������������������� -��������������������������� (������������������������default������������������������������������ISO���������������������������������������) ��������������������������� -��������� ISO ���������������������������������������ISO���������������������������������������������������������������������</shortdesc> -<csbody> -<p>������������������������������������������������������������������������������ -<dl> -<dlentry> -<dt>������</dt> -<dd>��������������������������������������������������������� -</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>��������������������������������������������������������� (���) ��������������������������� (���) ��������� -</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>��������������������������������������������������������������������������� -</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������������������������������������������������������ <uicontrol>dir</uicontrol> ��������� -</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>������������������������������������������������������������������������������������ -</dd> -</dlentry></dl></p> -<p>��������������������������������������������������������������������������������������� -<ul> -<li>������������������������������������������������������������������������������������<uicontrol>������������������������������</uicontrol>��������������������� -</li> -<li>������������������������������������������������������������������������������������<uicontrol>���������������������������������</uicontrol>��������������������� -</li> -<li>������������������������������������������������������������������������<uicontrol>���������������������������</uicontrol>��������������������� -</li> -</ul></p> -<p>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� -������������������������������������ -<dl><dlentry> -<dt>���������</dt> -<dd>������������������������������������������ <uicontrol>file</uicontrol> ��������� -</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>��������������������������������������������������� -</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������������������������������������������������������������������������������ -</dd> -</dlentry></dl>���������������������������������������������������������������������������<uicontrol>��������� (+)</uicontrol> ������������������������������������������������ -</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="ja-jp"> -<title>������������������������������������</title> -<shortdesc> ������������������������������������������������ -</shortdesc> -<csbody> -<p> <ol> -<li><uicontrol>������������������������������������</uicontrol>��������������������������������������������������������������������������������������������������� -</li> -<li><uicontrol>���������������������������������������������</uicontrol>��������������������������������������������������������� -<dl><dlentry> -<dt><uicontrol>DIR</uicontrol></dt> -<dd>������������������������������������������������������ -<uicontrol>DIR</uicontrol> ������������������������<uicontrol>������������������������</uicontrol> (���������������������������������������������������) ������������������������������ -</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>������������������������������������������������������������������������������ -<uicontrol>NFS</uicontrol> ������������������������<uicontrol>NFS ������������ IP</uicontrol> ��������������������� <uicontrol>NFS ������</uicontrol> -(���������������������������������������������������������) ������������������������������ -</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>iSCSI ��������������������������������������������������������������������������������������������������������� -<uicontrol>iSCSI</uicontrol> ������������������������<uicontrol>iSCSI ������������</uicontrol> IP ������������������������ iSCSI ������������������<uicontrol>���������������</uicontrol>������������������������������ -���������������������iSCSI ������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt><uicontrol>������</uicontrol></dt> -<dd>������������������������������������������������������������������������ -������������������������������������<uicontrol>���������������������������</uicontrol>������������������������������ -</dd> -</dlentry><dlentry> -<dt><uicontrol>SCSI ������������������������������</uicontrol></dt> -<dd>SCSI ��������������������������������������������������������������������������� -������������ SCSI ��������������������������������������������� -</dd> -</dlentry></dl></li> -<li><uicontrol>������������</uicontrol>������������������������������������ -</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 233 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/ja_JP/templates.dita b/plugins/kimchi/ui/pages/help/ja_JP/templates.dita deleted file mode 100644 index 24dc2ab..0000000 --- a/plugins/kimchi/ui/pages/help/ja_JP/templates.dita +++ /dev/null @@ -1,150 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="ja-jp"> -<title>������������������</title> -<shortdesc><wintitle>������������������������</wintitle>������������������KVM ��������������������������������������������������������������������������������������������������������������������������� -</shortdesc> -<csbody> -<p>��������������������������������������������������������������������� -<dl> -<dlentry> -<dt>OS</dt> -<dd>��������������������������������������������������������������������������������������������� -</dd> -</dlentry><dlentry> -<dt>���������������</dt> -<dd>������������������������������������������������������������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>��������������������������������������������������������������������� -</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>��������������������������������������������������������������������� (MB ������)��� -</dd> -</dlentry></dl></p> -<p>������������������������������������������������������������������������������ -<ul> -<li>���������������������������������������<uicontrol>������������</uicontrol>��������������������� -</li> -<li>���������������������������������������<uicontrol>������������</uicontrol>��������������������� -</li> -</ul>������������������������������������������������������������������<uicontrol>��������� (+)</uicontrol> ������������������������������������������������ -</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="ja-jp"> -<title>���������������������������</title> -<shortdesc>������������������������������������������������ -</shortdesc> -<csbody> -<p>��������������������������������������������������������������������� -<dl> -<dlentry> -<dt>������</dt> -<dd>������������������������������ -</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt>���������������</dt> -<dd>������������������������������������������������������������������������������������������������������������������������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt>CPU ���</dt> -<dd>��������������������������������������������������������������������� -</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>��������������������������������������������������������� (MB ������)��� -</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������������������ (GB ������)��� -</dd> -</dlentry><dlentry> -<dt>CDROM</dt> -<dd>KVM ������������������������������������������������������������ ISO ������������������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt>���������������������������</dt> -<dd>������������������������������������������������������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt> ������������������</dt> -<dd>KVM ��������������������������������������������������������������������������������������������� -������������������������������������������������������������������ -</dd> -</dlentry></dl> ������������������������������������������������������������������������ -������������������������������������<uicontrol>������������</uicontrol>������������������������������������ -</p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>���������������������������</title> -<shortdesc>��������������������������������������������������������������������� -������������������������������������������������������ ISO ������������������ISO������������������������������������������������������</shortdesc> -<csbody> -<p>��������������������������������������������������������������������������������������������������������� -<dl> -<dlentry> -<dt>������������ ISO ������������</dt> -<dd>������������������������������������������������������������������������ ISO ������������������������������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt>������������ ISO ������������</dt> -<dd>������������������������������������������ ISO ��������������������������������������������������������������������� -</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>��������������������������� - ������������ ISO ������������</title> -<shortdesc>��������������������������������� ISO ������������������������������������ -</shortdesc> -<csbody> -<p>������������������������������ ISO ������������������������������������ -<dl><dlentry> -<dt>OS</dt> -<dd>��������������������������������������������������������������������������������������������� -</dd> -</dlentry><dlentry> -<dt>���������������</dt> -<dd>������������������������������������������������������������������������������������������������������ -</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>ISO ��������������������������� -</dd> -</dlentry></dl></p> -<p>��������������������� ISO ��������������������������������������������������������������������������������������������� -<ul> -<li>��������������������������������������������� ISO ������������������������������<uicontrol>��������������� ISO ������������������������������������</uicontrol>��������������������������� -</li> -<li>������������������������ ISO ������������������������������������������������������������������������<uicontrol>���������������</uicontrol>���������������������<uicontrol>��������������� ISO ������������������������������������</uicontrol>��������������������������� -</li> -<li>��������������� ISO ��������������������������������������������������������������������������������������������������������������� -<ul> -<li>ISO ���������������������������������������������<uicontrol>������������ ISO ������������������������������</uicontrol>��������������������� -</li> -<li>��������������� ISO ������������������������������������<uicontrol>���ISO ���������������������</uicontrol>��������������������������� -</li> -</ul></li> -</ul></p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 229 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/kimchi.css b/plugins/kimchi/ui/pages/help/kimchi.css deleted file mode 100644 index 32fae4a..0000000 --- a/plugins/kimchi/ui/pages/help/kimchi.css +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -BODY { - background: #FFFFFF; - margin-bottom: 1em; - margin-left: .5em; -} - -bold { - font-weight: bold; -} - -boldItalic { - font-weight: bold; - font-style: italic; -} - -italic { - font-style: italic; -} - -underlined { - text-decoration: underline; -} - -uicontrol { - font-weight: bold; -} - -filepath { - font-family: monospace, monospace; -}.option { - font-family: monospace, monospace; -} - -cmdname { - font-weight: bold; - font-family: monospace, monospace; -} - -.defparmname { - font-weight: bold; - text-decoration: underline; - font-family: monospace, monospace; -} - -.kwd { - font-weight: bold; -} - -.defkwd { - font-weight: bold; - text-decoration: underline; -} - -var { - font-style : italic; -} - -strongwintitle { - font-weight : bold; -} - -parmname { - font-weight: bold; - font-family: monospace, monospace; - white-space: nowrap; -} - -code { - font-family: monospace, monospace; -} - -pre { - font-family: monospace, monospace; -} - -CITE { - font-style: italic; -} - -EM { - font-style: italic; -} - -STRONG { - font-weight: bold; -} - -VAR { - font-style: italic; -} - -dt { - font-weight: bold; -} - -/*********************************************************** - * Basic fonts - ***********************************************************/ -body, -td, -th, -caption { - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 10pt; -} - -pre, code { - font-family: MS Courier New, Courier, monospace; -} - -h1, h2, h3 { - font-size: 12pt; - font-weight: bold; - color: #336699; -} - -h4 { - font-size: 10pt; - font-weight: bold; - color: #336699; -} - -/*********************************************************** - * Basic indents, padding, and margin - ***********************************************************/ -body { - color: black; - background-color: white; - margin: 0; - padding-top: 0.2em; - padding-left: 0.6em; - padding-right: 0.2em; - padding-bottom: 1em; -} - -h1, -h2, -h3, -h4, -h5, -h6 { - padding: 0; - margin-top: 1em; - margin-bottom: 0.75em; - margin-left: 0; - margin-right: 0; -} - -address, -dl, -li, -p { - padding: 0; - margin-top: 0.75em; - margin-bottom: 0.75em; - margin-left: 0; - margin-right: 0; - line-height: 125%; -} - -td dl { - margin-left: 2em; -} - -pre { - padding: 0; - margin-top: 0.75em; - margin-bottom: 0.75em; - margin-left: 2em; - margin-right: 0; -} - -ol, -ul { - padding: 0; - margin-top: 0.75em; - margin-bottom: 0.75em; - margin-left: 2.00em; - margin-right: 0; -} - -dd { - margin-left: 3.00em; - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -dt { - margin-left: 1.00em; - margin-top: 0.75em; -} diff --git a/plugins/kimchi/ui/pages/help/ko_KR/Makefile.am b/plugins/kimchi/ui/pages/help/ko_KR/Makefile.am deleted file mode 100644 index e441955..0000000 --- a/plugins/kimchi/ui/pages/help/ko_KR/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -ko_KR_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/ko_KR - -dist_ko_KR_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/ko_KR/guests.dita b/plugins/kimchi/ui/pages/help/ko_KR/guests.dita deleted file mode 100644 index 2d9f32b..0000000 --- a/plugins/kimchi/ui/pages/help/ko_KR/guests.dita +++ /dev/null @@ -1,119 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="ko-kr"> -<title>���������</title> -<shortdesc><wintitle>���������</wintitle> ��������������� ��������� KVM ������ ��������� ���������������.</shortdesc> -<csbody> -<p>��� ������������ ������ ������ ��������� ���������������.<dl><dlentry> -<dt>������</dt> -<dd>������ ��������� ���������������.</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>������ ��������� ������������ ������������������.</dd> -</dlentry><dlentry> -<dt>������������ I/O</dt> -<dd>������ ������������ ���/������(I/O) ������ ������(KB)���������.</dd> -</dlentry><dlentry> -<dt>��������� I/O</dt> -<dd>������ ��������� ���/������(I/O) ������ ������(KB)���������.</dd> -</dlentry><dlentry> -<dt>���������������</dt> -<dd>��������� ������ ��������� ���������������, ������������ ��������� ������ ������ <tm tmtype="tm" trademark="Linux">Linux</tm> ��������� ������������ ������������������.</dd> -</dlentry></dl></p> -<p>������ ������ ������������ ��� ��������������� ���������������.<dl> -<dlentry> -<dt>������ ������</dt> -<dd>������������ ������ ��������������� ���������������. </dd> -</dlentry><dlentry> -<dt>������(������ ������ ������)</dt> -<dd>������������ ��������� ��������� ��������� ���������������. ������������ ��������������� ��������� ������ ��������� ������������ ������������ ��������� ������ ������������.</dd> -</dlentry></dl> </p> -<p>��� ��������������� ������ ��������� ��������� ��� ������������.<ul> -<li>��������� ������ ��������� ������ ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> -<li>��������� ������ ��������� ��������������� <uicontrol>������ ������</uicontrol>��� ���������������.</li> -<li>������������ ������ ��������������� <uicontrol>������ ������</uicontrol>��� ���������������.</li> -<li>������ ������������ ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������. ������������ ������ ��������� ������ ��������� ��� ������������.</li> -<li>������������ ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> -</ul>��������� ������ ������ ��������� ��������������� ��������� ��������� ��������� ������ <uicontrol>���������(+)</uicontrol> ������������ ���������������.</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="ko-kr"> -<title>������ ������ ������</title> -<shortdesc>������ ��������������� ������������ ������ ��������� ���������������.</shortdesc> -<csbody> -<p> <ol> -<li>������ ��������� ������������ ��� ��������� ��������� ������������������.</li> -<li rev="rev1">��������������� ������������������. <ul> -<li>��������������� ������������ ������, ��������� ������������ ��������� ������������������.</li> -<li>��������������� ������ ������, <uicontrol>������������ ������</uicontrol>��� ������������ ��������������� ������������������.</li> -</ul></li> -<li><uicontrol>������</uicontrol>��� ������������������.</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="ko-kr"> -<title>��������� ������</title> -<shortdesc>������ ������ ��������� ��������� ���������������. ������ ��������� ������������ ��������� ������������ ��������� ��� ������������. -������ ��������� ������ ������������ ���������������. </shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>��� ������������ ������ ������ ��������� <wintitle>������</wintitle> ������ ���������������.<dl> -<dlentry> -<dt>������</dt> -<dd>������ ��������� ���������������(������������ ��������� ������������ ��������� ��� ������).</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>������������ ������������(������������ ������ ������ ������ ��� ��������� ������ ������������ ���������).</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>��������� ������(MB)���������(������������ ������ ������ ������ ��� ��������� ������ ������������ ���������).</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������������ ��������� ������ ��� ������ ������(���������������) ��������� ��������� Linux ��������� ������������ ��������� ������������������.</dd> -</dlentry></dl></p> -<p>������ ��������� <wintitle>������������</wintitle> ������ ���������������.</p> -<dl><dlentry> -<dt>������������</dt> -<dd>��������� ��������� ISO ��������� ��������� ���������������.</dd> -</dlentry></dl> -<p> ������ ������������ ������������ ������ ��������� ��������� ��� ������������. ��������� ��������� ������ <uicontrol>������</uicontrol>��� ���������������. </p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="ko-kr"> -<title>������������ ������ ������, ������ ������ ������</title> -<shortdesc rev="rev1">������ ��������� ������ ������������ ��������� ������, ������ ������ ��������� ��� ������������. ������������ ��������� CDROM������������. ������������ ��������� ��������������� ������ ��������� ������������������.</shortdesc> -<csbody> -<ol> -<li><wintitle>��������� ������</wintitle> ��������� <wintitle>������������</wintitle>��� ������������������.</li> -<li>������������ ��������� ��������������� <uicontrol>��������� ���������(/)</uicontrol>��� ������ ��� ������ ������������ ������������������. ISO ������ ��������� ������������ <uicontrol>������</uicontrol>��� ������������������.</li> -<li>������������ ��������� ��������������� <uicontrol>��������� ������(-)</uicontrol>��� ������ ��� ������ ������������ ������������������. ������ ��������� ������������ <uicontrol>������</uicontrol>��� ������������������.</li> -<li>������������ ��������� ��������������� ������ <uicontrol>��������� ������(+)</uicontrol>��� ������ ��� ������ ������������ ������������������. ������ ������ ��� ISO ������ ��������� ������������ <uicontrol>������</uicontrol>��� ������������������.</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="ko-kr"> -<title>VM��� CDROM ������</title> -<shortdesc rev="rev1">��������� ��������� ������ ������ ��������� ������ CDROM��� ������������ ������ ��� ������������.</shortdesc> -<csbody> -<ol> -<li>������ ��������� ������������������ ������������������.</li> -<li>������ ������������ <uicontrol>������ ������</uicontrol>��� ������������������.</li> -<li>CDROM��� ������ ��������� ��������� ������������ ������ hdc ������ ������ ������ <uicontrol>��������� ���������(/)</uicontrol> ������������ ������������������.</li> -<li><wintitle>VM��� CDROM ������</wintitle> ��������������� ISO ������ ��������� ������������������. ������ ��� ��������� ������ ���������������.</li> -<li><uicontrol>������</uicontrol>��� ������������������.</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 231 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/ko_KR/host.dita b/plugins/kimchi/ui/pages/help/ko_KR/host.dita deleted file mode 100644 index ee4a9c3..0000000 --- a/plugins/kimchi/ui/pages/help/ko_KR/host.dita +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="ko-kr"> -<title>���������</title> -<shortdesc><wintitle>���������</wintitle> ��������������� ��������� ������������ ������ ��������� ������������ ��� ������������ ������������ ������������ ������ ��� ������ ��������������� ������������ ��������� ��� ������������.</shortdesc> -<csbody> -<p>������������ ������ ������ ��������� ��������� ��� ������������.<ul> -<li>��������� ������������ ��������������� <uicontrol>��������� ������</uicontrol>��� ���������������.</li> -<li>��������� ������������ ������ ��������������� <uicontrol>������ ������</uicontrol>��� ���������������.</li> -<li>������ ������������ ������ ������ ������, ��������� ������������ ������ VNC ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> -</ul></p> -<p>������������ ������ ��������� ��������������� ������ ��������� ������������������.<dl> -<dlentry> -<dt>������ ������</dt> -<dd>��� ������������ ��������� ������ ������ ������, ������, ������ ������, ������������ ������, ��������� ������(GB) ������ ���������������.</dd> -</dlentry><dlentry> -<dt>��������� ������</dt> -<dd>��� ������������ ������������ CPU, ���������, ��������� I/O, ������������ I/O��� ������ ��������� ������������ ������������ ���������������. ��������� ������ ��������� ��� ��������� ��������� ��������������� <uicontrol>��� ������������ ������ ������ ��������� ������</uicontrol>��� ���������������.</dd> -</dlentry><dlentry> -<dt>��������������� ������������</dt> -<dd>��� ������������ ��������� ������, ������, ������������, ������������ ������������ ������ ��������� ��������������� ������ ������ ������������ ������ ��������� ���������������. <uicontrol>������ ������������</uicontrol>��� ������������ ��������� ������ ������������ ��������������� ��� ������������. ��������������� ������ ������ ������������ ��������� ������ ������������.</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>��� ������������ ��������� ������������ ��������� ������������ ���������������. ������������ ���������������, ������������ ���������������, ���������������, ��������� ��� ������������. ������������ ������������ ������������ ��������� ������������ ������������, ������������ ������������ ������������ ������������ ������������ ������������ ��� ������������. ������ ������������ Red Hat Enterprise Linux ������ Fedora��� ������, <filepath>yum</filepath> ������������ ��������� ��� ������������. -������ ������������ Ubuntu ������ Debian��� ������, <filepath>deb</filepath> ������������ ������������������.<p>yum ������������ ������������ ������, GPG ��������� ������������ ��� ������������ ������������ ������������ ������������ ��������� ��� ������������. -������������ ��������� ��� <uicontrol>������</uicontrol>��� ������������������. <uicontrol>���</uicontrol>��� ������������ GPG ��������� ������������ ��������� ��� ������������ ������ GPG ��� ��������� URL��� ������������������.</p></dd> -</dlentry><dlentry> -<dt>��������� ���������</dt> -<dd>��� ������������ ������ ��� ������ ��������� ��������� ��������� ������������ ���������������. -��� ��������� ������, ������ ��������� ������ ���������, ������, ������������ ������ ������ ��������� ��������� ��� ������������.<p>��������� ������������ <cmdname>sosreport</cmdname> ��������� ������������ ���������������. ������ Red Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora ��� Ubuntu ������������ ������ ���������������. ��� ��������� ������ ��� ������ ������(���: ������ ������ ������ ������, ��������� ������, ��������� ��� ��������� ������ ������)��� ������������ .tar ��������� ���������������. -������ ��� ��������� ������ ��������������� ������������ ������ ��������� ������������ ������ ��������������� ��� ��������� ���������������.</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 232 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/ko_KR/network.dita b/plugins/kimchi/ui/pages/help/ko_KR/network.dita deleted file mode 100644 index 451510f..0000000 --- a/plugins/kimchi/ui/pages/help/ko_KR/network.dita +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="ko-kr"> -<title>������������</title> -<shortdesc><wintitle>������������</wintitle> ��������������� ������������ ��������� ������ ��������� ���������������.</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>������������ ������</dt> -<dd>��������������� ������ ������ <uicontrol>���������</uicontrol>���������.</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>��������������� ������(��������� ������ ������, ������������ ������ ���������)���������. </dd> -</dlentry><dlentry> -<dt>������������ ������</dt> -<dd>������������ ���������������. ���: <uicontrol>NAT</uicontrol>(Network Address Translation)</dd> -</dlentry><dlentry> -<dt>���������������</dt> -<dd>������������ ������������������������. ���: <uicontrol>virbr0</uicontrol>(���������)</dd> -</dlentry><dlentry> -<dt>������ ������</dt> -<dd>IP ���������������.</dd> -</dlentry></dl></p> -<p>������ ��������� ��������� ��� ������������.<ul> -<li rev="rev1">������������ ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> -<li>������������ ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> -<li>������ ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> -</ul>��������������� ��������������� ������ ��������� ��������� ������ <uicontrol>���������(+)</uicontrol> ������������ ���������������.</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="ko-kr"> -<title>������������ ������</title> -<shortdesc>��������������� ���������������.</shortdesc> -<csbody> -<p> <ol> -<li>��������������� ��������� ������������������.</li> -<li>������������ ��������� ��������������� ������������������. <dl rev="rev1"><dlentry> -<dt><uicontrol>���������</uicontrol></dt> -<dd>������ ���������������. ������������ ������ ������������ ������ ��������� ������������ ������ ��� ������������.</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>Network Address Translation ���������������. ������������ ������ ��������������� ��������� ������������ ��������� IP ��������� ���������������. ������ ������������ ��������������� ��������� ��������� ��� ������������.</dd> -</dlentry><dlentry> -<dt><uicontrol>������������</uicontrol></dt> -<dd>��������� ���������������. ������������ ������ ������������ ��������� ��� ������ ������ ������������ ������������������ ��������� ��������������� ������������ ��������� ��� ������������. ��������� ��������� ������, ������ ��������� ��� VLAN ��������� ������������ ���������.</dd> -</dlentry></dl></li> -<li><uicontrol>������</uicontrol>��� ������������������.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 230 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/ko_KR/storage.dita b/plugins/kimchi/ui/pages/help/ko_KR/storage.dita deleted file mode 100644 index 2e6f5e8..0000000 --- a/plugins/kimchi/ui/pages/help/ko_KR/storage.dita +++ /dev/null @@ -1,86 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="ko-kr"> -<title>������������</title> -<shortdesc><wintitle>������������</wintitle> ��������������� ������ ��������� ��� ������ '������' ��� 'ISO' ������������ ������ ������������ ������ ��������� ������������ ������ ���������������. -��������� ������ ISO��� ��������������� ������ 'ISO' ������������ ��� ��������� ������������������.</shortdesc> -<csbody> -<p>��� ������������ ������ ������ ������ ��������� ���������������.<dl> -<dlentry> -<dt>������</dt> -<dd>������������ ������ ������ ��� ������������������.</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������ ������ ������(��������� ������ ������, ������������ ������ ���������)���������. </dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������ ������ ��������� ������ ������ ���������������.</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������ ������ ���������������. ���: <uicontrol>dir</uicontrol></dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������ ��������� ��������� ������������.</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������������ ������ ������ ��������� ��������� ������������.</dd> -</dlentry></dl></p> -<p>��� ������������ ��������� ������ ��������� ��������� ��� ������������.<ul> -<li>������ ��������������� ������������ ������ ������������������ <uicontrol>���������</uicontrol>��� ���������������.</li> -<li>������������ ������ ��������������������� <uicontrol>������������</uicontrol>��� ���������������.</li> -<li>��������� ������������ ������ ��������������� <uicontrol>������ ������</uicontrol>��� ���������������.</li> -</ul></p> -<p>������������ ������ ������ ������������ ������ ��������������� ��������������� ������������ ��� ������ ������������ ������ ������������ ������������������. ������������������ ��������� ���������������.<dl><dlentry> -<dt>������</dt> -<dd>��������� ���������������. ���: <uicontrol>������</uicontrol></dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>��������� ��������� ������ ���������������.</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������ ��������� ���������������.</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������ ������ ������ ��������� ��������� ������������.</dd> -</dlentry></dl>������������ ������ ��������������� ������ ��������� ��������� ������ <uicontrol>���������(+)</uicontrol> ������������ ���������������.</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="ko-kr"> -<title>������������ ��� ������</title> -<shortdesc> ������������ ������ ���������������.</shortdesc> -<csbody> -<p> <ol> -<li><uicontrol>������������ ��� ������</uicontrol> ������������, ������������ ������ ������������ ��� ��������� ��������� ������������������.</li> -<li><uicontrol>������������ ��� ������</uicontrol> ������������ ������ ��������� ������������������. <dl><dlentry> -<dt><uicontrol>DIR</uicontrol></dt> -<dd>������������ ������ ���������������. <uicontrol>DIR</uicontrol> ��������� ��������� ������, <uicontrol>������������ ������</uicontrol>(������������ ������ ������ ������)��� ���������������.</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>������������ ������ ��������� ������ ���������������. <uicontrol>NFS</uicontrol>��� ��������� ������, <uicontrol>NFS ������ IP ������</uicontrol> ��� <uicontrol>NFS ������</uicontrol>(������ ��������������� ������)��� ���������������.</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>iSCSI ��������� ��������� ��������� ������������ ������ ���������������. -<uicontrol>iSCSI</uicontrol>��� ��������� ������, iSCSI ��������� ������ <uicontrol>iSCSI ������ IP ������</uicontrol> ��� <uicontrol>������</uicontrol>��� ���������������. ���������������, iSCSI ��������� ��������������� ��������� ��� ������������.</dd> -</dlentry><dlentry> -<dt><uicontrol>���������</uicontrol></dt> -<dd>��������� ������ ������������ ������ ���������������. <uicontrol>������ ������</uicontrol>������ ��������� ������ ��������� ���������������.</dd> -</dlentry><dlentry> -<dt><uicontrol>SCSI ��������� ������</uicontrol></dt> -<dd>SCSI ��������� ��������� ������������ ������ ���������������. ��������� SCSI ������������ ���������������.</dd> -</dlentry></dl></li> -<li><uicontrol>������</uicontrol>��� ������������������.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 233 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/ko_KR/templates.dita b/plugins/kimchi/ui/pages/help/ko_KR/templates.dita deleted file mode 100644 index de16d6e..0000000 --- a/plugins/kimchi/ui/pages/help/ko_KR/templates.dita +++ /dev/null @@ -1,111 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="ko-kr"> -<title>������������</title> -<shortdesc><wintitle>������������</wintitle> ��������������� KVM ������������ ������������ ��� ��������� ��� ������ ��������� ������ ������ ��������������� ���������������.</shortdesc> -<csbody> -<p>��� ��������������� ������ ������ ��������� ���������������.<dl> -<dlentry> -<dt>OS</dt> -<dd>������ ������ ������ ��������� ���������������.</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������ ������ ������ ��������� ���������������.</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>��������������� ������ ��������� ��������������� ������������.</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>��������� RAM(Random Access Memory)��� ���(MB)���������.</dd> -</dlentry></dl></p> -<p>��� ������������������ ������ ��������� ��������� ��� ������������.<ul> -<li>��������������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> -<li>��������������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> -</ul>��������������� ��������������� ������ ��������� ��������� ������ <uicontrol>���������(+)</uicontrol> ������������ ���������������.</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="ko-kr"> -<title>������������ ������</title> -<shortdesc>������ ��������������� ���������������.</shortdesc> -<csbody> -<p>��� ��������������� ������ ������ ��������� ���������������. <dl> -<dlentry> -<dt>������</dt> -<dd>��������������� ���������������.</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>��������������� ��������������� ��������� ������ ������ ������ ��������� ��������� ��������� ���������������.</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>��������������� ��������������� ��������� ������ ������ ������ ��������� ���������������.</dd> -</dlentry><dlentry> -<dt>CPU ���</dt> -<dd>��������������� ������ ��������� ��������������� ������������.</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������ ��������� ��������� ��������� ������(MB)���������.</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>��������� ������(GB)���������.</dd> -</dlentry><dlentry> -<dt>CDROM</dt> -<dd>KVM ������������ ������������ ��� ��������� ISO ��������� ��������� ������ ������ ���������������.</dd> -</dlentry><dlentry> -<dt>������������ ���</dt> -<dd>������ ������������ ��� ������ ������ ������������ ������������.</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>KVM ������������ ������ ��������� ������ ������������ ������������������������. ������ ��������������� ��������� ��� ������������.</dd> -</dlentry></dl> ������ ������������ ������������ ������ ��������� ��������� ��� ������������. ��������� ��������� ������ <uicontrol>������</uicontrol>��� ���������������. </p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>������������ ������</title> -<shortdesc>������ ��������������� ��������������� ���������������. ������ ��������� ������ 'ISO' ������������ ������ ��������� ������ ISO ������������ ��������� ��� ������������. </shortdesc> -<csbody> -<p>������ ������ ��������� ������ ��������� ��������� ������������������.<dl> -<dlentry> -<dt>������ ISO ���������</dt> -<dd>��������������� ������ ��������� ������ ISO ������������ ������������ ������ ��������������� ���������������.</dd> -</dlentry><dlentry> -<dt>������ ISO ���������</dt> -<dd>������ ISO ������������ ������ ��������� ��������������� ���������������.</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>������������ ������ - ������ ISO ���������</title> -<shortdesc>������ ISO ������������������ ��������������� ���������������.</shortdesc> -<csbody> -<p>��������������� ������ ��������� ISO ������������ ���������������.<dl><dlentry> -<dt>OS</dt> -<dd>������ ������ ������ ��������� ���������������.</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������ ������ ������ ��������� ���������������.</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>ISO ������������ ���������������.</dd> -</dlentry></dl></p> -<p>ISO ������������������ ��������������� ��������������� ������ ������ ��������� ������������������.<ul> -<li>��������������� ������������ ������ ISO ������������ ��������� ��� <uicontrol>��������� ISO��������� ������������ ������</uicontrol>��� ���������������.</li> -<li>��������� ��� ISO ������������������ ��������������� ��������������� <uicontrol>������</uicontrol>��� ��������� ��� <uicontrol>��������� ISO��������� ������������ ������</uicontrol>��� ���������������.</li> -<li>��������������� ISO ������������ ������ ��������� ������������ ������ ������, ������ ������ ��������� ��������� ��� ������������.<ul> -<li>ISO ������������ ��������� ��������������� <uicontrol>������ ISO ��������� ��������������� ���������.</uicontrol>��� ���������������.</li> -<li>������ ISO ������������ ��������������� <uicontrol>������ ISO ������</uicontrol>��� ���������������.</li> -</ul></li> -</ul></p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 229 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/pt_BR/Makefile.am b/plugins/kimchi/ui/pages/help/pt_BR/Makefile.am deleted file mode 100644 index 7fc2cb0..0000000 --- a/plugins/kimchi/ui/pages/help/pt_BR/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -pt_BR_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/pt_BR - -dist_pt_BR_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/pt_BR/guests.dita b/plugins/kimchi/ui/pages/help/pt_BR/guests.dita deleted file mode 100644 index ac58d5c..0000000 --- a/plugins/kimchi/ui/pages/help/pt_BR/guests.dita +++ /dev/null @@ -1,137 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="pt-br"> -<title>M��quinas Virtuais</title> -<shortdesc>A p��gina <wintitle>M��quinas Virtuais</wintitle> lista as m��quinas virtuais -KVM definidas.</shortdesc> -<csbody> -<p>Para cada convidado, as informa����es a seguir s��o exibidas:<dl><dlentry> -<dt>Nome</dt> -<dd>Nome da m��quina virtual.</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>Porcentagem de utiliza����o do processador na m��quina virtual.</dd> -</dlentry><dlentry> -<dt>E/S de rede</dt> -<dd>Taxa de transmiss��o de entrada/sa��da de rede em KB por segundo.</dd> -</dlentry><dlentry> -<dt>E/S de disco</dt> -<dd>Taxa de transmiss��o de entrada/sa��da de disco em KB por segundo.</dd> -</dlentry><dlentry> -<dt>Livetile</dt> -<dd>Estado do console do sistema operacional guest ou um ��cone que representa -a distribui����o <tm tmtype="tm" trademark="Linux">Linux</tm> se o -convidado n��o estiver ativo.</dd> -</dlentry></dl></p> -<p>Os ��cones de a����es a seguir s��o exibidos para cada convidado:<dl> -<dlentry> -<dt>Reiniciar</dt> -<dd>Clique para Reiniciar o convidado. </dd> -</dlentry><dlentry> -<dt>Energia (iniciar ou parar)</dt> -<dd>Clique para ligar ou desligar o convidado. Se o ��cone estiver vermelho, -a energia est�� desligada; se o ��cone estiver verde, a energia est�� ligada.</dd> -</dlentry></dl> </p> -<p>As a����es a seguir podem ser selecionadas para cada convidado:<ul> -<li>Selecione <uicontrol>Conectar</uicontrol> para conectar-se ao console -remoto para o sistema operacional guest.</li> -<li>Selecione <uicontrol>Gerenciar m��dia</uicontrol> para alterar o caminho -para a m��dia de instala����o.</li> -<li>Selecione <uicontrol>Reiniciar</uicontrol> para Reiniciar o convidado.</li> -<li>Selecione <uicontrol>Editar</uicontrol> para editar as propriedades de um -convidado existente. Os M��quinas Virtuais podem ser editados somente quando interrompidos.</li> -<li>Selecione <uicontrol>Excluir</uicontrol> para excluir o convidado.</li> -</ul>Para criar um convidado, ou m��quina virtual, clique no ��cone <uicontrol>mais -(+)</uicontrol> na parte superior direita da p��gina.</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="en-us"> -<title>Criar m��quina virtual</title> -<shortdesc>Crie uma m��quina virtual usando um modelo existente.</shortdesc> -<csbody> -<p> <ol> -<li>Digite o nome a ser usado para identificar a m��quina virtual.</li> -<li rev="rev1">Selecione um modelo. <ul> -<li>Se existirem modelos, selecione a partir dos modelos exibidos.</li> -<li>Se n��o existir nenhum modelo, clique em <uicontrol>Criar um modelo</uicontrol> para -criar um modelo.</li> -</ul></li> -<li>Clique em <uicontrol>Criar</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="en-us"> -<title>Editar convidado</title> -<shortdesc>Edite as propriedades de uma m��quina virtual existente. Algumas propriedades podem ser editadas enquanto o convidado est�� interrompido. Outras entrar��o em vigor na pr��xima inicializa����o.</shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>Para cada convidado, as informa����es a seguir s��o exibidas na guia <wintitle>Geral</wintitle>:<dl> -<dlentry> -<dt>Nome</dt> -<dd>Nome da m��quina virtual. (somente pode ser editado enquanto o convidado est�� interrompido)</dd> -</dlentry><dlentry> -<dt>CPUs</dt> -<dd>N��mero de processadores. (se o convidado estiver em execu����o, uma nova quantia entrar�� em vigor na pr��xima inicializa����o)</dd> -</dlentry><dlentry> -<dt>Mem��ria</dt> -<dd>Quantia de mem��ria em MB. (se o convidado estiver em execu����o, uma nova quantia entrar�� em vigor na pr��xima inicializa����o)</dd> -</dlentry><dlentry> -<dt>��cone</dt> -<dd>Imagem gr��fica representando a distribui����o Linux a ser exibida -no lugar do status atual (Livetile) quando o convidado n��o est�� ativo.</dd> -</dlentry></dl></p> -<p>As informa����es a seguir s��o exibidas na guia <wintitle>Armazenamento</wintitle>.</p> -<dl><dlentry> -<dt>Armazenamento</dt> -<dd>Exibe o local do arquivo ISO usado para instala����o.</dd> -</dlentry></dl> -<p> Os campos que n��o est��o desativados podem ser editados. Depois de editar um campo, -clique em <uicontrol>Salvar</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="en-us"> -<title>Incluir, substituir ou remover um dispositivo de armazenamento</title> -<shortdesc rev="rev1">�� poss��vel incluir, substituir ou remover um dispositivo de armazenamento -para sua m��quina virtual. O ��nico dispositivo suportado �� CD-ROM. Para editar -seus dispositivos de armazenamento, siga estas etapas:</shortdesc> -<csbody> -<ol> -<li>Na janela <wintitle>Editar convidado</wintitle>, selecione <wintitle>Armazenamento</wintitle>.</li> -<li>Para substituir um dispositivo de armazenamento, clique no primeiro ��cone com a <uicontrol>barra -laranja (/)</uicontrol>. Insira o caminho do arquivo ISO e clique em <uicontrol>Substituir</uicontrol>.</li> -<li>Para remover um dispositivo de armazenamento, clique no segundo ��cone com o <uicontrol>tra��o -vermelho (-)</uicontrol>. Confirme a exclus��o e clique em <uicontrol>OK</uicontrol>.</li> -<li>Para incluir um dispositivo de armazenamento, clique no terceiro ��cone com o <uicontrol>sinal de -mais (+)</uicontrol> verde. Insira um nome de dispositivo e um caminho de arquivo ISO e clique em <uicontrol>Conectar</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="en-us"> -<title>Substituir um CD-ROM da VM</title> -<shortdesc rev="rev1">�� poss��vel substituir o conte��do do CD-ROM para -uma m��quina virtual ap��s a instala����o ser conclu��da.</shortdesc> -<csbody> -<ol> -<li>Assegure-se de que a m��quina virtual esteja iniciada.</li> -<li>No menu A����es, selecione <uicontrol>Gerenciar m��dia</uicontrol>.</li> -<li>Para alterar o que est�� atualmente carregado no CD-ROM, clique no ��cone <uicontrol>barra -laranja (/)</uicontrol> pr��ximo ao campo hdc.</li> -<li>Na p��gina <wintitle>Substituir um CD-ROM da VM</wintitle>, insira -o caminho do arquivo ISO. Os outros dois campos s��o somente leitura.</li> -<li>Clique em <uicontrol>Substituir</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 231 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/pt_BR/host.dita b/plugins/kimchi/ui/pages/help/pt_BR/host.dita deleted file mode 100644 index 88f7eb2..0000000 --- a/plugins/kimchi/ui/pages/help/pt_BR/host.dita +++ /dev/null @@ -1,74 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="pt-br"> -<title>Host</title> -<shortdesc>A p��gina <wintitle>Host</wintitle> mostra informa����es sobre -o sistema host e permite encerrar, reiniciar e conectar -ao host.</shortdesc> -<csbody> -<p>�� poss��vel executar as a����es a segur no host:<ul> -<li>Selecione <uicontrol>Encerrar</uicontrol> para encerrar o sistema -host.</li> -<li>Selecione <uicontrol>Reiniciar</uicontrol> para reiniciar o sistema host.</li> -<li>Selecione <uicontrol>Conectar</uicontrol> para abrir uma conex��o VNC -para o sistema host, se ele j�� n��o estiver conectado.</li> -</ul></p> -<p>Clique nas se����es a seguir para exibir informa����es sobre o host:<dl> -<dlentry> -<dt>Informa����es b��sicas</dt> -<dd>Esta se����o exibe a distribui����o do sistema operacional do host, -a vers��o e o nome do c��digo, bem como o tipo de processador e quantia de -mem��ria em GB.</dd> -</dlentry><dlentry> -<dt>Estat��sticas do sistema</dt> -<dd>Esta se����o exibe gr��ficos para mostrar estat��sticas para CPU, mem��ria, -E/S de disco e E/S de rede para o host. Selecione <uicontrol>Coletando -dados depois de sair desta p��gina</uicontrol> para continuar a coletar dados -quando a guia do host estiver fora de visualiza����o.</dd> -</dlentry><dlentry> -<dt>Atualiza����es de software</dt> -<dd>Esta se����o exibe informa����es de todos os pacotes que -possuem atualiza����es dispon��veis, incluindo nome do pacote, vers��o, arquitetura -e reposit��rio. �� poss��vel atualizar todos os pacotes listados selecionando <uicontrol>Atualizar -todos</uicontrol>. N��o �� poss��vel selecionar pacotes individuais para atualiza����es.</dd> -</dlentry><dlentry> -<dt>Reposit��rios</dt> -<dd>Esta se����o exibe reposit��rios que est��o associados ao -sistema host. �� poss��vel incluir, ativar, editar ou remover reposit��rios. Incluir -um reposit��rio o associa com o sistema host enquanto ativar um reposit��rio -permite que o host o acesse. Se o seu sistema for Red Hat Enterprise -Linux ou Fedora, ser�� poss��vel incluir reposit��rios <filepath>yum</filepath>. -Se o seu sistema for Ubuntu ou Debian, inclua reposit��rios <filepath>deb</filepath>.<p>Se -voc�� estiver trabalhando com reposit��rios yum, ser�� poss��vel incluir uma verifica����o de GPG para -verificar se um pacote desse reposit��rio n��o foi corrompido. -Selecione um reposit��rio e, em seguida, <uicontrol>Editar</uicontrol>. Selecione <uicontrol>Sim</uicontrol> para -ativar a Verifica����o de GPG e, em seguida, insira uma URL no arquivo-chave de GPG para o -reposit��rio.</p></dd> -</dlentry><dlentry> -<dt>Relat��rios de depura����o</dt> -<dd>Esta se����o exibe relat��rios de depura����o, incluindo nome e caminho do arquivo. -�� poss��vel selecionar a partir das op����es para gerar um novo relat��rio ou renomear, remover -ou fazer o download de um relat��rio existente.<p>O relat��rio de depura����o �� gerado usando -o comando <cmdname>sosreport</cmdname>. Ele est�� dispon��vel para distribui����es -Red Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora -e Ubuntu. O comando gera um arquivo .tar que cont��m -informa����es de configura����o e de diagn��stico, como vers��o do kernel -em execu����o, m��dulos carregados e arquivos de configura����o de sistema e de servi��o. -O comando tamb��m executa programas externos para coletar informa����es adicionais -e armazena essa sa��da no archive resultante.</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 232 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/pt_BR/network.dita b/plugins/kimchi/ui/pages/help/pt_BR/network.dita deleted file mode 100644 index 1585298..0000000 --- a/plugins/kimchi/ui/pages/help/pt_BR/network.dita +++ /dev/null @@ -1,72 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="pt-br"> -<title>Rede</title> -<shortdesc>A p��gina <wintitle>Rede</wintitle> exibe informa����es -sobre a conex��o de rede.</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>Nome da rede</dt> -<dd>Nome da rede ou <uicontrol>padr��o</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Estado</dt> -<dd>Estado da rede, ativo (verde) ou inativo (vermelho). </dd> -</dlentry><dlentry> -<dt>Tipo de rede</dt> -<dd>Tipo de rede, por exemplo, <uicontrol>NAT</uicontrol> (convers��o -de endere��o de rede).</dd> -</dlentry><dlentry> -<dt>Interface</dt> -<dd>Interface de rede, por exemplo, <uicontrol>virbr0</uicontrol> (padr��o).</dd> -</dlentry><dlentry> -<dt>Espa��o de endere��o</dt> -<dd>Endere��o IP.</dd> -</dlentry></dl></p> -<p>As a����es a seguir podem ser selecionadas:<ul> -<li rev="rev1">Selecione <uicontrol>Iniciar</uicontrol> para iniciar a conex��o -de rede.</li> -<li>Selecione <uicontrol>Parar</uicontrol> para terminar a conex��o de rede.</li> -<li>Selecione <uicontrol>Excluir</uicontrol> para excluir as informa����es -de conex��o.</li> -</ul>Para criar uma rede, clique no ��cone <uicontrol>mais (+)</uicontrol> na -parte superior direita da exibi����o.</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="en-us"> -<title>Criar uma rede</title> -<shortdesc>Crie uma rede.</shortdesc> -<csbody> -<p> <ol> -<li>Digite o nome da rede.</li> -<li>Clique para selecionar o tipo de rede. <dl rev="rev1"><dlentry> -<dt><uicontrol>Isolado</uicontrol></dt> -<dd>Modo isolado. Os M��quinas Virtuais n��o podem enviar ou receber comunica����o para -ou de sistemas externos.</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>Modo de Convers��o de Endere��o de Rede. A comunica����o de M��quinas Virtuais com -sistemas externos usa o endere��o IP do host. Os sistemas externos n��o podem -iniciar a comunica����o com os M��quinas Virtuais.</dd> -</dlentry><dlentry> -<dt><uicontrol>bridged</uicontrol></dt> -<dd>Modo bridged. Os M��quinas Virtuais podem se comunicar com os sistemas externos e -ser contatados por sistemas externos como se fossem sistemas f��sicos -na rede. Para o modo bridged, devem-se especificar informa����es adicionais -de destino e de VLAN.</dd> -</dlentry></dl></li> -<li>Clique em <uicontrol>Criar</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 230 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/pt_BR/storage.dita b/plugins/kimchi/ui/pages/help/pt_BR/storage.dita deleted file mode 100644 index 03c8cab..0000000 --- a/plugins/kimchi/ui/pages/help/pt_BR/storage.dita +++ /dev/null @@ -1,102 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="pt-br"> -<title>Armazenamento</title> -<shortdesc>A p��gina <wintitle>Armazenamento</wintitle> lista os conjuntos de armazenamentos dispon��veis, inclusive o conjunto de armazenamentos 'padr��o' e 'ISO' integrado. -Se desejar usar seu pr��prio ISO, inclua-o em seu caminho do conjunto de armazenamentos 'ISO'.</shortdesc> -<csbody> -<p>Para cada storage pool, as informa����es a seguir s��o exibidas:<dl> -<dlentry> -<dt>Nome</dt> -<dd>Nome do storage pool e porcentagem usada.</dd> -</dlentry><dlentry> -<dt>Estado</dt> -<dd>Estado do storage pool, ativo (verde) ou inativo (vermelho). </dd> -</dlentry><dlentry> -<dt>Local</dt> -<dd>Caminho do arquivo para o local do storage pool.</dd> -</dlentry><dlentry> -<dt>Tipo</dt> -<dd>Tipo de storage pool, por exemplo, <uicontrol>dir</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Capacidade</dt> -<dd>Quantia de espa��o no storage pool.</dd> -</dlentry><dlentry> -<dt>Alocado</dt> -<dd>Quantia de espa��o j�� alocado no storage pool.</dd> -</dlentry></dl></p> -<p>As a����es a seguir podem ser selecionadas para cada storage pool:<ul> -<li>Selecione <uicontrol>Ativar</uicontrol> para ativar o storage pool -para que ele possa ser usado.</li> -<li>Selecione <uicontrol>Desativar</uicontrol> para desativar um storage pool -ativo.</li> -<li>Selecione <uicontrol>Indefinir</uicontrol> para remover um storage pool -inativo.</li> -</ul></p> -<p>Para exibir detalhes do volume de armazenamento para um storage pool, clique na -seta no lado direito da linha do storage pool. Os detalhes incluem -os seguintes:<dl><dlentry> -<dt>Tipo</dt> -<dd>O tipo de volume, por exemplo, <uicontrol>arquivo</uicontrol>.</dd> -</dlentry><dlentry> -<dt>Formato</dt> -<dd>O formato, que varia dependendo do tipo.</dd> -</dlentry><dlentry> -<dt>Capacidade</dt> -<dd>Tamanho do volume de armazenamento.</dd> -</dlentry><dlentry> -<dt>Aloca����o</dt> -<dd>Quantia de espa��o j�� alocado no storage pool.</dd> -</dlentry></dl>Para definir um storage pool, clique no ��cone <uicontrol>mais -(+)</uicontrol> na parte superior direita da exibi����o.</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="en-us"> -<title>Definir um storage pool</title> -<shortdesc> Defina um storage pool.</shortdesc> -<csbody> -<p> <ol> -<li>No campo <uicontrol>Nome do storage pool</uicontrol>, digite o -nome a ser usado para identificar o storage pool.</li> -<li>Na lista <uicontrol>Tipo de storage pool</uicontrol>, selecione o -tipo: <dl><dlentry> -<dt><uicontrol>DIR</uicontrol></dt> -<dd>Especifica um conjunto de diret��rios. Ao selecionar <uicontrol>DIR</uicontrol>, -digite o <uicontrol>Caminho do armazenamento</uicontrol> (caminho do arquivo para o -storage pool).</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>Especifica um conjunto de sistema de arquivos de rede. Ao selecionar <uicontrol>NFS</uicontrol>, -digite o endere��o <uicontrol>IP do servidor NFS</uicontrol> e o <uicontrol>Caminho -do NFS</uicontrol> (caminho do diret��rio exportado).</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>Especifica um conjunto com base em um destino alocado em um servidor iSCSI. -Ao selecionar <uicontrol>iSCSI</uicontrol>, digite o endere��o IP do <uicontrol>Servidor -iSCSI</uicontrol> e o <uicontrol>Destino</uicontrol> no -servidor iSCSI. Opcionalmente, �� poss��vel selecionar para incluir a autentica����o iSCSI.</dd> -</dlentry><dlentry> -<dt><uicontrol>L��gico</uicontrol></dt> -<dd>Especifica um storage pool do volume l��gico. Selecione o local para -o dispositivo em <uicontrol>Caminho do dispositivo</uicontrol>.</dd> -</dlentry><dlentry> -<dt><uicontrol>Fibre Channel SCSI</uicontrol></dt> -<dd>Especifica um conjunto com base em um Fibre Channel SCSI. Selecione qual -adaptador SCSI deve ser usado.</dd> -</dlentry></dl></li> -<li>Clique em <uicontrol>Criar</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 233 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/pt_BR/templates.dita b/plugins/kimchi/ui/pages/help/pt_BR/templates.dita deleted file mode 100644 index f3c6515..0000000 --- a/plugins/kimchi/ui/pages/help/pt_BR/templates.dita +++ /dev/null @@ -1,127 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="pt-br"> -<title>Modelos</title> -<shortdesc>A p��gina <wintitle>Modelos</wintitle> mostra os modelos de -m��quina virtual definidos que podem ser usados para criar M��quinas Virtuais do KVM.</shortdesc> -<csbody> -<p>Para cada modelo, as informa����es a seguir s��o exibidas:<dl> -<dlentry> -<dt>S.O.</dt> -<dd>Nome do sistema operacional ou distribui����o.</dd> -</dlentry><dlentry> -<dt>Vers��o</dt> -<dd>Vers��o do sistema operacional ou distribui����o.</dd> -</dlentry><dlentry> -<dt>CPUs</dt> -<dd>N��mero de processadores que est��o definidos para o modelo.</dd> -</dlentry><dlentry> -<dt>Mem��ria</dt> -<dd>Quantia de mem��ria de acesso aleat��rio a ser alocada, em MB.</dd> -</dlentry></dl></p> -<p>As a����es a seguir podem ser selecionadas para cada modelo:<ul> -<li>Selecione <uicontrol>Editar</uicontrol> para editar o modelo.</li> -<li>Selecione <uicontrol>Excluir</uicontrol> para excluir o modelo.</li> -</ul>Para incluir um modelo, clique no ��cone <uicontrol>mais (+)</uicontrol> na -parte superior direita da exibi����o.</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="en-us"> -<title>Editar modelo</title> -<shortdesc>Edite um modelo existente.</shortdesc> -<csbody> -<p>Para cada modelo, as informa����es a seguir s��o exibidas: <dl> -<dlentry> -<dt>Nome</dt> -<dd>Nome do modelo.</dd> -</dlentry><dlentry> -<dt>Fornecedor</dt> -<dd>O nome da empresa que criou o sistema operacional ou a distribui����o -que o modelo est�� configurado para usar.</dd> -</dlentry><dlentry> -<dt>Vers��o</dt> -<dd>A vers��o do sistema operacional ou distribui����o que o modelo -est�� configurado para usar.</dd> -</dlentry><dlentry> -<dt>N��mero de CPU</dt> -<dd>N��mero de processadores que est��o definidos para o modelo.</dd> -</dlentry><dlentry> -<dt>Mem��ria</dt> -<dd>Quantia de mem��ria em MB a ser alocada para a m��quina virtual.</dd> -</dlentry><dlentry> -<dt>Disco</dt> -<dd>O tamanho do disco em GB.</dd> -</dlentry><dlentry> -<dt>CD-ROM</dt> -<dd>O caminho do arquivo para o local do arquivo ISO usado para instalar o -convidado do KVM.</dd> -</dlentry><dlentry> -<dt>storage pool</dt> -<dd>storage pool espec��fico ou storage pool padr��o.</dd> -</dlentry><dlentry> -<dt>Rede</dt> -<dd>As interfaces de rede padr��o dispon��veis para o convidado do KVM. �� poss��vel -selecionar diversas redes.</dd> -</dlentry></dl> Os campos que n��o est��o desativados podem ser editados. Depois -de editar um campo, clique em <uicontrol>Salvar</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>Incluir modelo</title> -<shortdesc>Inclua um modelo a partir da m��dia de origem. -�� poss��vel incluir sua pr��pria imagem ISO em seu conjunto de armazenamentos 'ISO' para a descoberta a seguir.</shortdesc> -<csbody> -<p>Selecione o local da m��dia de origem a partir das op����es a seguir:<dl> -<dlentry> -<dt>Imagem ISO local</dt> -<dd>Selecione para varrer conjuntos de armazenamentos para imagens ISO de instala����o dispon��veis -no sistema.</dd> -</dlentry><dlentry> -<dt>Imagem ISO remota</dt> -<dd>Selecione para especificar um local remoto para uma imagem ISO de instala����o.</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>Incluir modelo - imagem ISO local</title> -<shortdesc>Inclua um modelo a partir de uma imagem ISO local.</shortdesc> -<csbody> -<p>As imagens ISO dispon��veis no sistema s��o exibidas.<dl><dlentry> -<dt>S.O.</dt> -<dd>Nome do sistema operacional ou distribui����o.</dd> -</dlentry><dlentry> -<dt>Vers��o</dt> -<dd>Vers��o do sistema operacional ou distribui����o.</dd> -</dlentry><dlentry> -<dt>Tamanho</dt> -<dd>Tamanho da imagem ISO.</dd> -</dlentry></dl></p> -<p>Para criar um modelo a partir de uma imagem ISO, escolha a partir das op����es -a seguir:<ul> -<li>Selecione uma imagem ISO para criar um modelo a partir dela, em seguida, clique em <uicontrol>Criar -modelos a partir do ISO selecionado</uicontrol>.</li> -<li>Selecione <uicontrol>Todos</uicontrol> para criar um modelo a partir de cada -imagem ISO listada, em seguida, clique em <uicontrol>Criar modelos a partir do -ISO selecionado</uicontrol>.</li> -<li>Se a imagem ISO que voc�� deseja usar n��o aparecer nos resultados de -varredura, ser�� poss��vel selecionar a partir das op����es a seguir:<ul> -<li>Selecione <uicontrol>Eu desejo usar um arquivo ISO espec��fico</uicontrol> para -especificar um caminho para a imagem ISO.</li> -<li>Clique em <uicontrol>Procurar mais ISOs</uicontrol> para procurar mais -imagens ISO.</li> -</ul></li> -</ul></p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 229 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/ru_RU/Makefile.am b/plugins/kimchi/ui/pages/help/ru_RU/Makefile.am deleted file mode 100644 index 85ca27a..0000000 --- a/plugins/kimchi/ui/pages/help/ru_RU/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -ru_RU_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/ru_RU - -dist_ru_RU_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/ru_RU/guests.dita b/plugins/kimchi/ui/pages/help/ru_RU/guests.dita deleted file mode 100644 index 701dd7e..0000000 --- a/plugins/kimchi/ui/pages/help/ru_RU/guests.dita +++ /dev/null @@ -1,122 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="ru-ru"> -<title>���������������� ��������������</title> -<shortdesc>���� ���������������� <wintitle>���������������� ��������������</wintitle> ������������������������ ������������ ������������������ ���������������������� ���������� KVM.</shortdesc> -<csbody> -<p>������ ������������ ���������������� �������������� ������������������������ ������������������ ��������������������:<dl><dlentry> -<dt>������</dt> -<dd>������ ���������������������� ������������.</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>�������������� �������������������������� �������������������� �� ���������������������� ������������.</dd> -</dlentry><dlentry> -<dt>�������������� ��������-����������</dt> -<dd>���������������� ���������������� ����������-������������ �� ����/��.</dd> -</dlentry><dlentry> -<dt>���������������� ��������-����������</dt> -<dd>���������������� ������������������ ����������-������������ �� ����/��.</dd> -</dlentry><dlentry> -<dt>Livetile</dt> -<dd>������������������ �������������� ���������������� ������������������������ �������������� ������ ������������, ���������������������������� �������������� ���� <tm tmtype="tm" trademark="Linux">Linux</tm>, �������� ���������������� �������������� ���� ��������������.</dd> -</dlentry></dl></p> -<p>������ ������������ ���������������� �������������� ������������������������ ������������������ ������������ ����������������:<dl> -<dlentry> -<dt>����������</dt> -<dd>���������� ���������������� ��������������. </dd> -</dlentry><dlentry> -<dt>�������������� (������������/������������������)</dt> -<dd>������������������/�������������������� �������������� ���������������� ��������������. �������� ������������ ��������������, �������������� ������������������. �������� ������������ ��������������, �������������� ����������������.</dd> -</dlentry></dl> </p> -<p>������ ������������ ���������������� �������������� ���������������� ������������������ ����������������:<ul> -<li><uicontrol>������������������������</uicontrol> - ������������������������ �� ������������������ �������������� ���������������� ������������������������ ��������������.</li> -<li><uicontrol>�������������������� ��������������������</uicontrol> - ������������������ �������� �� �������������������������� ����������������.</li> -<li><uicontrol>����������</uicontrol> - ���������� ���������������� ��������������.</li> -<li><uicontrol>����������������</uicontrol> - ������������������ �������������� ���������������� ��������������. ���������������� ���������������� �������������� ���������� ����������������, ������������ ���������� �������������� ����������������������.</li> -<li><uicontrol>��������������</uicontrol> - �������������� ���������������� ��������������.</li> -</ul>������ ���������������� ���������������� �������������� (���������������������� ������������) ���������������� ���� ������������ <uicontrol>�������� -(+)</uicontrol> �� ������������ �������������� �������� ����������������.</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="ru-ru"> -<title>���������������� ���������������������� ������������</title> -<shortdesc>���������������� ���������������������� ������������ �� �������������� ��������������.</shortdesc> -<csbody> -<p> <ol> -<li>�������������� ������ ������ �������������������������� ���������������������� ������������.</li> -<li rev="rev1">���������������� ������������. <ul> -<li>�������� �������� ��������������, ���������������� ������������ �� ������������.</li> -<li>�������� ���������������� ������, ���������������� ���� <uicontrol>�������������� ������������</uicontrol>, ���������� �������������� ������������.</li> -</ul></li> -<li>���������������� ���� <uicontrol>��������������</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="ru-ru"> -<title>������������������ ���������������� ��������������</title> -<shortdesc>������������������ �������������� ������������������������ ���������������������� ������������. ������������������ ���������������� ���������� ���������������� ������������ �������� ���������������������� ���������������� ����������. ������������ ���������������� �� �������� ���������� ������������������ ������������������������.</shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>������ ������������ ���������������� �������������� ������������������������ ������������������ �������������������� ���� �������������� <wintitle>����������</wintitle>:<dl> -<dlentry> -<dt>������</dt> -<dd>������ ���������������������� ������������. (���������� �������������������������� �������� ���������������������� ���������������� ����������)</dd> -</dlentry><dlentry> -<dt>��������������������</dt> -<dd>���������� ����������������������. (�������� ���������������� ���������� ����������������, ���������� ���������� �������������� �� �������� ���������� ������������������������)</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>���������� ������������ �� ����. (�������� ���������������� ���������� ����������������, ���������� ���������� �������������� �� �������� ���������� ������������������������)</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>���������������������� ����������������������, ���������������������������� �������������� ���� Linux. ������ ������������������������ ������������ ���������������� ������������������ -(Livetile), ���������� ���������������� �������������� ���� ��������������.</dd> -</dlentry></dl></p> -<p>���� �������������� <wintitle>���������������� ������������</wintitle> ������������������������ ������������������ ��������������������.</p> -<dl><dlentry> -<dt>���������������� ������������</dt> -<dd>�������������������� ������������������������ ���������� ISO ������ ������������������.</dd> -</dlentry></dl> -<p> ���������������� �������� ���������� ����������������. ���������� ������������������ �������� ���������������� ���� <uicontrol>������������������</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="ru-ru"> -<title>��������������������, ������������ �� �������������������� ������������������ ����������������</title> -<shortdesc rev="rev1">�� ���������������������� ������������ ���������� ������������������, ���������������� �� ������������������ �������������������� ����������������. ������������������������ ���������������������������� �������������������� - CDROM. ������ ������������������ ������������������ ���������������� ������������������ ������������������ ����������������:</shortdesc> -<csbody> -<ol> -<li>�� �������� <wintitle>���������������� ���������������� ��������������</wintitle> ���������������� <wintitle>���������������� ������������</wintitle>.</li> -<li>������ ������������ �������������������� ���������������� ���������������� ���� ������������ ������������ �� <uicontrol>������������������ ���������� ������������ (/)</uicontrol>. �������������� �������� �� ���������� ISO �� ���������������� ���� <uicontrol>����������������</uicontrol>.</li> -<li>������ �������������������� �������������������� ���������������� ���������������� ���� ������������ ������������ �� <uicontrol>�������������� ���������������������������� ������������ (-)</uicontrol>. ���������������������� ���������������� �� �������������� ������������ <uicontrol>OK</uicontrol>.</li> -<li>������ �������������������� �������������������� ���������������� ���������������� ���� �������������� ������������ �� <uicontrol>�������������� ������������ -(+)</uicontrol>. �������������� ������ �������������������� �� �������� �� ���������� ISO �� ���������������� ���� <uicontrol>��������������������</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="ru-ru"> -<title>������������ CDROM ���������������������� ������������</title> -<shortdesc rev="rev1">���� ������������������ ������������������ ���������� ���������������� �������������������� CDROM ������ ���������������������� ������������.</shortdesc> -<csbody> -<ol> -<li>������������������ ���������������������� ������������.</li> -<li>�� �������� ���������������� ���������������� <uicontrol>�������������������� ��������������������</uicontrol>.</li> -<li>������ ������������ ����������������, ������������������������ �� CDROM, ���������������� ���� ������������ �� <uicontrol>������������������ ���������� ������������ -(/)</uicontrol> ���������� �� ���������� hdc.</li> -<li>���� ���������������� <wintitle>������������ CDROM ���������������������� ������������</wintitle> �������������� �������� �� ���������� ISO. ������ ������������ �������� ���������������� ������������ ������ ������������.</li> -<li>���������������� ���������� <uicontrol>����������������</uicontrol>.</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 231 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/ru_RU/host.dita b/plugins/kimchi/ui/pages/help/ru_RU/host.dita deleted file mode 100644 index fb72c21..0000000 --- a/plugins/kimchi/ui/pages/help/ru_RU/host.dita +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="ru-ru"> -<title>��������</title> -<shortdesc>���������������� <wintitle>��������</wintitle> �������������������� �������������������� �� �������������� ���������� �� ������������������ �������������������������� ��������, �������������������������� �������� �� ������������������������ �� ��������.</shortdesc> -<csbody> -<p>���� ���������� ���������� ������������������ ������������������ ����������������:<ul> -<li><uicontrol>������������������ ������������</uicontrol> - �������������������� �������������� ����������.</li> -<li><uicontrol>��������������������������</uicontrol> - �������������������������� �������������� ����������.</li> -<li><uicontrol>������������������������</uicontrol> - �������������� �������������������� VNC �� ���������������� ����������, �������� ������ ������ ���� ����������������������.</li> -</ul></p> -<p>���������������� ���� ������������������ ���������������� ������ ������������������ �������������������� �� ����������:<dl> -<dlentry> -<dt>�������������� ��������������������</dt> -<dd>�� �������� �������������� ������������������������ �������������� ������������������������ ��������������, ������ ������������ �� �������������� ������, �� ���������� ������ �������������������� �� ���������� ������������ �� ����.</dd> -</dlentry><dlentry> -<dt>������������������ ��������������������</dt> -<dd>�� �������� �������������� ������������������������ ��������������, �������������������� ���������������������������� �������������������� �� ��������������������, ������������, ���������������� ����������-������������ �� �������������� ����������-������������ ������ ����������. ���������������� <uicontrol>�������� ������������ ���������� ���������������� �������� ����������������</uicontrol>, ���������� �������� ������������ ���������������������� ���������� ���������������� �������������� ��������.</dd> -</dlentry><dlentry> -<dt>�������������������� ������������������������ ����������������������</dt> -<dd>�� �������� �������������� ������������������������ �������������������� ������ �������� ��������������, ������ �������������� ���������������� ��������������������, �������������� ������ ������������, ������������, ���������������������� �� ������������������. ���������� ���������������� ������ ������������ �� ������������ �������������� ���� <uicontrol>���������������� ������</uicontrol>. ������������������ ������������ ������ �������������������� �������������� ������������.</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>�� �������� �������������� ������������������������ ������������������, ������������������ �� ���������������� ����������. ������������������ ���������� ������������������, ������������������������, ���������������� �� ��������������. ������ �������������������� ������������������ ���������������������� �� ���������������� ����������, ������ ������������������ ������������������ �������������������� ������������������ ������ ����������. �������� �������������� - Red Hat Enterprise Linux ������ Fedora, ���������� ���������������� ������������������ <filepath>yum</filepath>. -�������� �������������� - Ubuntu ������ Debian, ���������������� ������������������ <filepath>deb</filepath>.<p>������ ������������ �� ���������������������� yum ���������� ���������������� ���������������� GPG ������ ���������������� ���������������������� �������������� ���� �������������� ������������������. -���������������� ������������������ �� ���������������� ���� <uicontrol>����������������</uicontrol>. ���������������� <uicontrol>����</uicontrol>, ���������� ���������������� ���������������� GPG, �� �������������� URL ���������� ������������ GPG ������ ������������������.</p></dd> -</dlentry><dlentry> -<dt>�������������������� ������������</dt> -<dd>�� �������� �������������� ������������������������ �������������������� ������������, �������������� ������ �� ��������. -���������������� �������������� ������ ����������������, ����������������������������, ���������������� �� ���������������� ��������������.<p>�������������������� ���������� ������������������ ���������������� <cmdname>sosreport</cmdname>. ���� ���������������� ������ Red -Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora �� Ubuntu. �������������� �������������� �������� .tar �� �������������������������������� �� ������������������������������ ����������������������, ���������� ������ ������������ ��������, ���������������������� ������������ �� ���������� ������������������������ �������������� �� ����������. -�������������� ���������� ������������������ �������������� ������������������ ������ ���������� ���������������������������� �������������������� �� ������������������ ���� ���������� �� ���������������������������� ������������.</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 232 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/ru_RU/network.dita b/plugins/kimchi/ui/pages/help/ru_RU/network.dita deleted file mode 100644 index 9cdcdd1..0000000 --- a/plugins/kimchi/ui/pages/help/ru_RU/network.dita +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="ru-ru"> -<title>��������</title> -<shortdesc>���� ���������������� <wintitle>��������</wintitle> ������������������������ �������������������� �� �������������� ��������������������.</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>������ ��������</dt> -<dd>������ �������� ������ <uicontrol>���� ������������������</uicontrol>.</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>������������������ �������� - ���������������� (��������������) ������ �������������������� (��������������). </dd> -</dlentry><dlentry> -<dt>������ ��������</dt> -<dd>������ ��������, ���������������� <uicontrol>NAT</uicontrol> (���������������������������� �������������� ��������������).</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>�������������� ������������������, ���������������� <uicontrol>virbr0</uicontrol> (���� ������������������).</dd> -</dlentry><dlentry> -<dt>���������������� ������������������������</dt> -<dd>IP-����������.</dd> -</dlentry></dl></p> -<p>���������������� ������������������ ����������������:<ul> -<li rev="rev1"><uicontrol>������������������</uicontrol> - �������������� �������������� ��������������������.</li> -<li><uicontrol>��������������������</uicontrol> - �������������� �������������� ��������������������.</li> -<li><uicontrol>��������������</uicontrol> - �������������� �������������������� �� ��������������������.</li> -</ul>������ ���������������� �������� ���������������� ���� ������������ <uicontrol>���������� (+)</uicontrol> �� ������������ �������������� �������� ����������������.</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="ru-ru"> -<title>���������������� ��������</title> -<shortdesc>���������������� ��������.</shortdesc> -<csbody> -<p> <ol> -<li>�������������� ������ ��������.</li> -<li>���������������� ������ ��������. <dl rev="rev1"><dlentry> -<dt><uicontrol>��������������������������</uicontrol></dt> -<dd>�������������������������� ����������. ���������������� �������������� ���� ���������� ������������������������ �������������� �� ���������������� ������������������.</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>���������� ���������������������������� �������������� ��������������. ���������� �������������� ���������� ������������������ �� ���������������� ������������������ ���������������������������� ���������� IP-���������� ����������. �������������� �������������� ���� ���������� ������������������������ �� ����������������.</dd> -</dlentry><dlentry> -<dt><uicontrol>���������� ��������</uicontrol></dt> -<dd>���������� ������������ ���������� ��������. ���������������� �������������� ���������� ������������������������ �������������� �� ���������������� ������������������, �� �������������� �������������� ���������� ������������������������ �� ����������������, ������ �������� ���� ���� �������� ���������������������� ������������������ �� ��������. �� ������������ ������������ ���������� �������� �������������������� �������������� ���������������������������� �������������������� �� �������������� ������������������������ �� VLAN.</dd> -</dlentry></dl></li> -<li>���������������� ���� <uicontrol>��������������</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 230 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/ru_RU/storage.dita b/plugins/kimchi/ui/pages/help/ru_RU/storage.dita deleted file mode 100644 index fa37edc..0000000 --- a/plugins/kimchi/ui/pages/help/ru_RU/storage.dita +++ /dev/null @@ -1,88 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="ru-ru"> -<title>���������������� ������������</title> -<shortdesc>���� ���������������� <wintitle>���������������� ������������</wintitle> ������������������������ ������������ ������������������ ���������� ������������, �������������� �������� ������������ '���� ������������������' �� 'ISO'. -�������� ���� ������������ ������������������������ ���������������������� ISO, ���������������� ������ �� �������� ���������������� ������������ 'ISO'.</shortdesc> -<csbody> -<p>������ �������������� �������� ������������ ������������������������ ������������������ ��������������������:<dl> -<dlentry> -<dt>������</dt> -<dd>������ �������� ������������ �� �������������� ��������������������������.</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>������������������ �������� ������������ - ���������������� (��������������) ������ �������������������� (��������������). </dd> -</dlentry><dlentry> -<dt>������������������������</dt> -<dd>�������� �� ������������������������ �������� ������������.</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������ �������� ������������, ���������������� <uicontrol>��������������</uicontrol>.</dd> -</dlentry><dlentry> -<dt>��������������</dt> -<dd>���������� �������� ������������.</dd> -</dlentry><dlentry> -<dt>����������������</dt> -<dd>���������� �������������������� ������������ �� ��������.</dd> -</dlentry></dl></p> -<p>������ �������������� �������� ������������ ���������� ���������������� ������������������ ����������������:<ul> -<li><uicontrol>������������������������</uicontrol> - ������������������������ ������ ������������, ���������� ������ ���������� �������� ������������������������.</li> -<li><uicontrol>����������������������������</uicontrol> - ���������������������������� ���������������� ������ ������������.</li> -<li><uicontrol>��������������</uicontrol> - �������������� �������������������� ������ ������������.</li> -</ul></p> -<p>������ ������������������ ���������������� �� ���������� �������� ������������ ���������������� ���� �������������� �� ������������ ���������� ������������ �������� ������������. ���������������� ����������������:<dl><dlentry> -<dt>������</dt> -<dd>������ ��������, ���������������� <uicontrol>��������</uicontrol>.</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������ (�������������� ���� ��������).</dd> -</dlentry><dlentry> -<dt>��������������</dt> -<dd>������������ ��������.</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>���������� �������������������� ������������ �� ��������.</dd> -</dlentry></dl>������ ���������������� �������� ������������ ���������������� ���� ������������ <uicontrol>���������� (+)</uicontrol> �� ������������ �������������� �������� ����������������.</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="ru-ru"> -<title>���������������� �������� ������������</title> -<shortdesc> ���������������� �������� ������������.</shortdesc> -<csbody> -<p> <ol> -<li>�� �������� <uicontrol>������ �������� ������������</uicontrol> �������������� ������ ������ �������������������������� �������� ������������.</li> -<li>�� ������������ <uicontrol>������ �������� ������������</uicontrol> ���������������� ������: <dl><dlentry> -<dt><uicontrol>��������������</uicontrol></dt> -<dd>������������ ������-��������������. ������ ������������ �������� <uicontrol>��������������</uicontrol> ������������������ �������� -<uicontrol>�������� �� �������� ������������</uicontrol> (�������� �� �������� ������������ �� ���������������� ��������������).</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>������������ ������ ���� ������������ �������������� ���������������� ��������������. ������ ������������ <uicontrol>NFS</uicontrol> �������������� ���������� �� -�������� <uicontrol>IP-���������� �������������� NFS</uicontrol> �� �������� �� ���������������������������������� ���������������� �� �������� <uicontrol>�������� NFS</uicontrol>.</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>������������ ������ ���� ������������ ���������������� ��������������, ���������������������� ���� �������������� iSCSI. -������ ������������ �������� <uicontrol>iSCSI</uicontrol> �������������� IP-���������� �� �������� <uicontrol>������������ iSCSI</uicontrol> �� �������������� ������������ ���� �������������� iSCSI �� �������� <uicontrol>�������������� ������������</uicontrol>. ���������� ���������� ���������������� �������������������������� iSCSI.</dd> -</dlentry><dlentry> -<dt><uicontrol>��������������������</uicontrol></dt> -<dd>������������ ������ ������������ ���� ������������ ���������������������� ��������. ���������������� ������������������������ �������������������� �� �������� <uicontrol>�������� �� ��������������������</uicontrol>.</dd> -</dlentry><dlentry> -<dt><uicontrol>SCSI Fibre Channel</uicontrol></dt> -<dd>������������ ������ ���� ������������ SCSI Fibre Channel. ���������������� �������������� SCSI.</dd> -</dlentry></dl></li> -<li>���������������� ���� <uicontrol>��������������</uicontrol>.</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 233 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/ru_RU/templates.dita b/plugins/kimchi/ui/pages/help/ru_RU/templates.dita deleted file mode 100644 index 27ce4ae..0000000 --- a/plugins/kimchi/ui/pages/help/ru_RU/templates.dita +++ /dev/null @@ -1,111 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="ru-ru"> -<title>��������������</title> -<shortdesc>���� ���������������� <wintitle>��������������</wintitle> ������������������������ ������������������ �������������� ���������������������� ����������, �������������� ���������� ������������������������ ������ ���������������� ���������������� ������������ KVM.</shortdesc> -<csbody> -<p>������ �������������� �������������� ������������������������ ������������������ ��������������������:<dl> -<dlentry> -<dt>����</dt> -<dd>������ ������������������������ �������������� ������ ���������������� ������������������������ ��������������.</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������ ������������������������ �������������� ������ ���������������� ������������������������ ��������������.</dd> -</dlentry><dlentry> -<dt>��������������������</dt> -<dd>�������������������� ���������������������� ������ ��������������.</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>�������������������� ���������� ���������������������� ������������ �� ����.</dd> -</dlentry></dl></p> -<p>������ �������������� �������������� ���������� ���������������� ������������������ ����������������:<ul> -<li><uicontrol>����������������</uicontrol> - ���������������� ������������.</li> -<li><uicontrol>��������������</uicontrol> - �������������� ������������.</li> -</ul>������ �������������������� �������������� ���������������� ���� ������������ <uicontrol>���������� (+)</uicontrol> �� ������������ �������������� �������� ����������������.</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="ru-ru"> -<title>���������������� ������������</title> -<shortdesc>���������������� ������������������������ ������������.</shortdesc> -<csbody> -<p>������ �������������� �������������� ������������������������ ������������������ ��������������������: <dl> -<dlentry> -<dt>������</dt> -<dd>������ ��������������.</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������ ����������������, ������������������ ������������������������ �������������� ������ �������������� ������������������������ ��������������, ������ �������������������������� �������������� �������������������������� ������������.</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������ ������������������������ �������������� ������ ���������������� ������������������������ ��������������, ������ �������������������������� �������������� �������������������������� ������������.</dd> -</dlentry><dlentry> -<dt>�������������������� ����������������������</dt> -<dd>�������������������� ���������������������� ������ ��������������.</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>���������� ������������ �� ����, �������������������� ���������������������� ������������.</dd> -</dlentry><dlentry> -<dt>��������</dt> -<dd>������������ ���������� �� ����.</dd> -</dlentry><dlentry> -<dt>CDROM</dt> -<dd>�������� �� ���������� ISO ������ ������������������ ���������������� �������������� KVM.</dd> -</dlentry><dlentry> -<dt>������ ������������</dt> -<dd>������������������������ ������ ������������ ������ ������ ������������ ���� ������������������.</dd> -</dlentry><dlentry> -<dt>��������</dt> -<dd>�������������� �������������������� ���� ������������������, ������������������ ������ ���������������� �������������� KVM. ���������� �������������� ������������������ ����������.</dd> -</dlentry></dl> ���������������� �������� ���������� ����������������. ���������� ������������������ �������� ���������������� ���� <uicontrol>������������������</uicontrol>. </p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>�������������������� ��������������</title> -<shortdesc>�������������������� �������������� �� ������������������ ����������������. ���������������� ���������������������� ���������� ISO �� ���������������� ������������ ISO ������ ���������������������� ������������.</shortdesc> -<csbody> -<p>���������������� �������� ���� ������������������ ������������������ ������������������������ ������������������ ����������������:<dl> -<dlentry> -<dt>������������������ ���������� ISO</dt> -<dd>���������������� �������� �������������� ������ ������������ ������������������������ �������������� ISO �� ������������������ ���������� ������������ ��������������.</dd> -</dlentry><dlentry> -<dt>������������������ ���������� ISO</dt> -<dd>���������������� �������� ��������������, ���������� �������������� ������������������ ������������������������ �������������������������� ������������ ISO.</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>�������������������� �������������� (������������������ ���������� ISO)</title> -<shortdesc>�������������������� �������������� ���� �������������������� ������������ ISO.</shortdesc> -<csbody> -<p>���������� ���������������� ������������ ISO, ������������������ �� ��������������.<dl><dlentry> -<dt>����</dt> -<dd>������ ������������������������ �������������� ������ ���������������� ������������������������ ��������������.</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������ ������������������������ �������������� ������ ���������������� ������������������������ ��������������.</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������ ������������ ISO.</dd> -</dlentry></dl></p> -<p>������ ���������������� �������������� ���� ������������ ISO ���������������� �������� ���� ������������������ ������������������:<ul> -<li>���������������� ���������� ISO, ���� ���������������� ���������� �������������� ������������, ���������� ���������������� ���� <uicontrol>�������������� �������������� ���� ������������������ �������������� ISO</uicontrol>.</li> -<li>���������������� <uicontrol>������</uicontrol>, ���������� �������������� ������������ ���� �������������� ������������ ISO �� ������������, ���������� ���������������� ���� <uicontrol>�������������� �������������� ���� ������������������ �������������� ISO</uicontrol>.</li> -<li>�������� ������������������ ���������� ISO ���������������������� �� ���������������������� ������������, ���������������� �������� ���� ������������������ ������������������:<ul> -<li>���������������� <uicontrol>������������������������ �������������������� �������� ISO</uicontrol>, ���������� �������������� �������� �� ������������ ISO.</li> -<li>���������������� ���� <uicontrol>���������� ���������������������������� �������������� ISO</uicontrol> ������ ������������ ���������������������������� �������������� ISO.</li> -</ul></li> -</ul></p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 229 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/zh_CN/Makefile.am b/plugins/kimchi/ui/pages/help/zh_CN/Makefile.am deleted file mode 100644 index e785048..0000000 --- a/plugins/kimchi/ui/pages/help/zh_CN/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -zh_CN_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/zh_CN - -dist_zh_CN_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/zh_CN/guests.dita b/plugins/kimchi/ui/pages/help/zh_CN/guests.dita deleted file mode 100644 index d684af2..0000000 --- a/plugins/kimchi/ui/pages/help/zh_CN/guests.dita +++ /dev/null @@ -1,118 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="zh-cn"> -<title>������</title> -<shortdesc>���<wintitle>������</wintitle>��������������������������� KVM ������������</shortdesc> -<csbody> -<p>���������������������������������������������<dl><dlentry> -<dt>������</dt> -<dd>���������������������</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>���������������������������������������</dd> -</dlentry><dlentry> -<dt>������ I/O</dt> -<dd>������������/������������������������ KB/������������</dd> -</dlentry><dlentry> -<dt>������ I/O</dt> -<dd>������������/������������������������ KB/������������</dd> -</dlentry><dlentry> -<dt>Livetile</dt> -<dd>������������������������������������������������������������������������������������ <tm tmtype="tm" trademark="Linux">Linux</tm> ���������������������</dd> -</dlentry></dl></p> -<p>���������������������������������������������<dl> -<dlentry> -<dt>������</dt> -<dd>������������������������������</dd> -</dlentry><dlentry> -<dt>���������������������������</dt> -<dd>������������������������������������������������������������������������������������������������������������������������������������������������������</dd> -</dlentry></dl> </p> -<p>���������������������������������������<ul> -<li>������<uicontrol>������</uicontrol>���������������������������������������������������</li> -<li>������<uicontrol>������������</uicontrol>���������������������������������</li> -<li>������<uicontrol>������</uicontrol>������������������</li> -<li>������<uicontrol>������</uicontrol>���������������������������������������������������������������������</li> -<li>������<uicontrol>������</uicontrol>������������������</li> -</ul>���������������������������������������������������������<uicontrol>��������� (+) </uicontrol> ���������</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="zh-cn"> -<title>���������������</title> -<shortdesc>������������������������������������������</shortdesc> -<csbody> -<p> <ol> -<li>���������������������������������������</li> -<li rev="rev1">���������������<ul> -<li>���������������������������������������������������������������</li> -<li>���������������������������������������<uicontrol>������������</uicontrol>������������������</li> -</ul></li> -<li>������<uicontrol>������</uicontrol>���</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="zh-cn"> -<title>������������</title> -<shortdesc>���������������������������������������������������������������������������������������������������������������������������������������</shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>������������������������������<wintitle>������</wintitle>������������������������������������<dl> -<dlentry> -<dt>������</dt> -<dd>���������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>CPU ���</dt> -<dd>���������������������������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>��������������� MB ���������������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>��������������������������������������������������� Linux ������������������������������ (Livetile) ������������������</dd> -</dlentry></dl></p> -<p>���������<wintitle>���������</wintitle>������������������������������������</p> -<dl><dlentry> -<dt>���������</dt> -<dd>��������������������� ISO ������������������������</dd> -</dlentry></dl> -<p> ���������������������������������������������������������������������<uicontrol>������</uicontrol>���</p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="zh-cn"> -<title>������������������������������������</title> -<shortdesc rev="rev1">��������������������������������������������������������������������������������������� CDROM���������������������������������������������������</shortdesc> -<csbody> -<ol> -<li>������<wintitle>������������</wintitle>������������������������<wintitle>���������</wintitle>������</li> -<li>���������������������������������������������������������<uicontrol>������������ (/)</uicontrol>��������� ISO ���������������������<uicontrol>������</uicontrol>���</li> -<li>���������������������������������������������������������<uicontrol>��������������� (-)</uicontrol>������������������������������������<uicontrol>������</uicontrol>���</li> -<li>���������������������������������������������������������<uicontrol>��������������� (+)</uicontrol>��������������������� ISO ���������������������<uicontrol>������</uicontrol>���</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="zh-cn"> -<title>������ VM ��� CDROM</title> -<shortdesc rev="rev1">������������������������������������������������ CDROM ������������</shortdesc> -<csbody> -<ol> -<li>������������������������������</li> -<li>���������������������������������<uicontrol>������������</uicontrol>���</li> -<li>������������������������ CDROM ������������������������ hdc ���������������<uicontrol>������������ (/)</uicontrol> ���������</li> -<li>������<wintitle>������ VM ��� CDROM</wintitle>��������������������� ISO ���������������������������������������������</li> -<li>������<uicontrol>������</uicontrol>���</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 231 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/zh_CN/host.dita b/plugins/kimchi/ui/pages/help/zh_CN/host.dita deleted file mode 100644 index 78a89c3..0000000 --- a/plugins/kimchi/ui/pages/help/zh_CN/host.dita +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="zh-cn"> -<title>������</title> -<shortdesc>���<wintitle>������</wintitle>������������������������������������������������������������������������������������������������������</shortdesc> -<csbody> -<p>���������������������������������<ul> -<li>������<uicontrol>������</uicontrol>������������������������</li> -<li>������<uicontrol>������������</uicontrol>������������������������������</li> -<li>������<uicontrol>������</uicontrol>��������������������������� VNC ���������������������������������</li> -</ul></p> -<p>���������������������������������������������������<dl> -<dlentry> -<dt>������������</dt> -<dd>��������������������������������������������������������������������������������������������������������� GB ���������</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>��������������������������������������������� CPU������������������ I/O ��������� I/O ������������������������<uicontrol>���������������������������������</uicontrol>������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>���������������������������������������������������������������������������������������������������������������������������������������������<uicontrol>������������</uicontrol>���������������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� Red Hat Enterprise Linux ��� Fedora������������������ <filepath>yum</filepath> ��������������������������������� Ubuntu ��� Debian������������������ <filepath>deb</filepath> ������������<p>��������������� Yum ��������������������������� GPG ������������������������������������������������������������������������������������������������<uicontrol>������</uicontrol>���������<uicontrol>���</uicontrol>��������� GPG ��������������������������������� GPG ��������������� URL���</p></dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<p>��������������������� -<cmdname>sosreport</cmdname> ��������������������������������� Red -Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>���Fedora ��� Ubuntu ������������������������������������������������������������ .tar ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 232 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/zh_CN/network.dita b/plugins/kimchi/ui/pages/help/zh_CN/network.dita deleted file mode 100644 index f6aa532..0000000 --- a/plugins/kimchi/ui/pages/help/zh_CN/network.dita +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="zh-cn"> -<title>������</title> -<shortdesc>���<wintitle>������</wintitle>���������������������������������������������</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>���������</dt> -<dd>������������������<uicontrol>���������</uicontrol>���</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>���������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������������������<uicontrol>NAT</uicontrol>���������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������<uicontrol>virbr0</uicontrol>������������������</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>IP ���������</dd> -</dlentry></dl></p> -<p>���������������������������<ul> -<li rev="rev1">������<uicontrol>������</uicontrol>������������������������</li> -<li>������<uicontrol>������</uicontrol>������������������������</li> -<li>������<uicontrol>������</uicontrol>������������������������</li> -</ul>������������������������������������������������<uicontrol>��������� (+)</uicontrol> ���������</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="zh-cn"> -<title>������������</title> -<shortdesc>���������������</shortdesc> -<csbody> -<p> <ol> -<li>������������������������</li> -<li>������������������������������������<dl rev="rev1"><dlentry> -<dt><uicontrol>������</uicontrol></dt> -<dd>������������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>��������������������������������������������������������������������������� IP ������������������������������������������������������</dd> -</dlentry><dlentry> -<dt><uicontrol>������</uicontrol></dt> -<dd>������������������������������������������������������������������������������������������������������������������������������������������������������������������ VLAN ���������</dd> -</dlentry></dl></li> -<li>������<uicontrol>������</uicontrol>���</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 230 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/zh_CN/storage.dita b/plugins/kimchi/ui/pages/help/zh_CN/storage.dita deleted file mode 100644 index cfb09f5..0000000 --- a/plugins/kimchi/ui/pages/help/zh_CN/storage.dita +++ /dev/null @@ -1,84 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="zh-cn"> -<title>���������</title> -<shortdesc>���<wintitle>���������</wintitle>���������������������������������������������������������������������ISO��������������������������������������������� ISO������������������������ISO���������������������</shortdesc> -<csbody> -<p>������������������������������������������������<dl> -<dlentry> -<dt>������</dt> -<dd>������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������ </dt> -<dd>���������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������<uicontrol>dir</uicontrol>���</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>���������������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������������������������������������</dd> -</dlentry></dl></p> -<p>������������������������������������������<ul> -<li>������<uicontrol>������</uicontrol>���������������������������������������</li> -<li>������<uicontrol>������������</uicontrol>���������������������������������</li> -<li>������<uicontrol>������������</uicontrol>������������������������������</li> -</ul></p> -<p>���������������������������������������������������������������������������������������������������������������������<dl><dlentry> -<dt>������</dt> -<dd>������������������������<uicontrol>������</uicontrol>���</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>���������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>���������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������</dd> -</dlentry></dl>���������������������������������������������������<uicontrol>��������� (+)</uicontrol> ���������</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="zh-cn"> -<title>���������������</title> -<shortdesc> ������������������</shortdesc> -<csbody> -<p> <ol> -<li>���<uicontrol>���������������</uicontrol>���������������������������������������������������</li> -<li>���<uicontrol>���������������</uicontrol>���������������������������<dl><dlentry> -<dt><uicontrol>DIR</uicontrol></dt> -<dd>��������������������������� <uicontrol>DIR</uicontrol> ������������<uicontrol>������������</uicontrol>���������������������������������</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>��������������������������������������� <uicontrol>NFS</uicontrol> ������������ <uicontrol>NFS ��������� IP ������</uicontrol>��� <uicontrol>NFS ������</uicontrol>���������������������������������</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>������ iSCSI ������������������������������������������������ <uicontrol>iSCSI</uicontrol> ��������� iSCSI ������������������ <uicontrol>iSCSI ��������� IP ������</uicontrol>���<uicontrol>������</uicontrol>������������������������������������ iSCSI ���������</dd> -</dlentry><dlentry> -<dt><uicontrol>������</uicontrol></dt> -<dd>������������������������������<uicontrol>������������</uicontrol>���������������������������</dd> -</dlentry><dlentry> -<dt><uicontrol>SCSI ������������</uicontrol></dt> -<dd>������ SCSI ������������������������������������������ SCSI ������������</dd> -</dlentry></dl></li> -<li>������<uicontrol>������</uicontrol>���</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 233 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/zh_CN/templates.dita b/plugins/kimchi/ui/pages/help/zh_CN/templates.dita deleted file mode 100644 index ca50119..0000000 --- a/plugins/kimchi/ui/pages/help/zh_CN/templates.dita +++ /dev/null @@ -1,111 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="zh-cn"> -<title>������</title> -<shortdesc>���<wintitle>������</wintitle>������������������������������ KVM ������������������������������������</shortdesc> -<csbody> -<p>���������������������������������������������<dl> -<dlentry> -<dt>������������</dt> -<dd>������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������</dd> -</dlentry><dlentry> -<dt>CPU ���</dt> -<dd>���������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>��������������������������������������� MB ���������</dd> -</dlentry></dl></p> -<p>���������������������������������������<ul> -<li>������<uicontrol>������</uicontrol>������������������</li> -<li>������<uicontrol>������</uicontrol>������������������</li> -</ul>������������������������������������������������<uicontrol>��������� (+)</uicontrol> ���������</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="zh-cn"> -<title>������������</title> -<shortdesc>���������������������</shortdesc> -<csbody> -<p>���������������������������������������������<dl> -<dlentry> -<dt>������</dt> -<dd>������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������������������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>CPU ������</dt> -<dd>���������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>��������������������������������������� MB ���������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������ GB ���������</dd> -</dlentry><dlentry> -<dt>CDROM</dt> -<dd>������������ KVM ��������� ISO ������������������������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������ KVM ������������������������������������������������������������������</dd> -</dlentry></dl> ���������������������������������������������������������������������<uicontrol>������</uicontrol>���</p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>������������</title> -<shortdesc>������������������������������������������������������ ISO ������������������ISO������������������������������������</shortdesc> -<csbody> -<p>������������������������������������������������<dl> -<dlentry> -<dt>������ ISO ������</dt> -<dd>������������������������������������������ ISO ���������������������������������</dd> -</dlentry><dlentry> -<dt>������ ISO ������</dt> -<dd>��������������������������� ISO ������������������������</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>������������ - ������ ISO ������</title> -<shortdesc>��������� ISO ���������������������</shortdesc> -<csbody> -<p>��������������������������� ISO ���������<dl><dlentry> -<dt>������������</dt> -<dd>������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>ISO ������������������</dd> -</dlentry></dl></p> -<p>������ ISO ���������������������������������������������������<ul> -<li>������������������������������ ISO ���������������������<uicontrol>��������� ISO ������������</uicontrol>���</li> -<li>������<uicontrol>������</uicontrol>������������������������ ISO ���������������������������������<uicontrol>��������� ISO ������������</uicontrol>���</li> -<li>��������������������� ISO ������������������������������������������������������������������������<ul> -<li>������<uicontrol>������������������ ISO ������</uicontrol>��������� ISO ������������������</li> -<li>������<uicontrol>������������ ISO</uicontrol> ��������������� ISO ���������</li> -</ul></li> -</ul></p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 229 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/zh_TW/Makefile.am b/plugins/kimchi/ui/pages/help/zh_TW/Makefile.am deleted file mode 100644 index 9c8ac26..0000000 --- a/plugins/kimchi/ui/pages/help/zh_TW/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -zh_TW_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/zh_TW - -dist_zh_TW_help_DATA = $(wildcard *.html) $(NULL) - -EXTRA_DIST = $(wildcard *.dita) - -CLEANFILES = $(wildcard *.html) diff --git a/plugins/kimchi/ui/pages/help/zh_TW/guests.dita b/plugins/kimchi/ui/pages/help/zh_TW/guests.dita deleted file mode 100644 index cf73785..0000000 --- a/plugins/kimchi/ui/pages/help/zh_TW/guests.dita +++ /dev/null @@ -1,120 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhvirtm" xml:lang="zh-tw"> -<title>������</title> -<shortdesc>���<wintitle>������</wintitle>������������������������������ KVM ���������������</shortdesc> -<csbody> -<p>���������������������������������������������������<dl><dlentry> -<dt>������</dt> -<dd>������������������������</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������ I/O</dt> -<dd>������������/������������������ (KB/s)���</dd> -</dlentry><dlentry> -<dt>������ I/O</dt> -<dd>������������/������������������ (KB/s)���</dd> -</dlentry><dlentry> -<dt>Livetile</dt> -<dd>��������������������������������������������������� <tm tmtype="tm" trademark="Linux">Linux</tm> ������������������������������������������������������������������</dd> -</dlentry></dl></p> -<p>���������������������������������������������������������<dl> -<dlentry> -<dt>������</dt> -<dd>���������������������������</dd> -</dlentry><dlentry> -<dt>���������������������������</dt> -<dd>���������������������������������������������������������������������������������������������������������������������������������������������������</dd> -</dlentry></dl> </p> -<p>���������������������������������������������<ul> -<li>������<uicontrol>������</uicontrol>���������������������������������������������������</li> -<li>������<uicontrol>������������</uicontrol>���������������������������������</li> -<li>������<uicontrol>������</uicontrol>������������������</li> -<li>������<uicontrol>������</uicontrol>������������������������������������������������������������������������</li> -<li>������<uicontrol>������</uicontrol>������������������</li> -</ul>������������������������������������������������������������������������<uicontrol>������ (+)</uicontrol> ���������</p> -</csbody> -<cshelp id="kimhvirtmcrt" xml:lang="zh-tw"> -<title>������������������</title> -<shortdesc>���������������������������������������</shortdesc> -<csbody> -<p> <ol> -<li>������������������������������������������</li> -<li rev="rev1">���������������<ul> -<li>������������������������������������������������������</li> -<li>���������������������������������<uicontrol>������������</uicontrol>������������������</li> -</ul></li> -<li>���������<uicontrol>������</uicontrol>���</li> -</ol> </p> -</csbody> -</cshelp> -<cshelp id="kimhvirtmedit" xml:lang="zh-tw"> -<title>������������</title> -<shortdesc>������������������������������������������������������������������������������������������������������������������������������������</shortdesc> -<csprolog><csmetadata></csmetadata></csprolog> -<csbody> -<p>������������������������������������<wintitle>������</wintitle>���������������������������������<dl> -<dlentry> -<dt>������</dt> -<dd>������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>���������������������������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>��������������� (MB)������������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������������������������������ (Livetile) ��������������� Linux ������������������������������</dd> -</dlentry></dl></p> -<p>���������������������������<wintitle>������</wintitle>���������������</p> -<dl><dlentry> -<dt>���������</dt> -<dd>��������������������� ISO ������������������</dd> -</dlentry></dl> -<p> ���������������������������������������������������������������<uicontrol>������</uicontrol>���</p> -</csbody> -</cshelp> -<cshelp id="kimstoragedevice" xml:lang="zh-tw"> -<title>������������������������������������</title> -<shortdesc rev="rev1">������������������������������������������������������������������������������������������ CDROM������������������������������������������������������</shortdesc> -<csbody> -<ol> -<li>������<wintitle>������������</wintitle>������������������������<wintitle>���������</wintitle>������</li> -<li>���������������������������������������������<uicontrol>������������ (/)</uicontrol> ��������������������������� -ISO ������������������������������<uicontrol>������</uicontrol>���</li> -<li>���������������������������������������������<uicontrol>������������ (/)</uicontrol> ���������������������������������������������������<uicontrol>������</uicontrol>���</li> -<li>���������������������������������������������������<uicontrol>������ (+)</uicontrol> ������������������������������������������ -ISO ������������������������������<uicontrol>������</uicontrol>���</li> -</ol> -</csbody> -</cshelp> -<cshelp id="kimreplacemedia" xml:lang="zh-tw"> -<title>��������������������� CDROM</title> -<shortdesc rev="rev1">��������������������������������������������������� CDROM ������������</shortdesc> -<csbody> -<ol> -<li>������������������������������</li> -<li>������������������������������������<uicontrol>������������</uicontrol>���</li> -<li>��������������������� CDROM ��������������������������������� hdc ���������������<uicontrol>������������ (/)</uicontrol> ���������</li> -<li>������<wintitle>��������������������� CDROM</wintitle>��������������������� ISO ������������������������������������������������</li> -<li>���������<uicontrol>������</uicontrol>���</li> -</ol> -</csbody> -</cshelp> -<?tm 1391540919 3?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 231 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/zh_TW/host.dita b/plugins/kimchi/ui/pages/help/zh_TW/host.dita deleted file mode 100644 index a55aae4..0000000 --- a/plugins/kimchi/ui/pages/help/zh_TW/host.dita +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhhost" xml:lang="zh-tw"> -<title>������</title> -<shortdesc>���<wintitle>������</wintitle>���������������������������������������������������������������������������������������������������������</shortdesc> -<csbody> -<p>������������������������������������������<ul> -<li>������<uicontrol>������</uicontrol>������������������������</li> -<li>������<uicontrol>������������</uicontrol>������������������������������</li> -<li>������<uicontrol>������</uicontrol>��������������������������� VNC ������������������������������������������������</li> -</ul></p> -<p>������������������������������������������������������<dl> -<dlentry> -<dt>������������</dt> -<dd>������������������������������������������������������������������������������������������������������������������ (GB)���</dd> -</dlentry><dlentry> -<dt>������������������</dt> -<dd>��������������������������������������������������� CPU��������������������� I/O ��������� I/O ������������������������<uicontrol>���������������������������������</uicontrol>���������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>���������������������������������������������������������������������������������������������������������������������������������������������<uicontrol>������������</uicontrol>���������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ -Red Hat Enterprise Linux ��� Fedora������������������ <filepath>yum</filepath> ��������������������������������� -Ubuntu ��� Debian������������������ <filepath>deb</filepath> ������������<p>��������������������� -yum ��������������������������� GPG ���������������������������������������������������������������������������������������������<uicontrol>������</uicontrol>���������<uicontrol>���</uicontrol>��������� -GPG ��������������������������������� GPG ������������ URL���</p></dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>���������������������������������������������������������������������������������������������������������������������������������������������������������<p>��������������������� -<cmdname>sosreport</cmdname> ������������������������������������ Red -Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>���Fedora -��� Ubuntu ��������������������������������� .tar ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������</p> </dd> -</dlentry></dl></p> -</csbody> -<?tm 1392659967 1?> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 232 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/zh_TW/network.dita b/plugins/kimchi/ui/pages/help/zh_TW/network.dita deleted file mode 100644 index f392060..0000000 --- a/plugins/kimchi/ui/pages/help/zh_TW/network.dita +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhnetw" xml:lang="zh-tw"> -<title>������</title> -<shortdesc>���<wintitle>������</wintitle>������������������������������������������������</shortdesc> -<csbody> -<p><dl><dlentry> -<dt>������������</dt> -<dd>������������������������<uicontrol>���������</uicontrol>���</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>���������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>������������������������<uicontrol>NAT</uicontrol>���������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������<uicontrol>virbr0</uicontrol>������������������</dd> -</dlentry><dlentry> -<dt>������������</dt> -<dd>IP ���������</dd> -</dlentry></dl></p> -<p>������������������������<ul> -<li rev="rev1">������<uicontrol>������</uicontrol>������������������������</li> -<li>������<uicontrol>������</uicontrol>������������������������</li> -<li>������<uicontrol>������</uicontrol>������������������������</li> -</ul>���������������������������������������������������������<uicontrol>������ (+)</uicontrol> ���������</p> -</csbody> -<cshelp id="kimhnetwcrt" xml:lang="zh-tw"> -<title>������������</title> -<shortdesc>������������</shortdesc> -<csbody> -<p> <ol> -<li>������������������������</li> -<li>���������������������������������<dl rev="rev1"><dlentry> -<dt><uicontrol>���������</uicontrol></dt> -<dd>������������������������������������������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt><uicontrol>NAT</uicontrol></dt> -<dd>������������������������������������������������������������������ IP ������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt><uicontrol>���������</uicontrol></dt> -<dd>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� VLAN ���������</dd> -</dlentry></dl></li> -<li>���������<uicontrol>������</uicontrol>���</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 230 --> -<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/plugins/kimchi/ui/pages/help/zh_TW/storage.dita b/plugins/kimchi/ui/pages/help/zh_TW/storage.dita deleted file mode 100644 index 971619c..0000000 --- a/plugins/kimchi/ui/pages/help/zh_TW/storage.dita +++ /dev/null @@ -1,88 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhstor" xml:lang="zh-tw"> -<title>���������</title> -<shortdesc>���<wintitle>���������</wintitle>������������������������������������������������������������������������������������ 'ISO' ��������������������������������������� ISO��������������������� 'ISO' ������������������</shortdesc> -<csbody> -<p>������������������������������������������������������<dl> -<dlentry> -<dt>������</dt> -<dd>������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>���������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������<uicontrol>dir</uicontrol>���</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>���������������������������������������</dd> -</dlentry></dl></p> -<p>������������������������������������������������<ul> -<li>������<uicontrol>������</uicontrol>������������������������������������������</li> -<li>������<uicontrol>������������</uicontrol>���������������������������������������</li> -<li>������<uicontrol>������������</uicontrol>������������������������������������</li> -</ul></p> -<p>������������������������������������������������������������������������������������������������������������������������������<dl><dlentry> -<dt>������</dt> -<dd>���������������������������<uicontrol>������</uicontrol>���</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>���������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>���������������������������������������</dd> -</dlentry></dl>������������������������������������������������������������<uicontrol>������ (+)</uicontrol> ���������</p> -</csbody> -<cshelp id="kimhdefstor" xml:lang="zh-tw"> -<title>���������������</title> -<shortdesc> ������������������</shortdesc> -<csbody> -<p> <ol> -<li>���<uicontrol>���������������</uicontrol>���������������������������������������������������</li> -<li>���<uicontrol>���������������</uicontrol>���������������������������<dl><dlentry> -<dt><uicontrol>DIR</uicontrol></dt> -<dd>��������������������������������� <uicontrol>DIR</uicontrol> ���������������<uicontrol>���������������</uicontrol>���������������������������</dd> -</dlentry><dlentry> -<dt><uicontrol>NFS</uicontrol></dt> -<dd>��������������������������������������������� <uicontrol>NFS</uicontrol> ��������������� -<uicontrol>NFS ��������� IP</uicontrol> ��������� <uicontrol>NFS -������</uicontrol>���������������������������������</dd> -</dlentry><dlentry> -<dt><uicontrol>iSCSI</uicontrol></dt> -<dd>��������� iSCSI ��������������������������������������������������������� -<uicontrol>iSCSI</uicontrol> ��������������� <uicontrol>iSCSI -���������</uicontrol> IP ��������� iSCSI ���������������<uicontrol>������</uicontrol>������������������������������������ iSCSI ���������</dd> -</dlentry><dlentry> -<dt><uicontrol>������</uicontrol></dt> -<dd>���������������������������������<uicontrol>������������</uicontrol>���������������������������</dd> -</dlentry><dlentry> -<dt><uicontrol>SCSI ������������</uicontrol></dt> -<dd>������ SCSI ������������������������������������������������ SCSI ������������</dd> -</dlentry></dl></li> -<li>���������<uicontrol>������</uicontrol>���</li> -</ol> </p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 233 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/help/zh_TW/templates.dita b/plugins/kimchi/ui/pages/help/zh_TW/templates.dita deleted file mode 100644 index 4b3a6a6..0000000 --- a/plugins/kimchi/ui/pages/help/zh_TW/templates.dita +++ /dev/null @@ -1,112 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--Arbortext, Inc., 1988-2011, v.4002--> -<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" - "..\dtd\cshelp.dtd"> - - -<!--This DITA specialized document type is not supported by the Authoring Tools development team. -For support please see: -https://w3.opensource.ibm.com/projects/dita-cshelp/--> -<cshelp id="kimhtempl" xml:lang="zh-tw"> -<title>������</title> -<shortdesc>���<wintitle>������</wintitle>��������������������������������� -KVM ���������������������������������������</shortdesc> -<csbody> -<p>���������������������������������������������������<dl> -<dlentry> -<dt>OS</dt> -<dd>������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������������������</dd> -</dlentry><dlentry> -<dt>CPU</dt> -<dd>������������������������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>��������������������������������������� (MB)���</dd> -</dlentry></dl></p> -<p>���������������������������������������������<ul> -<li>������<uicontrol>������</uicontrol>������������������</li> -<li>������<uicontrol>������</uicontrol>������������������</li> -</ul>���������������������������������������������������������<uicontrol>������ (+)</uicontrol> ���������</p> -</csbody> -<cshelp id="kimhedittempl" xml:lang="zh-tw"> -<title>������������</title> -<shortdesc>���������������������</shortdesc> -<csbody> -<p>���������������������������������������������������<dl> -<dlentry> -<dt>������</dt> -<dd>������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������������������������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>���������������������������������������������������������������</dd> -</dlentry><dlentry> -<dt>CPU ������</dt> -<dd>������������������������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������������������������������������������ (MB)���</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������ (GB)���</dd> -</dlentry><dlentry> -<dt>CDROM</dt> -<dd>������������ KVM ��������� ISO ������������������������������</dd> -</dlentry><dlentry> -<dt>���������</dt> -<dd>������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>KVM ���������������������������������������������������������������������</dd> -</dlentry></dl> ���������������������������������������������������������������<uicontrol>������</uicontrol>���</p> -</csbody> -</cshelp> -<cshelp id="kimhaddtempl"> -<title>������������</title> -<shortdesc>������������������������������������������������������ ISO ������������������ 'ISO' ������������������������������������</shortdesc> -<csbody> -<p>������������������������������������������������<dl> -<dlentry> -<dt>������ ISO ���������</dt> -<dd>��������������������������������������������������������������� ISO ������������</dd> -</dlentry><dlentry> -<dt>������ ISO ���������</dt> -<dd>��������������������������� ISO ���������������������������</dd> -</dlentry></dl></p> -</csbody> -</cshelp> -<cshelp id="kimhaddloct"> -<title>������������ - ������ ISO ���������</title> -<shortdesc>��������� ISO ������������������������</shortdesc> -<csbody> -<p>������������������������������ ISO ������������<dl><dlentry> -<dt>OS</dt> -<dd>������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>������������������������������������������������</dd> -</dlentry><dlentry> -<dt>������</dt> -<dd>ISO ���������������������</dd> -</dlentry></dl></p> -<p>��������� ISO ������������������������������������������������������<ul> -<li>������������������������������ ISO ���������������������������<uicontrol>��������� ISO ������������</uicontrol>���</li> -<li>������<uicontrol>������</uicontrol>������������������������ ISO ���������������������������������������<uicontrol>��������� ISO ������������</uicontrol>���</li> -<li>������������������ ISO ���������������������������������������������������������������������������<ul> -<li>������<uicontrol>��������������������� ISO ������</uicontrol>��������� ISO ���������������������</li> -<li>���������<uicontrol>������������ ISO</uicontrol> ��������������� ISO ������������</li> -</ul></li> -</ul></p> -</csbody> -</cshelp> -</cshelp> - - -<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> -<!-- T9N_SRC_ID 229 --> -<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/plugins/kimchi/ui/pages/host.html.tmpl b/plugins/kimchi/ui/pages/host.html.tmpl deleted file mode 100644 index d87debc..0000000 --- a/plugins/kimchi/ui/pages/host.html.tmpl +++ /dev/null @@ -1,177 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# - -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<!DOCTYPE html> -<html> -<head> -<link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> -<script src="plugins/kimchi/js/kimchi.min.js"></script> -</head> -<body> -<div id="host-root-container"> - <div class="toolbar"> - <div class="tools"> - </div> - </div> - <div id="host-content-container" class="empty-when-logged-off"></div> -</div> - -<script id="host-tmpl" type="kimchi/template"> - <div class="host-panel"> - <div class="logo-container"> - <div class="logo" style="background-image: url({logo});"></div> - </div> - <div id="host-info-container" class="info-container"> - <h2 class="hostname">{hostname}</h2> - <div class="action-panel"> - <button id="host-button-shutdown" class="btn-normal-1 stop"> - <div class="button-icon action-icon-stop"></div> - $_("Shut down") - </button> - <button id="host-button-restart" class="btn-normal-1 restart"> - <div class="button-icon action-icon-restart"></div> - $_("Restart") - </button> - <button class="btn-normal-1 connect" disabled="disabled"> - <div class="button-icon action-icon-connect"></div> - $_("Connect") - </button> - </div> - <div class="host-section"> - <h3 class="section-header" - aria-expanded="false" - aria-controls="content-sys-info"> - $_("Basic Information") - </h3> - <div id="content-sys-info" class="section-content"> - <div class="section-row"> - <div class="section-label">$_("OS Distro")</div> - <div class="section-value">{os_distro}</div> - </div> - <div class="section-row"> - <div class="section-label">$_("OS Version")</div> - <div class="section-value">{os_version}</div> - </div> - <div class="section-row"> - <div class="section-label">$_("OS Code Name")</div> - <div class="section-value">{os_codename}</div> - </div> - <div class="section-row"> - <div class="section-label">$_("Processor")</div> - <div class="section-value">{cpu_model}</div> - </div> - <div class="section-row"> - <div class="section-label">$_("CPU(s)")</div> - <div class="section-value">{cpus}</div> - </div> - <div class="section-row"> - <div class="section-label">$_("Memory")</div> - <div class="section-value">{memory}</div> - </div> - </div> - </div> - <div class="host-section"> - <h3 class="section-header" - aria-controls="content-sys-statistics"> - $_("System Statistics") - </h3> - <div id="content-sys-statistics" class="section-content"> - <div class="section-row"> - <div class="section-label">$_("CPU")</div> - <div class="section-value"> - <div id="container-chart-cpu" class="inline-block"></div> - </div> - </div> - <div class="section-row"> - <div class="section-label">$_("Memory")</div> - <div class="section-value"> - <div id="container-chart-memory" class="inline-block"></div> - </div> - </div> - <div class="section-row"> - <div class="section-label">$_("Disk I/O")</div> - <div class="section-value"> - <div id="container-chart-disk-io" class="inline-block"></div> - </div> - </div> - <div class="section-row"> - <div class="section-label">$_("Network I/O")</div> - <div class="section-value"> - <div id="container-chart-network-io" class="inline-block"></div> - </div> - </div> - </div> - </div> - <div id="software-update-section" class="host-section hidden"> - <h3 class="section-header" - aria-controls="content-software-update"> - $_("Software Updates") - </h3> - <div id="content-software-update" class="section-content"> - <div class="section-row"> - <div class="section-value"> - <div id="software-updates-grid-container"></div> - <div id="software-updates-progress-container" class="hidden"> - <label for="software-updates-progress-textarea">$_("Update Progress")</label> - <textarea id="software-updates-progress-textarea" readonly></textarea> - </div> - </div> - </div> - </div> - </div> - <div id="repositories-section" class="host-section hidden"> - <h3 class="section-header" - aria-controls="content-repositories"> - $_("Repositories") - </h3> - <div id="content-repositories" class="section-content"> - <div class="section-row"> - <div class="section-value"> - <div id="repositories-grid-container"></div> - </div> - </div> - </div> - </div> - <div id="debug-report-section" class="host-section hidden"> - <h3 class="section-header" - aria-controls="content-sys-reports"> - $_("Debug Reports") - </h3> - <div id="content-sys-reports" class="section-content"> - <div class="section-row"> - <div class="section-value"> - <div id="available-reports-grid-container"></div> - </div> - </div> - </div> - </div> - </div> - </div> -</script> - -<script type="text/javascript"> - kimchi.host_main(); -</script> -</body> -</html> diff --git a/plugins/kimchi/ui/pages/i18n.json.tmpl b/plugins/kimchi/ui/pages/i18n.json.tmpl deleted file mode 100644 index cd320e0..0000000 --- a/plugins/kimchi/ui/pages/i18n.json.tmpl +++ /dev/null @@ -1,187 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2014-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -{ - "KCHAUTH6001E": "$_("The username or password you entered is incorrect. Please try again.")", - "KCHAUTH6002E": "$_("This field is required.")", - - "KCHAUTH6001M": "$_("Log in")", - "KCHAUTH6002M": "$_("Logging in...")", - - "Host": "$_("Host")", - "Guests": "$_("Guests")", - "Templates": "$_("Templates")", - "Storage": "$_("Storage")", - "Network": "$_("Network")", - - "KCHAPI6002E": "$_("Failed to get application configuration")", - "KCHAPI6003E": "$_("This is not a valid Linux path")", - "KCHAPI6004E": "$_("This is not a valid URL.")", - "KCHAPI6005E": "$_("No such data available.")", - "KCHAPI6007E": "$_("Can not contact the host system. Verify the host system is up and that you have network connectivity to it. HTTP request response %1. ")", - "KCHAPI6008E": "$_("Unable to read file.")", - "KCHAPI6009E": "$_("Error while uploading file.")", - - "KCHAPI6001M": "$_("Delete Confirmation")", - "KCHAPI6002M": "$_("OK")", - "KCHAPI6003M": "$_("Cancel")", - "KCHAPI6004M": "$_("Confirm")", - "KCHAPI6005M": "$_("Create")", - "KCHAPI6006M": "$_("Warning")", - "KCHAPI6007M": "$_("Save")", - "KCHAPI6008M": "$_("Creating...")", - "KCHAPI6009M": "$_("Cloning...")", - - "KCHGRD6001M": "$_("Loading...")", - "KCHGRD6002M": "$_("An error occurred while retrieving system information.")", - "KCHGRD6003M": "$_("Retry")", - "KCHGRD6004M": "$_("Detailed message:")", - - "KCHTMPL6001W": "$_("No ISO found")", - - "KCHTMPL6002E": "$_("This is not a valid ISO file.")", - - "KCHTMPL6002M": "$_("This may take a long time. Do you want to continue?")", - "KCHTMPL6003M": "$_("This will permanently delete the template. Would you like to continue?")", - - "KCHHOST6001E": "$_("Unable to shut down system as there are some virtual machines running!")", - - "KCHHOST6001M": "$_("Max:")", - "KCHHOST6002M": "$_("Utilization")", - "KCHHOST6003M": "$_("Available")", - "KCHHOST6004M": "$_("Read Rate")", - "KCHHOST6005M": "$_("Write Rate")", - "KCHHOST6006M": "$_("Received")", - "KCHHOST6007M": "$_("Sent")", - "KCHHOST6008M": "$_("Shutting down or restarting host will cause unsaved work lost. Continue to shut down/restarting?")", - - - "KCHREPO6001M": "$_("Confirm")", - "KCHREPO6002M": "$_("Repository will be removed permanently and can't be recovered. Do you want to continue?")", - "KCHREPO6003M": "$_("Repositories")", - "KCHREPO6004M": "$_("ID")", - "KCHREPO6005M": "$_("Name")", - "KCHREPO6006M": "$_("Base URL")", - "KCHREPO6007M": "$_("Is Mirror")", - "KCHREPO6008M": "$_("URL Args")", - "KCHREPO6009M": "$_("Enabled")", - "KCHREPO6010M": "$_("GPG Check")", - "KCHREPO6011M": "$_("GPG Key")", - "KCHREPO6012M": "$_("Add")", - "KCHREPO6013M": "$_("Edit")", - "KCHREPO6014M": "$_("Remove")", - "KCHREPO6016M": "$_("Enable")", - "KCHREPO6017M": "$_("Disable")", - - - "KCHUPD6001M": "$_("Software Updates")", - "KCHUPD6002M": "$_("Package Name")", - "KCHUPD6003M": "$_("Version")", - "KCHUPD6004M": "$_("Architecture")", - "KCHUPD6005M": "$_("Repository")", - "KCHUPD6006M": "$_("Update All")", - "KCHUPD6007M": "$_("Updating...")", - "KCHUPD6008M": "$_("Failed to retrieve packages update information.")", - "KCHUPD6009M": "$_("Failed to update package(s).")", - - - "KCHDR6001M": "$_("Debug report will be removed permanently and can't be recovered. Do you want to continue?")", - "KCHDR6002M": "$_("Debug Reports")", - "KCHDR6003M": "$_("Name")", - "KCHDR6005M": "$_("Generated Time")", - "KCHDR6006M": "$_("Generate")", - "KCHDR6007M": "$_("Generating...")", - "KCHDR6008M": "$_("Rename")", - "KCHDR6009M": "$_("Remove")", - "KCHDR6010M": "$_("Download")", - "KCHDR6011M": "$_("Report name should contain only letters, digits, underscore ('_') and/or hyphen ('-').")", - "KCHDR6012M": "$_("Pending...")", - "KCHDR6013M": "$_("Report name is the same as the original one.")", - - "KCHVM6001M": "$_("This will delete the virtual machine and its virtual disks. This operation cannot be undone. Would you like to continue?")", - "KCHVM6002M": "$_("Power off Confirmation")", - "KCHVM6003M": "$_("This action may produce undesirable results, " - "for example unflushed disk cache in the guest. " - "Would you like to continue?")", - "KCHVM6004M": "$_("Reset Confirmation")", - "KCHVM6005M": "$_("There is a risk of data loss caused by reset without" - " the guest OS shutdown. Would you like to continue?")", - "KCHVM6006M": "$_("Shut Down Confirmation")", - "KCHVM6007M": "$_("Note the guest OS may ignore this request. Would you like to continue?")", - "KCHVM6008M": "$_("Virtual Machine delete Confirmation")", - "KCHVM6009M": "$_("This virtual machine is not persistent. Power Off will delete it. Continue?")", - "KCHVM6010M": "$_("When the target guest has SCSI or iSCSI volumes, they will be cloned on default storage pool. The same will happen when the target pool does not have enough space to clone the volumes. Do you want to continue?")", - - "KCHVMCD6001M": "$_("This CDROM will be detached permanently and you can re-attach it. Continue to detach it?")", - "KCHVMCD6002M": "$_("Attach")", - "KCHVMCD6003M": "$_("Attaching...")", - "KCHVMCD6004M": "$_("Replace")", - "KCHVMCD6005M": "$_("Replacing...")", - "KCHVMCD6006M": "$_("Successfully attached!")", - "KCHVMCD6007M": "$_("Successfully replaced!")", - "KCHVMCD6008M": "$_("Successfully detached!")", - "KCHVMCD6009M": "$_("This disk will be detached permanently and you can re-attach it. Continue to detach it?")", - - "KCHVMED6001M": "$_("interface:")", - "KCHVMED6002M": "$_("address:")", - "KCHVMED6003M": "$_("link_type:")", - "KCHVMED6004M": "$_("block:")", - "KCHVMED6005M": "$_("drive_type:")", - "KCHVMED6006M": "$_("model:")", - "KCHVMED6007M": "$_("Affected devices:")", - - "KCHNET6001E": "$_("The VLAN id must be between 1 and 4094.")", - - "KCHNET6001M": "$_("unavailable")", - "KCHNET6002M": "$_("This action will interrupt network connectivity for any virtual machine that depend on this network.")", - "KCHNET6003M": "$_("Create a network")", - "KCHNET6004M": "$_("This network is not persistent. Instead of stop, this action will permanently delete it. Would you like to continue?")", - "KCHNET6001W": "$_("The bridged VLAN tag may not work well with NetworkManager enabled. You should consider disabling it.")", - - "KCHPOOL6001M": "$_("This will permanently delete the storage pool. Would you like to continue?")", - "KCHPOOL6002M": "$_("This storage pool is empty.")", - "KCHPOOL6003M": "$_("It will format your disk and you will loose any data in there, are you sure to continue? ")", - "KCHPOOL6004M": "$_("SCSI Fibre Channel")", - "KCHPOOL6005M": "$_("No SCSI adapters found.")", - "KCHPOOL6006M": "$_("Loading iSCSI targets...")", - "KCHPOOL6007M": "$_("No iSCSI found. Please input one.")", - "KCHPOOL6008M": "$_("Failed to load iSCSI targets.")", - - "KCHPOOL6001E": "$_("The storage pool name can not be blank.")", - "KCHPOOL6002E": "$_("The storage pool path can not be blank.")", - "KCHPOOL6003E": "$_("NFS server mount path can not be blank.")", - "KCHPOOL6005E": "$_("Invalid NFS mount path.")", - "KCHPOOL6006E": "$_("No logical device selected.")", - "KCHPOOL6007E": "$_("The iSCSI target can not be blank.")", - "KCHPOOL6008E": "$_("Server name can not be blank.")", - "KCHPOOL6009E": "$_("This is not a valid Server Name or IP. Please, modify it.")", - "KCHPOOL6010M": "$_("Looking for available partitions ...")", - "KCHPOOL6011M": "$_("No available partitions found.")", - "KCHPOOL6012M": "$_("This storage pool is not persistent. Instead of deactivate, this action will permanently delete it. Would you like to continue?")", - "KCHPOOL6013M": "$_("Unable to retrieve partitions information.")", - "KCHPOOL6014M": "$_("In progress...")", - "KCHPOOL6015M": "$_("Failed!")", - - "KCHVMSTOR0001E": "$_("CDROM path needs to be a valid local/remote path and cannot be blank.")", - "KCHVMSTOR0002E": "$_("Disk pool or volume cannot be blank.")" -} diff --git a/plugins/kimchi/ui/pages/network.html.tmpl b/plugins/kimchi/ui/pages/network.html.tmpl deleted file mode 100644 index 915feac..0000000 --- a/plugins/kimchi/ui/pages/network.html.tmpl +++ /dev/null @@ -1,133 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# - -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<!DOCTYPE html> -<html> -<head> -<link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> -<script src="plugins/kimchi/js/kimchi.min.js"></script> -</head> -<body> -<div class="toolbar"> - <div class="tools" style="display:none"> - <a id="networkAdd" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> - </div> -</div> -<div id="network-content" class="network"> - <div class="grid-control"><input type="text" class="filter" placeholder="$_("Filter")"></div> - <div id="networkGrid" class="list"> - <div> - <span class="column-name">$_("Network Name")</span><!-- - --><span class="column-state">$_("State")</span><!-- - --><span class="column-type">$_("Network Type")</span><!-- - --><span class="column-interface">$_("Interface")</span><!-- - --><span class="column-space">$_("Address Space")</span><!-- - --><span style="display:none">$_("Actions")</span> - </div> - <div id="networkBody" class="empty-when-logged-off"></div> - </div> - <div id="networkConfig" class="network-config"> - <div class="section-container"> - <div class="section-header">1. $_("Network Name")</div> - <div class="section-content"> - <input type="text" id="networkName" /> - <div class="input-hint"> - <span class="icon-info-circled light-grey c1 help-inline"></span> - <span class="input-hint-text help-inline">$_("Name should not contain '/' and '\"'.")</span> - </div> - </div> - </div> - <div class="section-container"> - <div class="section-header">2. $_("Network Type")</div> - <div class="section-content"> - <div class="input-container"> - <input type="radio" id="networkTypeIso" name="networkType" value="isolated" /> - <label for="networkTypeIso">$_("Isolated: no external network connection")</label> - </div> - <div class="input-container"> - <input type="radio" id="networkTypeNat" name="networkType" value="nat" /> - <label for="networkTypeNat">$_("NAT: outbound physical network connection only")</label> - </div> - <div class="input-container"> - <div class="bridged-inline"> - <input type="radio" id="networkTypeBri" name="networkType" value="bridged" /> - </div> - <div class="bridged-inline"> - <label for="networkTypeBri">$_("Bridged: Virtual machines are connected to physical network directly")</label><br /> - <label id="networkBriDisabledLabel" style="display:none">$_("(No interfaces found)")</label> - </div> - </div> - <div id="bridgeOptions"> - <div> - <div class="bridge-option-column"> - <label for="networkInterface">$_("Destination"): </label> - </div> - <div class="bridge-option-column"> - <div class="network-type-wrapper-controls"> - <div id ="networkDestinationID"> - <input id="networkDestinationInputId" name="type" type="hidden"/> - <span id="networkDestinationLabel" type="text"></span><span class="arrow"></span> - <div> - <ul id="networkInterface"></ul> - </div> - </div> - </div> - </div> - </div> - <div> - <input id="enableVlan" type="checkbox" value="" /> - <label for="enableVlan" id="labelEnableVlan">$_("Enable VLAN") </label> - </div> - <label for="networkVlanID" id="labelNetworkVlanID">$_("VLAN ID"): </label> - <input type="text" id="networkVlanID" class="network-label"/> - </div> - </div> - </div> - </div> - </div> -</div> -<script id="networkItem" type="text/html"> - <div id='{name}' class='remove-when-logged-off'> - <span class='column-name' title="{name}" val="{name}">{name}</span><!-- - --><span class='column-state' val="{state}"><span class='network-state {state}'></span></span><!-- - --><span class='column-type' val="{type}">{type}</span><!-- - --><span class='column-interface' val="{interface}">{interface}</span><!-- - --><span class='column-space' val="{addrSpace}">{addrSpace}</span><!-- - --><span class='column-action' style="display:none"> - <span class="ui-button-secondary dropdown popable action-button"> - $_("Actions") - <ul class='popover actionsheet right-side menu-container'> - <li nwAct="start" class='{startClass}'><a class='button-big'>$_("Start")</a></li> - <li nwAct="stop" class='{stopClass}'><a {stopDisabled} class='button-big'>$_("Stop")</a></li> - <li nwAct="delete" class='{deleteClass}'><a {deleteDisabled} class='red'>$_("Delete")</a></li> - </ul> - </span> - </span> - </div> -</script> -<script> - kimchi.initNetwork(); -</script> -</body> -</html> diff --git a/plugins/kimchi/ui/pages/report-add.html.tmpl b/plugins/kimchi/ui/pages/report-add.html.tmpl deleted file mode 100644 index 25bf0a9..0000000 --- a/plugins/kimchi/ui/pages/report-add.html.tmpl +++ /dev/null @@ -1,56 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<!DOCTYPE html> -<div id="report-add-window" class="window"> - <header> - <h1 class="title h1 grey">$_("Generate a New Debug Report")</h1> - </header> - <div class="content"> - <form id="form-report-add"> - <section class="form-section"> - <h2> - <label for="report-name-textbox">$_("Report Name")</label> - </h2> - <div class="field"> - <input type="text" class="text" id="report-name-textbox" name="name" /> - <span class="icon-info-circled light-grey c1"></span> - <span class="info-add-debug-report"> - $_("The name used to identify the report. If omitted, a name will be chosen based on current time. Name can contain: letters, digits, underscore (\"_\") and hyphen (\"-\").") - </span> - </div> - </section> - </form> - </div> - <footer> - <div class="btn-group"> - <button id="button-report-add" class="btn-normal"><span class="text">$_("Generate")</span></button> - <button id="button-report-cancel" class="btn-normal close" type="button"> - <span calss="text">$_("Cancel")</span> - </button> - </div> - </footer> -</div> -<script> - kimchi.report_add_main(); -</script> diff --git a/plugins/kimchi/ui/pages/report-rename.html.tmpl b/plugins/kimchi/ui/pages/report-rename.html.tmpl deleted file mode 100644 index 90a0a80..0000000 --- a/plugins/kimchi/ui/pages/report-rename.html.tmpl +++ /dev/null @@ -1,56 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2014-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<!DOCTYPE html> -<div id="report-rename-window" class="window"> - <header> - <h1 class="title h1 grey">$_("Rename a Debug Report")</h1> - </header> - <div class="content"> - <form id="form-report-rename"> - <section class="form-section"> - <h2> - <label for="report-name-textbox">$_("Report Name")</label> - </h2> - <div class="field"> - <input type="text" class="text" id="report-name-textbox" name="name" /> - <span class="icon-info-circled light-grey c1"></span> - <span class="info-debug-report-rename"> - $_("The name used to identify the report. Name can contain: letters, digits and hyphen (\"-\").") - </span> - </div> - </section> - </form> - </div> - <footer> - <div class="btn-group"> - <button id="button-report-rename" class="btn-normal"><span class="text">$_("Submit")</span></button> - <button id-"button-report-rename-cancel" class="btn-normal close" type="button"> - <span class="text">$_("Cancel")</span> - </button> - </div> - </footer> -</div> -<script> - kimchi.report_rename_main(); -</script> diff --git a/plugins/kimchi/ui/pages/repository-add.html.tmpl b/plugins/kimchi/ui/pages/repository-add.html.tmpl deleted file mode 100644 index 950252a..0000000 --- a/plugins/kimchi/ui/pages/repository-add.html.tmpl +++ /dev/null @@ -1,113 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2014-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<div id="repository-add-window" class="window"> - <form id="form-repository-add"> - <header class="window-header"> - <h1 class="title h1 grey">$_("Add a Repository")</h1> - </header> - <section> - <div class="content"> - <div class="form-section yum"> - <h2>$_("Identifier")</h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" class="text" name="repo_id" /> - </div> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("Single word, unique identifier for the repository.") - </p> - </div> - </div> - <section class="form-section yum"> - <h2>$_("Name")</h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" class="text" name="config[repo_name]" /> - </div> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("Textual name for the repository.") - </p> - </div> - </section> - <section class="form-section"> - <h2>$_("URL")<span class="required" role="presentation" title='$_("Required Field")'>*</span></h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" class="text required" name="baseurl" /> - </div> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("URL to the repository. Supported protocols are http, ftp, and file.") - </p> - </div> - <div class="field yum"> - <p class="yum"> - <input type="checkbox" name="isMirror" value="true" id="isMirror" /> - <label id="isMirrorLabel" for="isMirror">$_("Repository is a mirror")</label> - </p> - </div> - </section> - <section class="form-section repository-dist deb"> - <h2>$_("Distribution")</h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" class="text" name="config[dist]" /> - </div> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("Distribution of the DEB repository.") - </p> - </div> - </section> - <section class="form-section repository-comps deb"> - <h2>$_("Components")</h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" class="text" name="config[comps]" /> - </div> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("List of components in DEB repository.") - </p> - </div> - </section> - </div> - </section> - <footer> - <div class="btn-group"> - <button type="submit" id="button-repository-add" class="btn-normal" disabled="disabled"> - <span class="text">$_("Add")</span> - </button> - <button type="button" id="button-repository-close" class="btn-normal close"> - <span class="text">$("Cancel")</span> - </button> - </div> - </footer> - </form> -</div> -<script> - kimchi.repository_add_main(); -</script> diff --git a/plugins/kimchi/ui/pages/repository-edit.html.tmpl b/plugins/kimchi/ui/pages/repository-edit.html.tmpl deleted file mode 100644 index e5a3cfb..0000000 --- a/plugins/kimchi/ui/pages/repository-edit.html.tmpl +++ /dev/null @@ -1,117 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2014-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext - -<div id="repository-edit-window" class="window"> - <form id="form-repository-edit"> - <header> - <h1 class="title h1 grey">$_("Edit Repository")</h1> - </header> - <div class="content"> - <section id="form-repository-edit"> - <fieldset class="repository-edit-fieldset"> - <div class="repository-id yum"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-id-textbox">$_("ID")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-id-textbox" name="repo_id" type="text" disabled="disabled" readonly="readonly"/> - </div> - </div> - <div class="repository-name yum"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-name-textbox">$_("Name")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-name-textbox" class="yum" name="config[repo_name]" type="text" /> - </div> - </div> - <div class="repository-url"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-baseurl-textbox">$_("URL")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-baseurl-textbox" name="baseurl" type="text" /> - </div> - </div> - <div class="repository-dist deb"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-urlargs-textbox">$_("Distribution")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-urlargs-textbox" class="deb" name="config[dist]" type="text" /> - </div> - </div> - <div class="repository-mirrorlist yum"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-urlargs-textbox">$_("Mirror List URL")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-urlargs-textbox" class="yum" name="config[mirrorlist]" type="text" /> - </div> - </div> - <div class="repository-comps deb"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-urlargs-textbox">$_("Components")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-urlargs-textbox" class="deb" name="config[comps]" type="text" /> - </div> - </div> - <div class="repository-gpgkey yum"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-gpgkey-textbox">$_("GPG Key")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-gpgkey-textbox" class="yum" name="config[gpgkey]" type="text" /> - </div> - </div> - <div class="repository-gpgcheck yum"> - <div class="repository-edit-wrapper-label"> - <label>$_("GPG Check")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-gpgcheck-radio-true" class="yum" name="config[gpgcheck]" type="radio" value="true" /> - <label for="repository-edit-gpgcheck-radio-true">$_("Yes")</label> - <input id="repository-edit-gpgcheck-radio-false" class="yum" name="config[gpgcheck]" type="radio" value="false" /> - <label for="repository-edit-gpgcheck-radio-false">$_("No")</label> - </div> - </div> - </fieldset> - </section> - </div> - <footer> - <div class="btn-group"> - <button type="submit" id="repository-edit-button-save" class="btn-normal"> - <span class="text">$_("Save")</span> - </button> - <button type="button" id="repository-edit-button-cancel" class="close btn-normal"> - <span class="text">$_("Cancel")</span> - </button> - </div> - </footer> - </form> -</div> -<script type="text/javascript"> - kimchi.repository_edit_main(); -</script> diff --git a/plugins/kimchi/ui/pages/storage.html.tmpl b/plugins/kimchi/ui/pages/storage.html.tmpl deleted file mode 100644 index 7b51a8b..0000000 --- a/plugins/kimchi/ui/pages/storage.html.tmpl +++ /dev/null @@ -1,143 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# - -#unicode UTF-8 -#import gettext -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<!DOCTYPE html> -<html> -<head> -<link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> -<script src="plugins/kimchi/js/kimchi.min.js"></script> -</head> -<body> -<div class="toolbar"> - <div class="tools" style="display:none"> - <a id="storage-pool-add" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> - </div> -</div> -<div class='storage'> -<div class="grid-control"><input type="text" class="filter" placeholder="$_("Filter")"></div> -<div id='storageGrid'> - <div> - <span class="storage-name">$_("Name")</span> - <span class="storage-state" >$_("State")</span> - <span class="storage-type">$_("Type")</span> - <span class="storage-capacity">$_("Capacity")</span> - <span class="storage-allocate">$_("Allocated")</span> - <span class="storage-location">$_("Location")</span> - </div> - <div id="storagepoolsList" class="list-storage empty-when-logged-off"></div> -</div> -</div> -<div id="logicalPoolExtend" title="$_("Device path")"> - <p id="loading-info" class="text-help"> - <img src = "plugins/kimchi/images/theme-default/loading.gif" /> - $_("Looking for available partitions ...") - </p> - <div class="host-partition"> - </div> -</div> -<script id="storageTmpl" type="html/text"> - <div id="{name}" class="storage-li in" data-name="{name}" data-stat="{state}"> - <span class="storage-name" val="{name}{usage}%"> - <span title="{name}">{name}</span> - <span class="usage">{usage}%</span> - </span> - <span class="storage-state"> - <div class="status-dot toolable active" data-state="{state}"> - <label class="tooltip">$_("active")</label> - </div> - <div class="status-dot toolable inactive" data-state="{state}"> - <label class="tooltip">$_("inactive")</label> - </div> - </span> - <span class="storage-type" val="{type}"> - <div>{type}</div> - </span> - <span class="storage-capacity" val="{capacity}"> - <div data-type="{type}">{capacity}</div> - </span> - <span class="storage-allocate" val="{allocated}"> - <div data-type="{type}">{allocated}</div> - </span> - <span class="storage-location" val="{path}"> - <div>{path}</div> - </span> - <span class="bottom storage-button" style="display:none"> - <div class="btn dropdown popable storage-action" data-state="{state}" data-type="{type}" data-name="{name}"> - <span class="text">$_("Actions")</span><span class="arrow"></span> - <div class="popover actionsheet right-side" style="width: 250px"> - <button class="button-big pool-deactivate" data-stat="{state}" data-name="{name}" data-persistent="{persistent}"><span class="text">$_("Deactivate")</span></button> - <button class="button-big pool-activate" data-stat="{state}" data-name="{name}"><span class="text">$_("Activate")</span></button> - <button class="button-big pool-add-volume" data-stat="{state}" data-name="{name}" data-type="{type}"><span class="text">$_("Add Volume")</span></button> - <button class="button-big pool-extend {enableExt}" data-stat="{state}" data-name="{name}"><span class="text">$_("Extend")</span></button> - <button class="button-big red pool-delete" data-stat="{state}" data-name="{name}"><span class="text">$_("Undefine")</span></button> - </div> - </div> - </span> - <span class="handle"> - <div class="arrow-down"></div> - </span> - <div class="volumes"> - <div id="volume{name}" class="volumeslist" data-name="{name}" ></div> - <div class="clear"></div> - </div> - </div> -</script> -<script id="volumeTmpl" type="html/text"> - <div class="volume-box white-box" data-volume-name="{name}"> - <div class="storage-icon volume-default icon-{format} "> - </div> - <div class="volume-title"> - <div class="volume-name" title="{name}">{name}</div> - <div class="volume-progress hidden"> - <div class="progress-bar-outer"> - <div class="progress-bar-inner"></div> - </div> - <div class="progress-label"> - <span class="progress-status"></span> - <span class="progress-transferred"></span> - </div> - </div> - </div> - <div class="volume-setting"> - </div> - <div class="volume-type-position"> - <div title="{type}" class="volume-text">$_("Type"): {type}</div> - <div title="{format}" class="volume-text">$_("Format"): {format}</div> - </div> - <div class="volume-quota-position"> - <div title="{capacity}" class="volume-textquota">$_("Capacity"): {capacity}</div> - <div title="{allocation}"class="volume-textquota">$_("Allocation"): {allocation}</div> - </div> - </div> -</script> -<script id="logicalPoolExtendTmpl" type="html/text"> - <div> - <input type="checkbox" value="{path}" name="devices"> - <label for="{name}">{path}</label> - </div> -</script> -<script> - kimchi.storage_main(); -</script> -</body> -</html> diff --git a/plugins/kimchi/ui/pages/storagepool-add-volume.html.tmpl b/plugins/kimchi/ui/pages/storagepool-add-volume.html.tmpl deleted file mode 100644 index ab10939..0000000 --- a/plugins/kimchi/ui/pages/storagepool-add-volume.html.tmpl +++ /dev/null @@ -1,79 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2014-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<div id="sp-add-volume-window" class="window"> - <form id="form-sp-add-volume"> - <header class="window-header"> - <h1 class="title h1 grey">$_("Add a Volume to Storage Pool")</h1> - </header> - <section> - <div class="content"> - <div class="form-section"> - <h2> - <input type="radio" id="volume-type-download" class="volume-type" name="volumeType" value="download" checked="checked" /> - <label for="volume-type-download"> - $_("Fetch from remote URL") - </label> - </h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" id="volume-remote-url" class="text volume-input download" name="volumeRemoteURL" /> - </div><br> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("Enter the remote URL here.") - </p> - </div> - </div> - <div class="form-section"> - <h2> - <input type="radio" id="volume-type-upload" class="volume-type" name="volumeType" value="upload"/> - <label for="volume-type-upload"> - $_("Upload a file") - </label> - </h2> - <div class="field"> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("Choose the file you want to upload.") - </p> - <div class="textbox-wrapper"> - <input type="file" class="volume-input upload" id="volume-input-file" name="volumeLocalFile" disabled="disabled" /> - </div> - </div> - </div> - </div> - </section> - <footer> - <div class="btn-group"> - <button type="submit" id="sp-add-volume-button" class="btn-normal" disabled="disabled"> - <span class="text">$_("Add")</span> - </button> - <button type="button" class="btn-normal close"><span class="text">$_("Cancel")</span></button> - </div> - </footer> - </form> -</div> -<script type="text/javascript"> - kimchi.sp_add_volume_main(); -</script> diff --git a/plugins/kimchi/ui/pages/storagepool-add.html.tmpl b/plugins/kimchi/ui/pages/storagepool-add.html.tmpl deleted file mode 100644 index a697af5..0000000 --- a/plugins/kimchi/ui/pages/storagepool-add.html.tmpl +++ /dev/null @@ -1,186 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<!DOCTYPE html> -<html> -<body> - <div class="window storage-window storage-admin"> - <header> - <h1 class="title h1 grey">$_("Define a New Storage Pool")</h1> - </header> - <div class="content"> - <form id="form-pool-add"> - <section class="form-section"> - <h2>1. $_("Storage Pool Name")</h2> - <div class="field"> - <input id="poolId" required="required" type="text" class="text storage-base-input-width" name="name"><br> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("The name used to identify the storage pools, and it should not be empty.") - </p> - </div> - </section> - <section class="form-section"> - <h2>2. $_("Storage Pool Type")</h2> - <div class="storage-type-wrapper-controls"> - <div id="poolTypeId"> - <input id="poolTypeInputId" name="type" type="hidden" value="dir"/> - <span id="pool-type-label" class="text"></span><span class="arrow"></span> - <div> - <ul id="storagePool-list"> - </ul> - </div> - </div> - </div> - </section> - <div class="path-section"> - <section class="form-section"> - <h2>3. $_("Storage Path")</h2> - <div class="field"> - <input id="pathId" type="text" class="text storage-base-input-width"><br> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("The path of the Storage Pool. Each Storage Pool must have a unique path.")</p><br> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("Kimchi will try to create the directory when it does not already exist in your system.")</p> - </div> - <div class="clear"></div> - </section> - </div> - <div class="nfs-section tmpl-html"> - <section class="form-section"> - <h2>3. $_("NFS Server IP")</h2> - <div class="field storage-field"> - <div id="serverComboboxId" class="storage-add-input-width"> - <input id="nfsserverId"/> - <div> - <ul id="nfs-server-used"> - </ul> - </div> - </div><br> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("NFS server IP or hostname. It can be input or chosen from history.")</p> - </div> - </section> - <section class="form-section"> - <h2>4. $_("NFS Path")</h2> - <div class="field storage-field"> - <div id="targetFilterSelectId" class="storage-add-input-width"> - <input id="nfspathId" class="input" disabled/> - <div> - <ul id="nfs-server-target"> - </ul> - </div> - </div><br> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline">$_("The NFS exported path on NFS server.")</p> - </div> - </section> - </div> - <div class="logical-section tmpl-html"> - <section class="form-section storageType"> - <h2>3. $_("Device path")</h2> - <div class="host-partition"> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("Looking for available partitions ...") - <img src = "plugins/kimchi/images/theme-default/loading.gif" /> - </p> - </div> - </section> - </div> - <div class="iscsi-section tmpl-html"> - <section class="form-section"> - <h2>3. $_("iSCSI Server")</h2> - <div class="field"> - <span class="filter-select popable" id="iSCSIServer"> - <input id="iscsiserverId" type="text" placeholder="$_("Server")"> - <div class="popover"><ul class="option select-list"></ul></div> - </span> - <input id="iscsiportId" placeholder="$_("Port")" type="text" class="text storage-port-width" maxlength="4"><br> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("iSCSI server IP or hostname. It should not be empty.")</p> - </div> - </section> - <section class="form-section"> - <h2>4. $_("Target")</h2> - <div class="field"> - <span class="filter-select popable" id="iSCSITarget"> - <input id="iscsiTargetId" type="text"> - <div class="popover"><ul class="option select-list"></ul></div> - </span><br> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline">$_("The iSCSI target on iSCSI server")</p> - </div> - </section> - <section class="form-section"> - <div class="field"> - <input type="checkbox" id="authId" name="authname"> - <label for="authId">$_("Add iSCSI Authentication")</label> - </div> - </section> - <section class="authenticationfield form-section tmpl-html"> - <h2>5. $_("iSCSI Authentication")</h2> - <div class="field"> - <input id="usernameId" placeholder="$_("User Name")" type="text" class="text storage-auth-width"> - <input id="passwordId" placeholder="$_("Password")" type="password" class="text storage-auth-width"> - </div> - </section> - </div> - <div class="scsi-section tmpl-html"> - <section class="form-section"> - <h2>3. $_("SCSI Adapter")</h2> - <div class="storage-type-wrapper-controls"> - <div id="scsiAdapter"> - <input type="hidden"/> - <span class="text"></span><span class="arrow"></span> - <div><ul></ul></div> - </div> - </div> - </section> - </div> - </form> - </div> - <footer> - <div class="btn-group"> - <button id="pool-doAdd" class="btn-normal"> - <span class="text">$_("Create")</span> - </button> - <button class="btn-normal" id="pool-loading" style="display: none"><span class="text">$_("Please, wait...")</span></button> - <button class="btn-normal close" type="button"><span class="text">$_("Cancel")</span></button> - </div> - </footer> - </div> - <script> - kimchi.storagepool_add_main(); - </script> - <script id="partitionTmpl" type="html/text"> - <div> - <input type="checkbox" id="{name}" value="{path}" name="devices"> - <label for="{name}">{path}</label> - </div> - </script> -</body> -</html> diff --git a/plugins/kimchi/ui/pages/template-add.html.tmpl b/plugins/kimchi/ui/pages/template-add.html.tmpl deleted file mode 100644 index b44db79..0000000 --- a/plugins/kimchi/ui/pages/template-add.html.tmpl +++ /dev/null @@ -1,233 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<!DOCTYPE html> -<html> -<body> -<div class="window" style="width: 992px;height: 660px;"> - <header> - <h1 class="title h1 grey">$_("Add Template")</h1> - </header> - <div class="content" style="margin-bottom: 0"> - <div class="page-list"> - <!-- 1 --> - <div class="page" id="iso-type-box" style="left:0"> - <h2 class="step-title">$_("Where is the source media for this template? ")</h2> - <ul class="step-choose"> - <li> - <a id="iso-local" class="local">$_("Local ISO Image")</a> - </li> - <li> - <a id="vm-image-local" class="local">$_("Local Image File")</a> - </li> - <li> - <a id="iso-remote" class="remote">$_("Remote ISO Image")</a> - </li> - </ul> - </div> - - <!-- 1-1 --> - <div class="page" id="iso-local-box"> - <header> - <a class="back" id="iso-local-box-back"></a> - <h2 class="step-title">$_("Local ISO Image")</h2> - </header> - - <button class="btn-normal" id="iso-search" style="display: none"><span class="text">$_("Search ISOs")</span></button> - <button class="btn-normal" id="iso-search-loading" style="display: none"><span class="text">$_("Please, wait...")</span></button> - <!-- 1-1-1 --> - <div id="local-iso-field" class="iso-field" style="display: none;"> - <h3 class="step-subtitle"> - $_("The following ISOs are available:") - </h3> - <div class="toolbar"> - <label class="check-all"> - <input type="checkbox" id="select-all-local-iso">$_("All") - </label> - </div> - <div> - <form id="form-local-iso"> - <ul id="list-local-iso" class="list-iso"> - </ul> - </form> - <script id="tmpl-list-local-iso" type="text/html"> - <li> - <label> - <input type="checkbox" name="iso" value="{isoId}"> - <div class="box box-iso"> - <div class="iso-icon {os_distro}"> - </div> - <h3 class="iso-title" title="{name}"> - {name} - </h3> - <div class="iso-info"> - <div class="iso-info-col"> - <div class="iso-info-item" title="{os_distro}"> - $_("OS: "){os_distro} - </div> - <div class="iso-info-item" title="{os_version}"> - $_("Version: "){os_version} - </div> - </div> - <div class="iso-info-col"> - <div class="iso-info-item" title="{capacity}"> - $_("Size: "){capacity} - </div> - </div> - </div> - </div> - </label> - </li> - </script> - </div> - <div class="button-field"> - <button class="btn-normal" id="iso-more" style="display: none"><span class="text">$_("Search more ISOs")</span></button> - <button class="btn-normal" id="iso-more-loading" style="display: none"><span class="text">$_("Please, wait...")</span></button> - <button class="btn-normal" id="btn-template-local-iso-create" disabled="disabled"><span class="text">$_("Create Templates from Selected ISO")</span></button> - </div> - </div> - - <!-- 1-1-2 --> - <div id="iso-file-field"> - <h3 class="step-subtitle"> - <label> - <input type="checkbox" id="iso-file-check"> - $_("I want to use a specific ISO file") - </label> - </h3> - <div id="iso-file-box" class="custom-iso-field"> - <div class="input-wrapper"><input type="text" class="text" id="iso-file" name="iso-file"></div> - <button class="btn-normal" id="btn-template-file-create" disabled="disabled"><span class="text">$_("Create")</span></button> - </div> - </div> - - </div> - - <div class="page" id="vm-image-local-box"> - <header> - <a class="back" id="vm-image-local-box-back"></a> - <h2 class="step-title">$_("Local Image File")</h2> - </header> - <div class="body"> - <label for="vm-image-local-text">File Path:</label> - <input type="text" id="vm-image-local-text" /> - <button class="ui-button-primary">$_("Create")</button> - </div> - </div> - - <!-- 1-2 --> - <div class="page" id="iso-remote-box"> - <header> - <a class="back" id="iso-remote-box-back"></a> - <h2 class="step-title">$_("Remote ISO Image")</h2> - </header> - - <!-- 1-2-0 --> - <div id="load-remote-iso"> - <h3 class="step-subtitle"> - <label> - <img src = "plugins/kimchi/images/theme-default/loading.gif" /> - $_("Loading default remote ISOs ...") - </label> - </h3> - </div> - - <!-- 1-2-1 --> - <div id="remote-iso-field" class="iso-field" style="display: none;"> - <h3 class="step-subtitle"> - $_("The following ISOs are available:") - </h3> - <div class="toolbar"> - <label class="check-all"> - <input type="checkbox" id="select-all-remote-iso">$_("All") - </label> - </div> - <div> - <form id="form-remote-iso"> - <ul id="list-remote-iso" class="list-iso"> - </ul> - </form> - <script id="tmpl-list-remote-iso" type="text/html"> - <li> - <label> - <input type="checkbox" name="iso" value="{isoId}"> - <div class="box box-iso"> - <div class="iso-icon {os_distro}"> - </div> - <h3 class="iso-title" title="{name}"> - {name} - </h3> - <div class="iso-info"> - <div class="iso-info-col"> - <div class="iso-info-item" title="{os_distro}"> - $_("OS: "){os_distro} - </div> - <div class="iso-info-item" title="{os_version}"> - $_("Version: "){os_version} - </div> - - </div> - <div class="iso-info-col"> - <div class="iso-info-item" title="{os_arch}"> - $_("Arch: "){os_arch} - </div> - </div> - </div> - </div> - </label> - </li> - </script> - </div> - <div class="button-field"> - <button class="btn-normal" id="btn-template-remote-iso-create" disabled="disabled"><span class="text">$_("Create Templates from Selected ISO")</span></button> - </div> - </div> - - <!-- 1-2-2 --> - <div id="iso-url-field" style="display: none;"> - <h3 class="step-subtitle"> - <label> - <input type="checkbox" id="iso-url-check"> - $_("I want to use a custom URL") - </label> - </h3> - <div id="iso-url-box" class="custom-iso-field"> - <div class="input-wrapper"><input type="text" class="text" id="iso-url" name="iso-url"></div> - <button class="btn-normal" id="btn-template-url-create" disabled="disabled"><span class="text">$_("Create")</span></button> - </div> - </div> - - </div> - </div> - </div> - <footer> - <div class="button-group"> - <button class="btn-normal close" type="button"><span type="text">$_("Cancel")</span></button> - </div> - </footer> -</div> -<script> -kimchi.template_add_main(); -</script> -</body> -</html> diff --git a/plugins/kimchi/ui/pages/template-edit.html.tmpl b/plugins/kimchi/ui/pages/template-edit.html.tmpl deleted file mode 100644 index 0588294..0000000 --- a/plugins/kimchi/ui/pages/template-edit.html.tmpl +++ /dev/null @@ -1,193 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2015 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext - -<div id="template-edit-window" class="window"> - <header> - <h1 class="title h1 grey">$_("Edit Template")</h1> - </header> - <div class="content"> - <div id="edit-template-tabs"> - <input type="hidden" id="template-name" name="templateName" /> - <ul> - <li> - <a href="#form-template-general">$_("General")</a> - </li> - <li> - <a href="#form-template-storage">$_("Storage")</a> - </li> - <li> - <a href="#form-template-interface">$_("Interface")</a> - </li> - <li> - <a href="#form-template-processor">$_("Processor")</a> - </li> - </ul> - <form id="form-template-general"> - <div class="form-template-inline-wrapper"> - <div class="template-edit-wrapper-label"> - <label for="template-edit-id-textbox">$_("Name")</label> - </div> - <div class="template-edit-wrapper-label"> - <label for="template-edit-vendor-textbox">$_("Vendor")</label> - </div> - <div class="template-edit-wrapper-label"> - <label for="template-edit-version-textbox">$_("Version")</label> - </div> - <div class="template-edit-wrapper-label"> - <label for="template-edit-memory-textbox">$_("Memory (MB)")</label> - </div> - <div class="template-edit-wrapper-label templ-edit-cdrom"> - <label for="template-edit-cdrom-textbox">$_("CDROM")</label> - </div> - <div class="template-edit-wrapper-label templ-edit-vm-image hide"> - <label for="template-edit-vmimage-textbox">$_("Image File")</label> - </div> - <div class="template-edit-wrapper-label"> - <label>$_("Graphics")</label> - </div> - </div> - <div class="form-template-inline-wrapper"> - <div class="template-edit-wrapper-controls"> - <input id="template-edit-id-textbox" name="name" type="text" /> - </div> - <div class="template-edit-wrapper-controls"> - <input id="template-edit-vendor-textbox" name="os_distro" type="text" disabled="disabled" /> - </div> - <div class="template-edit-wrapper-controls"> - <input id="template-edit-version-textbox" name="os_version" type="text" disabled="disabled" /> - </div> - <div class="template-edit-wrapper-controls"> - <input id="template-edit-memory-textbox" name="memory" type="text" /> - </div> - <div class="template-edit-wrapper-controls templ-edit-cdrom"> - <input id="template-edit-cdrom-textbox" name="cdrom" type="text" disabled="disabled" /> - </div> - <div class="template-edit-wrapper-controls templ-edit-vm-image hide"> - <input id="template-edit-vmimage-textbox" name="vm-image" type="text" disabled="disabled" /> - </div> - <div class="template-edit-wrapper-controls"> - <div class="btn dropdown popable"> - <input id="template-edit-graphics" name="graphics" type="hidden" /> - <span class="text" id="template-edit-graphics-label"></span><span class="arrow"></span> - <div class="popover" style="width: 100%"> - <ul class="select-list" id="template-edit-graphics-list" data-target="template-edit-graphics" data-label="template-edit-graphics-label"> - </ul> - </div> - </div> - </div> - </div> - </form> - <form id="form-template-storage"> - <div class="template-tab-header"> - <span class="template-storage-cell">$_("Storage Pool")</span> - <span class="template-storage-cell">$_("Type")</span> - <span class="template-storage-cell">$_("Disk(GB)")</span> - <span class="template-storage-cell">$_("Disk Format")</span> - <button type="button" id="template-edit-storage-add-button" class="action-area"></button> - </div> - <div class="template-tab-body"> - </div> - </form> - <form id="form-template-interface"> - <div class="template-tab-header"> - <span class="template-interface-cell">$_("Network")</span> - <span class="template-interface-cell">$_("Type")</span> - <button type="button" id="template-edit-interface-add-button" class="action-area"></button> - </div> - <div class="template-tab-body"></div> - </form> - <form id="form-template-processor"> - <div> - <label for="cpus">$_("CPU Number"):</label> - <input type="text" value="1" id="cpus" /> - </div> - <div class="manual"> - <input type="checkbox" id="cpus-check" /> - <label for="cpus-check">$_("Manually set CPU topology")</label> - </div> - <div class="topology hide"> - <div> - <label for="cores">$_("Cores"):</label> - <input type="text" value="1" id="cores" /> - </div> - <div> - <label for="threads">$_("Threads"):</label> - <select id="threads"></select> - </div> - </div> - </form> - </div> - </div> - <footer> - <div class="btn-group"> - <a id="tmpl-edit-button-save" class="btn-normal" href="javascript:void(0);"><span class="text">$_("Save")</span></a> - <button class="btn-normal close" type="button"><span class="text">$_("Cancel")</span></button> - </div> - </footer> -</div> -<script> - kimchi.template_edit_main(); -</script> -<script id="template-storage-pool-tmpl" type="text/html"> - <div class='item'> - <span class="template-storage-cell"> - <input class="template-storage-name" value={storageName} type="text" style="display:none" /> - <select id="selectStorageName"></select> - </span> - <span class="template-storage-cell"> - <input class="template-storage-type" value={storageType} readonly=true type="text" /> - </span> - <span class="template-storage-cell"> - <input class="template-storage-disk" value={storageDisk} type="text" /> - </span> - <span class="template-storage-cell"> - <input class="template-storage-disk-format" value={storageDiskFormat} type="text" style="display:none" /> - <select id="diskFormat"> - <option value="qcow2">qcow2</option> - <option value="raw">raw</option> - <option value="bochs">bochs</option> - <option value="cloop">cloop</option> - <option value="cow">cow</option> - <option value="dmg">dmg</option> - <option value="qcow">qcow</option> - <option value="qed">qed</option> - <option value="vmdk">vmdk</option> - <option value="vpc">vpc</option> - </select> - </span> - </div> -</script> -<script id="template-interface-tmpl" type="text/html"> - <div class="item" id={networkID}> - <span class="template-interface-cell"> - <select></select> - </span> - <span class="template-interface-cell"> - <input value={type} readonly=true type="text" /> - </span> - <span class="action-area"> - <button class="delete"></button> - </span> - </div> -</script> diff --git a/plugins/kimchi/ui/pages/templates.html.tmpl b/plugins/kimchi/ui/pages/templates.html.tmpl deleted file mode 100644 index af1cf3f..0000000 --- a/plugins/kimchi/ui/pages/templates.html.tmpl +++ /dev/null @@ -1,77 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2013-2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) -#silent _ = t.gettext -#silent _t = t.gettext -<!DOCTYPE html> -<html> -<head> -<link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> -<script src="plugins/kimchi/js/kimchi.min.js"></script> -</head> -<body> -<div class="toolbar"> - <div class="tools" style="display:none"> - <a id="template-add" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> - </div> -</div> -<div> - <div id="noTemplates" class="list-no-result" style="display: none;"> - $_("No templates found.") - </div> - - <ul id="templateList" class="empty-when-logged-off"></ul> - - <script id="templateTmpl" type="html/text"> - - <div class="template-box white-box template-border"> - <div class="btn dropdown popable" style="width: 70px"> - <span class="text">$_("Actions")</span><span class="arrow"></span> - <div class="popover actionsheet right-side" style="width: 250px"> - <a class="button-big template-edit" data-template='{name}'>$_("Edit")</a> - <a class="button-big template-clone" data-template='{name}'>$_("Clone")</a> - <a class="button-big red template-delete" data-template='{name}'>$_("Delete")</a> - </div> - </div> - - <div class="template-icon template-icon-position"> - <img alt="" src="{icon}"> - <img alt="" src="{location}" class="template-type-icon-position"> - </div> - <div class="template-general template-title template-title-position"> - <h2 class="title" title="{name}">{name}</h2> - </div> - <div class="template-os-position"> - <div class="template-text">$_("OS"): {os_distro}</div> - <div class="template-text">$_("Version"): {os_version}</div> - </div> - <div class="template-cpu-position"> - <div class="template-text">$_("CPUs"): {cpus}</div> - <div class="template-text">$_("Memory"): {memory}M</div> - </div> - </div> - </script> -</div> -<script> - kimchi.template_main(); -</script> -</body> -</html> diff --git a/plugins/kimchi/ui/robots.txt b/plugins/kimchi/ui/robots.txt deleted file mode 100644 index 1f53798..0000000 --- a/plugins/kimchi/ui/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / diff --git a/plugins/kimchi/ui/spice-html5/Makefile.am b/plugins/kimchi/ui/spice-html5/Makefile.am deleted file mode 100644 index c43f1ef..0000000 --- a/plugins/kimchi/ui/spice-html5/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2014 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -SUBDIRS = pages - -if WITH_SPICE -SUBDIRS += css thirdparty - -spicehtml5dir = $(datadir)/wok/plugins/kimchi/ui/spice-html5 -dist_spicehtml5_DATA = $(wildcard *.js) $(NULL) -endif diff --git a/plugins/kimchi/ui/spice-html5/atKeynames.js b/plugins/kimchi/ui/spice-html5/atKeynames.js deleted file mode 100644 index e1e27fd..0000000 --- a/plugins/kimchi/ui/spice-html5/atKeynames.js +++ /dev/null @@ -1,183 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Aric Stewart <aric@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ -/* - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Thomas Roell not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Thomas Roell makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - */ -/* - * Copyright (c) 1994-2003 by The XFree86 Project, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of the copyright holder(s) - * and author(s) shall not be used in advertising or otherwise to promote - * the sale, use or other dealings in this Software without prior written - * authorization from the copyright holder(s) and author(s). - */ - -/* - * NOTE: The AT/MF keyboards can generate (via the 8042) two (MF: three) - * sets of scancodes. Set3 can only be generated by a MF keyboard. - * Set2 sends a makecode for keypress, and the same code prefixed by a - * F0 for keyrelease. This is a little bit ugly to handle. Thus we use - * here for X386 the PC/XT compatible Set1. This set uses 8bit scancodes. - * Bit 7 ist set if the key is released. The code E0 switches to a - * different meaning to add the new MF cursorkeys, while not breaking old - * applications. E1 is another special prefix. Since I assume that there - * will be further versions of PC/XT scancode compatible keyboards, we - * may be in trouble one day. - * - * IDEA: 1) Use Set2 on AT84 keyboards and translate it to MF Set3. - * 2) Use the keyboards native set and translate it to common keysyms. - */ - -/* - * definition of the AT84/MF101/MF102 Keyboard: - * ============================================================ - * Defined Key Cap Glyphs Pressed value - * Key Name Main Also (hex) (dec) - * ---------------- ---------- ------- ------ ------ - */ - -var KEY_Escape =/* Escape 0x01 */ 1 -var KEY_1 =/* 1 ! 0x02 */ 2 -var KEY_2 =/* 2 @ 0x03 */ 3 -var KEY_3 =/* 3 # 0x04 */ 4 -var KEY_4 =/* 4 $ 0x05 */ 5 -var KEY_5 =/* 5 % 0x06 */ 6 -var KEY_6 =/* 6 ^ 0x07 */ 7 -var KEY_7 =/* 7 & 0x08 */ 8 -var KEY_8 =/* 8 * 0x09 */ 9 -var KEY_9 =/* 9 ( 0x0a */ 10 -var KEY_0 =/* 0 ) 0x0b */ 11 -var KEY_Minus =/* - (Minus) _ (Under) 0x0c */ 12 -var KEY_Equal =/* = (Equal) + 0x0d */ 13 -var KEY_BackSpace =/* Back Space 0x0e */ 14 -var KEY_Tab =/* Tab 0x0f */ 15 -var KEY_Q =/* Q 0x10 */ 16 -var KEY_W =/* W 0x11 */ 17 -var KEY_E =/* E 0x12 */ 18 -var KEY_R =/* R 0x13 */ 19 -var KEY_T =/* T 0x14 */ 20 -var KEY_Y =/* Y 0x15 */ 21 -var KEY_U =/* U 0x16 */ 22 -var KEY_I =/* I 0x17 */ 23 -var KEY_O =/* O 0x18 */ 24 -var KEY_P =/* P 0x19 */ 25 -var KEY_LBrace =/* [ { 0x1a */ 26 -var KEY_RBrace =/* ] } 0x1b */ 27 -var KEY_Enter =/* Enter 0x1c */ 28 -var KEY_LCtrl =/* Ctrl(left) 0x1d */ 29 -var KEY_A =/* A 0x1e */ 30 -var KEY_S =/* S 0x1f */ 31 -var KEY_D =/* D 0x20 */ 32 -var KEY_F =/* F 0x21 */ 33 -var KEY_G =/* G 0x22 */ 34 -var KEY_H =/* H 0x23 */ 35 -var KEY_J =/* J 0x24 */ 36 -var KEY_K =/* K 0x25 */ 37 -var KEY_L =/* L 0x26 */ 38 -var KEY_SemiColon =/* ;(SemiColon) :(Colon) 0x27 */ 39 -var KEY_Quote =/* ' (Apostr) " (Quote) 0x28 */ 40 -var KEY_Tilde =/* ` (Accent) ~ (Tilde) 0x29 */ 41 -var KEY_ShiftL =/* Shift(left) 0x2a */ 42 -var KEY_BSlash =/* \(BckSlash) |(VertBar)0x2b */ 43 -var KEY_Z =/* Z 0x2c */ 44 -var KEY_X =/* X 0x2d */ 45 -var KEY_C =/* C 0x2e */ 46 -var KEY_V =/* V 0x2f */ 47 -var KEY_B =/* B 0x30 */ 48 -var KEY_N =/* N 0x31 */ 49 -var KEY_M =/* M 0x32 */ 50 -var KEY_Comma =/* , (Comma) < (Less) 0x33 */ 51 -var KEY_Period =/* . (Period) >(Greater)0x34 */ 52 -var KEY_Slash =/* / (Slash) ? 0x35 */ 53 -var KEY_ShiftR =/* Shift(right) 0x36 */ 54 -var KEY_KP_Multiply =/* * 0x37 */ 55 -var KEY_Alt =/* Alt(left) 0x38 */ 56 -var KEY_Space =/* (SpaceBar) 0x39 */ 57 -var KEY_CapsLock =/* CapsLock 0x3a */ 58 -var KEY_F1 =/* F1 0x3b */ 59 -var KEY_F2 =/* F2 0x3c */ 60 -var KEY_F3 =/* F3 0x3d */ 61 -var KEY_F4 =/* F4 0x3e */ 62 -var KEY_F5 =/* F5 0x3f */ 63 -var KEY_F6 =/* F6 0x40 */ 64 -var KEY_F7 =/* F7 0x41 */ 65 -var KEY_F8 =/* F8 0x42 */ 66 -var KEY_F9 =/* F9 0x43 */ 67 -var KEY_F10 =/* F10 0x44 */ 68 -var KEY_NumLock =/* NumLock 0x45 */ 69 -var KEY_ScrollLock =/* ScrollLock 0x46 */ 70 -var KEY_KP_7 =/* 7 Home 0x47 */ 71 -var KEY_KP_8 =/* 8 Up 0x48 */ 72 -var KEY_KP_9 =/* 9 PgUp 0x49 */ 73 -var KEY_KP_Minus =/* - (Minus) 0x4a */ 74 -var KEY_KP_4 =/* 4 Left 0x4b */ 75 -var KEY_KP_5 =/* 5 0x4c */ 76 -var KEY_KP_6 =/* 6 Right 0x4d */ 77 -var KEY_KP_Plus =/* + (Plus) 0x4e */ 78 -var KEY_KP_1 =/* 1 End 0x4f */ 79 -var KEY_KP_2 =/* 2 Down 0x50 */ 80 -var KEY_KP_3 =/* 3 PgDown 0x51 */ 81 -var KEY_KP_0 =/* 0 Insert 0x52 */ 82 -var KEY_KP_Decimal =/* . (Decimal) Delete 0x53 */ 83 -var KEY_SysReqest =/* SysReqest 0x54 */ 84 - /* NOTUSED 0x55 */ -var KEY_Less =/* < (Less) >(Greater) 0x56 */ 86 -var KEY_F11 =/* F11 0x57 */ 87 -var KEY_F12 =/* F12 0x58 */ 88 - -var KEY_Prefix0 =/* special 0x60 */ 96 -var KEY_Prefix1 =/* specail 0x61 */ 97 diff --git a/plugins/kimchi/ui/spice-html5/bitmap.js b/plugins/kimchi/ui/spice-html5/bitmap.js deleted file mode 100644 index 03f5127..0000000 --- a/plugins/kimchi/ui/spice-html5/bitmap.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - - -/*---------------------------------------------------------------------------- -** bitmap.js -** Handle SPICE_IMAGE_TYPE_BITMAP -**--------------------------------------------------------------------------*/ -function convert_spice_bitmap_to_web(context, spice_bitmap) -{ - var ret; - var offset, x; - var u8 = new Uint8Array(spice_bitmap.data); - if (spice_bitmap.format != SPICE_BITMAP_FMT_32BIT && - spice_bitmap.format != SPICE_BITMAP_FMT_RGBA) - return undefined; - - ret = context.createImageData(spice_bitmap.x, spice_bitmap.y); - for (offset = 0; offset < (spice_bitmap.y * spice_bitmap.stride); ) - for (x = 0; x < spice_bitmap.x; x++, offset += 4) - { - ret.data[offset + 0 ] = u8[offset + 2]; - ret.data[offset + 1 ] = u8[offset + 1]; - ret.data[offset + 2 ] = u8[offset + 0]; - - // FIXME - We effectively treat all images as having SPICE_IMAGE_FLAGS_HIGH_BITS_SET - if (spice_bitmap.format == SPICE_BITMAP_FMT_32BIT) - ret.data[offset + 3] = 255; - else - ret.data[offset + 3] = u8[offset]; - } - - return ret; -} diff --git a/plugins/kimchi/ui/spice-html5/css/Makefile.am b/plugins/kimchi/ui/spice-html5/css/Makefile.am deleted file mode 100644 index ed51972..0000000 --- a/plugins/kimchi/ui/spice-html5/css/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2014 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -spicecssdir = $(datadir)/wok/plugins/kimchi/ui/spice-html5 - -dist_spicecss_DATA = $(wildcard *.css) $(NULL) diff --git a/plugins/kimchi/ui/spice-html5/css/spice.css b/plugins/kimchi/ui/spice-html5/css/spice.css deleted file mode 100644 index 5d092ba..0000000 --- a/plugins/kimchi/ui/spice-html5/css/spice.css +++ /dev/null @@ -1,118 +0,0 @@ -body -{ - background-color: #999999; - color: #000000; margin: 0; padding: 0; - font-family: "Lucida Grande", "Lucida Sans Unicode", "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif; - font-size: 12pt; - line-height: 1.5em; -} - -* { margin: 0; } - -#login -{ - width: 95%; - margin-left: auto; - margin-right: auto; - border: 1px solid #999999; - background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#24414e)); - background: -moz-linear-gradient(top, #fff, #24414e); - background-color: #24414e; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; - border-radius: 10px; -} -#login span.logo -{ - display: inline-block; - margin-right: 5px; - padding: 2px 10px 2px 20px; - border-right: 1px solid #999999; - font-size: 20px; - font-weight: bolder; - text-shadow: #efefef 1px 1px 0px; -} -#login label { color: #ffffff; text-shadow: 1px 1px 0px rgba(175, 210, 220, 0.8); } -#login input -{ - padding: 5px; - background-color: #fAfAfA; - border: 1px inset #999999; - outline: none; - -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; - box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; -} -#login input#host { width: 200px; } -#login input#port { width: 75px; } -#login input#password { width: 100px; } -#login button -{ - padding: 5px 10px 5px 10px; - margin-left: 5px; - text-shadow: #efefef 1px 1px 0px; - border: 1px outset #999999; - cursor: pointer; - -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; -} -#login button:hover -{ - background-color: #666666; - color: #ffffff; -} - -#spice-area -{ - height: 100%; - width: 95%; - padding: 0; - margin-left: auto; - margin-right: auto; - border: solid #222222 1px; - -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); - box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); - -moz-border-radius: 10px; - -webkit-border-radius: 10px; - border-radius: 10px; -} -.spice-screen -{ - min-height: 600px; - height: 100%; - margin: 10px; - padding: 0; - background-color: #333333; -} -.spice-message { - width: 700px; - height: 50px; - overflow: auto; - margin-top: 5px; - margin-left: auto; - margin-right: auto; - padding: 10px; - background-color: #efefef; - border: solid #c3c3c3 2px; - font-size: 8pt; - line-height: 1.1em; - font-family: 'Andale Mono', monospace; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; - border-radius: 10px; - -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); - box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); -} -.spice-message p { - margin-bottom: 0em; - margin-top: 0em; -} -.spice-message-warning { - color: orange; -} -.spice-message-error { - color: red; -} - diff --git a/plugins/kimchi/ui/spice-html5/cursor.js b/plugins/kimchi/ui/spice-html5/cursor.js deleted file mode 100644 index 71e941d..0000000 --- a/plugins/kimchi/ui/spice-html5/cursor.js +++ /dev/null @@ -1,110 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - - -/*---------------------------------------------------------------------------- -** SpiceCursorConn -** Drive the Spice Cursor Channel -**--------------------------------------------------------------------------*/ -function SpiceCursorConn() -{ - SpiceConn.apply(this, arguments); -} - -SpiceCursorConn.prototype = Object.create(SpiceConn.prototype); -SpiceCursorConn.prototype.process_channel_message = function(msg) -{ - if (msg.type == SPICE_MSG_CURSOR_INIT) - { - var cursor_init = new SpiceMsgCursorInit(msg.data); - DEBUG > 1 && console.log("SpiceMsgCursorInit"); - if (this.parent && this.parent.inputs && - this.parent.inputs.mouse_mode == SPICE_MOUSE_MODE_SERVER) - { - // FIXME - this imagines that the server actually - // provides the current cursor position, - // instead of 0,0. As of May 11, 2012, - // that assumption was false :-(. - this.parent.inputs.mousex = cursor_init.position.x; - this.parent.inputs.mousey = cursor_init.position.y; - } - // FIXME - We don't handle most of the parameters here... - return true; - } - - if (msg.type == SPICE_MSG_CURSOR_SET) - { - var cursor_set = new SpiceMsgCursorSet(msg.data); - DEBUG > 1 && console.log("SpiceMsgCursorSet"); - if (cursor_set.flags & SPICE_CURSOR_FLAGS_NONE) - { - document.getElementById(this.parent.screen_id).style.cursor = "none"; - return true; - } - - if (cursor_set.flags > 0) - this.log_warn("FIXME: No support for cursor flags " + cursor_set.flags); - - if (cursor_set.cursor.header.type != SPICE_CURSOR_TYPE_ALPHA) - { - this.log_warn("FIXME: No support for cursor type " + cursor_set.cursor.header.type); - return false; - } - - this.set_cursor(cursor_set.cursor); - - return true; - } - - if (msg.type == SPICE_MSG_CURSOR_HIDE) - { - DEBUG > 1 && console.log("SpiceMsgCursorHide"); - document.getElementById(this.parent.screen_id).style.cursor = "none"; - return true; - } - - if (msg.type == SPICE_MSG_CURSOR_RESET) - { - DEBUG > 1 && console.log("SpiceMsgCursorReset"); - document.getElementById(this.parent.screen_id).style.cursor = "auto"; - return true; - } - - if (msg.type == SPICE_MSG_CURSOR_INVAL_ALL) - { - DEBUG > 1 && console.log("SpiceMsgCursorInvalAll"); - // FIXME - There may be something useful to do here... - return true; - } - - return false; -} - -SpiceCursorConn.prototype.set_cursor = function(cursor) -{ - var pngstr = create_rgba_png(cursor.header.height, cursor.header.width, cursor.data); - var curstr = 'url(data:image/png,' + pngstr + ') ' + - cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y + ", default"; - var screen = document.getElementById(this.parent.screen_id); - screen.style.cursor = 'auto'; - screen.style.cursor = curstr; - if (window.getComputedStyle(screen, null).cursor == 'auto') - SpiceSimulateCursor.simulate_cursor(this, cursor, screen, pngstr); -} diff --git a/plugins/kimchi/ui/spice-html5/display.js b/plugins/kimchi/ui/spice-html5/display.js deleted file mode 100644 index 2aa5985..0000000 --- a/plugins/kimchi/ui/spice-html5/display.js +++ /dev/null @@ -1,823 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - - -/*---------------------------------------------------------------------------- -** FIXME: putImageData does not support Alpha blending -** or compositing. So if we have data in an ImageData -** format, we have to draw it onto a context, -** and then use drawImage to put it onto the target, -** as drawImage does alpha. -**--------------------------------------------------------------------------*/ -function putImageDataWithAlpha(context, d, x, y) -{ - var c = document.createElement("canvas"); - var t = c.getContext("2d"); - c.setAttribute('width', d.width); - c.setAttribute('height', d.height); - t.putImageData(d, 0, 0); - context.drawImage(c, x, y, d.width, d.height); -} - -/*---------------------------------------------------------------------------- -** FIXME: Spice will send an image with '0' alpha when it is intended to -** go on a surface w/no alpha. So in that case, we have to strip -** out the alpha. The test case for this was flux box; in a Xspice -** server, right click on the desktop to get the menu; the top bar -** doesn't paint/highlight correctly w/out this change. -**--------------------------------------------------------------------------*/ -function stripAlpha(d) -{ - var i; - for (i = 0; i < (d.width * d.height * 4); i += 4) - d.data[i + 3] = 255; -} - -/*---------------------------------------------------------------------------- -** SpiceDisplayConn -** Drive the Spice Display Channel -**--------------------------------------------------------------------------*/ -function SpiceDisplayConn() -{ - SpiceConn.apply(this, arguments); -} - -SpiceDisplayConn.prototype = Object.create(SpiceConn.prototype); -SpiceDisplayConn.prototype.process_channel_message = function(msg) -{ - if (msg.type == SPICE_MSG_DISPLAY_MARK) - { - // FIXME - DISPLAY_MARK not implemented (may be hard or impossible) - this.known_unimplemented(msg.type, "Display Mark"); - return true; - } - - if (msg.type == SPICE_MSG_DISPLAY_RESET) - { - DEBUG > 2 && console.log("Display reset"); - this.surfaces[this.primary_surface].canvas.context.restore(); - return true; - } - - if (msg.type == SPICE_MSG_DISPLAY_DRAW_COPY) - { - var draw_copy = new SpiceMsgDisplayDrawCopy(msg.data); - - DEBUG > 1 && this.log_draw("DrawCopy", draw_copy); - - if (! draw_copy.base.box.is_same_size(draw_copy.data.src_area)) - this.log_warn("FIXME: DrawCopy src_area is a different size than base.box; we do not handle that yet."); - if (draw_copy.base.clip.type != SPICE_CLIP_TYPE_NONE) - this.log_warn("FIXME: DrawCopy we don't handle clipping yet"); - if (draw_copy.data.rop_descriptor != SPICE_ROPD_OP_PUT) - this.log_warn("FIXME: DrawCopy we don't handle ropd type: " + draw_copy.data.rop_descriptor); - if (draw_copy.data.mask.flags) - this.log_warn("FIXME: DrawCopy we don't handle mask flag: " + draw_copy.data.mask.flags); - if (draw_copy.data.mask.bitmap) - this.log_warn("FIXME: DrawCopy we don't handle mask"); - - if (draw_copy.data && draw_copy.data.src_bitmap) - { - if (draw_copy.data.src_bitmap.descriptor.flags && - draw_copy.data.src_bitmap.descriptor.flags != SPICE_IMAGE_FLAGS_CACHE_ME && - draw_copy.data.src_bitmap.descriptor.flags != SPICE_IMAGE_FLAGS_HIGH_BITS_SET) - { - this.log_warn("FIXME: DrawCopy unhandled image flags: " + draw_copy.data.src_bitmap.descriptor.flags); - DEBUG <= 1 && this.log_draw("DrawCopy", draw_copy); - } - - if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_QUIC) - { - var canvas = this.surfaces[draw_copy.base.surface_id].canvas; - if (! draw_copy.data.src_bitmap.quic) - { - this.log_warn("FIXME: DrawCopy could not handle this QUIC file."); - return false; - } - var source_img = convert_spice_quic_to_web(canvas.context, - draw_copy.data.src_bitmap.quic); - - return this.draw_copy_helper( - { base: draw_copy.base, - src_area: draw_copy.data.src_area, - image_data: source_img, - tag: "copyquic." + draw_copy.data.src_bitmap.quic.type, - has_alpha: (draw_copy.data.src_bitmap.quic.type == QUIC_IMAGE_TYPE_RGBA ? true : false) , - descriptor : draw_copy.data.src_bitmap.descriptor - }); - } - else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_FROM_CACHE || - draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS) - { - if (! this.cache || ! this.cache[draw_copy.data.src_bitmap.descriptor.id]) - { - this.log_warn("FIXME: DrawCopy did not find image id " + draw_copy.data.src_bitmap.descriptor.id + " in cache."); - return false; - } - - return this.draw_copy_helper( - { base: draw_copy.base, - src_area: draw_copy.data.src_area, - image_data: this.cache[draw_copy.data.src_bitmap.descriptor.id], - tag: "copycache." + draw_copy.data.src_bitmap.descriptor.id, - has_alpha: true, /* FIXME - may want this to be false... */ - descriptor : draw_copy.data.src_bitmap.descriptor - }); - - /* FIXME - LOSSLESS CACHE ramifications not understood or handled */ - } - else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_SURFACE) - { - var source_context = this.surfaces[draw_copy.data.src_bitmap.surface_id].canvas.context; - var target_context = this.surfaces[draw_copy.base.surface_id].canvas.context; - - var source_img = source_context.getImageData( - draw_copy.data.src_area.left, draw_copy.data.src_area.top, - draw_copy.data.src_area.right - draw_copy.data.src_area.left, - draw_copy.data.src_area.bottom - draw_copy.data.src_area.top); - var computed_src_area = new SpiceRect; - computed_src_area.top = computed_src_area.left = 0; - computed_src_area.right = source_img.width; - computed_src_area.bottom = source_img.height; - - /* FIXME - there is a potential optimization here. - That is, if the surface is from 0,0, and - both surfaces are alpha surfaces, you should - be able to just do a drawImage, which should - save time. */ - - return this.draw_copy_helper( - { base: draw_copy.base, - src_area: computed_src_area, - image_data: source_img, - tag: "copysurf." + draw_copy.data.src_bitmap.surface_id, - has_alpha: this.surfaces[draw_copy.data.src_bitmap.surface_id].format == SPICE_SURFACE_FMT_32_xRGB ? false : true, - descriptor : draw_copy.data.src_bitmap.descriptor - }); - - return true; - } - else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_JPEG) - { - if (! draw_copy.data.src_bitmap.jpeg) - { - this.log_warn("FIXME: DrawCopy could not handle this JPEG file."); - return false; - } - - // FIXME - how lame is this. Be have it in binary format, and we have - // to put it into string to get it back into jpeg. Blech. - var tmpstr = "data:image/jpeg,"; - var img = new Image; - var i; - var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg.data); - for (i = 0; i < qdv.length; i++) - { - tmpstr += '%'; - if (qdv[i] < 16) - tmpstr += '0'; - tmpstr += qdv[i].toString(16); - } - - img.o = - { base: draw_copy.base, - tag: "jpeg." + draw_copy.data.src_bitmap.surface_id, - descriptor : draw_copy.data.src_bitmap.descriptor, - sc : this, - }; - img.onload = handle_draw_jpeg_onload; - img.src = tmpstr; - - return true; - } - else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_JPEG_ALPHA) - { - if (! draw_copy.data.src_bitmap.jpeg_alpha) - { - this.log_warn("FIXME: DrawCopy could not handle this JPEG ALPHA file."); - return false; - } - - // FIXME - how lame is this. Be have it in binary format, and we have - // to put it into string to get it back into jpeg. Blech. - var tmpstr = "data:image/jpeg,"; - var img = new Image; - var i; - var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg_alpha.data); - for (i = 0; i < qdv.length; i++) - { - tmpstr += '%'; - if (qdv[i] < 16) - tmpstr += '0'; - tmpstr += qdv[i].toString(16); - } - - img.o = - { base: draw_copy.base, - tag: "jpeg." + draw_copy.data.src_bitmap.surface_id, - descriptor : draw_copy.data.src_bitmap.descriptor, - sc : this, - }; - - if (this.surfaces[draw_copy.base.surface_id].format == SPICE_SURFACE_FMT_32_ARGB) - { - - var canvas = this.surfaces[draw_copy.base.surface_id].canvas; - img.alpha_img = convert_spice_lz_to_web(canvas.context, - draw_copy.data.src_bitmap.jpeg_alpha.alpha); - } - img.onload = handle_draw_jpeg_onload; - img.src = tmpstr; - - return true; - } - else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_BITMAP) - { - var canvas = this.surfaces[draw_copy.base.surface_id].canvas; - if (! draw_copy.data.src_bitmap.bitmap) - { - this.log_err("null bitmap"); - return false; - } - - var source_img = convert_spice_bitmap_to_web(canvas.context, - draw_copy.data.src_bitmap.bitmap); - if (! source_img) - { - this.log_warn("FIXME: Unable to interpret bitmap of format: " + - draw_copy.data.src_bitmap.bitmap.format); - return false; - } - - return this.draw_copy_helper( - { base: draw_copy.base, - src_area: draw_copy.data.src_area, - image_data: source_img, - tag: "bitmap." + draw_copy.data.src_bitmap.bitmap.format, - has_alpha: draw_copy.data.src_bitmap.bitmap == SPICE_BITMAP_FMT_32BIT ? false : true, - descriptor : draw_copy.data.src_bitmap.descriptor - }); - } - else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_LZ_RGB) - { - var canvas = this.surfaces[draw_copy.base.surface_id].canvas; - if (! draw_copy.data.src_bitmap.lz_rgb) - { - this.log_err("null lz_rgb "); - return false; - } - - if (draw_copy.data.src_bitmap.lz_rgb.top_down != 1) - this.log_warn("FIXME: Implement non top down support for lz_rgb"); - - var source_img = convert_spice_lz_to_web(canvas.context, - draw_copy.data.src_bitmap.lz_rgb); - if (! source_img) - { - this.log_warn("FIXME: Unable to interpret bitmap of type: " + - draw_copy.data.src_bitmap.lz_rgb.type); - return false; - } - - return this.draw_copy_helper( - { base: draw_copy.base, - src_area: draw_copy.data.src_area, - image_data: source_img, - tag: "lz_rgb." + draw_copy.data.src_bitmap.lz_rgb.type, - has_alpha: draw_copy.data.src_bitmap.lz_rgb.type == LZ_IMAGE_TYPE_RGBA ? true : false , - descriptor : draw_copy.data.src_bitmap.descriptor - }); - } - else - { - this.log_warn("FIXME: DrawCopy unhandled image type: " + draw_copy.data.src_bitmap.descriptor.type); - this.log_draw("DrawCopy", draw_copy); - return false; - } - } - - this.log_warn("FIXME: DrawCopy no src_bitmap."); - return false; - } - - if (msg.type == SPICE_MSG_DISPLAY_DRAW_FILL) - { - var draw_fill = new SpiceMsgDisplayDrawFill(msg.data); - - DEBUG > 1 && this.log_draw("DrawFill", draw_fill); - - if (draw_fill.data.rop_descriptor != SPICE_ROPD_OP_PUT) - this.log_warn("FIXME: DrawFill we don't handle ropd type: " + draw_fill.data.rop_descriptor); - if (draw_fill.data.mask.flags) - this.log_warn("FIXME: DrawFill we don't handle mask flag: " + draw_fill.data.mask.flags); - if (draw_fill.data.mask.bitmap) - this.log_warn("FIXME: DrawFill we don't handle mask"); - - if (draw_fill.data.brush.type == SPICE_BRUSH_TYPE_SOLID) - { - // FIXME - do brushes ever have alpha? - var color = draw_fill.data.brush.color & 0xffffff; - var color_str = "rgb(" + (color >> 16) + ", " + ((color >> 8) & 0xff) + ", " + (color & 0xff) + ")"; - this.surfaces[draw_fill.base.surface_id].canvas.context.fillStyle = color_str; - - this.surfaces[draw_fill.base.surface_id].canvas.context.fillRect( - draw_fill.base.box.left, draw_fill.base.box.top, - draw_fill.base.box.right - draw_fill.base.box.left, - draw_fill.base.box.bottom - draw_fill.base.box.top); - - if (DUMP_DRAWS && this.parent.dump_id) - { - var debug_canvas = document.createElement("canvas"); - debug_canvas.setAttribute('width', this.surfaces[draw_fill.base.surface_id].canvas.width); - debug_canvas.setAttribute('height', this.surfaces[draw_fill.base.surface_id].canvas.height); - debug_canvas.setAttribute('id', "fillbrush." + draw_fill.base.surface_id + "." + this.surfaces[draw_fill.base.surface_id].draw_count); - debug_canvas.getContext("2d").fillStyle = color_str; - debug_canvas.getContext("2d").fillRect( - draw_fill.base.box.left, draw_fill.base.box.top, - draw_fill.base.box.right - draw_fill.base.box.left, - draw_fill.base.box.bottom - draw_fill.base.box.top); - document.getElementById(this.parent.dump_id).appendChild(debug_canvas); - } - - this.surfaces[draw_fill.base.surface_id].draw_count++; - - } - else - { - this.log_warn("FIXME: DrawFill can't handle brush type: " + draw_fill.data.brush.type); - } - return true; - } - - if (msg.type == SPICE_MSG_DISPLAY_COPY_BITS) - { - var copy_bits = new SpiceMsgDisplayCopyBits(msg.data); - - DEBUG > 1 && this.log_draw("CopyBits", copy_bits); - - var source_canvas = this.surfaces[copy_bits.base.surface_id].canvas; - var source_context = source_canvas.context; - - var width = source_canvas.width - copy_bits.src_pos.x; - var height = source_canvas.height - copy_bits.src_pos.y; - if (width > (copy_bits.base.box.right - copy_bits.base.box.left)) - width = copy_bits.base.box.right - copy_bits.base.box.left; - if (height > (copy_bits.base.box.bottom - copy_bits.base.box.top)) - height = copy_bits.base.box.bottom - copy_bits.base.box.top; - - var source_img = source_context.getImageData( - copy_bits.src_pos.x, copy_bits.src_pos.y, width, height); - //source_context.putImageData(source_img, copy_bits.base.box.left, copy_bits.base.box.top); - putImageDataWithAlpha(source_context, source_img, copy_bits.base.box.left, copy_bits.base.box.top); - - if (DUMP_DRAWS && this.parent.dump_id) - { - var debug_canvas = document.createElement("canvas"); - debug_canvas.setAttribute('width', width); - debug_canvas.setAttribute('height', height); - debug_canvas.setAttribute('id', "copybits" + copy_bits.base.surface_id + "." + this.surfaces[copy_bits.base.surface_id].draw_count); - debug_canvas.getContext("2d").putImageData(source_img, 0, 0); - document.getElementById(this.parent.dump_id).appendChild(debug_canvas); - } - - - this.surfaces[copy_bits.base.surface_id].draw_count++; - return true; - } - - if (msg.type == SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES) - { - this.known_unimplemented(msg.type, "Inval All Palettes"); - return true; - } - - if (msg.type == SPICE_MSG_DISPLAY_SURFACE_CREATE) - { - if (! ("surfaces" in this)) - this.surfaces = []; - - var m = new SpiceMsgSurfaceCreate(msg.data); - DEBUG > 1 && console.log(this.type + ": MsgSurfaceCreate id " + m.surface.surface_id - + "; " + m.surface.width + "x" + m.surface.height - + "; format " + m.surface.format - + "; flags " + m.surface.flags); - if (m.surface.format != SPICE_SURFACE_FMT_32_xRGB && - m.surface.format != SPICE_SURFACE_FMT_32_ARGB) - { - this.log_warn("FIXME: cannot handle surface format " + m.surface.format + " yet."); - return false; - } - - var canvas = document.createElement("canvas"); - canvas.setAttribute('width', m.surface.width); - canvas.setAttribute('height', m.surface.height); - canvas.setAttribute('id', "spice_surface_" + m.surface.surface_id); - canvas.setAttribute('tabindex', m.surface.surface_id); - canvas.context = canvas.getContext("2d"); - - if (DUMP_CANVASES && this.parent.dump_id) - document.getElementById(this.parent.dump_id).appendChild(canvas); - - m.surface.canvas = canvas; - m.surface.draw_count = 0; - this.surfaces[m.surface.surface_id] = m.surface; - - if (m.surface.flags & SPICE_SURFACE_FLAGS_PRIMARY) - { - this.primary_surface = m.surface.surface_id; - - /* This .save() is done entirely to enable SPICE_MSG_DISPLAY_RESET */ - canvas.context.save(); - document.getElementById(this.parent.screen_id).appendChild(canvas); - - /* We're going to leave width dynamic, but correctly set the height */ - document.getElementById(this.parent.screen_id).style.height = m.surface.height + "px"; - this.hook_events(); - } - return true; - } - - if (msg.type == SPICE_MSG_DISPLAY_SURFACE_DESTROY) - { - var m = new SpiceMsgSurfaceDestroy(msg.data); - DEBUG > 1 && console.log(this.type + ": MsgSurfaceDestroy id " + m.surface_id); - this.delete_surface(m.surface_id); - return true; - } - - if (msg.type == SPICE_MSG_DISPLAY_STREAM_CREATE) - { - var m = new SpiceMsgDisplayStreamCreate(msg.data); - DEBUG > 1 && console.log(this.type + ": MsgStreamCreate id" + m.id); - if (!this.streams) - this.streams = new Array(); - if (this.streams[m.id]) - console.log("Stream already exists"); - else - this.streams[m.id] = m; - if (m.codec_type != SPICE_VIDEO_CODEC_TYPE_MJPEG) - console.log("Unhandled stream codec: "+m.codec_type); - return true; - } - - if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA) - { - var m = new SpiceMsgDisplayStreamData(msg.data); - if (!this.streams[m.base.id]) - { - console.log("no stream for data"); - return false; - } - if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_MJPEG) - { - var tmpstr = "data:image/jpeg,"; - var img = new Image; - var i; - for (i = 0; i < m.data.length; i++) - { - tmpstr += '%'; - if (m.data[i] < 16) - tmpstr += '0'; - tmpstr += m.data[i].toString(16); - } - var strm_base = new SpiceMsgDisplayBase(); - strm_base.surface_id = this.streams[m.base.id].surface_id; - strm_base.box = this.streams[m.base.id].dest; - strm_base.clip = this.streams[m.base.id].clip; - img.o = - { base: strm_base, - tag: "mjpeg." + m.base.id, - descriptor: null, - sc : this, - }; - img.onload = handle_draw_jpeg_onload; - img.src = tmpstr; - } - return true; - } - - if (msg.type == SPICE_MSG_DISPLAY_STREAM_CLIP) - { - var m = new SpiceMsgDisplayStreamClip(msg.data); - DEBUG > 1 && console.log(this.type + ": MsgStreamClip id" + m.id); - this.streams[m.id].clip = m.clip; - return true; - } - - if (msg.type == SPICE_MSG_DISPLAY_STREAM_DESTROY) - { - var m = new SpiceMsgDisplayStreamDestroy(msg.data); - DEBUG > 1 && console.log(this.type + ": MsgStreamDestroy id" + m.id); - this.streams[m.id] = undefined; - return true; - } - if (msg.type == SPICE_MSG_DISPLAY_INVAL_LIST) - { - var m = new SpiceMsgDisplayInvalList(msg.data); - var i; - DEBUG > 1 && console.log(this.type + ": MsgInvalList " + m.count + " items"); - for (i = 0; i < m.count; i++) - if (this.cache[m.resources[i].id] != undefined) - delete this.cache[m.resources[i].id]; - return true; - } - - return false; -} - -SpiceDisplayConn.prototype.delete_surface = function(surface_id) -{ - var canvas = document.getElementById("spice_surface_" + surface_id); - if (DUMP_CANVASES && this.parent.dump_id) - document.getElementById(this.parent.dump_id).removeChild(canvas); - if (this.primary_surface == surface_id) - { - this.unhook_events(); - this.primary_surface = undefined; - document.getElementById(this.parent.screen_id).removeChild(canvas); - } - - delete this.surfaces[surface_id]; -} - - -SpiceDisplayConn.prototype.draw_copy_helper = function(o) -{ - - var canvas = this.surfaces[o.base.surface_id].canvas; - if (o.has_alpha) - { - /* FIXME - This is based on trial + error, not a serious thoughtful - analysis of what Spice requires. See display.js for more. */ - if (this.surfaces[o.base.surface_id].format == SPICE_SURFACE_FMT_32_xRGB) - { - stripAlpha(o.image_data); - canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top); - } - else - putImageDataWithAlpha(canvas.context, o.image_data, - o.base.box.left, o.base.box.top); - } - else - canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top); - - if (o.src_area.left > 0 || o.src_area.top > 0) - { - this.log_warn("FIXME: DrawCopy not shifting draw copies just yet..."); - } - - if (o.descriptor && (o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) - { - if (! ("cache" in this)) - this.cache = {}; - this.cache[o.descriptor.id] = o.image_data; - } - - if (DUMP_DRAWS && this.parent.dump_id) - { - var debug_canvas = document.createElement("canvas"); - debug_canvas.setAttribute('width', o.image_data.width); - debug_canvas.setAttribute('height', o.image_data.height); - debug_canvas.setAttribute('id', o.tag + "." + - this.surfaces[o.base.surface_id].draw_count + "." + - o.base.surface_id + "@" + o.base.box.left + "x" + o.base.box.top); - debug_canvas.getContext("2d").putImageData(o.image_data, 0, 0); - document.getElementById(this.parent.dump_id).appendChild(debug_canvas); - } - - this.surfaces[o.base.surface_id].draw_count++; - - return true; -} - - -SpiceDisplayConn.prototype.log_draw = function(prefix, draw) -{ - var str = prefix + "." + draw.base.surface_id + "." + this.surfaces[draw.base.surface_id].draw_count + ": "; - str += "base.box " + draw.base.box.left + ", " + draw.base.box.top + " to " + - draw.base.box.right + ", " + draw.base.box.bottom; - str += "; clip.type " + draw.base.clip.type; - - if (draw.data) - { - if (draw.data.src_area) - str += "; src_area " + draw.data.src_area.left + ", " + draw.data.src_area.top + " to " - + draw.data.src_area.right + ", " + draw.data.src_area.bottom; - - if (draw.data.src_bitmap && draw.data.src_bitmap != null) - { - str += "; src_bitmap id: " + draw.data.src_bitmap.descriptor.id; - str += "; src_bitmap width " + draw.data.src_bitmap.descriptor.width + ", height " + draw.data.src_bitmap.descriptor.height; - str += "; src_bitmap type " + draw.data.src_bitmap.descriptor.type + ", flags " + draw.data.src_bitmap.descriptor.flags; - if (draw.data.src_bitmap.surface_id !== undefined) - str += "; src_bitmap surface_id " + draw.data.src_bitmap.surface_id; - if (draw.data.src_bitmap.quic) - str += "; QUIC type " + draw.data.src_bitmap.quic.type + - "; width " + draw.data.src_bitmap.quic.width + - "; height " + draw.data.src_bitmap.quic.height ; - if (draw.data.src_bitmap.lz_rgb) - str += "; LZ_RGB length " + draw.data.src_bitmap.lz_rgb.length + - "; magic " + draw.data.src_bitmap.lz_rgb.magic + - "; version 0x" + draw.data.src_bitmap.lz_rgb.version.toString(16) + - "; type " + draw.data.src_bitmap.lz_rgb.type + - "; width " + draw.data.src_bitmap.lz_rgb.width + - "; height " + draw.data.src_bitmap.lz_rgb.height + - "; stride " + draw.data.src_bitmap.lz_rgb.stride + - "; top down " + draw.data.src_bitmap.lz_rgb.top_down; - } - else - str += "; src_bitmap is null"; - - if (draw.data.brush) - { - if (draw.data.brush.type == SPICE_BRUSH_TYPE_SOLID) - str += "; brush.color 0x" + draw.data.brush.color.toString(16); - if (draw.data.brush.type == SPICE_BRUSH_TYPE_PATTERN) - { - str += "; brush.pat "; - if (draw.data.brush.pattern.pat != null) - str += "[SpiceImage]"; - else - str += "[null]"; - str += " at " + draw.data.brush.pattern.pos.x + ", " + draw.data.brush.pattern.pos.y; - } - } - - str += "; rop_descriptor " + draw.data.rop_descriptor; - if (draw.data.scale_mode !== undefined) - str += "; scale_mode " + draw.data.scale_mode; - str += "; mask.flags " + draw.data.mask.flags; - str += "; mask.pos " + draw.data.mask.pos.x + ", " + draw.data.mask.pos.y; - if (draw.data.mask.bitmap != null) - { - str += "; mask.bitmap width " + draw.data.mask.bitmap.descriptor.width + ", height " + draw.data.mask.bitmap.descriptor.height; - str += "; mask.bitmap type " + draw.data.mask.bitmap.descriptor.type + ", flags " + draw.data.mask.bitmap.descriptor.flags; - } - else - str += "; mask.bitmap is null"; - } - - console.log(str); -} - -SpiceDisplayConn.prototype.hook_events = function() -{ - if (this.primary_surface !== undefined) - { - var canvas = this.surfaces[this.primary_surface].canvas; - canvas.sc = this.parent; - canvas.addEventListener('mousemove', handle_mousemove); - canvas.addEventListener('mousedown', handle_mousedown); - canvas.addEventListener('contextmenu', handle_contextmenu); - canvas.addEventListener('mouseup', handle_mouseup); - canvas.addEventListener('keydown', handle_keydown); - canvas.addEventListener('keyup', handle_keyup); - canvas.addEventListener('mouseout', handle_mouseout); - canvas.addEventListener('mouseover', handle_mouseover); - canvas.addEventListener('mousewheel', handle_mousewheel); - canvas.focus(); - } -} - -SpiceDisplayConn.prototype.unhook_events = function() -{ - if (this.primary_surface !== undefined) - { - var canvas = this.surfaces[this.primary_surface].canvas; - canvas.removeEventListener('mousemove', handle_mousemove); - canvas.removeEventListener('mousedown', handle_mousedown); - canvas.removeEventListener('contextmenu', handle_contextmenu); - canvas.removeEventListener('mouseup', handle_mouseup); - canvas.removeEventListener('keydown', handle_keydown); - canvas.removeEventListener('keyup', handle_keyup); - canvas.removeEventListener('mouseout', handle_mouseout); - canvas.removeEventListener('mouseover', handle_mouseover); - canvas.removeEventListener('mousewheel', handle_mousewheel); - } -} - - -SpiceDisplayConn.prototype.destroy_surfaces = function() -{ - for (var s in this.surfaces) - { - this.delete_surface(this.surfaces[s].surface_id); - } - - this.surfaces = undefined; -} - - -function handle_mouseover(e) -{ - this.focus(); -} - -function handle_mouseout(e) -{ - if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor) - this.sc.cursor.spice_simulated_cursor.style.display = 'none'; - this.blur(); -} - -function handle_draw_jpeg_onload() -{ - var temp_canvas = null; - var context; - - /*------------------------------------------------------------ - ** FIXME: - ** The helper should be extended to be able to handle actual HtmlImageElements - ** ...and the cache should be modified to do so as well - **----------------------------------------------------------*/ - if (this.o.sc.surfaces[this.o.base.surface_id] === undefined) - { - // This can happen; if the jpeg image loads after our surface - // has been destroyed (e.g. open a menu, close it quickly), - // we'll find we have no surface. - DEBUG > 2 && this.o.sc.log_info("Discarding jpeg; presumed lost surface " + this.o.base.surface_id); - temp_canvas = document.createElement("canvas"); - temp_canvas.setAttribute('width', this.o.base.box.right); - temp_canvas.setAttribute('height', this.o.base.box.bottom); - context = temp_canvas.getContext("2d"); - } - else - context = this.o.sc.surfaces[this.o.base.surface_id].canvas.context; - - if (this.alpha_img) - { - var c = document.createElement("canvas"); - var t = c.getContext("2d"); - c.setAttribute('width', this.alpha_img.width); - c.setAttribute('height', this.alpha_img.height); - t.putImageData(this.alpha_img, 0, 0); - t.globalCompositeOperation = 'source-in'; - t.drawImage(this, 0, 0); - - context.drawImage(c, this.o.base.box.left, this.o.base.box.top); - - if (this.o.descriptor && - (this.o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) - { - if (! ("cache" in this.o.sc)) - this.o.sc.cache = {}; - - this.o.sc.cache[this.o.descriptor.id] = - t.getImageData(0, 0, - this.alpha_img.width, - this.alpha_img.height); - } - } - else - { - context.drawImage(this, this.o.base.box.left, this.o.base.box.top); - - // Give the Garbage collector a clue to recycle this; avoids - // fairly massive memory leaks during video playback - this.src = null; - - if (this.o.descriptor && - (this.o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) - { - if (! ("cache" in this.o.sc)) - this.o.sc.cache = {}; - - this.o.sc.cache[this.o.descriptor.id] = - context.getImageData(this.o.base.box.left, this.o.base.box.top, - this.o.base.box.right - this.o.base.box.left, - this.o.base.box.bottom - this.o.base.box.top); - } - } - - if (temp_canvas == null) - { - if (DUMP_DRAWS && this.o.sc.parent.dump_id) - { - var debug_canvas = document.createElement("canvas"); - debug_canvas.setAttribute('id', this.o.tag + "." + - this.o.sc.surfaces[this.o.base.surface_id].draw_count + "." + - this.o.base.surface_id + "@" + this.o.base.box.left + "x" + this.o.base.box.top); - debug_canvas.getContext("2d").drawImage(this, 0, 0); - document.getElementById(this.o.sc.parent.dump_id).appendChild(debug_canvas); - } - - this.o.sc.surfaces[this.o.base.surface_id].draw_count++; - } -} diff --git a/plugins/kimchi/ui/spice-html5/enums.js b/plugins/kimchi/ui/spice-html5/enums.js deleted file mode 100644 index d99b38e..0000000 --- a/plugins/kimchi/ui/spice-html5/enums.js +++ /dev/null @@ -1,324 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - - -/*---------------------------------------------------------------------------- -** enums.js -** 'constants' for Spice -**--------------------------------------------------------------------------*/ -var SPICE_MAGIC = "REDQ"; -var SPICE_VERSION_MAJOR = 2; -var SPICE_VERSION_MINOR = 2; - -var SPICE_CONNECT_TIMEOUT = (30 * 1000); - -var SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION = 0; -var SPICE_COMMON_CAP_AUTH_SPICE = 1; -var SPICE_COMMON_CAP_AUTH_SASL = 2; -var SPICE_COMMON_CAP_MINI_HEADER = 3; - -var SPICE_TICKET_KEY_PAIR_LENGTH = 1024; -var SPICE_TICKET_PUBKEY_BYTES = (SPICE_TICKET_KEY_PAIR_LENGTH / 8 + 34); - -var SPICE_LINK_ERR_OK = 0, - SPICE_LINK_ERR_ERROR = 1, - SPICE_LINK_ERR_INVALID_MAGIC = 2, - SPICE_LINK_ERR_INVALID_DATA = 3, - SPICE_LINK_ERR_VERSION_MISMATCH = 4, - SPICE_LINK_ERR_NEED_SECURED = 5, - SPICE_LINK_ERR_NEED_UNSECURED = 6, - SPICE_LINK_ERR_PERMISSION_DENIED = 7, - SPICE_LINK_ERR_BAD_CONNECTION_ID = 8, - SPICE_LINK_ERR_CHANNEL_NOT_AVAILABLE = 9; - -var SPICE_MSG_MIGRATE = 1; -var SPICE_MSG_MIGRATE_DATA = 2; -var SPICE_MSG_SET_ACK = 3; -var SPICE_MSG_PING = 4; -var SPICE_MSG_WAIT_FOR_CHANNELS = 5; -var SPICE_MSG_DISCONNECTING = 6; -var SPICE_MSG_NOTIFY = 7; -var SPICE_MSG_LIST = 8; - -var SPICE_MSG_MAIN_MIGRATE_BEGIN = 101; -var SPICE_MSG_MAIN_MIGRATE_CANCEL = 102; -var SPICE_MSG_MAIN_INIT = 103; -var SPICE_MSG_MAIN_CHANNELS_LIST = 104; -var SPICE_MSG_MAIN_MOUSE_MODE = 105; -var SPICE_MSG_MAIN_MULTI_MEDIA_TIME = 106; -var SPICE_MSG_MAIN_AGENT_CONNECTED = 107; -var SPICE_MSG_MAIN_AGENT_DISCONNECTED = 108; -var SPICE_MSG_MAIN_AGENT_DATA = 109; -var SPICE_MSG_MAIN_AGENT_TOKEN = 110; -var SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST = 111; -var SPICE_MSG_MAIN_MIGRATE_END = 112; -var SPICE_MSG_MAIN_NAME = 113; -var SPICE_MSG_MAIN_UUID = 114; -var SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS = 115; -var SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS = 116; -var SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK = 117; -var SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK = 118; -var SPICE_MSG_END_MAIN = 119; - - - -var SPICE_MSGC_ACK_SYNC = 1; -var SPICE_MSGC_ACK = 2; -var SPICE_MSGC_PONG = 3; -var SPICE_MSGC_MIGRATE_FLUSH_MARK = 4; -var SPICE_MSGC_MIGRATE_DATA = 5; -var SPICE_MSGC_DISCONNECTING = 6; - - -var SPICE_MSGC_MAIN_CLIENT_INFO = 101; -var SPICE_MSGC_MAIN_MIGRATE_CONNECTED = 102; -var SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR = 103; -var SPICE_MSGC_MAIN_ATTACH_CHANNELS = 104; -var SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST = 105; -var SPICE_MSGC_MAIN_AGENT_START = 106; -var SPICE_MSGC_MAIN_AGENT_DATA = 107; -var SPICE_MSGC_MAIN_AGENT_TOKEN = 108; -var SPICE_MSGC_MAIN_MIGRATE_END = 109; -var SPICE_MSGC_END_MAIN = 110; - -var SPICE_MSG_DISPLAY_MODE = 101; -var SPICE_MSG_DISPLAY_MARK = 102; -var SPICE_MSG_DISPLAY_RESET = 103; -var SPICE_MSG_DISPLAY_COPY_BITS = 104; -var SPICE_MSG_DISPLAY_INVAL_LIST = 105; -var SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS = 106; -var SPICE_MSG_DISPLAY_INVAL_PALETTE = 107; -var SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES= 108; - -var SPICE_MSG_DISPLAY_STREAM_CREATE = 122; -var SPICE_MSG_DISPLAY_STREAM_DATA = 123; -var SPICE_MSG_DISPLAY_STREAM_CLIP = 124; -var SPICE_MSG_DISPLAY_STREAM_DESTROY = 125; -var SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL= 126; - -var SPICE_MSG_DISPLAY_DRAW_FILL = 302; -var SPICE_MSG_DISPLAY_DRAW_OPAQUE = 303; -var SPICE_MSG_DISPLAY_DRAW_COPY = 304; -var SPICE_MSG_DISPLAY_DRAW_BLEND = 305; -var SPICE_MSG_DISPLAY_DRAW_BLACKNESS = 306; -var SPICE_MSG_DISPLAY_DRAW_WHITENESS = 307; -var SPICE_MSG_DISPLAY_DRAW_INVERS = 308; -var SPICE_MSG_DISPLAY_DRAW_ROP3 = 309; -var SPICE_MSG_DISPLAY_DRAW_STROKE = 310; -var SPICE_MSG_DISPLAY_DRAW_TEXT = 311; -var SPICE_MSG_DISPLAY_DRAW_TRANSPARENT = 312; -var SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND = 313; -var SPICE_MSG_DISPLAY_SURFACE_CREATE = 314; -var SPICE_MSG_DISPLAY_SURFACE_DESTROY = 315; - -var SPICE_MSGC_DISPLAY_INIT = 101; - -var SPICE_MSG_INPUTS_INIT = 101; -var SPICE_MSG_INPUTS_KEY_MODIFIERS = 102; - -var SPICE_MSG_INPUTS_MOUSE_MOTION_ACK = 111; - -var SPICE_MSGC_INPUTS_KEY_DOWN = 101; -var SPICE_MSGC_INPUTS_KEY_UP = 102; -var SPICE_MSGC_INPUTS_KEY_MODIFIERS = 103; - -var SPICE_MSGC_INPUTS_MOUSE_MOTION = 111; -var SPICE_MSGC_INPUTS_MOUSE_POSITION = 112; -var SPICE_MSGC_INPUTS_MOUSE_PRESS = 113; -var SPICE_MSGC_INPUTS_MOUSE_RELEASE = 114; - -var SPICE_MSG_CURSOR_INIT = 101; -var SPICE_MSG_CURSOR_RESET = 102; -var SPICE_MSG_CURSOR_SET = 103; -var SPICE_MSG_CURSOR_MOVE = 104; -var SPICE_MSG_CURSOR_HIDE = 105; -var SPICE_MSG_CURSOR_TRAIL = 106; -var SPICE_MSG_CURSOR_INVAL_ONE = 107; -var SPICE_MSG_CURSOR_INVAL_ALL = 108; - -var SPICE_MSG_PLAYBACK_DATA = 101; -var SPICE_MSG_PLAYBACK_MODE = 102; -var SPICE_MSG_PLAYBACK_START = 103; -var SPICE_MSG_PLAYBACK_STOP = 104; -var SPICE_MSG_PLAYBACK_VOLUME = 105; -var SPICE_MSG_PLAYBACK_MUTE = 106; -var SPICE_MSG_PLAYBACK_LATENCY = 107; - -var SPICE_PLAYBACK_CAP_CELT_0_5_1 = 0; -var SPICE_PLAYBACK_CAP_VOLUME = 1; -var SPICE_PLAYBACK_CAP_LATENCY = 2; -var SPICE_PLAYBACK_CAP_OPUS = 3; - -var SPICE_AUDIO_DATA_MODE_INVALID = 0; -var SPICE_AUDIO_DATA_MODE_RAW = 1; -var SPICE_AUDIO_DATA_MODE_CELT_0_5_1 = 2; -var SPICE_AUDIO_DATA_MODE_OPUS = 3; - -var SPICE_AUDIO_FMT_INVALID = 0; -var SPICE_AUDIO_FMT_S16 = 1; - -var SPICE_CHANNEL_MAIN = 1; -var SPICE_CHANNEL_DISPLAY = 2; -var SPICE_CHANNEL_INPUTS = 3; -var SPICE_CHANNEL_CURSOR = 4; -var SPICE_CHANNEL_PLAYBACK = 5; -var SPICE_CHANNEL_RECORD = 6; -var SPICE_CHANNEL_TUNNEL = 7; -var SPICE_CHANNEL_SMARTCARD = 8; -var SPICE_CHANNEL_USBREDIR = 9; - -var SPICE_SURFACE_FLAGS_PRIMARY = (1 << 0); - -var SPICE_NOTIFY_SEVERITY_INFO = 0; -var SPICE_NOTIFY_SEVERITY_WARN = 1; -var SPICE_NOTIFY_SEVERITY_ERROR = 2; - -var SPICE_MOUSE_MODE_SERVER = (1 << 0), - SPICE_MOUSE_MODE_CLIENT = (1 << 1), - SPICE_MOUSE_MODE_MASK = 0x3; - -var SPICE_CLIP_TYPE_NONE = 0; -var SPICE_CLIP_TYPE_RECTS = 1; - -var SPICE_IMAGE_TYPE_BITMAP = 0; -var SPICE_IMAGE_TYPE_QUIC = 1; -var SPICE_IMAGE_TYPE_RESERVED = 2; -var SPICE_IMAGE_TYPE_LZ_PLT = 100; -var SPICE_IMAGE_TYPE_LZ_RGB = 101; -var SPICE_IMAGE_TYPE_GLZ_RGB = 102; -var SPICE_IMAGE_TYPE_FROM_CACHE = 103; -var SPICE_IMAGE_TYPE_SURFACE = 104; -var SPICE_IMAGE_TYPE_JPEG = 105; -var SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS = 106; -var SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB = 107; -var SPICE_IMAGE_TYPE_JPEG_ALPHA = 108; - -var SPICE_IMAGE_FLAGS_CACHE_ME = (1 << 0), - SPICE_IMAGE_FLAGS_HIGH_BITS_SET = (1 << 1), - SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME = (1 << 2); - -var SPICE_BITMAP_FLAGS_PAL_CACHE_ME = (1 << 0), - SPICE_BITMAP_FLAGS_PAL_FROM_CACHE = (1 << 1), - SPICE_BITMAP_FLAGS_TOP_DOWN = (1 << 2), - SPICE_BITMAP_FLAGS_MASK = 0x7; - -var SPICE_BITMAP_FMT_INVALID = 0, - SPICE_BITMAP_FMT_1BIT_LE = 1, - SPICE_BITMAP_FMT_1BIT_BE = 2, - SPICE_BITMAP_FMT_4BIT_LE = 3, - SPICE_BITMAP_FMT_4BIT_BE = 4, - SPICE_BITMAP_FMT_8BIT = 5, - SPICE_BITMAP_FMT_16BIT = 6, - SPICE_BITMAP_FMT_24BIT = 7, - SPICE_BITMAP_FMT_32BIT = 8, - SPICE_BITMAP_FMT_RGBA = 9; - - -var SPICE_CURSOR_FLAGS_NONE = (1 << 0), - SPICE_CURSOR_FLAGS_CACHE_ME = (1 << 1), - SPICE_CURSOR_FLAGS_FROM_CACHE = (1 << 2), - SPICE_CURSOR_FLAGS_MASK = 0x7; - -var SPICE_MOUSE_BUTTON_MASK_LEFT = (1 << 0), - SPICE_MOUSE_BUTTON_MASK_MIDDLE = (1 << 1), - SPICE_MOUSE_BUTTON_MASK_RIGHT = (1 << 2), - SPICE_MOUSE_BUTTON_MASK_MASK = 0x7; - -var SPICE_MOUSE_BUTTON_INVALID = 0; -var SPICE_MOUSE_BUTTON_LEFT = 1; -var SPICE_MOUSE_BUTTON_MIDDLE = 2; -var SPICE_MOUSE_BUTTON_RIGHT = 3; -var SPICE_MOUSE_BUTTON_UP = 4; -var SPICE_MOUSE_BUTTON_DOWN = 5; - -var SPICE_BRUSH_TYPE_NONE = 0, - SPICE_BRUSH_TYPE_SOLID = 1, - SPICE_BRUSH_TYPE_PATTERN = 2; - -var SPICE_SURFACE_FMT_INVALID = 0, - SPICE_SURFACE_FMT_1_A = 1, - SPICE_SURFACE_FMT_8_A = 8, - SPICE_SURFACE_FMT_16_555 = 16, - SPICE_SURFACE_FMT_32_xRGB = 32, - SPICE_SURFACE_FMT_16_565 = 80, - SPICE_SURFACE_FMT_32_ARGB = 96; - -var SPICE_ROPD_INVERS_SRC = (1 << 0), - SPICE_ROPD_INVERS_BRUSH = (1 << 1), - SPICE_ROPD_INVERS_DEST = (1 << 2), - SPICE_ROPD_OP_PUT = (1 << 3), - SPICE_ROPD_OP_OR = (1 << 4), - SPICE_ROPD_OP_AND = (1 << 5), - SPICE_ROPD_OP_XOR = (1 << 6), - SPICE_ROPD_OP_BLACKNESS = (1 << 7), - SPICE_ROPD_OP_WHITENESS = (1 << 8), - SPICE_ROPD_OP_INVERS = (1 << 9), - SPICE_ROPD_INVERS_RES = (1 << 10), - SPICE_ROPD_MASK = 0x7ff; - -var LZ_IMAGE_TYPE_INVALID = 0, - LZ_IMAGE_TYPE_PLT1_LE = 1, - LZ_IMAGE_TYPE_PLT1_BE = 2, // PLT stands for palette - LZ_IMAGE_TYPE_PLT4_LE = 3, - LZ_IMAGE_TYPE_PLT4_BE = 4, - LZ_IMAGE_TYPE_PLT8 = 5, - LZ_IMAGE_TYPE_RGB16 = 6, - LZ_IMAGE_TYPE_RGB24 = 7, - LZ_IMAGE_TYPE_RGB32 = 8, - LZ_IMAGE_TYPE_RGBA = 9, - LZ_IMAGE_TYPE_XXXA = 10; - - -var QUIC_IMAGE_TYPE_INVALID = 0, - QUIC_IMAGE_TYPE_GRAY = 1, - QUIC_IMAGE_TYPE_RGB16 = 2, - QUIC_IMAGE_TYPE_RGB24 = 3, - QUIC_IMAGE_TYPE_RGB32 = 4, - QUIC_IMAGE_TYPE_RGBA = 5; - -var SPICE_INPUT_MOTION_ACK_BUNCH = 4; - - -var SPICE_CURSOR_TYPE_ALPHA = 0, - SPICE_CURSOR_TYPE_MONO = 1, - SPICE_CURSOR_TYPE_COLOR4 = 2, - SPICE_CURSOR_TYPE_COLOR8 = 3, - SPICE_CURSOR_TYPE_COLOR16 = 4, - SPICE_CURSOR_TYPE_COLOR24 = 5, - SPICE_CURSOR_TYPE_COLOR32 = 6; - -var SPICE_VIDEO_CODEC_TYPE_MJPEG = 1; - -var VD_AGENT_PROTOCOL = 1; - -var VD_AGENT_MOUSE_STATE = 1, - VD_AGENT_MONITORS_CONFIG = 2, - VD_AGENT_REPLY = 3, - VD_AGENT_CLIPBOARD = 4, - VD_AGENT_DISPLAY_CONFIG = 5, - VD_AGENT_ANNOUNCE_CAPABILITIES = 6, - VD_AGENT_CLIPBOARD_GRAB = 7, - VD_AGENT_CLIPBOARD_REQUEST = 8, - VD_AGENT_CLIPBOARD_RELEASE = 9, - VD_AGENT_FILE_XFER_START =10, - VD_AGENT_FILE_XFER_STATUS =11, - VD_AGENT_FILE_XFER_DATA =12, - VD_AGENT_CLIENT_DISCONNECTED =13, - VD_AGENT_MAX_CLIPBOARD =14; diff --git a/plugins/kimchi/ui/spice-html5/inputs.js b/plugins/kimchi/ui/spice-html5/inputs.js deleted file mode 100644 index c904eda..0000000 --- a/plugins/kimchi/ui/spice-html5/inputs.js +++ /dev/null @@ -1,280 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- - ** Modifier Keystates - ** These need to be tracked because focus in and out can get the keyboard - ** out of sync. - **------------------------------------------------------------------------*/ -var Shift_state = -1; -var Ctrl_state = -1; -var Alt_state = -1; -var Meta_state = -1; - -/*---------------------------------------------------------------------------- -** SpiceInputsConn -** Drive the Spice Inputs channel (e.g. mouse + keyboard) -**--------------------------------------------------------------------------*/ -function SpiceInputsConn() -{ - SpiceConn.apply(this, arguments); - - this.mousex = undefined; - this.mousey = undefined; - this.button_state = 0; - this.waiting_for_ack = 0; -} - -SpiceInputsConn.prototype = Object.create(SpiceConn.prototype); -SpiceInputsConn.prototype.process_channel_message = function(msg) -{ - if (msg.type == SPICE_MSG_INPUTS_INIT) - { - var inputs_init = new SpiceMsgInputsInit(msg.data); - this.keyboard_modifiers = inputs_init.keyboard_modifiers; - DEBUG > 1 && console.log("MsgInputsInit - modifier " + this.keyboard_modifiers); - // FIXME - We don't do anything with the keyboard modifiers... - return true; - } - if (msg.type == SPICE_MSG_INPUTS_KEY_MODIFIERS) - { - var key = new SpiceMsgInputsKeyModifiers(msg.data); - this.keyboard_modifiers = key.keyboard_modifiers; - DEBUG > 1 && console.log("MsgInputsKeyModifiers - modifier " + this.keyboard_modifiers); - // FIXME - We don't do anything with the keyboard modifiers... - return true; - } - if (msg.type == SPICE_MSG_INPUTS_MOUSE_MOTION_ACK) - { - DEBUG > 1 && console.log("mouse motion ack"); - this.waiting_for_ack -= SPICE_INPUT_MOTION_ACK_BUNCH; - return true; - } - return false; -} - - - -function handle_mousemove(e) -{ - var msg = new SpiceMiniData(); - var move; - if (this.sc.mouse_mode == SPICE_MOUSE_MODE_CLIENT) - { - move = new SpiceMsgcMousePosition(this.sc, e) - msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_POSITION, move); - } - else - { - move = new SpiceMsgcMouseMotion(this.sc, e) - msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_MOTION, move); - } - if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") - { - if (this.sc.inputs.waiting_for_ack < (2 * SPICE_INPUT_MOTION_ACK_BUNCH)) - { - this.sc.inputs.send_msg(msg); - this.sc.inputs.waiting_for_ack++; - } - else - { - DEBUG > 0 && this.sc.log_info("Discarding mouse motion"); - } - } - - if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor) - { - this.sc.cursor.spice_simulated_cursor.style.display = 'block'; - this.sc.cursor.spice_simulated_cursor.style.left = e.pageX - this.sc.cursor.spice_simulated_cursor.spice_hot_x + 'px'; - this.sc.cursor.spice_simulated_cursor.style.top = e.pageY - this.sc.cursor.spice_simulated_cursor.spice_hot_y + 'px'; - e.preventDefault(); - } - -} - -function handle_mousedown(e) -{ - var press = new SpiceMsgcMousePress(this.sc, e) - var msg = new SpiceMiniData(); - msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_PRESS, press); - if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") - this.sc.inputs.send_msg(msg); - - e.preventDefault(); -} - -function handle_contextmenu(e) -{ - e.preventDefault(); - return false; -} - -function handle_mouseup(e) -{ - var release = new SpiceMsgcMouseRelease(this.sc, e) - var msg = new SpiceMiniData(); - msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_RELEASE, release); - if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") - this.sc.inputs.send_msg(msg); - - e.preventDefault(); -} - -function handle_mousewheel(e) -{ - var press = new SpiceMsgcMousePress; - var release = new SpiceMsgcMouseRelease; - if (e.wheelDelta > 0) - press.button = release.button = SPICE_MOUSE_BUTTON_UP; - else - press.button = release.button = SPICE_MOUSE_BUTTON_DOWN; - press.buttons_state = 0; - release.buttons_state = 0; - - var msg = new SpiceMiniData(); - msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_PRESS, press); - if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") - this.sc.inputs.send_msg(msg); - - msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_RELEASE, release); - if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") - this.sc.inputs.send_msg(msg); - - e.preventDefault(); -} - -function handle_keydown(e) -{ - var key = new SpiceMsgcKeyDown(e) - var msg = new SpiceMiniData(); - check_and_update_modifiers(e, key.code, this.sc); - msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key); - if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") - this.sc.inputs.send_msg(msg); - - e.preventDefault(); -} - -function handle_keyup(e) -{ - var key = new SpiceMsgcKeyUp(e) - var msg = new SpiceMiniData(); - check_and_update_modifiers(e, key.code, this.sc); - msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key); - if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") - this.sc.inputs.send_msg(msg); - - e.preventDefault(); -} - -function sendCtrlAltDel() -{ - if (sc && sc.inputs && sc.inputs.state === "ready"){ - var key = new SpiceMsgcKeyDown(); - var msg = new SpiceMiniData(); - - update_modifier(true, KEY_LCtrl, sc); - update_modifier(true, KEY_Alt, sc); - - key.code = KEY_KP_Decimal; - msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key); - sc.inputs.send_msg(msg); - msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key); - sc.inputs.send_msg(msg); - - if(Ctrl_state == false) update_modifier(false, KEY_LCtrl, sc); - if(Alt_state == false) update_modifier(false, KEY_Alt, sc); - } -} - -function update_modifier(state, code, sc) -{ - var msg = new SpiceMiniData(); - if (!state) - { - var key = new SpiceMsgcKeyUp() - key.code =(0x80|code); - msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key); - } - else - { - var key = new SpiceMsgcKeyDown() - key.code = code; - msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key); - } - - sc.inputs.send_msg(msg); -} - -function check_and_update_modifiers(e, code, sc) -{ - if (Shift_state === -1) - { - Shift_state = e.shiftKey; - Ctrl_state = e.ctrlKey; - Alt_state = e.altKey; - Meta_state = e.metaKey; - } - - if (code === KEY_ShiftL) - Shift_state = true; - else if (code === KEY_Alt) - Alt_state = true; - else if (code === KEY_LCtrl) - Ctrl_state = true; - else if (code === 0xE0B5) - Meta_state = true; - else if (code === (0x80|KEY_ShiftL)) - Shift_state = false; - else if (code === (0x80|KEY_Alt)) - Alt_state = false; - else if (code === (0x80|KEY_LCtrl)) - Ctrl_state = false; - else if (code === (0x80|0xE0B5)) - Meta_state = false; - - if (sc && sc.inputs && sc.inputs.state === "ready") - { - if (Shift_state != e.shiftKey) - { - console.log("Shift state out of sync"); - update_modifier(e.shiftKey, KEY_ShiftL, sc); - Shift_state = e.shiftKey; - } - if (Alt_state != e.altKey) - { - console.log("Alt state out of sync"); - update_modifier(e.altKey, KEY_Alt, sc); - Alt_state = e.altKey; - } - if (Ctrl_state != e.ctrlKey) - { - console.log("Ctrl state out of sync"); - update_modifier(e.ctrlKey, KEY_LCtrl, sc); - Ctrl_state = e.ctrlKey; - } - if (Meta_state != e.metaKey) - { - console.log("Meta state out of sync"); - update_modifier(e.metaKey, 0xE0B5, sc); - Meta_state = e.metaKey; - } - } -} diff --git a/plugins/kimchi/ui/spice-html5/lz.js b/plugins/kimchi/ui/spice-html5/lz.js deleted file mode 100644 index 4292eac..0000000 --- a/plugins/kimchi/ui/spice-html5/lz.js +++ /dev/null @@ -1,166 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - - -/*---------------------------------------------------------------------------- -** lz.js -** Functions for handling SPICE_IMAGE_TYPE_LZ_RGB -** Adapted from lz.c . -**--------------------------------------------------------------------------*/ -function lz_rgb32_decompress(in_buf, at, out_buf, type, default_alpha) -{ - var encoder = at; - var op = 0; - var ctrl; - var ctr = 0; - - for (ctrl = in_buf[encoder++]; (op * 4) < out_buf.length; ctrl = in_buf[encoder++]) - { - var ref = op; - var len = ctrl >> 5; - var ofs = (ctrl & 31) << 8; - -//if (type == LZ_IMAGE_TYPE_RGBA) -//console.log(ctr++ + ": from " + (encoder + 28) + ", ctrl " + ctrl + ", len " + len + ", ofs " + ofs + ", op " + op); - if (ctrl >= 32) { - - var code; - len--; - - if (len == 7 - 1) { - do { - code = in_buf[encoder++]; - len += code; - } while (code == 255); - } - code = in_buf[encoder++]; - ofs += code; - - - if (code == 255) { - if ((ofs - code) == (31 << 8)) { - ofs = in_buf[encoder++] << 8; - ofs += in_buf[encoder++]; - ofs += 8191; - } - } - len += 1; - if (type == LZ_IMAGE_TYPE_RGBA) - len += 2; - - ofs += 1; - - ref -= ofs; - if (ref == (op - 1)) { - var b = ref; -//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha " + out_buf[(b*4)+3] + " dupped into pixel " + op + " through pixel " + (op + len)); - for (; len; --len) { - if (type == LZ_IMAGE_TYPE_RGBA) - { - out_buf[(op*4) + 3] = out_buf[(b*4)+3]; - } - else - { - for (i = 0; i < 4; i++) - out_buf[(op*4) + i] = out_buf[(b*4)+i]; - } - op++; - } - } else { -//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha copied to pixel " + op + " through " + (op + len) + " from " + ref); - for (; len; --len) { - if (type == LZ_IMAGE_TYPE_RGBA) - { - out_buf[(op*4) + 3] = out_buf[(ref*4)+3]; - } - else - { - for (i = 0; i < 4; i++) - out_buf[(op*4) + i] = out_buf[(ref*4)+i]; - } - op++; ref++; - } - } - } else { - ctrl++; - - if (type == LZ_IMAGE_TYPE_RGBA) - { -//console.log("alpha " + in_buf[encoder] + " set into pixel " + op); - out_buf[(op*4) + 3] = in_buf[encoder++]; - } - else - { - out_buf[(op*4) + 0] = in_buf[encoder + 2]; - out_buf[(op*4) + 1] = in_buf[encoder + 1]; - out_buf[(op*4) + 2] = in_buf[encoder + 0]; - if (default_alpha) - out_buf[(op*4) + 3] = 255; - encoder += 3; - } - op++; - - - for (--ctrl; ctrl; ctrl--) { - if (type == LZ_IMAGE_TYPE_RGBA) - { -//console.log("alpha " + in_buf[encoder] + " set into pixel " + op); - out_buf[(op*4) + 3] = in_buf[encoder++]; - } - else - { - out_buf[(op*4) + 0] = in_buf[encoder + 2]; - out_buf[(op*4) + 1] = in_buf[encoder + 1]; - out_buf[(op*4) + 2] = in_buf[encoder + 0]; - if (default_alpha) - out_buf[(op*4) + 3] = 255; - encoder += 3; - } - op++; - } - } - - } - return encoder - 1; -} - -function convert_spice_lz_to_web(context, lz_image) -{ - var at; - if (lz_image.type === LZ_IMAGE_TYPE_RGB32 || lz_image.type === LZ_IMAGE_TYPE_RGBA) - { - var u8 = new Uint8Array(lz_image.data); - var ret = context.createImageData(lz_image.width, lz_image.height); - - at = lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGB32, lz_image.type != LZ_IMAGE_TYPE_RGBA); - if (lz_image.type == LZ_IMAGE_TYPE_RGBA) - lz_rgb32_decompress(u8, at, ret.data, LZ_IMAGE_TYPE_RGBA, false); - } - else if (lz_image.type === LZ_IMAGE_TYPE_XXXA) - { - var u8 = new Uint8Array(lz_image.data); - var ret = context.createImageData(lz_image.width, lz_image.height); - lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGBA, false); - } - else - return undefined; - - return ret; -} diff --git a/plugins/kimchi/ui/spice-html5/main.js b/plugins/kimchi/ui/spice-html5/main.js deleted file mode 100644 index 91f1963..0000000 --- a/plugins/kimchi/ui/spice-html5/main.js +++ /dev/null @@ -1,231 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** SpiceMainConn -** This is the master Javascript class for establishing and -** managing a connection to a Spice Server. -** -** Invocation: You must pass an object with properties as follows: -** uri (required) Uri of a WebSocket listener that is -** connected to a spice server. -** password (required) Password to send to the spice server -** message_id (optional) Identifier of an element in the DOM -** where SpiceConn will write messages. -** It will use classes spice-messages-x, -** where x is one of info, warning, or error. -** screen_id (optional) Identifier of an element in the DOM -** where SpiceConn will create any new -** client screens. This is the main UI. -** dump_id (optional) If given, an element to use for -** dumping every single image + canvas drawn. -** Sometimes useful for debugging. -** onerror (optional) If given, a function to receive async -** errors. Note that you should also catch -** errors for ones that occur inline -** onagent (optional) If given, a function to be called when -** a VD agent is connected; a good opportunity -** to request a resize -** -** Throws error if there are troubles. Requires a modern (by 2012 standards) -** browser, including WebSocket and WebSocket.binaryType == arraybuffer -** -**--------------------------------------------------------------------------*/ -function SpiceMainConn() -{ - if (typeof WebSocket === "undefined") - throw new Error("WebSocket unavailable. You need to use a different browser."); - - SpiceConn.apply(this, arguments); - -} - -SpiceMainConn.prototype = Object.create(SpiceConn.prototype); -SpiceMainConn.prototype.process_channel_message = function(msg) -{ - if (msg.type == SPICE_MSG_MAIN_INIT) - { - this.log_info("Connected to " + this.ws.url); - this.report_success("Connected") - this.main_init = new SpiceMsgMainInit(msg.data); - this.connection_id = this.main_init.session_id; - - if (DEBUG > 0) - { - // FIXME - there is a lot here we don't handle; mouse modes, agent, - // ram_hint, multi_media_time - this.log_info("session id " + this.main_init.session_id + - " ; display_channels_hint " + this.main_init.display_channels_hint + - " ; supported_mouse_modes " + this.main_init.supported_mouse_modes + - " ; current_mouse_mode " + this.main_init.current_mouse_mode + - " ; agent_connected " + this.main_init.agent_connected + - " ; agent_tokens " + this.main_init.agent_tokens + - " ; multi_media_time " + this.main_init.multi_media_time + - " ; ram_hint " + this.main_init.ram_hint); - } - - this.handle_mouse_mode(this.main_init.current_mouse_mode, - this.main_init.supported_mouse_modes); - - if (this.main_init.agent_connected) - this.connect_agent(); - - var attach = new SpiceMiniData; - attach.type = SPICE_MSGC_MAIN_ATTACH_CHANNELS; - attach.size = attach.buffer_size(); - this.send_msg(attach); - return true; - } - - if (msg.type == SPICE_MSG_MAIN_MOUSE_MODE) - { - var mode = new SpiceMsgMainMouseMode(msg.data); - DEBUG > 0 && this.log_info("Mouse supported modes " + mode.supported_modes + "; current " + mode.current_mode); - this.handle_mouse_mode(mode.current_mode, mode.supported_modes); - return true; - } - - if (msg.type == SPICE_MSG_MAIN_CHANNELS_LIST) - { - var i; - var chans; - DEBUG > 0 && console.log("channels"); - chans = new SpiceMsgChannels(msg.data); - for (i = 0; i < chans.channels.length; i++) - { - var conn = { - uri: this.ws.url, - parent: this, - connection_id : this.connection_id, - type : chans.channels[i].type, - chan_id : chans.channels[i].id - }; - if (chans.channels[i].type == SPICE_CHANNEL_DISPLAY) - this.display = new SpiceDisplayConn(conn); - else if (chans.channels[i].type == SPICE_CHANNEL_INPUTS) - { - this.inputs = new SpiceInputsConn(conn); - this.inputs.mouse_mode = this.mouse_mode; - } - else if (chans.channels[i].type == SPICE_CHANNEL_CURSOR) - this.cursor = new SpiceCursorConn(conn); - else if (chans.channels[i].type == SPICE_CHANNEL_PLAYBACK) - this.cursor = new SpicePlaybackConn(conn); - else - { - this.log_err("Channel type " + chans.channels[i].type + " unknown."); - if (! ("extra_channels" in this)) - this.extra_channels = []; - this.extra_channels[i] = new SpiceConn(conn); - } - - } - - return true; - } - - if (msg.type == SPICE_MSG_MAIN_AGENT_CONNECTED || - msg.type == SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS) - { - this.connect_agent(); - return true; - } - - if (msg.type == SPICE_MSG_MAIN_AGENT_DISCONNECTED) - { - this.agent_connected = false; - return true; - } - - return false; -} - -SpiceMainConn.prototype.stop = function(msg) -{ - this.state = "closing"; - - if (this.inputs) - { - this.inputs.cleanup(); - this.inputs = undefined; - } - - if (this.cursor) - { - this.cursor.cleanup(); - this.cursor = undefined; - } - - if (this.display) - { - this.display.cleanup(); - this.display.destroy_surfaces(); - this.display = undefined; - } - - this.cleanup(); - - if ("extra_channels" in this) - for (var e in this.extra_channels) - this.extra_channels[e].cleanup(); - this.extra_channels = undefined; -} - -SpiceMainConn.prototype.resize_window = function(flags, width, height, depth, x, y) -{ - if (this.agent_connected > 0) - { - var monitors_config = new VDAgentMonitorsConfig(flags, width, height, depth, x, y); - var agent_data = new SpiceMsgcMainAgentData(VD_AGENT_MONITORS_CONFIG, monitors_config); - var mr = new SpiceMiniData(); - mr.build_msg(SPICE_MSGC_MAIN_AGENT_DATA, agent_data); - this.send_msg(mr); - } -} - -SpiceMainConn.prototype.connect_agent = function() -{ - this.agent_connected = true; - - var agent_start = new SpiceMsgcMainAgentStart(0); - var mr = new SpiceMiniData(); - mr.build_msg(SPICE_MSGC_MAIN_AGENT_START, agent_start); - this.send_msg(mr); - - if (this.onagent !== undefined) - this.onagent(this); - -} - -SpiceMainConn.prototype.handle_mouse_mode = function(current, supported) -{ - this.mouse_mode = current; - if (current != SPICE_MOUSE_MODE_CLIENT && (supported & SPICE_MOUSE_MODE_CLIENT)) - { - var mode_request = new SpiceMsgcMainMouseModeRequest(SPICE_MOUSE_MODE_CLIENT); - var mr = new SpiceMiniData(); - mr.build_msg(SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST, mode_request); - this.send_msg(mr); - } - - if (this.inputs) - this.inputs.mouse_mode = current; -} - diff --git a/plugins/kimchi/ui/spice-html5/pages/Makefile.am b/plugins/kimchi/ui/spice-html5/pages/Makefile.am deleted file mode 100644 index 431ec6c..0000000 --- a/plugins/kimchi/ui/spice-html5/pages/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2014 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -spicepagesdir = $(datadir)/wok/plugins/kimchi/ui/spice-html5/pages - -dist_spicepages_DATA = $(wildcard *.html) $(NULL) diff --git a/plugins/kimchi/ui/spice-html5/pages/spice_auto.html b/plugins/kimchi/ui/spice-html5/pages/spice_auto.html deleted file mode 100644 index c87f5c2..0000000 --- a/plugins/kimchi/ui/spice-html5/pages/spice_auto.html +++ /dev/null @@ -1,200 +0,0 @@ -<!-- - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. - - -------------------------------------------------- - Spice Javascript client template. - Refer to main.js for more detailed information - -------------------------------------------------- - ---> - -<!doctype html> -<html> - <head> - - <!-- - The below sources were updated according to Kimchi configuration - to get the Javascript and CSS files from the installed spice-html5 - package. - Kimchi is not using the default spice_auto.html because Kimchi uses - wss:// for all connections and it is only supported by recent - versions of spice-html5. - In addition to it, Kimchi points user to the right token on URL - (check line 146 of this file). - --> - <title>Spice Javascript client</title> - <script src="spice-html5/spicearraybuffer.js"></script> - <script src="spice-html5/enums.js"></script> - <script src="spice-html5/atKeynames.js"></script> - <script src="spice-html5/utils.js"></script> - <script src="spice-html5/png.js"></script> - <script src="spice-html5/lz.js"></script> - <script src="spice-html5/quic.js"></script> - <script src="spice-html5/bitmap.js"></script> - <script src="spice-html5/spicedataview.js"></script> - <script src="spice-html5/spicetype.js"></script> - <script src="spice-html5/spicemsg.js"></script> - <script src="spice-html5/wire.js"></script> - <script src="spice-html5/spiceconn.js"></script> - <script src="spice-html5/display.js"></script> - <script src="spice-html5/main.js"></script> - <script src="spice-html5/inputs.js"></script> - <script src="spice-html5/webm.js"></script> - <script src="spice-html5/playback.js"></script> - <script src="spice-html5/simulatecursor.js"></script> - <script src="spice-html5/cursor.js"></script> - <script src="spice-html5/thirdparty/jsbn.js"></script> - <script src="spice-html5/thirdparty/rsa.js"></script> - <script src="spice-html5/thirdparty/prng4.js"></script> - <script src="spice-html5/thirdparty/rng.js"></script> - <script src="spice-html5/thirdparty/sha1.js"></script> - <script src="spice-html5/ticket.js"></script> - <script src="spice-html5/resize.js"></script> - <link rel="stylesheet" type="text/css" href="spice-html5/spice.css" /> - - <script> - var host = null, port = null; - var sc; - - function spice_set_cookie(name, value, days) { - var date, expires; - date = new Date(); - date.setTime(date.getTime() + (days*24*60*60*1000)); - expires = "; expires=" + date.toGMTString(); - document.cookie = name + "=" + value + expires + "; path=/"; - }; - - function spice_query_var(name, defvalue) { - var match = RegExp('[?&]' + name + '=([^&]*)') - .exec(window.location.search); - return match ? - decodeURIComponent(match[1].replace(/\+/g, ' ')) - : defvalue; - } - - function spice_error(e) - { - disconnect(); - } - - function connect() - { - var host, port, password, scheme = "ws://", uri; - - // By default, use the host and port of server that served this file - host = spice_query_var('host', window.location.hostname); - - // Note that using the web server port only makes sense - // if your web server has a reverse proxy to relay the WebSocket - // traffic to the correct destination port. - var default_port = window.location.port; - if (!default_port) { - if (window.location.protocol == 'http:') { - default_port = 80; - } - else if (window.location.protocol == 'https:') { - default_port = 443; - } - } - port = spice_query_var('port', default_port); - if (window.location.protocol == 'https:') { - scheme = "wss://"; - } - - // If a token variable is passed in, set the parameter in a cookie. - // This is used by nova-spiceproxy. - token = spice_query_var('token', null); - if (token) { - spice_set_cookie('token', token, 1) - } - - password = spice_query_var('password', ''); - path = spice_query_var('path', 'websockify'); - - if ((!host) || (!port)) { - console.log("must specify host and port in URL"); - return; - } - - if (sc) { - sc.stop(); - } - - /* - * The following line was modified from the original one: - * - * 'uri = scheme + host + ":" + port;' - * - * to point wok.user to a specific console represented by - * token value. - */ - uri = scheme + host + ":" + port + "/?token=" + token; - - try - { - sc = new SpiceMainConn({uri: uri, screen_id: "spice-screen", dump_id: "debug-div", - message_id: "message-div", password: password, onerror: spice_error, onagent: agent_connected }); - } - catch (e) - { - alert(e.toString()); - disconnect(); - } - - } - - function disconnect() - { - console.log(">> disconnect"); - if (sc) { - sc.stop(); - } - console.log("<< disconnect"); - } - - function agent_connected(sc) - { - window.addEventListener('resize', handle_resize); - window.spice_connection = this; - - resize_helper(this); - } - - connect(); - </script> - - </head> - - <body> - - <div id="login"> - <span class="logo">SPICE</span> - </div> - - <div id="spice-area"> - <div id="spice-screen" class="spice-screen"></div> - </div> - - <div id="message-div" class="spice-message"></div> - - <div id="debug-div"> - <!-- If DUMPXXX is turned on, dumped images will go here --> - </div> - - </body> -</html> diff --git a/plugins/kimchi/ui/spice-html5/playback.js b/plugins/kimchi/ui/spice-html5/playback.js deleted file mode 100644 index 7209fbe..0000000 --- a/plugins/kimchi/ui/spice-html5/playback.js +++ /dev/null @@ -1,278 +0,0 @@ -"use strict"; -/* - Copyright (C) 2014 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** SpicePlaybackConn -** Drive the Spice Playback channel (sound out) -**--------------------------------------------------------------------------*/ -function SpicePlaybackConn() -{ - SpiceConn.apply(this, arguments); - - this.queue = new Array(); - this.append_okay = false; - this.start_time = 0; - this.skip_until = 0; - this.gap_time = 0; -} - -SpicePlaybackConn.prototype = Object.create(SpiceConn.prototype); -SpicePlaybackConn.prototype.process_channel_message = function(msg) -{ - if (!!!window.MediaSource) - { - this.log_err('MediaSource API is not available'); - return false; - } - - if (msg.type == SPICE_MSG_PLAYBACK_START) - { - var start = new SpiceMsgPlaybackStart(msg.data); - - DEBUG > 0 && console.log("PlaybackStart; frequency " + start.frequency); - - if (start.frequency != OPUS_FREQUENCY) - { - this.log_err('This player cannot handle frequency ' + start.frequency); - return false; - } - - if (start.channels != OPUS_CHANNELS) - { - this.log_err('This player cannot handle ' + start.channels + ' channels'); - return false; - } - - if (start.format != SPICE_AUDIO_FMT_S16) - { - this.log_err('This player cannot format ' + start.format); - return false; - } - - if (! this.source_buffer) - { - this.media_source = new MediaSource(); - this.media_source.spiceconn = this; - - this.audio = document.createElement("audio"); - this.audio.setAttribute('autoplay', true); - this.audio.src = window.URL.createObjectURL(this.media_source); - document.getElementById(this.parent.screen_id).appendChild(this.audio); - - this.media_source.addEventListener('sourceopen', handle_source_open, false); - this.media_source.addEventListener('sourceended', handle_source_ended, false); - this.media_source.addEventListener('sourceclosed', handle_source_closed, false); - - this.bytes_written = 0; - - return true; - } - } - - if (msg.type == SPICE_MSG_PLAYBACK_DATA) - { - var data = new SpiceMsgPlaybackData(msg.data); - - // If this packet has the same time as the last, just bump up by one. - if (this.last_data_time && data.time <= this.last_data_time) - { - // FIXME - this is arguably wrong. But delaying the transmission was worse, - // in initial testing. Could use more research. - DEBUG > 1 && console.log("Hacking time of " + data.time + " to " + this.last_data_time + 1); - data.time = this.last_data_time + 1; - } - - /* Gap detection: If there has been a delay since our last packet, then audio must - have paused. Handling that gets tricky. In Chrome, you can seek forward, - but you cannot in Firefox. And seeking forward in Chrome is nice, as it keeps - Chrome from being overly cautious in it's buffer strategy. - - So we do two things. First, we seek forward. Second, we compute how much of a gap - there would have been, and essentially eliminate it. - */ - if (this.last_data_time && data.time >= (this.last_data_time + GAP_DETECTION_THRESHOLD)) - { - this.skip_until = data.time; - this.gap_time = (data.time - this.start_time) - - (this.source_buffer.buffered.end(this.source_buffer.buffered.end.length - 1) * 1000.0).toFixed(0); - } - - this.last_data_time = data.time; - - - DEBUG > 1 && console.log("PlaybackData; time " + data.time + "; length " + data.data.byteLength); - - if (! this.source_buffer) - return true; - - if (this.start_time == 0) - this.start_playback(data); - - else if (data.time - this.cluster_time >= MAX_CLUSTER_TIME || this.skip_until > 0) - this.new_cluster(data); - - else - this.simple_block(data, false); - - if (this.skip_until > 0) - { - this.audio.currentTime = (this.skip_until - this.start_time - this.gap_time) / 1000.0; - this.skip_until = 0; - } - - if (this.audio.paused) - this.audio.play(); - - return true; - } - - if (msg.type == SPICE_MSG_PLAYBACK_MODE) - { - var mode = new SpiceMsgPlaybackMode(msg.data); - if (mode.mode != SPICE_AUDIO_DATA_MODE_OPUS) - { - this.log_err('This player cannot handle mode ' + mode.mode); - delete this.source_buffer; - } - return true; - } - - if (msg.type == SPICE_MSG_PLAYBACK_STOP) - { - return true; - } - - return false; -} - -SpicePlaybackConn.prototype.start_playback = function(data) -{ - this.start_time = data.time; - - var h = new webm_Header(); - - var mb = new ArrayBuffer(h.buffer_size()) - - this.bytes_written = h.to_buffer(mb); - - this.source_buffer.addEventListener('error', handle_sourcebuffer_error, false); - this.source_buffer.addEventListener('updateend', handle_append_buffer_done, false); - playback_append_buffer(this, mb); - - this.new_cluster(data); -} - -SpicePlaybackConn.prototype.new_cluster = function(data) -{ - this.cluster_time = data.time; - - var c = new webm_Cluster(data.time - this.start_time - this.gap_time); - - var mb = new ArrayBuffer(c.buffer_size()); - this.bytes_written += c.to_buffer(mb); - - if (this.append_okay) - playback_append_buffer(this, mb); - else - this.queue.push(mb); - - this.simple_block(data, true); -} - -SpicePlaybackConn.prototype.simple_block = function(data, keyframe) -{ - var sb = new webm_SimpleBlock(data.time - this.cluster_time, data.data, keyframe); - var mb = new ArrayBuffer(sb.buffer_size()); - - this.bytes_written += sb.to_buffer(mb); - - if (this.append_okay) - playback_append_buffer(this, mb); - else - this.queue.push(mb); -} - -function handle_source_open(e) -{ - var p = this.spiceconn; - - if (p.source_buffer) - return; - - p.source_buffer = this.addSourceBuffer(SPICE_PLAYBACK_CODEC); - if (! p.source_buffer) - { - p.log_err('Codec ' + SPICE_PLAYBACK_CODEC + ' not available.'); - return; - } - p.source_buffer.spiceconn = p; - p.source_buffer.mode = "segments"; - - // FIXME - Experimentation with segments and sequences was unsatisfying. - // Switching to sequence did not solve our gap problem, - // but the browsers didn't fully support the time seek capability - // we would expect to gain from 'segments'. - // Segments worked at the time of this patch, so segments it is for now. - -} - -function handle_source_ended(e) -{ - var p = this.spiceconn; - p.log_err('Audio source unexpectedly ended.'); -} - -function handle_source_closed(e) -{ - var p = this.spiceconn; - p.log_err('Audio source unexpectedly closed.'); -} - -function handle_append_buffer_done(b) -{ - var p = this.spiceconn; - if (p.queue.length > 0) - { - var mb = p.queue.shift(); - playback_append_buffer(p, mb); - } - else - p.append_okay = true; - -} - -function handle_sourcebuffer_error(e) -{ - var p = this.spiceconn; - p.log_err('source_buffer error ' + e.message); -} - -function playback_append_buffer(p, b) -{ - try - { - p.source_buffer.appendBuffer(b); - p.append_okay = false; - } - catch (e) - { - p.log_err("Error invoking appendBuffer: " + e.message); - } -} diff --git a/plugins/kimchi/ui/spice-html5/png.js b/plugins/kimchi/ui/spice-html5/png.js deleted file mode 100644 index 6a26151..0000000 --- a/plugins/kimchi/ui/spice-html5/png.js +++ /dev/null @@ -1,256 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** crc logic from rfc2083 ported to Javascript -**--------------------------------------------------------------------------*/ - -var rfc2083_crc_table = Array(256); -var rfc2083_crc_table_computed = 0; -/* Make the table for a fast CRC. */ -function rfc2083_make_crc_table() -{ - var c; - var n, k; - for (n = 0; n < 256; n++) - { - c = n; - for (k = 0; k < 8; k++) - { - if (c & 1) - c = ((0xedb88320 ^ (c >>> 1)) >>> 0) & 0xffffffff; - else - c = c >>> 1; - } - rfc2083_crc_table[n] = c; - } - - rfc2083_crc_table_computed = 1; -} - -/* Update a running CRC with the bytes buf[0..len-1]--the CRC - should be initialized to all 1's, and the transmitted value - is the 1's complement of the final running CRC (see the - crc() routine below)). */ - -function rfc2083_update_crc(crc, u8buf, at, len) -{ - var c = crc; - var n; - - if (!rfc2083_crc_table_computed) - rfc2083_make_crc_table(); - - for (n = 0; n < len; n++) - { - c = rfc2083_crc_table[(c ^ u8buf[at + n]) & 0xff] ^ (c >>> 8); - } - - return c; -} - -function rfc2083_crc(u8buf, at, len) -{ - return rfc2083_update_crc(0xffffffff, u8buf, at, len) ^ 0xffffffff; -} - -function crc32(mb, at, len) -{ - var u8 = new Uint8Array(mb); - return rfc2083_crc(u8, at, len); -} - -function PngIHDR(width, height) -{ - this.width = width; - this.height = height; - this.depth = 8; - this.type = 6; - this.compression = 0; - this.filter = 0; - this.interlace = 0; -} - -PngIHDR.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var orig = at; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.buffer_size() - 12); at += 4; - dv.setUint8(at, 'I'.charCodeAt(0)); at++; - dv.setUint8(at, 'H'.charCodeAt(0)); at++; - dv.setUint8(at, 'D'.charCodeAt(0)); at++; - dv.setUint8(at, 'R'.charCodeAt(0)); at++; - dv.setUint32(at, this.width); at += 4; - dv.setUint32(at, this.height); at += 4; - dv.setUint8(at, this.depth); at++; - dv.setUint8(at, this.type); at++; - dv.setUint8(at, this.compression); at++; - dv.setUint8(at, this.filter); at++; - dv.setUint8(at, this.interlace); at++; - dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4; - return at; - }, - buffer_size: function() - { - return 12 + 13; - } -} - - -function adler() -{ - this.s1 = 1; - this.s2 = 0; -} - -adler.prototype.update = function(b) -{ - this.s1 += b; - this.s1 %= 65521; - this.s2 += this.s1; - this.s2 %= 65521; -} - -function PngIDAT(width, height, bytes) -{ - if (bytes.byteLength > 65535) - { - throw new Error("Cannot handle more than 64K"); - } - this.data = bytes; - this.width = width; - this.height = height; -} - -PngIDAT.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var orig = at; - var x, y, i, j; - var dv = new SpiceDataView(a); - var zsum = new adler(); - dv.setUint32(at, this.buffer_size() - 12); at += 4; - dv.setUint8(at, 'I'.charCodeAt(0)); at++; - dv.setUint8(at, 'D'.charCodeAt(0)); at++; - dv.setUint8(at, 'A'.charCodeAt(0)); at++; - dv.setUint8(at, 'T'.charCodeAt(0)); at++; - - /* zlib header. */ - dv.setUint8(at, 0x78); at++; - dv.setUint8(at, 0x01); at++; - - /* Deflate header. Specifies uncompressed, final bit */ - dv.setUint8(at, 0x80); at++; - dv.setUint16(at, this.data.byteLength + this.height); at += 2; - dv.setUint16(at, ~(this.data.byteLength + this.height)); at += 2; - var u8 = new Uint8Array(this.data); - for (i = 0, y = 0; y < this.height; y++) - { - /* Filter type 0 - uncompressed */ - dv.setUint8(at, 0); at++; - zsum.update(0); - for (x = 0; x < this.width && i < this.data.byteLength; x++) - { - zsum.update(u8[i]); - dv.setUint8(at, u8[i++]); at++; - zsum.update(u8[i]); - dv.setUint8(at, u8[i++]); at++; - zsum.update(u8[i]); - dv.setUint8(at, u8[i++]); at++; - zsum.update(u8[i]); - dv.setUint8(at, u8[i++]); at++; - } - } - - /* zlib checksum. */ - dv.setUint16(at, zsum.s2); at+=2; - dv.setUint16(at, zsum.s1); at+=2; - - /* FIXME - something is not quite right with the zlib code; - you get an error from libpng if you open the image in - gimp. But it works, so it's good enough for now... */ - - dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4; - return at; - }, - buffer_size: function() - { - return 12 + this.data.byteLength + this.height + 4 + 2 + 1 + 2 + 2; - } -} - - -function PngIEND() -{ -} - -PngIEND.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var orig = at; - var i; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.buffer_size() - 12); at += 4; - dv.setUint8(at, 'I'.charCodeAt(0)); at++; - dv.setUint8(at, 'E'.charCodeAt(0)); at++; - dv.setUint8(at, 'N'.charCodeAt(0)); at++; - dv.setUint8(at, 'D'.charCodeAt(0)); at++; - dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4; - return at; - }, - buffer_size: function() - { - return 12; - } -} - - -function create_rgba_png(width, height, bytes) -{ - var i; - var ihdr = new PngIHDR(width, height); - var idat = new PngIDAT(width, height, bytes); - var iend = new PngIEND; - - var mb = new ArrayBuffer(ihdr.buffer_size() + idat.buffer_size() + iend.buffer_size()); - var at = ihdr.to_buffer(mb); - at = idat.to_buffer(mb, at); - at = iend.to_buffer(mb, at); - - var u8 = new Uint8Array(mb); - var str = ""; - for (i = 0; i < at; i++) - { - str += "%"; - if (u8[i] < 16) - str += "0"; - str += u8[i].toString(16); - } - - - return "%89PNG%0D%0A%1A%0A" + str; -} diff --git a/plugins/kimchi/ui/spice-html5/quic.js b/plugins/kimchi/ui/spice-html5/quic.js deleted file mode 100644 index 9bb9f47..0000000 --- a/plugins/kimchi/ui/spice-html5/quic.js +++ /dev/null @@ -1,1335 +0,0 @@ -/*"use strict";*/ -/* use strict is commented out because it results in a 5x slowdone in chrome */ -/* - * Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - * Copyright (C) 2012 by Aric Stewart <aric@codeweavers.com> - * - * This file is part of spice-html5. - * - * spice-html5 is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * spice-html5 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with spice-html5. If not, see <http://www.gnu.org/licenses/>. - */ - -var encoder; - -var QUIC_IMAGE_TYPE_INVALID = 0; -var QUIC_IMAGE_TYPE_GRAY = 1; -var QUIC_IMAGE_TYPE_RGB16 = 2; -var QUIC_IMAGE_TYPE_RGB24 = 3; -var QUIC_IMAGE_TYPE_RGB32 = 4; -var QUIC_IMAGE_TYPE_RGBA = 5; -var DEFevol = 3; -var DEFwmimax = 6; -var DEFwminext = 2048; -var need_init = true; -var DEFmaxclen = 26; -var evol = DEFevol; -var wmimax = DEFwmimax; -var wminext = DEFwminext; -var family_5bpc = { nGRcodewords:[0,0,0,0,0,0,0,0], - notGRcwlen:[0,0,0,0,0,0,0,0], - notGRprefixmask:[0,0,0,0,0,0,0,0], - notGRsuffixlen:[0,0,0,0,0,0,0,0], - xlatU2L:[0,0,0,0,0,0,0,0], - xlatL2U:[0,0,0,0,0,0,0,0] - }; -var family_8bpc = { nGRcodewords:[0,0,0,0,0,0,0,0], - notGRcwlen:[0,0,0,0,0,0,0,0], - notGRprefixmask:[0,0,0,0,0,0,0,0], - notGRsuffixlen:[0,0,0,0,0,0,0,0], - xlatU2L:[0,0,0,0,0,0,0,0], - xlatL2U:[0,0,0,0,0,0,0,0] - }; -var bppmask = [ 0x00000000, - 0x00000001, 0x00000003, 0x00000007, 0x0000000f, - 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, - 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, - 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, - 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, - 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, - 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, - 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff]; - -var zeroLUT = []; - -var besttrigtab = [ - [ 550, 900, 800, 700, 500, 350, 300, 200, 180, 180, 160], - [ 110, 550, 900, 800, 550, 400, 350, 250, 140, 160, 140], - [ 100, 120, 550, 900, 700, 500, 400, 300, 220, 250, 160]]; - -var J = [ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - -var lzeroes = [ - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0]; - -var tabrand_chaos = [ - 0x02c57542, 0x35427717, 0x2f5a2153, 0x9244f155, 0x7bd26d07, 0x354c6052, - 0x57329b28, 0x2993868e, 0x6cd8808c, 0x147b46e0, 0x99db66af, 0xe32b4cac, - 0x1b671264, 0x9d433486, 0x62a4c192, 0x06089a4b, 0x9e3dce44, 0xdaabee13, - 0x222425ea, 0xa46f331d, 0xcd589250, 0x8bb81d7f, 0xc8b736b9, 0x35948d33, - 0xd7ac7fd0, 0x5fbe2803, 0x2cfbc105, 0x013dbc4e, 0x7a37820f, 0x39f88e9e, - 0xedd58794, 0xc5076689, 0xfcada5a4, 0x64c2f46d, 0xb3ba3243, 0x8974b4f9, - 0x5a05aebd, 0x20afcd00, 0x39e2b008, 0x88a18a45, 0x600bde29, 0xf3971ace, - 0xf37b0a6b, 0x7041495b, 0x70b707ab, 0x06beffbb, 0x4206051f, 0xe13c4ee3, - 0xc1a78327, 0x91aa067c, 0x8295f72a, 0x732917a6, 0x1d871b4d, 0x4048f136, - 0xf1840e7e, 0x6a6048c1, 0x696cb71a, 0x7ff501c3, 0x0fc6310b, 0x57e0f83d, - 0x8cc26e74, 0x11a525a2, 0x946934c7, 0x7cd888f0, 0x8f9d8604, 0x4f86e73b, - 0x04520316, 0xdeeea20c, 0xf1def496, 0x67687288, 0xf540c5b2, 0x22401484, - 0x3478658a, 0xc2385746, 0x01979c2c, 0x5dad73c8, 0x0321f58b, 0xf0fedbee, - 0x92826ddf, 0x284bec73, 0x5b1a1975, 0x03df1e11, 0x20963e01, 0xa17cf12b, - 0x740d776e, 0xa7a6bf3c, 0x01b5cce4, 0x1118aa76, 0xfc6fac0a, 0xce927e9b, - 0x00bf2567, 0x806f216c, 0xbca69056, 0x795bd3e9, 0xc9dc4557, 0x8929b6c2, - 0x789d52ec, 0x3f3fbf40, 0xb9197368, 0xa38c15b5, 0xc3b44fa8, 0xca8333b0, - 0xb7e8d590, 0xbe807feb, 0xbf5f8360, 0xd99e2f5c, 0x372928e1, 0x7c757c4c, - 0x0db5b154, 0xc01ede02, 0x1fc86e78, 0x1f3985be, 0xb4805c77, 0x00c880fa, - 0x974c1b12, 0x35ab0214, 0xb2dc840d, 0x5b00ae37, 0xd313b026, 0xb260969d, - 0x7f4c8879, 0x1734c4d3, 0x49068631, 0xb9f6a021, 0x6b863e6f, 0xcee5debf, - 0x29f8c9fb, 0x53dd6880, 0x72b61223, 0x1f67a9fd, 0x0a0f6993, 0x13e59119, - 0x11cca12e, 0xfe6b6766, 0x16b6effc, 0x97918fc4, 0xc2b8a563, 0x94f2f741, - 0x0bfa8c9a, 0xd1537ae8, 0xc1da349c, 0x873c60ca, 0x95005b85, 0x9b5c080e, - 0xbc8abbd9, 0xe1eab1d2, 0x6dac9070, 0x4ea9ebf1, 0xe0cf30d4, 0x1ef5bd7b, - 0xd161043e, 0x5d2fa2e2, 0xff5d3cae, 0x86ed9f87, 0x2aa1daa1, 0xbd731a34, - 0x9e8f4b22, 0xb1c2c67a, 0xc21758c9, 0xa182215d, 0xccb01948, 0x8d168df7, - 0x04238cfe, 0x368c3dbc, 0x0aeadca5, 0xbad21c24, 0x0a71fee5, 0x9fc5d872, - 0x54c152c6, 0xfc329483, 0x6783384a, 0xeddb3e1c, 0x65f90e30, 0x884ad098, - 0xce81675a, 0x4b372f7d, 0x68bf9a39, 0x43445f1e, 0x40f8d8cb, 0x90d5acb6, - 0x4cd07282, 0x349eeb06, 0x0c9d5332, 0x520b24ef, 0x80020447, 0x67976491, - 0x2f931ca3, 0xfe9b0535, 0xfcd30220, 0x61a9e6cc, 0xa487d8d7, 0x3f7c5dd1, - 0x7d0127c5, 0x48f51d15, 0x60dea871, 0xc9a91cb7, 0x58b53bb3, 0x9d5e0b2d, - 0x624a78b4, 0x30dbee1b, 0x9bdf22e7, 0x1df5c299, 0x2d5643a7, 0xf4dd35ff, - 0x03ca8fd6, 0x53b47ed8, 0x6f2c19aa, 0xfeb0c1f4, 0x49e54438, 0x2f2577e6, - 0xbf876969, 0x72440ea9, 0xfa0bafb8, 0x74f5b3a0, 0x7dd357cd, 0x89ce1358, - 0x6ef2cdda, 0x1e7767f3, 0xa6be9fdb, 0x4f5f88f8, 0xba994a3a, 0x08ca6b65, - 0xe0893818, 0x9e00a16a, 0xf42bfc8f, 0x9972eedc, 0x749c8b51, 0x32c05f5e, - 0xd706805f, 0x6bfbb7cf, 0xd9210a10, 0x31a1db97, 0x923a9559, 0x37a7a1f6, - 0x059f8861, 0xca493e62, 0x65157e81, 0x8f6467dd, 0xab85ff9f, 0x9331aff2, - 0x8616b9f5, 0xedbd5695, 0xee7e29b1, 0x313ac44f, 0xb903112f, 0x432ef649, - 0xdc0a36c0, 0x61cf2bba, 0x81474925, 0xa8b6c7ad, 0xee5931de, 0xb2f8158d, - 0x59fb7409, 0x2e3dfaed, 0x9af25a3f, 0xe1fed4d5 ]; - -var rgb32_pixel_pad = 3; -var rgb32_pixel_r = 2; -var rgb32_pixel_g = 1; -var rgb32_pixel_b = 0; -var rgb32_pixel_size = 4; - -/* Helper Functions */ - -function ceil_log_2(val) -{ - if (val === 1) - return 0; - - var result = 1; - val -= 1; - while (val = val >>> 1) - result++; - - return result; -} - -function family_init(family, bpc, limit) -{ - var l; - for (l = 0; l < bpc; l++) - { - var altprefixlen, altcodewords; - altprefixlen = limit - bpc; - if (altprefixlen > bppmask[bpc - l]) - altprefixlen = bppmask[bpc - l]; - - altcodewords = bppmask[bpc] + 1 - (altprefixlen << l); - family.nGRcodewords[l] = (altprefixlen << l); - family.notGRcwlen[l] = altprefixlen + ceil_log_2(altcodewords); - family.notGRprefixmask[l] = bppmask[32 - altprefixlen]>>>0; - family.notGRsuffixlen[l] = ceil_log_2(altcodewords); - } - - /* decorelate_init */ - var pixelbitmask = bppmask[bpc]; - var pixelbitmaskshr = pixelbitmask >>> 1; - var s; - for (s = 0; s <= pixelbitmask; s++) { - if (s <= pixelbitmaskshr) { - family.xlatU2L[s] = s << 1; - } else { - family.xlatU2L[s] = ((pixelbitmask - s) << 1) + 1; - } - } - - /* corelate_init */ - for (s = 0; s <= pixelbitmask; s++) { - if (s & 0x01) { - family.xlatL2U[s] = pixelbitmask - (s >>> 1); - } else { - family.xlatL2U[s] = (s >>> 1); - } - } -} - -function quic_image_bpc(type) -{ - switch (type) { - case QUIC_IMAGE_TYPE_GRAY: - return 8; - case QUIC_IMAGE_TYPE_RGB16: - return 5; - case QUIC_IMAGE_TYPE_RGB24: - return 8; - case QUIC_IMAGE_TYPE_RGB32: - return 8; - case QUIC_IMAGE_TYPE_RGBA: - return 8; - case QUIC_IMAGE_TYPE_INVALID: - default: - console.log("quic: bad image type\n"); - return 0; - } -} - -function cnt_l_zeroes(bits) -{ - if (bits & 0xff800000) { - return lzeroes[bits >>> 24]; - } else if (bits & 0xffff8000) { - return 8 + lzeroes[(bits >>> 16) & 0x000000ff]; - } else if (bits & 0xffffff80) { - return 16 + lzeroes[(bits >>> 8) & 0x000000ff]; - } else { - return 24 + lzeroes[bits & 0x000000ff]; - } -} - -function golomb_decoding_8bpc(l, bits) -{ - var rc; - var cwlen; - - if (bits < 0 || bits > family_8bpc.notGRprefixmask[l]) - { - var zeroprefix = cnt_l_zeroes(bits); - cwlen = zeroprefix + 1 + l; - rc = (zeroprefix << l) | (bits >> (32-cwlen)) & bppmask[l]; - } - else - { - cwlen = family_8bpc.notGRcwlen[l]; - rc = family_8bpc.nGRcodewords[l] + ((bits >> (32-cwlen)) & bppmask[family_8bpc.notGRsuffixlen[l]]); - } - return {'codewordlen':cwlen, 'rc':rc}; -} - -function golomb_code_len_8bpc(n, l) -{ - if (n < family_8bpc.nGRcodewords[l]) { - return (n >>> l) + 1 + l; - } else { - return family_8bpc.notGRcwlen[l]; - } -} - -function QuicModel(bpc) -{ - var bstart; - var bend = 0; - - this.levels = 0x1 << bpc; - this.n_buckets_ptrs = 0; - - switch (evol) { - case 1: - this.repfirst = 3; - this.firstsize = 1; - this.repnext = 2; - this.mulsize = 2; - break; - case 3: - this.repfirst = 1; - this.firstsize = 1; - this.repnext = 1; - this.mulsize = 2; - break; - case 5: - this.repfirst = 1; - this.firstsize = 1; - this.repnext = 1; - this.mulsize = 4; - break; - case 0: - case 2: - case 4: - console.log("quic: findmodelparams(): evol value obsolete!!!\n"); - default: - console.log("quic: findmodelparams(): evol out of range!!!\n"); - } - - this.n_buckets = 0; - var repcntr = this.repfirst + 1; - var bsize = this.firstsize; - - do { - if (this.n_buckets) { - bstart = bend + 1; - } else { - bstart = 0; - } - - if (!--repcntr) { - repcntr = this.repnext; - bsize *= this.mulsize; - } - - bend = bstart + bsize - 1; - if (bend + bsize >= this.levels) { - bend = this.levels - 1; - } - - if (!this.n_buckets_ptrs) { - this.n_buckets_ptrs = this.levels; - } - - (this.n_buckets)++; - } while (bend < this.levels - 1); -} - -QuicModel.prototype = { - n_buckets : 0, - n_buckets_ptrs : 0, - repfirst : 0, - firstsize : 0, - repnext : 0, - mulsize : 0, - levels :0 -} - -function QuicBucket() -{ - this.counters = [0,0,0,0,0,0,0,0]; -} - -QuicBucket.prototype = { - bestcode: 0, - - reste : function (bpp) - { - this.bestcode = bpp; - this.counters = [0,0,0,0,0,0,0,0]; - }, - - update_model_8bpc : function (state, curval, bpp) - { - var i; - - var bestcode = bpp - 1; - var bestcodelen = (this.counters[bestcode] += golomb_code_len_8bpc(curval, bestcode)); - - for (i = bpp - 2; i >= 0; i--) { - var ithcodelen = (this.counters[i] += golomb_code_len_8bpc(curval, i)); - - if (ithcodelen < bestcodelen) { - bestcode = i; - bestcodelen = ithcodelen; - } - } - - this.bestcode = bestcode; - - if (bestcodelen > state.wm_trigger) { - for (i = 0; i < bpp; i++) { - this.counters[i] = this.counters[i] >>> 1; - } - } - } -} - -function QuicFamilyStat() -{ - this.buckets_ptrs = []; - this.buckets_buf = []; -} - -QuicFamilyStat.prototype = { - - fill_model_structures : function(model) - { - var bstart; - var bend = 0; - var bnumber = 0; - - var repcntr = model.repfirst + 1; - var bsize = model.firstsize; - - do { - if (bnumber) { - bstart = bend + 1; - } else { - bstart = 0; - } - - if (!--repcntr) { - repcntr = model.repnext; - bsize *= model.mulsize; - } - - bend = bstart + bsize - 1; - if (bend + bsize >= model.levels) { - bend = model.levels - 1; - } - - this.buckets_buf[bnumber] = new QuicBucket; - - var i; - for (i = bstart; i <= bend; i++) { - this.buckets_ptrs[i] = this.buckets_buf[bnumber]; - } - - bnumber++; - } while (bend < model.levels - 1); - return true; - } -} - -function QuicChannel(model_8bpc, model_5bpc) -{ - this.state = new CommonState; - this.family_stat_8bpc = new QuicFamilyStat; - this.family_stat_5bpc = new QuicFamilyStat; - this.correlate_row = { zero: 0 , row:[] }; - this.model_8bpc = model_8bpc; - this.model_5bpc = model_5bpc; - this.buckets_ptrs = []; - - if (!this.family_stat_8bpc.fill_model_structures(this.model_8bpc)) - return undefined; - - if (!this.family_stat_5bpc.fill_model_structures(this.model_5bpc)) - return undefined; -} - -QuicChannel.prototype = { - - reste : function (bpc) - { - var j; - this.correlate_row = { zero: 0 , row: []}; - - if (bpc == 8) { - for (j = 0; j < this.model_8bpc.n_buckets; j++) - this.family_stat_8bpc.buckets_buf[j].reste(7); - this.buckets_ptrs = this.family_stat_8bpc.buckets_ptrs; - } else if (bpc == 5) { - for (j = 0; j < this.model_5bpc.n_buckets; j++) - this.family_stat_8bpc.buckets_buf[j].reste(4); - this.buckets_ptrs = this.family_stat_5bpc.buckets_ptrs; - } else { - console.log("quic: %s: bad bpc %d\n", __FUNCTION__, bpc); - return false; - } - - this.state.reste(); - return true; - } -} - -function CommonState() -{ -} - -CommonState.prototype = { - waitcnt: 0, - tabrand_seed: 0xff, - wm_trigger: 0, - wmidx: 0, - wmileft: wminext, - melcstate: 0, - melclen: 0, - melcorder: 0, - - set_wm_trigger : function() - { - var wm = this.wmidx; - if (wm > 10) { - wm = 10; - } - - this.wm_trigger = besttrigtab[Math.floor(evol / 2)][wm]; - }, - - reste : function() - { - this.waitcnt = 0; - this.tabrand_seed = 0x0ff; - this.wmidx = 0; - this.wmileft = wminext; - - this.set_wm_trigger(); - - this.melcstate = 0; - this.melclen = J[0]; - this.melcorder = 1 << this.melclen; - }, - - tabrand : function() - { - this.tabrand_seed++; - return tabrand_chaos[this.tabrand_seed & 0x0ff]; - } -} - - -function QuicEncoder() -{ - this.rgb_state = new CommonState; - this.model_8bpc = new QuicModel(8); - this.model_5bpc = new QuicModel(5); - this.channels = []; - - var i; - for (i = 0; i < 4; i++) { - this.channels[i] = new QuicChannel(this.model_8bpc, this.model_5bpc); - if (!this.channels[i]) - { - console.log("quic: failed to create channel"); - return undefined; - } - } -} - -QuicEncoder.prototype = { - type: 0, - width: 0, - height: 0, - io_idx: 0, - io_available_bits: 0, - io_word: 0, - io_next_word: 0, - io_now: 0, - io_end: 0, - rows_completed: 0, - }; - -QuicEncoder.prototype.reste = function(io_ptr) -{ - this.rgb_state.reste(); - - this.io_now = io_ptr; - this.io_end = this.io_now.length; - this.io_idx = 0; - this.rows_completed = 0; - return true; -} - -QuicEncoder.prototype.read_io_word = function() -{ - if (this.io_idx >= this.io_end) - throw("quic: out of data"); - this.io_next_word = this.io_now[this.io_idx++] | this.io_now[this.io_idx++]<<8 | this.io_now[this.io_idx++]<<16 | this.io_now[this.io_idx++]<<24; -} - -QuicEncoder.prototype.decode_eatbits = function (len) -{ - this.io_word = this.io_word << len; - - var delta = (this.io_available_bits - len); - if (delta >= 0) - { - this.io_available_bits = delta; - this.io_word |= this.io_next_word >>> this.io_available_bits; - } - else - { - delta = -1 * delta; - this.io_word |= this.io_next_word << delta; - this.read_io_word(); - this.io_available_bits = 32 - delta; - this.io_word |= this.io_next_word >>> this.io_available_bits; - } -} - -QuicEncoder.prototype.decode_eat32bits = function() -{ - this.decode_eatbits(16); - this.decode_eatbits(16); -} - -QuicEncoder.prototype.reste_channels = function(bpc) -{ - var i; - - for (i = 0; i < 4; i++) - if (!this.channels[i].reste(bpc)) - return false; - return true; -} - -QuicEncoder.prototype.quic_decode_begin = function(io_ptr) -{ - if (!this.reste(io_ptr)) { - return false; - } - - this.io_idx = 0; - this.io_next_word = this.io_now[this.io_idx++] | this.io_now[this.io_idx++]<<8 | this.io_now[this.io_idx++]<<16 | this.io_now[this.io_idx++]<<24; - this.io_word = this.io_next_word; - this.io_available_bits = 0; - - var magic = this.io_word; - this.decode_eat32bits(); - if (magic != 0x43495551) /*QUIC*/ { - console.log("quic: bad magic "+magic.toString(16)); - return false; - } - - var version = this.io_word; - this.decode_eat32bits(); - if (version != ((0 << 16) | (0 & 0xffff))) { - console.log("quic: bad version "+version.toString(16)); - return false; - } - - this.type = this.io_word; - this.decode_eat32bits(); - - this.width = this.io_word; - this.decode_eat32bits(); - - this.height = this.io_word; - this.decode_eat32bits(); - - var bpc = quic_image_bpc(this.type); - - if (!this.reste_channels(bpc)) - return false; - - return true; -} - -QuicEncoder.prototype.quic_rgb32_uncompress_row0_seg = function (i, cur_row, end, - waitmask, bpc, bpc_mask) -{ - var stopidx; - var n_channels = 3; - var c; - var a; - - if (!i) { - cur_row[rgb32_pixel_pad] = 0; - c = 0; - do - { - a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].bestcode, this.io_word); - this.channels[c].correlate_row.row[0] = a.rc; - cur_row[2-c] = (family_8bpc.xlatL2U[a.rc]&0xFF); - this.decode_eatbits(a.codewordlen); - } while (++c < n_channels); - - if (this.rgb_state.waitcnt) { - --this.rgb_state.waitcnt; - } else { - this.rgb_state.waitcnt = (this.rgb_state.tabrand() & waitmask); - c = 0; - do - { - this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[0], bpc); - } while (++c < n_channels); - } - stopidx = ++i + this.rgb_state.waitcnt; - } else { - stopidx = i + this.rgb_state.waitcnt; - } - - while (stopidx < end) { - for (; i <= stopidx; i++) { - cur_row[(i* rgb32_pixel_size)+rgb32_pixel_pad] = 0; - c = 0; - do - { - a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i - 1]].bestcode, this.io_word); - this.channels[c].correlate_row.row[i] = a.rc; - cur_row[(i* rgb32_pixel_size)+(2-c)] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1) * rgb32_pixel_size) + (2-c)]) & bpc_mask; - this.decode_eatbits(a.codewordlen); - } while (++c < n_channels); - } - c = 0; - do - { - this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[stopidx - 1]].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[stopidx], bpc); - } while (++c < n_channels); - stopidx = i + (this.rgb_state.tabrand() & waitmask); - } - - for (; i < end; i++) { - cur_row[(i* rgb32_pixel_size)+rgb32_pixel_pad] = 0; - c = 0; - do - { - a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i - 1]].bestcode, this.io_word); - this.channels[c].correlate_row.row[i] = a.rc; - cur_row[(i* rgb32_pixel_size)+(2-c)] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1) * rgb32_pixel_size) + (2-c)]) & bpc_mask; - this.decode_eatbits(a.codewordlen); - } while (++c < n_channels); - } - this.rgb_state.waitcnt = stopidx - end; -} - -QuicEncoder.prototype.quic_rgb32_uncompress_row0 = function (cur_row) -{ - var bpc = 8; - var bpc_mask = 0xff; - var pos = 0; - var width = this.width; - - while ((wmimax > this.rgb_state.wmidx) && (this.rgb_state.wmileft <= width)) { - if (this.rgb_state.wmileft) { - this.quic_rgb32_uncompress_row0_seg(pos, cur_row, - pos + this.rgb_state.wmileft, - bppmask[this.rgb_state.wmidx], - bpc, bpc_mask); - pos += this.rgb_state.wmileft; - width -= this.rgb_state.wmileft; - } - - this.rgb_state.wmidx++; - this.rgb_state.set_wm_trigger(); - this.rgb_state.wmileft = wminext; - } - - if (width) { - this.quic_rgb32_uncompress_row0_seg(pos, cur_row, pos + width, - bppmask[this.rgb_state.wmidx], bpc, bpc_mask); - if (wmimax > this.rgb_state.wmidx) { - this.rgb_state.wmileft -= width; - } - } -} - -QuicEncoder.prototype.quic_rgb32_uncompress_row_seg = function( prev_row, cur_row, i, end, bpc, bpc_mask) -{ - var n_channels = 3; - var waitmask = bppmask[this.rgb_state.wmidx]; - - var a; - var run_index = 0; - var stopidx = 0; - var run_end = 0; - var c; - - if (!i) - { - cur_row[rgb32_pixel_pad] = 0; - - c = 0; - do { - a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].bestcode, this.io_word); - this.channels[c].correlate_row.row[0] = a.rc; - cur_row[2-c] = (family_8bpc.xlatL2U[this.channels[c].correlate_row.row[0]] + prev_row[2-c]) & bpc_mask; - this.decode_eatbits(a.codewordlen); - } while (++c < n_channels); - - if (this.rgb_state.waitcnt) { - --this.rgb_state.waitcnt; - } else { - this.rgb_state.waitcnt = (this.rgb_state.tabrand() & waitmask); - c = 0; - do { - this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[0], bpc); - } while (++c < n_channels); - } - stopidx = ++i + this.rgb_state.waitcnt; - } else { - stopidx = i + this.rgb_state.waitcnt; - } - for (;;) { - var rc = 0; - while (stopidx < end && !rc) { - for (; i <= stopidx && !rc; i++) { - var pixel = i * rgb32_pixel_size; - var pixelm1 = (i-1) * rgb32_pixel_size; - var pixelm2 = (i-2) * rgb32_pixel_size; - - if ( prev_row[pixelm1+rgb32_pixel_r] == prev_row[pixel+rgb32_pixel_r] && prev_row[pixelm1+rgb32_pixel_g] == prev_row[pixel+rgb32_pixel_g] && prev_row[pixelm1 + rgb32_pixel_b] == prev_row[pixel+rgb32_pixel_b]) - { - if (run_index != i && i > 2 && (cur_row[pixelm1+rgb32_pixel_r] == cur_row[pixelm2+rgb32_pixel_r] && cur_row[pixelm1+rgb32_pixel_g] == cur_row[pixelm2+rgb32_pixel_g] && cur_row[pixelm1+rgb32_pixel_b] == cur_row[pixelm2+rgb32_pixel_b])) - { - /* do run */ - this.rgb_state.waitcnt = stopidx - i; - run_index = i; - run_end = i + this.decode_run(this.rgb_state); - - for (; i < run_end; i++) { - var pixel = i * rgb32_pixel_size; - var pixelm1 = (i-1) * rgb32_pixel_size; - cur_row[pixel+rgb32_pixel_pad] = 0; - cur_row[pixel+rgb32_pixel_r] = cur_row[pixelm1+rgb32_pixel_r]; - cur_row[pixel+rgb32_pixel_g] = cur_row[pixelm1+rgb32_pixel_g]; - cur_row[pixel+rgb32_pixel_b] = cur_row[pixelm1+rgb32_pixel_b]; - } - - if (i == end) { - return; - } - else - { - stopidx = i + this.rgb_state.waitcnt; - rc = 1; - break; - } - } - } - - c = 0; - cur_row[pixel+rgb32_pixel_pad] = 0; - do { - var cc = this.channels[c]; - var cr = cc.correlate_row; - - a = golomb_decoding_8bpc(cc.buckets_ptrs[cr.row[i-1]].bestcode, this.io_word); - cr.row[i] = a.rc; - cur_row[pixel+(2-c)] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+(2-c)] + prev_row[pixel+(2-c)]) >> 1)) & bpc_mask; - this.decode_eatbits(a.codewordlen); - } while (++c < n_channels); - } - if (rc) - break; - - c = 0; - do { - this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[stopidx - 1]].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[stopidx], bpc); - } while (++c < n_channels); - - stopidx = i + (this.rgb_state.tabrand() & waitmask); - } - - for (; i < end && !rc; i++) { - var pixel = i * rgb32_pixel_size; - var pixelm1 = (i-1) * rgb32_pixel_size; - var pixelm2 = (i-2) * rgb32_pixel_size; - - if (prev_row[pixelm1+rgb32_pixel_r] == prev_row[pixel+rgb32_pixel_r] && prev_row[pixelm1+rgb32_pixel_g] == prev_row[pixel+rgb32_pixel_g] && prev_row[pixelm1+rgb32_pixel_b] == prev_row[pixel+rgb32_pixel_b]) - { - if (run_index != i && i > 2 && (cur_row[pixelm1+rgb32_pixel_r] == cur_row[pixelm2+rgb32_pixel_r] && cur_row[pixelm1+rgb32_pixel_g] == cur_row[pixelm2+rgb32_pixel_g] && cur_row[pixelm1+rgb32_pixel_b] == cur_row[pixelm2+rgb32_pixel_b])) - { - /* do run */ - this.rgb_state.waitcnt = stopidx - i; - run_index = i; - run_end = i + this.decode_run(this.rgb_state); - - for (; i < run_end; i++) { - var pixel = i * rgb32_pixel_size; - var pixelm1 = (i-1) * rgb32_pixel_size; - cur_row[pixel+rgb32_pixel_pad] = 0; - cur_row[pixel+rgb32_pixel_r] = cur_row[pixelm1+rgb32_pixel_r]; - cur_row[pixel+rgb32_pixel_g] = cur_row[pixelm1+rgb32_pixel_g]; - cur_row[pixel+rgb32_pixel_b] = cur_row[pixelm1+rgb32_pixel_b]; - } - - if (i == end) { - return; - } - else - { - stopidx = i + this.rgb_state.waitcnt; - rc = 1; - break; - } - } - } - - cur_row[pixel+rgb32_pixel_pad] = 0; - c = 0; - do - { - a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i-1]].bestcode, this.io_word); - this.channels[c].correlate_row.row[i] = a.rc; - cur_row[pixel+(2-c)] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+(2-c)] + prev_row[pixel+(2-c)]) >> 1)) & bpc_mask; - this.decode_eatbits(a.codewordlen); - } while (++c < n_channels); - } - - if (!rc) - { - this.rgb_state.waitcnt = stopidx - end; - return; - } - } -} - -QuicEncoder.prototype.decode_run = function(state) -{ - var runlen = 0; - - do { - var hits; - var x = (~(this.io_word >>> 24)>>>0)&0xff; - var temp = zeroLUT[x]; - - for (hits = 1; hits <= temp; hits++) { - runlen += state.melcorder; - - if (state.melcstate < 32) { - state.melclen = J[++state.melcstate]; - state.melcorder = (1 << state.melclen); - } - } - if (temp != 8) { - this.decode_eatbits(temp + 1); - - break; - } - this.decode_eatbits(8); - } while (true); - - if (state.melclen) { - runlen += this.io_word >>> (32 - state.melclen); - this.decode_eatbits(state.melclen); - } - - if (state.melcstate) { - state.melclen = J[--state.melcstate]; - state.melcorder = (1 << state.melclen); - } - - return runlen; -} - -QuicEncoder.prototype.quic_rgb32_uncompress_row = function (prev_row, cur_row) -{ - var bpc = 8; - var bpc_mask = 0xff; - var pos = 0; - var width = this.width; - - while ((wmimax > this.rgb_state.wmidx) && (this.rgb_state.wmileft <= width)) { - if (this.rgb_state.wmileft) { - this.quic_rgb32_uncompress_row_seg(prev_row, cur_row, pos, - pos + this.rgb_state.wmileft, bpc, bpc_mask); - pos += this.rgb_state.wmileft; - width -= this.rgb_state.wmileft; - } - - this.rgb_state.wmidx++; - this.rgb_state.set_wm_trigger(); - this.rgb_state.wmileft = wminext; - } - - if (width) { - this.quic_rgb32_uncompress_row_seg(prev_row, cur_row, pos, - pos + width, bpc, bpc_mask); - if (wmimax > this.rgb_state.wmidx) { - this.rgb_state.wmileft -= width; - } - } -} - -QuicEncoder.prototype.quic_four_uncompress_row0_seg = function (channel, i, - correlate_row, cur_row, end, waitmask, - bpc, bpc_mask) -{ - var stopidx; - var a; - - if (i == 0) { - a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.zero].bestcode, this.io_word); - correlate_row.row[0] = a.rc; - cur_row[rgb32_pixel_pad] = family_8bpc.xlatL2U[a.rc]; - this.decode_eatbits(a.codewordlen); - - if (channel.state.waitcnt) { - --channel.state.waitcnt; - } else { - channel.state.waitcnt = (channel.state.tabrand() & waitmask); - channel.buckets_ptrs[correlate_row.zero].update_model_8bpc(channel.state, correlate_row.row[0], bpc); - } - stopidx = ++i + channel.state.waitcnt; - } else { - stopidx = i + channel.state.waitcnt; - } - - while (stopidx < end) { - var pbucket; - - for (; i <= stopidx; i++) { - pbucket = channel.buckets_ptrs[correlate_row.row[i - 1]]; - - a = golomb_decoding_8bpc(pbucket.bestcode, this.io_word); - correlate_row.row[i] = a.rc; - cur_row[(i*rgb32_pixel_size)+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1)*rgb32_pixel_size)+rgb32_pixel_pad]) & bpc_mask; - this.decode_eatbits(a.codewordlen); - } - - pbucket.update_model_8bpc(channel.state, correlate_row.row[stopidx], bpc); - - stopidx = i + (channel.state.tabrand() & waitmask); - } - - for (; i < end; i++) { - a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.row[i-1]].bestcode, this.io_word); - - correlate_row.row[i] = a.rc; - cur_row[(i*rgb32_pixel_size)+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1)*rgb32_pixel_size)+rgb32_pixel_pad]) & bpc_mask; - this.decode_eatbits(a.codewordlen); - } - channel.state.waitcnt = stopidx - end; -} - -QuicEncoder.prototype.quic_four_uncompress_row0 = function(channel, cur_row) -{ - var bpc = 8; - var bpc_mask = 0xff; - var correlate_row = channel.correlate_row; - var pos = 0; - var width = this.width; - - while ((wmimax > channel.state.wmidx) && (channel.state.wmileft <= width)) { - if (channel.state.wmileft) { - this.quic_four_uncompress_row0_seg(channel, pos, correlate_row, cur_row, - pos + channel.state.wmileft, bppmask[channel.state.wmidx], - bpc, bpc_mask); - pos += channel.state.wmileft; - width -= channel.state.wmileft; - } - - channel.state.wmidx++; - channel.state.set_wm_trigger(); - channel.state.wmileft = wminext; - } - - if (width) { - this.quic_four_uncompress_row0_seg(channel, pos, correlate_row, cur_row, pos + width, - bppmask[channel.state.wmidx], bpc, bpc_mask); - if (wmimax > channel.state.wmidx) { - channel.state.wmileft -= width; - } - } -} - -QuicEncoder.prototype.quic_four_uncompress_row_seg = function (channel, - correlate_row, prev_row, cur_row, i, - end, bpc, bpc_mask) -{ - var waitmask = bppmask[channel.state.wmidx]; - var stopidx; - - var run_index = 0; - var run_end; - - var a; - - if (i == 0) { - a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.zero].bestcode, this.io_word); - - correlate_row.row[0] = a.rc - cur_row[rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + prev_row[rgb32_pixel_pad]) & bpc_mask; - this.decode_eatbits(a.codewordlen); - - if (channel.state.waitcnt) { - --channel.state.waitcnt; - } else { - channel.state.waitcnt = (channel.state.tabrand() & waitmask); - channel.buckets_ptrs[correlate_row.zero].update_model_8bpc(channel.state, correlate_row.row[0], bpc); - } - stopidx = ++i + channel.state.waitcnt; - } else { - stopidx = i + channel.state.waitcnt; - } - for (;;) { - var rc = 0; - while (stopidx < end && !rc) { - var pbucket; - for (; i <= stopidx && !rc; i++) { - var pixel = i * rgb32_pixel_size; - var pixelm1 = (i-1) * rgb32_pixel_size; - var pixelm2 = (i-2) * rgb32_pixel_size; - - if (prev_row[pixelm1+rgb32_pixel_pad] == prev_row[pixel+rgb32_pixel_pad]) - { - if (run_index != i && i > 2 && cur_row[pixelm1+rgb32_pixel_pad] == cur_row[pixelm2+rgb32_pixel_pad]) - { - /* do run */ - channel.state.waitcnt = stopidx - i; - run_index = i; - - run_end = i + this.decode_run(channel.state); - - for (; i < run_end; i++) { - var pixel = i * rgb32_pixel_size; - var pixelm1 = (i-1) * rgb32_pixel_size; - cur_row[pixel+rgb32_pixel_pad] = cur_row[pixelm1+rgb32_pixel_pad]; - } - - if (i == end) { - return; - } - else - { - stopidx = i + channel.state.waitcnt; - rc = 1; - break; - } - } - } - - pbucket = channel.buckets_ptrs[correlate_row.row[i - 1]]; - a = golomb_decoding_8bpc(pbucket.bestcode, this.io_word); - correlate_row.row[i] = a.rc - cur_row[pixel+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+rgb32_pixel_pad] + prev_row[pixel+rgb32_pixel_pad]) >> 1)) & bpc_mask; - this.decode_eatbits(a.codewordlen); - } - if (rc) - break; - - pbucket.update_model_8bpc(channel.state, correlate_row.row[stopidx], bpc); - - stopidx = i + (channel.state.tabrand() & waitmask); - } - - for (; i < end && !rc; i++) { - var pixel = i * rgb32_pixel_size; - var pixelm1 = (i-1) * rgb32_pixel_size; - var pixelm2 = (i-2) * rgb32_pixel_size; - if (prev_row[pixelm1+rgb32_pixel_pad] == prev_row[pixel+rgb32_pixel_pad]) - { - if (run_index != i && i > 2 && cur_row[pixelm1+rgb32_pixel_pad] == cur_row[pixelm2+rgb32_pixel_pad]) - { - /* do run */ - channel.state.waitcnt = stopidx - i; - run_index = i; - - run_end = i + this.decode_run(channel.state); - - for (; i < run_end; i++) { - var pixel = i * rgb32_pixel_size; - var pixelm1 = (i-1) * rgb32_pixel_size; - cur_row[pixel+rgb32_pixel_pad] = cur_row[pixelm1+rgb32_pixel_pad]; - } - - if (i == end) { - return; - } - else - { - stopidx = i + channel.state.waitcnt; - rc = 1; - break; - } - } - } - - a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.row[i-1]].bestcode, this.io_word); - correlate_row.row[i] = a.rc; - cur_row[pixel+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+rgb32_pixel_pad] + prev_row[pixel+rgb32_pixel_pad]) >> 1)) & bpc_mask; - this.decode_eatbits(a.codewordlen); - } - - if (!rc) - { - channel.state.waitcnt = stopidx - end; - return; - } - } -} - -QuicEncoder.prototype.quic_four_uncompress_row = function(channel, prev_row, - cur_row) -{ - var bpc = 8; - var bpc_mask = 0xff; - var correlate_row = channel.correlate_row; - var pos = 0; - var width = this.width; - - while ((wmimax > channel.state.wmidx) && (channel.state.wmileft <= width)) { - if (channel.state.wmileft) { - this.quic_four_uncompress_row_seg(channel, correlate_row, prev_row, cur_row, pos, - pos + channel.state.wmileft, bpc, bpc_mask); - pos += channel.state.wmileft; - width -= channel.state.wmileft; - } - - channel.state.wmidx++; - channel.state.set_wm_trigger(); - channel.state.wmileft = wminext; - } - - if (width) { - this.quic_four_uncompress_row_seg(channel, correlate_row, prev_row, cur_row, pos, - pos + width, bpc, bpc_mask); - if (wmimax > channel.state.wmidx) { - channel.state.wmileft -= width; - } - } -} - -/* We need to be generating rgb32 or rgba */ -QuicEncoder.prototype.quic_decode = function(buf, stride) -{ - var row; - - switch (this.type) - { - case QUIC_IMAGE_TYPE_RGB32: - case QUIC_IMAGE_TYPE_RGB24: - this.channels[0].correlate_row.zero = 0; - this.channels[1].correlate_row.zero = 0; - this.channels[2].correlate_row.zero = 0; - this.quic_rgb32_uncompress_row0(buf); - - this.rows_completed++; - for (row = 1; row < this.height; row++) - { - var prev = buf; - buf = prev.subarray(stride); - this.channels[0].correlate_row.zero = this.channels[0].correlate_row.row[0]; - this.channels[1].correlate_row.zero = this.channels[1].correlate_row.row[0]; - this.channels[2].correlate_row.zero = this.channels[2].correlate_row.row[0]; - this.quic_rgb32_uncompress_row(prev, buf); - this.rows_completed++; - }; - break; - case QUIC_IMAGE_TYPE_RGB16: - console.log("quic: unsupported output format\n"); - return false; - break; - case QUIC_IMAGE_TYPE_RGBA: - this.channels[0].correlate_row.zero = 0; - this.channels[1].correlate_row.zero = 0; - this.channels[2].correlate_row.zero = 0; - this.quic_rgb32_uncompress_row0(buf); - - this.channels[3].correlate_row.zero = 0; - this.quic_four_uncompress_row0(this.channels[3], buf); - - this.rows_completed++; - for (row = 1; row < this.height; row++) { - var prev = buf; - buf = prev.subarray(stride); - - this.channels[0].correlate_row.zero = this.channels[0].correlate_row.row[0]; - this.channels[1].correlate_row.zero = this.channels[1].correlate_row.row[0]; - this.channels[2].correlate_row.zero = this.channels[2].correlate_row.row[0]; - this.quic_rgb32_uncompress_row(prev, buf); - - this.channels[3].correlate_row.zero = this.channels[3].correlate_row.row[0]; - this.quic_four_uncompress_row(encoder.channels[3], prev, buf); - this.rows_completed++; - } - break; - - case QUIC_IMAGE_TYPE_GRAY: - console.log("quic: unsupported output format\n"); - return false; - break; - - case QUIC_IMAGE_TYPE_INVALID: - default: - console.log("quic: bad image type\n"); - return false; - } - return true; -} - -QuicEncoder.prototype.simple_quic_decode = function(buf) -{ - var stride = 4; /* FIXME - proper stride calc please */ - if (!this.quic_decode_begin(buf)) - return undefined; - if (this.type != QUIC_IMAGE_TYPE_RGB32 && this.type != QUIC_IMAGE_TYPE_RGB24 - && this.type != QUIC_IMAGE_TYPE_RGBA) - return undefined; - var out = new Uint8Array(this.width*this.height*4); - out[0] = 69; - if (this.quic_decode( out, (this.width * stride))) - return out; - return undefined; -} - -function SpiceQuic() -{ -} - -SpiceQuic.prototype = -{ - from_dv: function(dv, at, mb) - { - if (!encoder) - throw("quic: no quic encoder"); - this.data_size = dv.getUint32(at, true); - at += 4; - var buf = new Uint8Array(mb.slice(at)); - this.outptr = encoder.simple_quic_decode(buf); - if (this.outptr) - { - this.type = encoder.type; - this.width = encoder.width; - this.height = encoder.height; - } - at += buf.length; - return at; - }, -} - -function convert_spice_quic_to_web(context, spice_quic) -{ - var ret = context.createImageData(spice_quic.width, spice_quic.height); - var i; - for (i = 0; i < (ret.width * ret.height * 4); i+=4) - { - ret.data[i + 0] = spice_quic.outptr[i + 2]; - ret.data[i + 1] = spice_quic.outptr[i + 1]; - ret.data[i + 2] = spice_quic.outptr[i + 0]; - if (spice_quic.type !== QUIC_IMAGE_TYPE_RGBA) - ret.data[i + 3] = 255; - else - ret.data[i + 3] = 255 - spice_quic.outptr[i + 3]; - } - return ret; -} - -/* Module initialization */ -if (need_init) -{ - need_init = false; - - family_init(family_8bpc, 8, DEFmaxclen); - family_init(family_5bpc, 5, DEFmaxclen); - /* init_zeroLUT */ - var i, j, k, l; - - j = k = 1; - l = 8; - for (i = 0; i < 256; ++i) { - zeroLUT[i] = l; - --k; - if (k == 0) { - k = j; - --l; - j *= 2; - } - } - - encoder = new QuicEncoder; - - if (!encoder) - throw("quic: failed to create encoder"); -} diff --git a/plugins/kimchi/ui/spice-html5/resize.js b/plugins/kimchi/ui/spice-html5/resize.js deleted file mode 100644 index f5410d3..0000000 --- a/plugins/kimchi/ui/spice-html5/resize.js +++ /dev/null @@ -1,70 +0,0 @@ -"use strict"; -/* - Copyright (C) 2014 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** resize.js -** This bit of Javascript is a set of logic to help with window -** resizing, using the agent channel to request screen resizes. -** -** It's a bit tricky, as we want to wait for resizing to settle down -** before sending a size. Further, while horizontal resizing to use the whole -** browser width is fairly easy to arrange with css, resizing an element to use -** the whole vertical space (or to force a middle div to consume the bulk of the browser -** window size) is tricky, and the consensus seems to be that Javascript is -** the only right way to do it. -**--------------------------------------------------------------------------*/ -function resize_helper(sc) -{ - var w = document.getElementById(sc.screen_id).clientWidth; - var h = document.getElementById(sc.screen_id).clientHeight; - - var m = document.getElementById(sc.message_id); - - /* Resize vertically; basically we leave a 20 pixel margin - at the bottom, and use the position of the message window - to figure out how to resize */ - var hd = window.innerHeight - m.offsetHeight - m.offsetTop - 20; - - /* Xorg requires height be a multiple of 8; round up */ - h = h + hd; - if (h % 8 > 0) - h += (8 - (h % 8)); - - /* Xorg requires width be a multiple of 8; round up */ - if (w % 8 > 0) - w += (8 - (w % 8)); - - - sc.resize_window(0, w, h, 32, 0, 0); - sc.spice_resize_timer = undefined; -} - -function handle_resize(e) -{ - var sc = window.spice_connection; - - if (sc && sc.spice_resize_timer) - { - window.clearTimeout(sc.spice_resize_timer); - sc.spice_resize_timer = undefined; - } - - sc.spice_resize_timer = window.setTimeout(resize_helper, 200, sc); -} diff --git a/plugins/kimchi/ui/spice-html5/simulatecursor.js b/plugins/kimchi/ui/spice-html5/simulatecursor.js deleted file mode 100644 index b1fce06..0000000 --- a/plugins/kimchi/ui/spice-html5/simulatecursor.js +++ /dev/null @@ -1,202 +0,0 @@ -"use strict"; -/* - Copyright (C) 2013 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** SpiceSimulateCursor -** Internet Explorer 10 does not support data uri's in cursor assignment. -** This file provides a number of gimmicks to compensate. First, if there -** is a preloaded cursor available, we will use that. Failing that, we will -** simulate a cursor using an image that is moved around the screen. -**--------------------------------------------------------------------------*/ -var SpiceSimulateCursor = { - -cursors : new Array(), -unknown_cursors : new Array(), -warned: false, - -add_cursor: function(sha1, value) -{ - SpiceSimulateCursor.cursors[sha1] = value; -}, - -unknown_cursor: function(sha1, curdata) -{ - if (! SpiceSimulateCursor.warned) - { - SpiceSimulateCursor.warned = true; - alert("Internet Explorer does not support dynamic cursors. " + - "This page will now simulate cursors with images, " + - "which will be imperfect. We recommend using Chrome or Firefox instead. " + - "\n\nIf you need to use Internet Explorer, you can create a static cursor " + - "file for each cursor your application uses. " + - "View the console log for more information on creating static cursors for your environment."); - } - - if (! SpiceSimulateCursor.unknown_cursors[sha1]) - { - SpiceSimulateCursor.unknown_cursors[sha1] = curdata; - console.log('Unknown cursor. Simulation required. To avoid simulation for this cursor, create and include a custom javascript file, and add the following line:'); - console.log('SpiceCursorSimulator.add_cursor("' + sha1 + '"), "<your filename here>.cur");'); - console.log('And then run following command, redirecting output into <your filename here>.cur:'); - console.log('php -r "echo urldecode(\'' + curdata + '\');"'); - } -}, - -simulate_cursor: function (spicecursor, cursor, screen, pngstr) -{ - var cursor_sha = hex_sha1(pngstr + ' ' + cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y); - if (typeof SpiceSimulateCursor.cursors != 'undefined') - if (typeof SpiceSimulateCursor.cursors[cursor_sha] != 'undefined') - { - var curstr = 'url(' + SpiceSimulateCursor.cursors[cursor_sha] + '), default'; - screen.style.cursor = curstr; - } - - if (window.getComputedStyle(screen, null).cursor == 'auto') - { - SpiceSimulateCursor.unknown_cursor(cursor_sha, - SpiceSimulateCursor.create_icondir(cursor.header.width, cursor.header.height, - cursor.data.byteLength, cursor.header.hot_spot_x, cursor.header.hot_spot_y) + pngstr); - - document.getElementById(spicecursor.parent.screen_id).style.cursor = 'none'; - if (! spicecursor.spice_simulated_cursor) - { - spicecursor.spice_simulated_cursor = document.createElement('img'); - - spicecursor.spice_simulated_cursor.style.position = 'absolute'; - spicecursor.spice_simulated_cursor.style.display = 'none'; - spicecursor.spice_simulated_cursor.style.overflow = 'hidden'; - - spicecursor.spice_simulated_cursor.spice_screen = document.getElementById(spicecursor.parent.screen_id); - - spicecursor.spice_simulated_cursor.addEventListener('mousemove', SpiceSimulateCursor.handle_sim_mousemove); - - spicecursor.spice_simulated_cursor.spice_screen.appendChild(spicecursor.spice_simulated_cursor); - } - - spicecursor.spice_simulated_cursor.src = 'data:image/png,' + pngstr; - - spicecursor.spice_simulated_cursor.spice_hot_x = cursor.header.hot_spot_x; - spicecursor.spice_simulated_cursor.spice_hot_y = cursor.header.hot_spot_y; - - spicecursor.spice_simulated_cursor.style.pointerEvents = "none"; - } - else - { - if (spicecursor.spice_simulated_cursor) - { - spicecursor.spice_simulated_cursor.spice_screen.removeChild(spicecursor.spice_simulated_cursor); - delete spicecursor.spice_simulated_cursor; - } - } -}, - -handle_sim_mousemove: function(e) -{ - var retval; - var f = SpiceSimulateCursor.duplicate_mouse_event(e, this.spice_screen); - return this.spice_screen.dispatchEvent(f); -}, - -duplicate_mouse_event: function(e, target) -{ - var evt = document.createEvent("mouseevent"); - evt.initMouseEvent(e.type, true, true, e.view, e.detail, - e.screenX, e.screenY, e.clientX, e.clientY, - e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget); - return evt; -}, - -ICONDIR: function () -{ -}, - -ICONDIRENTRY: function(width, height, bytes, hot_x, hot_y) -{ - this.width = width; - this.height = height; - this.bytes = bytes; - this.hot_x = hot_x; - this.hot_y = hot_y; -}, - - -create_icondir: function (width, height, bytes, hot_x, hot_y) -{ - var i; - var header = new SpiceSimulateCursor.ICONDIR(); - var entry = new SpiceSimulateCursor.ICONDIRENTRY(width, height, bytes, hot_x, hot_y); - - var mb = new ArrayBuffer(header.buffer_size() + entry.buffer_size()); - var at = header.to_buffer(mb); - at = entry.to_buffer(mb, at); - - var u8 = new Uint8Array(mb); - var str = ""; - for (i = 0; i < at; i++) - { - str += "%"; - if (u8[i] < 16) - str += "0"; - str += u8[i].toString(16); - } - return str; -}, - -}; - -SpiceSimulateCursor.ICONDIR.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint16(at, 0, true); at += 2; - dv.setUint16(at, 2, true); at += 2; - dv.setUint16(at, 1, true); at += 2; - return at; - }, - buffer_size: function() - { - return 6; - } -}; - -SpiceSimulateCursor.ICONDIRENTRY.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint8(at, this.width); at++; - dv.setUint8(at, this.height); at++; - dv.setUint8(at, 0); at++; /* color palette count, unused */ - dv.setUint8(at, 0); at++; /* reserved */ - dv.setUint16(at, this.hot_x, true); at += 2; - dv.setUint16(at, this.hot_y, true); at += 2; - dv.setUint32(at, this.bytes, true); at += 4; - dv.setUint32(at, at + 4, true); at += 4; /* Offset to bytes */ - return at; - }, - buffer_size: function() - { - return 16; - } -}; diff --git a/plugins/kimchi/ui/spice-html5/spicearraybuffer.js b/plugins/kimchi/ui/spice-html5/spicearraybuffer.js deleted file mode 100644 index 228bce6..0000000 --- a/plugins/kimchi/ui/spice-html5/spicearraybuffer.js +++ /dev/null @@ -1,58 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** SpiceArrayBufferSlice -** This function is a work around for IE 10, which has no slice() -** method in it's subclass. -**--------------------------------------------------------------------------*/ -function SpiceArrayBufferSlice(start, end) -{ - start = start || 0; - end = end || this.byteLength; - if (end < 0) - end = this.byteLength + end; - if (start < 0) - start = this.byteLength + start; - if (start < 0) - start = 0; - if (end < 0) - end = 0; - if (end > this.byteLength) - end = this.byteLength; - if (start > end) - start = end; - - var ret = new ArrayBuffer(end - start); - var in1 = new Uint8Array(this, start, end - start); - var out = new Uint8Array(ret); - var i; - - for (i = 0; i < end - start; i++) - out[i] = in1[i]; - - return ret; -} - -if (! ArrayBuffer.prototype.slice) -{ - ArrayBuffer.prototype.slice = SpiceArrayBufferSlice; - console.log("WARNING: ArrayBuffer.slice() is missing; we are extending ArrayBuffer to compensate"); -} diff --git a/plugins/kimchi/ui/spice-html5/spiceconn.js b/plugins/kimchi/ui/spice-html5/spiceconn.js deleted file mode 100644 index e33227e..0000000 --- a/plugins/kimchi/ui/spice-html5/spiceconn.js +++ /dev/null @@ -1,460 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** SpiceConn -** This is the base Javascript class for establishing and -** managing a connection to a Spice Server. -** It is used to provide core functionality to the Spice main, -** display, inputs, and cursor channels. See main.js for -** usage. -**--------------------------------------------------------------------------*/ -function SpiceConn(o) -{ - if (o === undefined || o.uri === undefined || ! o.uri) - throw new Error("You must specify a uri"); - - this.ws = new WebSocket(o.uri, 'binary'); - - if (! this.ws.binaryType) - throw new Error("WebSocket doesn't support binaryType. Try a different browser."); - - this.connection_id = o.connection_id !== undefined ? o.connection_id : 0; - this.type = o.type !== undefined ? o.type : SPICE_CHANNEL_MAIN; - this.chan_id = o.chan_id !== undefined ? o.chan_id : 0; - if (o.parent !== undefined) - { - this.parent = o.parent; - this.message_id = o.parent.message_id; - this.password = o.parent.password; - } - if (o.screen_id !== undefined) - this.screen_id = o.screen_id; - if (o.dump_id !== undefined) - this.dump_id = o.dump_id; - if (o.message_id !== undefined) - this.message_id = o.message_id; - if (o.password !== undefined) - this.password = o.password; - if (o.onerror !== undefined) - this.onerror = o.onerror; - if (o.onsuccess !== undefined) - this.onsuccess = o.onsuccess; - if (o.onagent !== undefined) - this.onagent = o.onagent; - - this.state = "connecting"; - this.ws.parent = this; - this.wire_reader = new SpiceWireReader(this, this.process_inbound); - this.messages_sent = 0; - this.warnings = []; - - this.ws.addEventListener('open', function(e) { - DEBUG > 0 && console.log(">> WebSockets.onopen"); - DEBUG > 0 && console.log("id " + this.parent.connection_id +"; type " + this.parent.type); - - /*********************************************************************** - ** WHERE IT ALL REALLY BEGINS - ***********************************************************************/ - this.parent.send_hdr(); - this.parent.wire_reader.request(SpiceLinkHeader.prototype.buffer_size()); - this.parent.state = "start"; - }); - this.ws.addEventListener('error', function(e) { - this.parent.log_err(">> WebSockets.onerror" + e.toString()); - this.parent.report_error(e); - }); - this.ws.addEventListener('close', function(e) { - DEBUG > 0 && console.log(">> WebSockets.onclose"); - DEBUG > 0 && console.log("id " + this.parent.connection_id +"; type " + this.parent.type); - DEBUG > 0 && console.log(e); - if (this.parent.state != "closing" && this.parent.state != "error" && this.parent.onerror !== undefined) - { - var e; - if (this.parent.state == "connecting") - e = new Error("Connection refused."); - else if (this.parent.state == "start" || this.parent.state == "link") - e = new Error("Unexpected protocol mismatch."); - else if (this.parent.state == "ticket") - e = new Error("Bad password."); - else - e = new Error("Unexpected close while " + this.parent.state); - - this.parent.onerror(e); - this.parent.log_err(e.toString()); - } - }); - - if (this.ws.readyState == 2 || this.ws.readyState == 3) - throw new Error("Unable to connect to " + o.uri); - - this.timeout = window.setTimeout(spiceconn_timeout, SPICE_CONNECT_TIMEOUT, this); -} - -SpiceConn.prototype = -{ - send_hdr : function () - { - var hdr = new SpiceLinkHeader; - var msg = new SpiceLinkMess; - - msg.connection_id = this.connection_id; - msg.channel_type = this.type; - // FIXME - we're not setting a channel_id... - msg.common_caps.push( - (1 << SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION) | - (1 << SPICE_COMMON_CAP_MINI_HEADER) - ); - - if (msg.channel_type == SPICE_CHANNEL_PLAYBACK) - msg.channel_caps.push( - (1 << SPICE_PLAYBACK_CAP_OPUS) - ); - - hdr.size = msg.buffer_size(); - - var mb = new ArrayBuffer(hdr.buffer_size() + msg.buffer_size()); - hdr.to_buffer(mb); - msg.to_buffer(mb, hdr.buffer_size()); - - DEBUG > 1 && console.log("Sending header:"); - DEBUG > 2 && hexdump_buffer(mb); - this.ws.send(mb); - }, - - send_ticket: function(ticket) - { - var hdr = new SpiceLinkAuthTicket(); - hdr.auth_mechanism = SPICE_COMMON_CAP_AUTH_SPICE; - // FIXME - we need to implement RSA to make this work right - hdr.encrypted_data = ticket; - var mb = new ArrayBuffer(hdr.buffer_size()); - - hdr.to_buffer(mb); - DEBUG > 1 && console.log("Sending ticket:"); - DEBUG > 2 && hexdump_buffer(mb); - this.ws.send(mb); - }, - - send_msg: function(msg) - { - var mb = new ArrayBuffer(msg.buffer_size()); - msg.to_buffer(mb); - this.messages_sent++; - DEBUG > 0 && console.log(">> hdr " + this.channel_type() + " type " + msg.type + " size " + mb.byteLength); - DEBUG > 2 && hexdump_buffer(mb); - this.ws.send(mb); - }, - - process_inbound: function(mb, saved_header) - { - DEBUG > 2 && console.log(this.type + ": processing message of size " + mb.byteLength + "; state is " + this.state); - if (this.state == "ready") - { - if (saved_header == undefined) - { - var msg = new SpiceMiniData(mb); - - if (msg.type > 500) - { - alert("Something has gone very wrong; we think we have message of type " + msg.type); - debugger; - } - - if (msg.size == 0) - { - this.process_message(msg); - this.wire_reader.request(SpiceMiniData.prototype.buffer_size()); - } - else - { - this.wire_reader.request(msg.size); - this.wire_reader.save_header(msg); - } - } - else - { - saved_header.data = mb; - this.process_message(saved_header); - this.wire_reader.request(SpiceMiniData.prototype.buffer_size()); - this.wire_reader.save_header(undefined); - } - } - - else if (this.state == "start") - { - this.reply_hdr = new SpiceLinkHeader(mb); - if (this.reply_hdr.magic != SPICE_MAGIC) - { - this.state = "error"; - var e = new Error('Error: magic mismatch: ' + this.reply_hdr.magic); - this.report_error(e); - } - else - { - // FIXME - Determine major/minor version requirements - this.wire_reader.request(this.reply_hdr.size); - this.state = "link"; - } - } - - else if (this.state == "link") - { - this.reply_link = new SpiceLinkReply(mb); - // FIXME - Screen the caps - require minihdr at least, right? - if (this.reply_link.error) - { - this.state = "error"; - var e = new Error('Error: reply link error ' + this.reply_link.error); - this.report_error(e); - } - else - { - this.send_ticket(rsa_encrypt(this.reply_link.pub_key, this.password + String.fromCharCode(0))); - this.state = "ticket"; - this.wire_reader.request(SpiceLinkAuthReply.prototype.buffer_size()); - } - } - - else if (this.state == "ticket") - { - this.auth_reply = new SpiceLinkAuthReply(mb); - if (this.auth_reply.auth_code == SPICE_LINK_ERR_OK) - { - DEBUG > 0 && console.log(this.type + ': Connected'); - - if (this.type == SPICE_CHANNEL_DISPLAY) - { - // FIXME - pixmap and glz dictionary config info? - var dinit = new SpiceMsgcDisplayInit(); - var reply = new SpiceMiniData(); - reply.build_msg(SPICE_MSGC_DISPLAY_INIT, dinit); - DEBUG > 0 && console.log("Request display init"); - this.send_msg(reply); - } - this.state = "ready"; - this.wire_reader.request(SpiceMiniData.prototype.buffer_size()); - if (this.timeout) - { - window.clearTimeout(this.timeout); - delete this.timeout; - } - } - else - { - this.state = "error"; - if (this.auth_reply.auth_code == SPICE_LINK_ERR_PERMISSION_DENIED) - { - var e = new Error("Permission denied."); - } - else - { - var e = new Error("Unexpected link error " + this.auth_reply.auth_code); - } - this.report_error(e); - } - } - }, - - process_common_messages : function(msg) - { - if (msg.type == SPICE_MSG_SET_ACK) - { - var ack = new SpiceMsgSetAck(msg.data); - // FIXME - what to do with generation? - this.ack_window = ack.window; - DEBUG > 1 && console.log(this.type + ": set ack to " + ack.window); - this.msgs_until_ack = this.ack_window; - var ackack = new SpiceMsgcAckSync(ack); - var reply = new SpiceMiniData(); - reply.build_msg(SPICE_MSGC_ACK_SYNC, ackack); - this.send_msg(reply); - return true; - } - - if (msg.type == SPICE_MSG_PING) - { - DEBUG > 1 && console.log("ping!"); - var pong = new SpiceMiniData; - pong.type = SPICE_MSGC_PONG; - if (msg.data) - { - pong.data = msg.data.slice(0, 12); - } - pong.size = pong.buffer_size(); - this.send_msg(pong); - return true; - } - - if (msg.type == SPICE_MSG_NOTIFY) - { - // FIXME - Visibility + what - var notify = new SpiceMsgNotify(msg.data); - if (notify.severity == SPICE_NOTIFY_SEVERITY_ERROR) - this.log_err(notify.message); - else if (notify.severity == SPICE_NOTIFY_SEVERITY_WARN ) - this.log_warn(notify.message); - else - this.log_info(notify.message); - return true; - } - - return false; - - }, - - process_message: function(msg) - { - var rc; - DEBUG > 0 && console.log("<< hdr " + this.channel_type() + " type " + msg.type + " size " + (msg.data && msg.data.byteLength)); - rc = this.process_common_messages(msg); - if (! rc) - { - if (this.process_channel_message) - { - rc = this.process_channel_message(msg); - if (! rc) - this.log_warn(this.type + ": Unknown message type " + msg.type + "!"); - } - else - this.log_err(this.type + ": No message handlers for this channel; message " + msg.type); - } - - if (this.msgs_until_ack !== undefined && this.ack_window) - { - this.msgs_until_ack--; - if (this.msgs_until_ack <= 0) - { - this.msgs_until_ack = this.ack_window; - var ack = new SpiceMiniData(); - ack.type = SPICE_MSGC_ACK; - this.send_msg(ack); - DEBUG > 1 && console.log(this.type + ": sent ack"); - } - } - - return rc; - }, - - channel_type: function() - { - if (this.type == SPICE_CHANNEL_MAIN) - return "main"; - else if (this.type == SPICE_CHANNEL_DISPLAY) - return "display"; - else if (this.type == SPICE_CHANNEL_INPUTS) - return "inputs"; - else if (this.type == SPICE_CHANNEL_CURSOR) - return "cursor"; - return "unknown-" + this.type; - - }, - - log_info: function() - { - var msg = Array.prototype.join.call(arguments, " "); - console.log(msg); - if (this.message_id) - { - var p = document.createElement("p"); - p.appendChild(document.createTextNode(msg)); - p.className += "spice-message-info"; - document.getElementById(this.message_id).appendChild(p); - } - }, - - log_warn: function() - { - var msg = Array.prototype.join.call(arguments, " "); - console.log("WARNING: " + msg); - if (this.message_id) - { - var p = document.createElement("p"); - p.appendChild(document.createTextNode(msg)); - p.className += "spice-message-warning"; - document.getElementById(this.message_id).appendChild(p); - } - }, - - log_err: function() - { - var msg = Array.prototype.join.call(arguments, " "); - console.log("ERROR: " + msg); - if (this.message_id) - { - var p = document.createElement("p"); - p.appendChild(document.createTextNode(msg)); - p.className += "spice-message-error"; - document.getElementById(this.message_id).appendChild(p); - } - }, - - known_unimplemented: function(type, msg) - { - if ( (!this.warnings[type]) || DEBUG > 1) - { - var str = ""; - if (DEBUG <= 1) - str = " [ further notices suppressed ]"; - this.log_warn("Unimplemented function " + type + "(" + msg + ")" + str); - this.warnings[type] = true; - } - }, - - report_error: function(e) - { - this.log_err(e.toString()); - if (this.onerror != undefined) - this.onerror(e); - else - throw(e); - }, - - report_success: function(m) - { - if (this.onsuccess != undefined) - this.onsuccess(m); - }, - - cleanup: function() - { - if (this.timeout) - { - window.clearTimeout(this.timeout); - delete this.timeout; - } - if (this.ws) - { - this.ws.close(); - this.ws = undefined; - } - }, - - handle_timeout: function() - { - var e = new Error("Connection timed out."); - this.report_error(e); - }, -} - -function spiceconn_timeout(sc) -{ - SpiceConn.prototype.handle_timeout.call(sc); -} diff --git a/plugins/kimchi/ui/spice-html5/spicedataview.js b/plugins/kimchi/ui/spice-html5/spicedataview.js deleted file mode 100644 index 800df03..0000000 --- a/plugins/kimchi/ui/spice-html5/spicedataview.js +++ /dev/null @@ -1,120 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** SpiceDataView -** FIXME FIXME -** This is used because Firefox does not have DataView yet. -** We should use DataView if we have it, because it *has* to -** be faster than this code -**--------------------------------------------------------------------------*/ -function SpiceDataView(buffer, byteOffset, byteLength) -{ - if (byteOffset !== undefined) - { - if (byteLength !== undefined) - this.u8 = new Uint8Array(buffer, byteOffset, byteLength); - else - this.u8 = new Uint8Array(buffer, byteOffset); - } - else - this.u8 = new Uint8Array(buffer); -}; - -SpiceDataView.prototype = { - getUint8: function(byteOffset) - { - return this.u8[byteOffset]; - }, - getUint16: function(byteOffset, littleEndian) - { - var low = 1, high = 0; - if (littleEndian) - { - low = 0; - high = 1; - } - - return (this.u8[byteOffset + high] << 8) | this.u8[byteOffset + low]; - }, - getUint32: function(byteOffset, littleEndian) - { - var low = 2, high = 0; - if (littleEndian) - { - low = 0; - high = 2; - } - - return (this.getUint16(byteOffset + high, littleEndian) << 16) | - this.getUint16(byteOffset + low, littleEndian); - }, - getUint64: function (byteOffset, littleEndian) - { - var low = 4, high = 0; - if (littleEndian) - { - low = 0; - high = 4; - } - - return (this.getUint32(byteOffset + high, littleEndian) << 32) | - this.getUint32(byteOffset + low, littleEndian); - }, - setUint8: function(byteOffset, b) - { - this.u8[byteOffset] = (b & 0xff); - }, - setUint16: function(byteOffset, i, littleEndian) - { - var low = 1, high = 0; - if (littleEndian) - { - low = 0; - high = 1; - } - this.u8[byteOffset + high] = (i & 0xffff) >> 8; - this.u8[byteOffset + low] = (i & 0x00ff); - }, - setUint32: function(byteOffset, w, littleEndian) - { - var low = 2, high = 0; - if (littleEndian) - { - low = 0; - high = 2; - } - - this.setUint16(byteOffset + high, (w & 0xffffffff) >> 16, littleEndian); - this.setUint16(byteOffset + low, (w & 0x0000ffff), littleEndian); - }, - setUint64: function(byteOffset, w, littleEndian) - { - var low = 4, high = 0; - if (littleEndian) - { - low = 0; - high = 4; - } - - this.setUint32(byteOffset + high, (w & 0xffffffffffffffff) >> 32, littleEndian); - this.setUint32(byteOffset + low, (w & 0x00000000ffffffff), littleEndian); - }, -} diff --git a/plugins/kimchi/ui/spice-html5/spicemsg.js b/plugins/kimchi/ui/spice-html5/spicemsg.js deleted file mode 100644 index c64f5a3..0000000 --- a/plugins/kimchi/ui/spice-html5/spicemsg.js +++ /dev/null @@ -1,1047 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** Spice messages -** This file contains classes for passing messages to and from -** a spice server. This file should arguably be generated from -** spice.proto, but it was instead put together by hand. -**--------------------------------------------------------------------------*/ -function SpiceLinkHeader(a, at) -{ - this.magic = SPICE_MAGIC; - this.major_version = SPICE_VERSION_MAJOR; - this.minor_version = SPICE_VERSION_MINOR; - this.size = 0; - if (a !== undefined) - this.from_buffer(a, at); -} - -SpiceLinkHeader.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.magic = ""; - for (var i = 0; i < 4; i++) - this.magic += String.fromCharCode(dv.getUint8(at + i)); - at += 4; - - this.major_version = dv.getUint32(at, true); at += 4; - this.minor_version = dv.getUint32(at, true); at += 4; - this.size = dv.getUint32(at, true); at += 4; - }, - - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - for (var i = 0; i < 4; i++) - dv.setUint8(at + i, this.magic.charCodeAt(i)); - at += 4; - - dv.setUint32(at, this.major_version, true); at += 4; - dv.setUint32(at, this.minor_version, true); at += 4; - dv.setUint32(at, this.size, true); at += 4; - }, - buffer_size: function() - { - return 16; - }, -} - -function SpiceLinkMess(a, at) -{ - this.connection_id = 0; - this.channel_type = 0; - this.channel_id = 0; - this.common_caps = []; - this.channel_caps = []; - - if (a !== undefined) - this.from_buffer(a, at); -} - -SpiceLinkMess.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var i; - var orig_at = at; - var dv = new SpiceDataView(a); - this.connection_id = dv.getUint32(at, true); at += 4; - this.channel_type = dv.getUint8(at, true); at++; - this.channel_id = dv.getUint8(at, true); at++; - var num_common_caps = dv.getUint32(at, true); at += 4; - var num_channel_caps = dv.getUint32(at, true); at += 4; - var caps_offset = dv.getUint32(at, true); at += 4; - - at = orig_at + caps_offset; - this.common_caps = []; - for (i = 0; i < num_common_caps; i++) - { - this.common_caps.unshift(dv.getUint32(at, true)); at += 4; - } - - this.channel_caps = []; - for (i = 0; i < num_channel_caps; i++) - { - this.channel_caps.unshift(dv.getUint32(at, true)); at += 4; - } - }, - - to_buffer: function(a, at) - { - at = at || 0; - var orig_at = at; - var i; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.connection_id, true); at += 4; - dv.setUint8(at, this.channel_type, true); at++; - dv.setUint8(at, this.channel_id, true); at++; - dv.setUint32(at, this.common_caps.length, true); at += 4; - dv.setUint32(at, this.channel_caps.length, true); at += 4; - dv.setUint32(at, (at - orig_at) + 4, true); at += 4; - - for (i = 0; i < this.common_caps.length; i++) - { - dv.setUint32(at, this.common_caps[i], true); at += 4; - } - - for (i = 0; i < this.channel_caps.length; i++) - { - dv.setUint32(at, this.channel_caps[i], true); at += 4; - } - }, - buffer_size: function() - { - return 18 + (4 * this.common_caps.length) + (4 * this.channel_caps.length); - } -} - -function SpiceLinkReply(a, at) -{ - this.error = 0; - this.pub_key = undefined; - this.common_caps = []; - this.channel_caps = []; - - if (a !== undefined) - this.from_buffer(a, at); -} - -SpiceLinkReply.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var i; - var orig_at = at; - var dv = new SpiceDataView(a); - this.error = dv.getUint32(at, true); at += 4; - - this.pub_key = create_rsa_from_mb(a, at); - at += SPICE_TICKET_PUBKEY_BYTES; - - var num_common_caps = dv.getUint32(at, true); at += 4; - var num_channel_caps = dv.getUint32(at, true); at += 4; - var caps_offset = dv.getUint32(at, true); at += 4; - - at = orig_at + caps_offset; - this.common_caps = []; - for (i = 0; i < num_common_caps; i++) - { - this.common_caps.unshift(dv.getUint32(at, true)); at += 4; - } - - this.channel_caps = []; - for (i = 0; i < num_channel_caps; i++) - { - this.channel_caps.unshift(dv.getUint32(at, true)); at += 4; - } - }, -} - -function SpiceLinkAuthTicket(a, at) -{ - this.auth_mechanism = 0; - this.encrypted_data = undefined; -} - -SpiceLinkAuthTicket.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var i; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.auth_mechanism, true); at += 4; - for (i = 0; i < SPICE_TICKET_KEY_PAIR_LENGTH / 8; i++) - { - if (this.encrypted_data && i < this.encrypted_data.length) - dv.setUint8(at, this.encrypted_data[i], true); - else - dv.setUint8(at, 0, true); - at++; - } - }, - buffer_size: function() - { - return 4 + (SPICE_TICKET_KEY_PAIR_LENGTH / 8); - } -} - -function SpiceLinkAuthReply(a, at) -{ - this.auth_code = 0; - if (a !== undefined) - this.from_buffer(a, at); -} - -SpiceLinkAuthReply.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.auth_code = dv.getUint32(at, true); at += 4; - }, - buffer_size: function() - { - return 4; - } -} - -function SpiceMiniData(a, at) -{ - this.type = 0; - this.size = 0; - this.data = undefined; - if (a !== undefined) - this.from_buffer(a, at); -} - -SpiceMiniData.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var i; - var dv = new SpiceDataView(a); - this.type = dv.getUint16(at, true); at += 2; - this.size = dv.getUint32(at, true); at += 4; - if (a.byteLength > at) - { - this.data = a.slice(at); - at += this.data.byteLength; - } - }, - to_buffer : function(a, at) - { - at = at || 0; - var i; - var dv = new SpiceDataView(a); - dv.setUint16(at, this.type, true); at += 2; - dv.setUint32(at, this.data ? this.data.byteLength : 0, true); at += 4; - if (this.data && this.data.byteLength > 0) - { - var u8arr = new Uint8Array(this.data); - for (i = 0; i < u8arr.length; i++, at++) - dv.setUint8(at, u8arr[i], true); - } - }, - build_msg : function(in_type, extra) - { - this.type = in_type; - this.size = extra.buffer_size(); - this.data = new ArrayBuffer(this.size); - extra.to_buffer(this.data); - }, - buffer_size: function() - { - if (this.data) - return 6 + this.data.byteLength; - else - return 6; - }, -} - -function SpiceMsgChannels(a, at) -{ - this.num_of_channels = 0; - this.channels = []; - if (a !== undefined) - this.from_buffer(a, at); -} - -SpiceMsgChannels.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var i; - var dv = new SpiceDataView(a); - this.num_of_channels = dv.getUint32(at, true); at += 4; - for (i = 0; i < this.num_of_channels; i++) - { - var chan = new SpiceChannelId(); - at = chan.from_dv(dv, at, a); - this.channels.push(chan); - } - }, -} - -function SpiceMsgMainInit(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgMainInit.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.session_id = dv.getUint32(at, true); at += 4; - this.display_channels_hint = dv.getUint32(at, true); at += 4; - this.supported_mouse_modes = dv.getUint32(at, true); at += 4; - this.current_mouse_mode = dv.getUint32(at, true); at += 4; - this.agent_connected = dv.getUint32(at, true); at += 4; - this.agent_tokens = dv.getUint32(at, true); at += 4; - this.multi_media_time = dv.getUint32(at, true); at += 4; - this.ram_hint = dv.getUint32(at, true); at += 4; - }, -} - -function SpiceMsgMainMouseMode(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgMainMouseMode.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.supported_modes = dv.getUint16(at, true); at += 2; - this.current_mode = dv.getUint16(at, true); at += 2; - }, -} - -function SpiceMsgSetAck(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgSetAck.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.generation = dv.getUint32(at, true); at += 4; - this.window = dv.getUint32(at, true); at += 4; - }, -} - -function SpiceMsgcAckSync(ack) -{ - this.generation = ack.generation; -} - -SpiceMsgcAckSync.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.generation, true); at += 4; - }, - buffer_size: function() - { - return 4; - } -} - -function SpiceMsgcMainMouseModeRequest(mode) -{ - this.mode = mode; -} - -SpiceMsgcMainMouseModeRequest.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint16(at, this.mode, true); at += 2; - }, - buffer_size: function() - { - return 2; - } -} - -function SpiceMsgcMainAgentStart(num_tokens) -{ - this.num_tokens = num_tokens; -} - -SpiceMsgcMainAgentStart.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.num_tokens, true); at += 4; - }, - buffer_size: function() - { - return 4; - } -} - -function SpiceMsgcMainAgentData(type, data) -{ - this.protocol = VD_AGENT_PROTOCOL; - this.type = type; - this.opaque = 0; - this.size = data.buffer_size(); - this.data = data; -} - -SpiceMsgcMainAgentData.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.protocol, true); at += 4; - dv.setUint32(at, this.type, true); at += 4; - dv.setUint64(at, this.opaque, true); at += 8; - dv.setUint32(at, this.size, true); at += 4; - this.data.to_buffer(a, at); - }, - buffer_size: function() - { - return 4 + 4 + 8 + 4 + this.data.buffer_size(); - } -} - -function VDAgentMonitorsConfig(flags, width, height, depth, x, y) -{ - this.num_mon = 1; - this.flags = flags; - this.width = width; - this.height = height; - this.depth = depth; - this.x = x; - this.y = y; -} - -VDAgentMonitorsConfig.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.num_mon, true); at += 4; - dv.setUint32(at, this.flags, true); at += 4; - dv.setUint32(at, this.height, true); at += 4; - dv.setUint32(at, this.width, true); at += 4; - dv.setUint32(at, this.depth, true); at += 4; - dv.setUint32(at, this.x, true); at += 4; - dv.setUint32(at, this.y, true); at += 4; - }, - buffer_size: function() - { - return 28; - } -} - -function SpiceMsgNotify(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgNotify.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var i; - var dv = new SpiceDataView(a); - this.time_stamp = dv.getUint64(at, true); at += 8; - this.severity = dv.getUint32(at, true); at += 4; - this.visibility = dv.getUint32(at, true); at += 4; - this.what = dv.getUint32(at, true); at += 4; - this.message_len = dv.getUint32(at, true); at += 4; - this.message = ""; - for (i = 0; i < this.message_len; i++) - { - var c = dv.getUint8(at, true); at++; - this.message += String.fromCharCode(c); - } - }, -} - -function SpiceMsgcDisplayInit() -{ - this.pixmap_cache_id = 1; - this.glz_dictionary_id = 0; - this.pixmap_cache_size = 10 * 1024 * 1024; - this.glz_dictionary_window_size = 0; -} - -SpiceMsgcDisplayInit.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint8(at, this.pixmap_cache_id, true); at++; - dv.setUint64(at, this.pixmap_cache_size, true); at += 8; - dv.setUint8(at, this.glz_dictionary_id, true); at++; - dv.setUint32(at, this.glz_dictionary_window_size, true); at += 4; - }, - buffer_size: function() - { - return 14; - } -} - -function SpiceMsgDisplayBase() -{ -} - -SpiceMsgDisplayBase.prototype = -{ - from_dv : function(dv, at, mb) - { - this.surface_id = dv.getUint32(at, true); at += 4; - this.box = new SpiceRect; - at = this.box.from_dv(dv, at, mb); - this.clip = new SpiceClip; - return this.clip.from_dv(dv, at, mb); - }, -} - -function SpiceMsgDisplayDrawCopy(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgDisplayDrawCopy.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.base = new SpiceMsgDisplayBase; - at = this.base.from_dv(dv, at, a); - this.data = new SpiceCopy; - return this.data.from_dv(dv, at, a); - }, -} - -function SpiceMsgDisplayDrawFill(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgDisplayDrawFill.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.base = new SpiceMsgDisplayBase; - at = this.base.from_dv(dv, at, a); - this.data = new SpiceFill; - return this.data.from_dv(dv, at, a); - }, -} - -function SpiceMsgDisplayCopyBits(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgDisplayCopyBits.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.base = new SpiceMsgDisplayBase; - at = this.base.from_dv(dv, at, a); - this.src_pos = new SpicePoint; - return this.src_pos.from_dv(dv, at, a); - }, -} - - -function SpiceMsgSurfaceCreate(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgSurfaceCreate.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.surface = new SpiceSurface; - return this.surface.from_dv(dv, at, a); - }, -} - -function SpiceMsgSurfaceDestroy(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgSurfaceDestroy.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.surface_id = dv.getUint32(at, true); at += 4; - }, -} - -function SpiceMsgInputsInit(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgInputsInit.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.keyboard_modifiers = dv.getUint16(at, true); at += 2; - return at; - }, -} - -function SpiceMsgInputsKeyModifiers(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgInputsKeyModifiers.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.keyboard_modifiers = dv.getUint16(at, true); at += 2; - return at; - }, -} - -function SpiceMsgCursorInit(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgCursorInit.prototype = -{ - from_buffer: function(a, at, mb) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.position = new SpicePoint16; - at = this.position.from_dv(dv, at, mb); - this.trail_length = dv.getUint16(at, true); at += 2; - this.trail_frequency = dv.getUint16(at, true); at += 2; - this.visible = dv.getUint8(at, true); at ++; - this.cursor = new SpiceCursor; - return this.cursor.from_dv(dv, at, a); - }, -} - -function SpiceMsgPlaybackData(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgPlaybackData.prototype = -{ - from_buffer: function(a, at, mb) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.time = dv.getUint32(at, true); at += 4; - if (a.byteLength > at) - { - this.data = a.slice(at); - at += this.data.byteLength; - } - return at; - }, -} - -function SpiceMsgPlaybackMode(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgPlaybackMode.prototype = -{ - from_buffer: function(a, at, mb) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.time = dv.getUint32(at, true); at += 4; - this.mode = dv.getUint16(at, true); at += 2; - if (a.byteLength > at) - { - this.data = a.slice(at); - at += this.data.byteLength; - } - return at; - }, -} - -function SpiceMsgPlaybackStart(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgPlaybackStart.prototype = -{ - from_buffer: function(a, at, mb) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.channels = dv.getUint32(at, true); at += 4; - this.format = dv.getUint16(at, true); at += 2; - this.frequency = dv.getUint32(at, true); at += 4; - this.time = dv.getUint32(at, true); at += 4; - return at; - }, -} - - - -function SpiceMsgCursorSet(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgCursorSet.prototype = -{ - from_buffer: function(a, at, mb) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.position = new SpicePoint16; - at = this.position.from_dv(dv, at, mb); - this.visible = dv.getUint8(at, true); at ++; - this.cursor = new SpiceCursor; - return this.cursor.from_dv(dv, at, a); - }, -} - - -function SpiceMsgcMousePosition(sc, e) -{ - // FIXME - figure out how to correctly compute display_id - this.display_id = 0; - this.buttons_state = sc.buttons_state; - if (e) - { - var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; - var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft; - - this.x = e.clientX - sc.display.surfaces[sc.display.primary_surface].canvas.offsetLeft + scrollLeft; - this.y = e.clientY - sc.display.surfaces[sc.display.primary_surface].canvas.offsetTop + scrollTop; - sc.mousex = this.x; - sc.mousey = this.y; - } - else - { - this.x = this.y = this.buttons_state = 0; - } -} - -SpiceMsgcMousePosition.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.x, true); at += 4; - dv.setUint32(at, this.y, true); at += 4; - dv.setUint16(at, this.buttons_state, true); at += 2; - dv.setUint8(at, this.display_id, true); at += 1; - return at; - }, - buffer_size: function() - { - return 11; - } -} - -function SpiceMsgcMouseMotion(sc, e) -{ - // FIXME - figure out how to correctly compute display_id - this.display_id = 0; - this.buttons_state = sc.buttons_state; - if (e) - { - this.x = e.clientX - sc.display.surfaces[sc.display.primary_surface].canvas.offsetLeft; - this.y = e.clientY - sc.display.surfaces[sc.display.primary_surface].canvas.offsetTop; - - if (sc.mousex !== undefined) - { - this.x -= sc.mousex; - this.y -= sc.mousey; - } - sc.mousex = e.clientX - sc.display.surfaces[sc.display.primary_surface].canvas.offsetLeft; - sc.mousey = e.clientY - sc.display.surfaces[sc.display.primary_surface].canvas.offsetTop; - } - else - { - this.x = this.y = this.buttons_state = 0; - } -} - -/* Use the same functions as for MousePosition */ -SpiceMsgcMouseMotion.prototype.to_buffer = SpiceMsgcMousePosition.prototype.to_buffer; -SpiceMsgcMouseMotion.prototype.buffer_size = SpiceMsgcMousePosition.prototype.buffer_size; - -function SpiceMsgcMousePress(sc, e) -{ - if (e) - { - this.button = e.button + 1; - this.buttons_state = 1 << e.button; - sc.buttons_state = this.buttons_state; - } - else - { - this.button = SPICE_MOUSE_BUTTON_LEFT; - this.buttons_state = SPICE_MOUSE_BUTTON_MASK_LEFT; - } -} - -SpiceMsgcMousePress.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint8(at, this.button, true); at ++; - dv.setUint16(at, this.buttons_state, true); at += 2; - return at; - }, - buffer_size: function() - { - return 3; - } -} - -function SpiceMsgcMouseRelease(sc, e) -{ - if (e) - { - this.button = e.button + 1; - this.buttons_state = 0; - sc.buttons_state = this.buttons_state; - } - else - { - this.button = SPICE_MOUSE_BUTTON_LEFT; - this.buttons_state = 0; - } -} - -/* Use the same functions as for MousePress */ -SpiceMsgcMouseRelease.prototype.to_buffer = SpiceMsgcMousePress.prototype.to_buffer; -SpiceMsgcMouseRelease.prototype.buffer_size = SpiceMsgcMousePress.prototype.buffer_size; - - -function SpiceMsgcKeyDown(e) -{ - if (e) - { - this.code = keycode_to_start_scan(e.keyCode); - } - else - { - this.code = 0; - } -} - -SpiceMsgcKeyDown.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.code, true); at += 4; - return at; - }, - buffer_size: function() - { - return 4; - } -} - -function SpiceMsgcKeyUp(e) -{ - if (e) - { - this.code = keycode_to_end_scan(e.keyCode); - } - else - { - this.code = 0; - } -} - -/* Use the same functions as for KeyDown */ -SpiceMsgcKeyUp.prototype.to_buffer = SpiceMsgcKeyDown.prototype.to_buffer; -SpiceMsgcKeyUp.prototype.buffer_size = SpiceMsgcKeyDown.prototype.buffer_size; - -function SpiceMsgDisplayStreamCreate(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgDisplayStreamCreate.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.surface_id = dv.getUint32(at, true); at += 4; - this.id = dv.getUint32(at, true); at += 4; - this.flags = dv.getUint8(at, true); at += 1; - this.codec_type = dv.getUint8(at, true); at += 1; - this.stamp = dv.getUint64(at, true); at += 8; - this.stream_width = dv.getUint32(at, true); at += 4; - this.stream_height = dv.getUint32(at, true); at += 4; - this.src_width = dv.getUint32(at, true); at += 4; - this.src_height = dv.getUint32(at, true); at += 4; - - this.dest = new SpiceRect; - at = this.dest.from_dv(dv, at, a); - this.clip = new SpiceClip; - this.clip.from_dv(dv, at, a); - }, -} - -function SpiceStreamDataHeader(a, at) -{ -} - -SpiceStreamDataHeader.prototype = -{ - from_dv : function(dv, at, mb) - { - this.id = dv.getUint32(at, true); at += 4; - this.multi_media_time = dv.getUint32(at, true); at += 4; - return at; - }, -} - -function SpiceMsgDisplayStreamData(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgDisplayStreamData.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.base = new SpiceStreamDataHeader; - at = this.base.from_dv(dv, at, a); - this.data_size = dv.getUint32(at, true); at += 4; - this.data = dv.u8.subarray(at, at + this.data_size); - }, -} - -function SpiceMsgDisplayStreamClip(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgDisplayStreamClip.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.id = dv.getUint32(at, true); at += 4; - this.clip = new SpiceClip; - this.clip.from_dv(dv, at, a); - }, -} - -function SpiceMsgDisplayStreamDestroy(a, at) -{ - this.from_buffer(a, at); -} - -SpiceMsgDisplayStreamDestroy.prototype = -{ - from_buffer: function(a, at) - { - at = at || 0; - var dv = new SpiceDataView(a); - this.id = dv.getUint32(at, true); at += 4; - }, -} - -function SpiceMsgDisplayInvalList(a, at) -{ - this.count = 0; - this.resources = []; - this.from_buffer(a,at); -} - -SpiceMsgDisplayInvalList.prototype = -{ - from_buffer: function (a, at) - { - var i; - at = at || 0; - var dv = new SpiceDataView(a); - this.count = dv.getUint16(at, true); at += 2; - for (i = 0; i < this.count; i++) - { - this.resources[i] = {}; - this.resources[i].type = dv.getUint8(at, true); at++; - this.resources[i].id = dv.getUint64(at, true); at += 8; - } - }, -} diff --git a/plugins/kimchi/ui/spice-html5/spicetype.js b/plugins/kimchi/ui/spice-html5/spicetype.js deleted file mode 100644 index 951b277..0000000 --- a/plugins/kimchi/ui/spice-html5/spicetype.js +++ /dev/null @@ -1,473 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** Spice types -** This file contains classes for common spice types. -** Generally, they are used as helpers in reading and writing messages -** to and from the server. -**--------------------------------------------------------------------------*/ - -function SpiceChannelId() -{ -} -SpiceChannelId.prototype = -{ - from_dv: function(dv, at, mb) - { - this.type = dv.getUint8(at, true); at ++; - this.id = dv.getUint8(at, true); at ++; - return at; - }, -} - -function SpiceRect() -{ -} - -SpiceRect.prototype = -{ - from_dv: function(dv, at, mb) - { - this.top = dv.getUint32(at, true); at += 4; - this.left = dv.getUint32(at, true); at += 4; - this.bottom = dv.getUint32(at, true); at += 4; - this.right = dv.getUint32(at, true); at += 4; - return at; - }, - is_same_size : function(r) - { - if ((this.bottom - this.top) == (r.bottom - r.top) && - (this.right - this.left) == (r.right - r.left) ) - return true; - - return false; - }, -} - -function SpiceClipRects() -{ -} - -SpiceClipRects.prototype = -{ - from_dv: function(dv, at, mb) - { - var i; - this.num_rects = dv.getUint32(at, true); at += 4; - if (this.num_rects > 0) - this.rects = []; - for (i = 0; i < this.num_rects; i++) - { - this.rects[i] = new SpiceRect(); - at = this.rects[i].from_dv(dv, at, mb); - } - return at; - }, -} - -function SpiceClip() -{ -} - -SpiceClip.prototype = -{ - from_dv: function(dv, at, mb) - { - this.type = dv.getUint8(at, true); at ++; - if (this.type == SPICE_CLIP_TYPE_RECTS) - { - this.rects = new SpiceClipRects(); - at = this.rects.from_dv(dv, at, mb); - } - return at; - }, -} - -function SpiceImageDescriptor() -{ -} - -SpiceImageDescriptor.prototype = -{ - from_dv: function(dv, at, mb) - { - this.id = dv.getUint64(at, true); at += 8; - this.type = dv.getUint8(at, true); at ++; - this.flags = dv.getUint8(at, true); at ++; - this.width = dv.getUint32(at, true); at += 4; - this.height= dv.getUint32(at, true); at += 4; - return at; - }, -} - -function SpicePalette() -{ -} - -SpicePalette.prototype = -{ - from_dv: function(dv, at, mb) - { - var i; - this.unique = dv.getUint64(at, true); at += 8; - this.num_ents = dv.getUint16(at, true); at += 2; - this.ents = []; - for (i = 0; i < this.num_ents; i++) - { - this.ents[i] = dv.getUint32(at, true); at += 4; - } - return at; - }, -} - -function SpiceBitmap() -{ -} - -SpiceBitmap.prototype = -{ - from_dv: function(dv, at, mb) - { - this.format = dv.getUint8(at, true); at++; - this.flags = dv.getUint8(at, true); at++; - this.x = dv.getUint32(at, true); at += 4; - this.y = dv.getUint32(at, true); at += 4; - this.stride = dv.getUint32(at, true); at += 4; - if (this.flags & SPICE_BITMAP_FLAGS_PAL_FROM_CACHE) - { - this.palette_id = dv.getUint64(at, true); at += 8; - } - else - { - var offset = dv.getUint32(at, true); at += 4; - if (offset == 0) - this.palette = null; - else - { - this.palette = new SpicePalette; - this.palette.from_dv(dv, offset, mb); - } - } - // FIXME - should probably constrain this to the offset - // of palette, if non zero - this.data = mb.slice(at); - at += this.data.byteLength; - return at; - }, -} - -function SpiceImage() -{ -} - -SpiceImage.prototype = -{ - from_dv: function(dv, at, mb) - { - this.descriptor = new SpiceImageDescriptor; - at = this.descriptor.from_dv(dv, at, mb); - - if (this.descriptor.type == SPICE_IMAGE_TYPE_LZ_RGB) - { - this.lz_rgb = new Object(); - this.lz_rgb.length = dv.getUint32(at, true); at += 4; - var initial_at = at; - this.lz_rgb.magic = ""; - for (var i = 3; i >= 0; i--) - this.lz_rgb.magic += String.fromCharCode(dv.getUint8(at + i)); - at += 4; - - // NOTE: The endian change is *correct* - this.lz_rgb.version = dv.getUint32(at); at += 4; - this.lz_rgb.type = dv.getUint32(at); at += 4; - this.lz_rgb.width = dv.getUint32(at); at += 4; - this.lz_rgb.height = dv.getUint32(at); at += 4; - this.lz_rgb.stride = dv.getUint32(at); at += 4; - this.lz_rgb.top_down = dv.getUint32(at); at += 4; - - var header_size = at - initial_at; - - this.lz_rgb.data = mb.slice(at, this.lz_rgb.length + at - header_size); - at += this.lz_rgb.data.byteLength; - - } - - if (this.descriptor.type == SPICE_IMAGE_TYPE_BITMAP) - { - this.bitmap = new SpiceBitmap; - at = this.bitmap.from_dv(dv, at, mb); - } - - if (this.descriptor.type == SPICE_IMAGE_TYPE_SURFACE) - { - this.surface_id = dv.getUint32(at, true); at += 4; - } - - if (this.descriptor.type == SPICE_IMAGE_TYPE_JPEG) - { - this.jpeg = new Object; - this.jpeg.data_size = dv.getUint32(at, true); at += 4; - this.jpeg.data = mb.slice(at); - at += this.jpeg.data.byteLength; - } - - if (this.descriptor.type == SPICE_IMAGE_TYPE_JPEG_ALPHA) - { - this.jpeg_alpha = new Object; - this.jpeg_alpha.flags = dv.getUint8(at, true); at += 1; - this.jpeg_alpha.jpeg_size = dv.getUint32(at, true); at += 4; - this.jpeg_alpha.data_size = dv.getUint32(at, true); at += 4; - this.jpeg_alpha.data = mb.slice(at, this.jpeg_alpha.jpeg_size + at); - at += this.jpeg_alpha.data.byteLength; - // Alpha channel is an LZ image - this.jpeg_alpha.alpha = new Object(); - this.jpeg_alpha.alpha.length = this.jpeg_alpha.data_size - this.jpeg_alpha.jpeg_size; - var initial_at = at; - this.jpeg_alpha.alpha.magic = ""; - for (var i = 3; i >= 0; i--) - this.jpeg_alpha.alpha.magic += String.fromCharCode(dv.getUint8(at + i)); - at += 4; - - // NOTE: The endian change is *correct* - this.jpeg_alpha.alpha.version = dv.getUint32(at); at += 4; - this.jpeg_alpha.alpha.type = dv.getUint32(at); at += 4; - this.jpeg_alpha.alpha.width = dv.getUint32(at); at += 4; - this.jpeg_alpha.alpha.height = dv.getUint32(at); at += 4; - this.jpeg_alpha.alpha.stride = dv.getUint32(at); at += 4; - this.jpeg_alpha.alpha.top_down = dv.getUint32(at); at += 4; - - var header_size = at - initial_at; - - this.jpeg_alpha.alpha.data = mb.slice(at, this.jpeg_alpha.alpha.length + at - header_size); - at += this.jpeg_alpha.alpha.data.byteLength; - } - - if (this.descriptor.type == SPICE_IMAGE_TYPE_QUIC) - { - this.quic = new SpiceQuic; - at = this.quic.from_dv(dv, at, mb); - } - return at; - }, -} - - -function SpiceQMask() -{ -} - -SpiceQMask.prototype = -{ - from_dv: function(dv, at, mb) - { - this.flags = dv.getUint8(at, true); at++; - this.pos = new SpicePoint; - at = this.pos.from_dv(dv, at, mb); - var offset = dv.getUint32(at, true); at += 4; - if (offset == 0) - { - this.bitmap = null; - return at; - } - - this.bitmap = new SpiceImage; - return this.bitmap.from_dv(dv, offset, mb); - }, -} - - -function SpicePattern() -{ -} - -SpicePattern.prototype = -{ - from_dv: function(dv, at, mb) - { - var offset = dv.getUint32(at, true); at += 4; - if (offset == 0) - { - this.pat = null; - } - else - { - this.pat = new SpiceImage; - this.pat.from_dv(dv, offset, mb); - } - - this.pos = new SpicePoint; - return this.pos.from_dv(dv, at, mb); - } -} - -function SpiceBrush() -{ -} - -SpiceBrush.prototype = -{ - from_dv: function(dv, at, mb) - { - this.type = dv.getUint8(at, true); at ++; - if (this.type == SPICE_BRUSH_TYPE_SOLID) - { - this.color = dv.getUint32(at, true); at += 4; - } - else if (this.type == SPICE_BRUSH_TYPE_PATTERN) - { - this.pattern = new SpicePattern; - at = this.pattern.from_dv(dv, at, mb); - } - return at; - }, -} - -function SpiceFill() -{ -} - -SpiceFill.prototype = -{ - from_dv: function(dv, at, mb) - { - this.brush = new SpiceBrush; - at = this.brush.from_dv(dv, at, mb); - this.rop_descriptor = dv.getUint16(at, true); at += 2; - this.mask = new SpiceQMask; - return this.mask.from_dv(dv, at, mb); - }, -} - - -function SpiceCopy() -{ -} - -SpiceCopy.prototype = -{ - from_dv: function(dv, at, mb) - { - var offset = dv.getUint32(at, true); at += 4; - if (offset == 0) - { - this.src_bitmap = null; - } - else - { - this.src_bitmap = new SpiceImage; - this.src_bitmap.from_dv(dv, offset, mb); - } - this.src_area = new SpiceRect; - at = this.src_area.from_dv(dv, at, mb); - this.rop_descriptor = dv.getUint16(at, true); at += 2; - this.scale_mode = dv.getUint8(at, true); at ++; - this.mask = new SpiceQMask; - return this.mask.from_dv(dv, at, mb); - }, -} - -function SpicePoint16() -{ -} - -SpicePoint16.prototype = -{ - from_dv: function(dv, at, mb) - { - this.x = dv.getUint16(at, true); at += 2; - this.y = dv.getUint16(at, true); at += 2; - return at; - }, -} - -function SpicePoint() -{ -} - -SpicePoint.prototype = -{ - from_dv: function(dv, at, mb) - { - this.x = dv.getUint32(at, true); at += 4; - this.y = dv.getUint32(at, true); at += 4; - return at; - }, -} - -function SpiceCursorHeader() -{ -} - -SpiceCursorHeader.prototype = -{ - from_dv: function(dv, at, mb) - { - this.unique = dv.getUint64(at, true); at += 8; - this.type = dv.getUint8(at, true); at ++; - this.width = dv.getUint16(at, true); at += 2; - this.height = dv.getUint16(at, true); at += 2; - this.hot_spot_x = dv.getUint16(at, true); at += 2; - this.hot_spot_y = dv.getUint16(at, true); at += 2; - return at; - }, -} - -function SpiceCursor() -{ -} - -SpiceCursor.prototype = -{ - from_dv: function(dv, at, mb) - { - this.flags = dv.getUint16(at, true); at += 2; - if (this.flags & SPICE_CURSOR_FLAGS_NONE) - this.header = null; - else - { - this.header = new SpiceCursorHeader; - at = this.header.from_dv(dv, at, mb); - this.data = mb.slice(at); - at += this.data.byteLength; - } - return at; - }, -} - -function SpiceSurface() -{ -} - -SpiceSurface.prototype = -{ - from_dv: function(dv, at, mb) - { - this.surface_id = dv.getUint32(at, true); at += 4; - this.width = dv.getUint32(at, true); at += 4; - this.height = dv.getUint32(at, true); at += 4; - this.format = dv.getUint32(at, true); at += 4; - this.flags = dv.getUint32(at, true); at += 4; - return at; - }, -} - -/* FIXME - SpiceImage types lz_plt, jpeg, zlib_glz, and jpeg_alpha are - completely unimplemented */ diff --git a/plugins/kimchi/ui/spice-html5/thirdparty/Makefile.am b/plugins/kimchi/ui/spice-html5/thirdparty/Makefile.am deleted file mode 100644 index 474478d..0000000 --- a/plugins/kimchi/ui/spice-html5/thirdparty/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# -# Kimchi -# -# Copyright IBM, Corp. 2014 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -thirdpartydir = $(datadir)/wok/plugins/kimchi/ui/spice-html5/thirdparty - -dist_thirdparty_DATA = $(wildcard *.js) $(NULL) diff --git a/plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js b/plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js deleted file mode 100644 index 9b9476e..0000000 --- a/plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js +++ /dev/null @@ -1,589 +0,0 @@ -// Downloaded from http://www-cs-students.stanford.edu/~tjw/jsbn/ by Jeremy White on 6/1/2012 - -/* - * Copyright (c) 2003-2005 Tom Wu - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * In addition, the following condition applies: - * - * All redistributions must retain an intact copy of this copyright notice - * and disclaimer. - */ - - -// Basic JavaScript BN library - subset useful for RSA encryption. - -// Bits per digit -var dbits; - -// JavaScript engine analysis -var canary = 0xdeadbeefcafe; -var j_lm = ((canary&0xffffff)==0xefcafe); - -// (public) Constructor -function BigInteger(a,b,c) { - if(a != null) - if("number" == typeof a) this.fromNumber(a,b,c); - else if(b == null && "string" != typeof a) this.fromString(a,256); - else this.fromString(a,b); -} - -// return new, unset BigInteger -function nbi() { return new BigInteger(null); } - -// am: Compute w_j += (x*this_i), propagate carries, -// c is initial carry, returns final carry. -// c < 3*dvalue, x < 2*dvalue, this_i < dvalue -// We need to select the fastest one that works in this environment. - -// am1: use a single mult and divide to get the high bits, -// max digit bits should be 26 because -// max internal value = 2*dvalue^2-2*dvalue (< 2^53) -function am1(i,x,w,j,c,n) { - while(--n >= 0) { - var v = x*this[i++]+w[j]+c; - c = Math.floor(v/0x4000000); - w[j++] = v&0x3ffffff; - } - return c; -} -// am2 avoids a big mult-and-extract completely. -// Max digit bits should be <= 30 because we do bitwise ops -// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) -function am2(i,x,w,j,c,n) { - var xl = x&0x7fff, xh = x>>15; - while(--n >= 0) { - var l = this[i]&0x7fff; - var h = this[i++]>>15; - var m = xh*l+h*xl; - l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff); - c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); - w[j++] = l&0x3fffffff; - } - return c; -} -// Alternately, set max digit bits to 28 since some -// browsers slow down when dealing with 32-bit numbers. -function am3(i,x,w,j,c,n) { - var xl = x&0x3fff, xh = x>>14; - while(--n >= 0) { - var l = this[i]&0x3fff; - var h = this[i++]>>14; - var m = xh*l+h*xl; - l = xl*l+((m&0x3fff)<<14)+w[j]+c; - c = (l>>28)+(m>>14)+xh*h; - w[j++] = l&0xfffffff; - } - return c; -} -if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) { - BigInteger.prototype.am = am2; - dbits = 30; -} -else if(j_lm && (navigator.appName != "Netscape")) { - BigInteger.prototype.am = am1; - dbits = 26; -} -else { // Mozilla/Netscape seems to prefer am3 - BigInteger.prototype.am = am3; - dbits = 28; -} - -BigInteger.prototype.DB = dbits; -BigInteger.prototype.DM = ((1<<dbits)-1); -BigInteger.prototype.DV = (1<<dbits); - -var BI_FP = 52; -BigInteger.prototype.FV = Math.pow(2,BI_FP); -BigInteger.prototype.F1 = BI_FP-dbits; -BigInteger.prototype.F2 = 2*dbits-BI_FP; - -// Digit conversions -var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; -var BI_RC = new Array(); -var rr,vv; -rr = "0".charCodeAt(0); -for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv; -rr = "a".charCodeAt(0); -for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; -rr = "A".charCodeAt(0); -for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; - -function int2char(n) { return BI_RM.charAt(n); } -function intAt(s,i) { - var c = BI_RC[s.charCodeAt(i)]; - return (c==null)?-1:c; -} - -// (protected) copy this to r -function bnpCopyTo(r) { - for(var i = this.t-1; i >= 0; --i) r[i] = this[i]; - r.t = this.t; - r.s = this.s; -} - -// (protected) set from integer value x, -DV <= x < DV -function bnpFromInt(x) { - this.t = 1; - this.s = (x<0)?-1:0; - if(x > 0) this[0] = x; - else if(x < -1) this[0] = x+DV; - else this.t = 0; -} - -// return bigint initialized to value -function nbv(i) { var r = nbi(); r.fromInt(i); return r; } - -// (protected) set from string and radix -function bnpFromString(s,b) { - var k; - if(b == 16) k = 4; - else if(b == 8) k = 3; - else if(b == 256) k = 8; // byte array - else if(b == 2) k = 1; - else if(b == 32) k = 5; - else if(b == 4) k = 2; - else { this.fromRadix(s,b); return; } - this.t = 0; - this.s = 0; - var i = s.length, mi = false, sh = 0; - while(--i >= 0) { - var x = (k==8)?s[i]&0xff:intAt(s,i); - if(x < 0) { - if(s.charAt(i) == "-") mi = true; - continue; - } - mi = false; - if(sh == 0) - this[this.t++] = x; - else if(sh+k > this.DB) { - this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh; - this[this.t++] = (x>>(this.DB-sh)); - } - else - this[this.t-1] |= x<<sh; - sh += k; - if(sh >= this.DB) sh -= this.DB; - } - if(k == 8 && (s[0]&0x80) != 0) { - this.s = -1; - if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh; - } - this.clamp(); - if(mi) BigInteger.ZERO.subTo(this,this); -} - -// (protected) clamp off excess high words -function bnpClamp() { - var c = this.s&this.DM; - while(this.t > 0 && this[this.t-1] == c) --this.t; -} - -// (public) return string representation in given radix -function bnToString(b) { - if(this.s < 0) return "-"+this.negate().toString(b); - var k; - if(b == 16) k = 4; - else if(b == 8) k = 3; - else if(b == 2) k = 1; - else if(b == 32) k = 5; - else if(b == 4) k = 2; - else return this.toRadix(b); - var km = (1<<k)-1, d, m = false, r = "", i = this.t; - var p = this.DB-(i*this.DB)%k; - if(i-- > 0) { - if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); } - while(i >= 0) { - if(p < k) { - d = (this[i]&((1<<p)-1))<<(k-p); - d |= this[--i]>>(p+=this.DB-k); - } - else { - d = (this[i]>>(p-=k))&km; - if(p <= 0) { p += this.DB; --i; } - } - if(d > 0) m = true; - if(m) r += int2char(d); - } - } - return m?r:"0"; -} - -// (public) -this -function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } - -// (public) |this| -function bnAbs() { return (this.s<0)?this.negate():this; } - -// (public) return + if this > a, - if this < a, 0 if equal -function bnCompareTo(a) { - var r = this.s-a.s; - if(r != 0) return r; - var i = this.t; - r = i-a.t; - if(r != 0) return r; - while(--i >= 0) if((r=this[i]-a[i]) != 0) return r; - return 0; -} - -// returns bit length of the integer x -function nbits(x) { - var r = 1, t; - if((t=x>>>16) != 0) { x = t; r += 16; } - if((t=x>>8) != 0) { x = t; r += 8; } - if((t=x>>4) != 0) { x = t; r += 4; } - if((t=x>>2) != 0) { x = t; r += 2; } - if((t=x>>1) != 0) { x = t; r += 1; } - return r; -} - -// (public) return the number of bits in "this" -function bnBitLength() { - if(this.t <= 0) return 0; - return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM)); -} - -// (protected) r = this << n*DB -function bnpDLShiftTo(n,r) { - var i; - for(i = this.t-1; i >= 0; --i) r[i+n] = this[i]; - for(i = n-1; i >= 0; --i) r[i] = 0; - r.t = this.t+n; - r.s = this.s; -} - -// (protected) r = this >> n*DB -function bnpDRShiftTo(n,r) { - for(var i = n; i < this.t; ++i) r[i-n] = this[i]; - r.t = Math.max(this.t-n,0); - r.s = this.s; -} - -// (protected) r = this << n -function bnpLShiftTo(n,r) { - var bs = n%this.DB; - var cbs = this.DB-bs; - var bm = (1<<cbs)-1; - var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i; - for(i = this.t-1; i >= 0; --i) { - r[i+ds+1] = (this[i]>>cbs)|c; - c = (this[i]&bm)<<bs; - } - for(i = ds-1; i >= 0; --i) r[i] = 0; - r[ds] = c; - r.t = this.t+ds+1; - r.s = this.s; - r.clamp(); -} - -// (protected) r = this >> n -function bnpRShiftTo(n,r) { - r.s = this.s; - var ds = Math.floor(n/this.DB); - if(ds >= this.t) { r.t = 0; return; } - var bs = n%this.DB; - var cbs = this.DB-bs; - var bm = (1<<bs)-1; - r[0] = this[ds]>>bs; - for(var i = ds+1; i < this.t; ++i) { - r[i-ds-1] |= (this[i]&bm)<<cbs; - r[i-ds] = this[i]>>bs; - } - if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs; - r.t = this.t-ds; - r.clamp(); -} - -// (protected) r = this - a -function bnpSubTo(a,r) { - var i = 0, c = 0, m = Math.min(a.t,this.t); - while(i < m) { - c += this[i]-a[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - if(a.t < this.t) { - c -= a.s; - while(i < this.t) { - c += this[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - c += this.s; - } - else { - c += this.s; - while(i < a.t) { - c -= a[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - c -= a.s; - } - r.s = (c<0)?-1:0; - if(c < -1) r[i++] = this.DV+c; - else if(c > 0) r[i++] = c; - r.t = i; - r.clamp(); -} - -// (protected) r = this * a, r != this,a (HAC 14.12) -// "this" should be the larger one if appropriate. -function bnpMultiplyTo(a,r) { - var x = this.abs(), y = a.abs(); - var i = x.t; - r.t = i+y.t; - while(--i >= 0) r[i] = 0; - for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t); - r.s = 0; - r.clamp(); - if(this.s != a.s) BigInteger.ZERO.subTo(r,r); -} - -// (protected) r = this^2, r != this (HAC 14.16) -function bnpSquareTo(r) { - var x = this.abs(); - var i = r.t = 2*x.t; - while(--i >= 0) r[i] = 0; - for(i = 0; i < x.t-1; ++i) { - var c = x.am(i,x[i],r,2*i,0,1); - if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { - r[i+x.t] -= x.DV; - r[i+x.t+1] = 1; - } - } - if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1); - r.s = 0; - r.clamp(); -} - -// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) -// r != q, this != m. q or r may be null. -function bnpDivRemTo(m,q,r) { - var pm = m.abs(); - if(pm.t <= 0) return; - var pt = this.abs(); - if(pt.t < pm.t) { - if(q != null) q.fromInt(0); - if(r != null) this.copyTo(r); - return; - } - if(r == null) r = nbi(); - var y = nbi(), ts = this.s, ms = m.s; - var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus - if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } - else { pm.copyTo(y); pt.copyTo(r); } - var ys = y.t; - var y0 = y[ys-1]; - if(y0 == 0) return; - var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0); - var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2; - var i = r.t, j = i-ys, t = (q==null)?nbi():q; - y.dlShiftTo(j,t); - if(r.compareTo(t) >= 0) { - r[r.t++] = 1; - r.subTo(t,r); - } - BigInteger.ONE.dlShiftTo(ys,t); - t.subTo(y,y); // "negative" y so we can replace sub with am later - while(y.t < ys) y[y.t++] = 0; - while(--j >= 0) { - // Estimate quotient digit - var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2); - if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out - y.dlShiftTo(j,t); - r.subTo(t,r); - while(r[i] < --qd) r.subTo(t,r); - } - } - if(q != null) { - r.drShiftTo(ys,q); - if(ts != ms) BigInteger.ZERO.subTo(q,q); - } - r.t = ys; - r.clamp(); - if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder - if(ts < 0) BigInteger.ZERO.subTo(r,r); -} - -// (public) this mod a -function bnMod(a) { - var r = nbi(); - this.abs().divRemTo(a,null,r); - if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); - return r; -} - -// Modular reduction using "classic" algorithm -function Classic(m) { this.m = m; } -function cConvert(x) { - if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); - else return x; -} -function cRevert(x) { return x; } -function cReduce(x) { x.divRemTo(this.m,null,x); } -function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } -function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - -Classic.prototype.convert = cConvert; -Classic.prototype.revert = cRevert; -Classic.prototype.reduce = cReduce; -Classic.prototype.mulTo = cMulTo; -Classic.prototype.sqrTo = cSqrTo; - -// (protected) return "-1/this % 2^DB"; useful for Mont. reduction -// justification: -// xy == 1 (mod m) -// xy = 1+km -// xy(2-xy) = (1+km)(1-km) -// x[y(2-xy)] = 1-k^2m^2 -// x[y(2-xy)] == 1 (mod m^2) -// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 -// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. -// JS multiply "overflows" differently from C/C++, so care is needed here. -function bnpInvDigit() { - if(this.t < 1) return 0; - var x = this[0]; - if((x&1) == 0) return 0; - var y = x&3; // y == 1/x mod 2^2 - y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 - y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 - y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 - // last step - calculate inverse mod DV directly; - // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints - y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits - // we really want the negative inverse, and -DV < y < DV - return (y>0)?this.DV-y:-y; -} - -// Montgomery reduction -function Montgomery(m) { - this.m = m; - this.mp = m.invDigit(); - this.mpl = this.mp&0x7fff; - this.mph = this.mp>>15; - this.um = (1<<(m.DB-15))-1; - this.mt2 = 2*m.t; -} - -// xR mod m -function montConvert(x) { - var r = nbi(); - x.abs().dlShiftTo(this.m.t,r); - r.divRemTo(this.m,null,r); - if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); - return r; -} - -// x/R mod m -function montRevert(x) { - var r = nbi(); - x.copyTo(r); - this.reduce(r); - return r; -} - -// x = x/R mod m (HAC 14.32) -function montReduce(x) { - while(x.t <= this.mt2) // pad x so am has enough room later - x[x.t++] = 0; - for(var i = 0; i < this.m.t; ++i) { - // faster way of calculating u0 = x[i]*mp mod DV - var j = x[i]&0x7fff; - var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM; - // use am to combine the multiply-shift-add into one call - j = i+this.m.t; - x[j] += this.m.am(0,u0,x,i,0,this.m.t); - // propagate carry - while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } - } - x.clamp(); - x.drShiftTo(this.m.t,x); - if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); -} - -// r = "x^2/R mod m"; x != r -function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - -// r = "xy/R mod m"; x,y != r -function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } - -Montgomery.prototype.convert = montConvert; -Montgomery.prototype.revert = montRevert; -Montgomery.prototype.reduce = montReduce; -Montgomery.prototype.mulTo = montMulTo; -Montgomery.prototype.sqrTo = montSqrTo; - -// (protected) true iff this is even -function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; } - -// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) -function bnpExp(e,z) { - if(e > 0xffffffff || e < 1) return BigInteger.ONE; - var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; - g.copyTo(r); - while(--i >= 0) { - z.sqrTo(r,r2); - if((e&(1<<i)) > 0) z.mulTo(r2,g,r); - else { var t = r; r = r2; r2 = t; } - } - return z.revert(r); -} - -// (public) this^e % m, 0 <= e < 2^32 -function bnModPowInt(e,m) { - var z; - if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); - return this.exp(e,z); -} - -// protected -BigInteger.prototype.copyTo = bnpCopyTo; -BigInteger.prototype.fromInt = bnpFromInt; -BigInteger.prototype.fromString = bnpFromString; -BigInteger.prototype.clamp = bnpClamp; -BigInteger.prototype.dlShiftTo = bnpDLShiftTo; -BigInteger.prototype.drShiftTo = bnpDRShiftTo; -BigInteger.prototype.lShiftTo = bnpLShiftTo; -BigInteger.prototype.rShiftTo = bnpRShiftTo; -BigInteger.prototype.subTo = bnpSubTo; -BigInteger.prototype.multiplyTo = bnpMultiplyTo; -BigInteger.prototype.squareTo = bnpSquareTo; -BigInteger.prototype.divRemTo = bnpDivRemTo; -BigInteger.prototype.invDigit = bnpInvDigit; -BigInteger.prototype.isEven = bnpIsEven; -BigInteger.prototype.exp = bnpExp; - -// public -BigInteger.prototype.toString = bnToString; -BigInteger.prototype.negate = bnNegate; -BigInteger.prototype.abs = bnAbs; -BigInteger.prototype.compareTo = bnCompareTo; -BigInteger.prototype.bitLength = bnBitLength; -BigInteger.prototype.mod = bnMod; -BigInteger.prototype.modPowInt = bnModPowInt; - -// "constants" -BigInteger.ZERO = nbv(0); -BigInteger.ONE = nbv(1); diff --git a/plugins/kimchi/ui/spice-html5/thirdparty/prng4.js b/plugins/kimchi/ui/spice-html5/thirdparty/prng4.js deleted file mode 100644 index 4715372..0000000 --- a/plugins/kimchi/ui/spice-html5/thirdparty/prng4.js +++ /dev/null @@ -1,79 +0,0 @@ -// Downloaded from http://www-cs-students.stanford.edu/~tjw/jsbn/ by Jeremy White on 6/1/2012 - -/* - * Copyright (c) 2003-2005 Tom Wu - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * In addition, the following condition applies: - * - * All redistributions must retain an intact copy of this copyright notice - * and disclaimer. - */ - - -// prng4.js - uses Arcfour as a PRNG - -function Arcfour() { - this.i = 0; - this.j = 0; - this.S = new Array(); -} - -// Initialize arcfour context from key, an array of ints, each from [0..255] -function ARC4init(key) { - var i, j, t; - for(i = 0; i < 256; ++i) - this.S[i] = i; - j = 0; - for(i = 0; i < 256; ++i) { - j = (j + this.S[i] + key[i % key.length]) & 255; - t = this.S[i]; - this.S[i] = this.S[j]; - this.S[j] = t; - } - this.i = 0; - this.j = 0; -} - -function ARC4next() { - var t; - this.i = (this.i + 1) & 255; - this.j = (this.j + this.S[this.i]) & 255; - t = this.S[this.i]; - this.S[this.i] = this.S[this.j]; - this.S[this.j] = t; - return this.S[(t + this.S[this.i]) & 255]; -} - -Arcfour.prototype.init = ARC4init; -Arcfour.prototype.next = ARC4next; - -// Plug in your RNG constructor here -function prng_newstate() { - return new Arcfour(); -} - -// Pool size must be a multiple of 4 and greater than 32. -// An array of bytes the size of the pool will be passed to init() -var rng_psize = 256; diff --git a/plugins/kimchi/ui/spice-html5/thirdparty/rng.js b/plugins/kimchi/ui/spice-html5/thirdparty/rng.js deleted file mode 100644 index 829a23c..0000000 --- a/plugins/kimchi/ui/spice-html5/thirdparty/rng.js +++ /dev/null @@ -1,102 +0,0 @@ -// Downloaded from http://www-cs-students.stanford.edu/~tjw/jsbn/ by Jeremy White on 6/1/2012 - -/* - * Copyright (c) 2003-2005 Tom Wu - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * In addition, the following condition applies: - * - * All redistributions must retain an intact copy of this copyright notice - * and disclaimer. - */ - - -// Random number generator - requires a PRNG backend, e.g. prng4.js - -// For best results, put code like -// <body onClick='rng_seed_time();' onKeyPress='rng_seed_time();'> -// in your main HTML document. - -var rng_state; -var rng_pool; -var rng_pptr; - -// Mix in a 32-bit integer into the pool -function rng_seed_int(x) { - rng_pool[rng_pptr++] ^= x & 255; - rng_pool[rng_pptr++] ^= (x >> 8) & 255; - rng_pool[rng_pptr++] ^= (x >> 16) & 255; - rng_pool[rng_pptr++] ^= (x >> 24) & 255; - if(rng_pptr >= rng_psize) rng_pptr -= rng_psize; -} - -// Mix in the current time (w/milliseconds) into the pool -function rng_seed_time() { - rng_seed_int(new Date().getTime()); -} - -// Initialize the pool with junk if needed. -if(rng_pool == null) { - rng_pool = new Array(); - rng_pptr = 0; - var t; - if(navigator.appName == "Netscape" && navigator.appVersion < "5" && window.crypto) { - // Extract entropy (256 bits) from NS4 RNG if available - var z = window.crypto.random(32); - for(t = 0; t < z.length; ++t) - rng_pool[rng_pptr++] = z.charCodeAt(t) & 255; - } - while(rng_pptr < rng_psize) { // extract some randomness from Math.random() - t = Math.floor(65536 * Math.random()); - rng_pool[rng_pptr++] = t >>> 8; - rng_pool[rng_pptr++] = t & 255; - } - rng_pptr = 0; - rng_seed_time(); - //rng_seed_int(window.screenX); - //rng_seed_int(window.screenY); -} - -function rng_get_byte() { - if(rng_state == null) { - rng_seed_time(); - rng_state = prng_newstate(); - rng_state.init(rng_pool); - for(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr) - rng_pool[rng_pptr] = 0; - rng_pptr = 0; - //rng_pool = null; - } - // TODO: allow reseeding after first request - return rng_state.next(); -} - -function rng_get_bytes(ba) { - var i; - for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte(); -} - -function SecureRandom() {} - -SecureRandom.prototype.nextBytes = rng_get_bytes; diff --git a/plugins/kimchi/ui/spice-html5/thirdparty/rsa.js b/plugins/kimchi/ui/spice-html5/thirdparty/rsa.js deleted file mode 100644 index 1bbf249..0000000 --- a/plugins/kimchi/ui/spice-html5/thirdparty/rsa.js +++ /dev/null @@ -1,146 +0,0 @@ -// Downloaded from http://www-cs-students.stanford.edu/~tjw/jsbn/ by Jeremy White on 6/1/2012 - -/* - * Copyright (c) 2003-2005 Tom Wu - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * In addition, the following condition applies: - * - * All redistributions must retain an intact copy of this copyright notice - * and disclaimer. - */ - - -// Depends on jsbn.js and rng.js - -// Version 1.1: support utf-8 encoding in pkcs1pad2 - -// convert a (hex) string to a bignum object -function parseBigInt(str,r) { - return new BigInteger(str,r); -} - -function linebrk(s,n) { - var ret = ""; - var i = 0; - while(i + n < s.length) { - ret += s.substring(i,i+n) + "\n"; - i += n; - } - return ret + s.substring(i,s.length); -} - -function byte2Hex(b) { - if(b < 0x10) - return "0" + b.toString(16); - else - return b.toString(16); -} - -// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint -function pkcs1pad2(s,n) { - if(n < s.length + 11) { // TODO: fix for utf-8 - alert("Message too long for RSA"); - return null; - } - var ba = new Array(); - var i = s.length - 1; - while(i >= 0 && n > 0) { - var c = s.charCodeAt(i--); - if(c < 128) { // encode using utf-8 - ba[--n] = c; - } - else if((c > 127) && (c < 2048)) { - ba[--n] = (c & 63) | 128; - ba[--n] = (c >> 6) | 192; - } - else { - ba[--n] = (c & 63) | 128; - ba[--n] = ((c >> 6) & 63) | 128; - ba[--n] = (c >> 12) | 224; - } - } - ba[--n] = 0; - var rng = new SecureRandom(); - var x = new Array(); - while(n > 2) { // random non-zero pad - x[0] = 0; - while(x[0] == 0) rng.nextBytes(x); - ba[--n] = x[0]; - } - ba[--n] = 2; - ba[--n] = 0; - return new BigInteger(ba); -} - -// "empty" RSA key constructor -function RSAKey() { - this.n = null; - this.e = 0; - this.d = null; - this.p = null; - this.q = null; - this.dmp1 = null; - this.dmq1 = null; - this.coeff = null; -} - -// Set the public key fields N and e from hex strings -function RSASetPublic(N,E) { - if(N != null && E != null && N.length > 0 && E.length > 0) { - this.n = parseBigInt(N,16); - this.e = parseInt(E,16); - } - else - alert("Invalid RSA public key"); -} - -// Perform raw public operation on "x": return x^e (mod n) -function RSADoPublic(x) { - return x.modPowInt(this.e, this.n); -} - -// Return the PKCS#1 RSA encryption of "text" as an even-length hex string -function RSAEncrypt(text) { - var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3); - if(m == null) return null; - var c = this.doPublic(m); - if(c == null) return null; - var h = c.toString(16); - if((h.length & 1) == 0) return h; else return "0" + h; -} - -// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string -//function RSAEncryptB64(text) { -// var h = this.encrypt(text); -// if(h) return hex2b64(h); else return null; -//} - -// protected -RSAKey.prototype.doPublic = RSADoPublic; - -// public -RSAKey.prototype.setPublic = RSASetPublic; -RSAKey.prototype.encrypt = RSAEncrypt; -//RSAKey.prototype.encrypt_b64 = RSAEncryptB64; diff --git a/plugins/kimchi/ui/spice-html5/thirdparty/sha1.js b/plugins/kimchi/ui/spice-html5/thirdparty/sha1.js deleted file mode 100644 index 8118cb4..0000000 --- a/plugins/kimchi/ui/spice-html5/thirdparty/sha1.js +++ /dev/null @@ -1,346 +0,0 @@ -/* - * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined - * in FIPS 180-1 - * Version 2.2 Copyright Paul Johnston 2000 - 2009. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * Distributed under the BSD License - * See http://pajhome.org.uk/crypt/md5 for details. - */ - - /* Downloaded 6/1/2012 from the above address by Jeremy White. - License reproduce here for completeness: - -Copyright (c) 1998 - 2009, Paul Johnston & Contributors -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ - -/* - * Configurable variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - */ -var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ -var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ - -/* - * These are the functions you'll usually want to call - * They take string arguments and return either hex or base-64 encoded strings - */ -function hex_sha1(s) { return rstr2hex(rstr_sha1(str2rstr_utf8(s))); } -function b64_sha1(s) { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); } -function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); } -function hex_hmac_sha1(k, d) - { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); } -function b64_hmac_sha1(k, d) - { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); } -function any_hmac_sha1(k, d, e) - { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); } - -/* - * Perform a simple self-test to see if the VM is working - */ -function sha1_vm_test() -{ - return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d"; -} - -/* - * Calculate the SHA1 of a raw string - */ -function rstr_sha1(s) -{ - return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8)); -} - -/* - * Calculate the HMAC-SHA1 of a key and some data (raw strings) - */ -function rstr_hmac_sha1(key, data) -{ - var bkey = rstr2binb(key); - if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8); - - var ipad = Array(16), opad = Array(16); - for(var i = 0; i < 16; i++) - { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - - var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8); - return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160)); -} - -/* - * Convert a raw string to a hex string - */ -function rstr2hex(input) -{ - try { hexcase } catch(e) { hexcase=0; } - var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; - var output = ""; - var x; - for(var i = 0; i < input.length; i++) - { - x = input.charCodeAt(i); - output += hex_tab.charAt((x >>> 4) & 0x0F) - + hex_tab.charAt( x & 0x0F); - } - return output; -} - -/* - * Convert a raw string to a base-64 string - */ -function rstr2b64(input) -{ - try { b64pad } catch(e) { b64pad=''; } - var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - var output = ""; - var len = input.length; - for(var i = 0; i < len; i += 3) - { - var triplet = (input.charCodeAt(i) << 16) - | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) - | (i + 2 < len ? input.charCodeAt(i+2) : 0); - for(var j = 0; j < 4; j++) - { - if(i * 8 + j * 6 > input.length * 8) output += b64pad; - else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); - } - } - return output; -} - -/* - * Convert a raw string to an arbitrary string encoding - */ -function rstr2any(input, encoding) -{ - var divisor = encoding.length; - var remainders = Array(); - var i, q, x, quotient; - - /* Convert to an array of 16-bit big-endian values, forming the dividend */ - var dividend = Array(Math.ceil(input.length / 2)); - for(i = 0; i < dividend.length; i++) - { - dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); - } - - /* - * Repeatedly perform a long division. The binary array forms the dividend, - * the length of the encoding is the divisor. Once computed, the quotient - * forms the dividend for the next step. We stop when the dividend is zero. - * All remainders are stored for later use. - */ - while(dividend.length > 0) - { - quotient = Array(); - x = 0; - for(i = 0; i < dividend.length; i++) - { - x = (x << 16) + dividend[i]; - q = Math.floor(x / divisor); - x -= q * divisor; - if(quotient.length > 0 || q > 0) - quotient[quotient.length] = q; - } - remainders[remainders.length] = x; - dividend = quotient; - } - - /* Convert the remainders to the output string */ - var output = ""; - for(i = remainders.length - 1; i >= 0; i--) - output += encoding.charAt(remainders[i]); - - /* Append leading zero equivalents */ - var full_length = Math.ceil(input.length * 8 / - (Math.log(encoding.length) / Math.log(2))) - for(i = output.length; i < full_length; i++) - output = encoding[0] + output; - - return output; -} - -/* - * Encode a string as utf-8. - * For efficiency, this assumes the input is valid utf-16. - */ -function str2rstr_utf8(input) -{ - var output = ""; - var i = -1; - var x, y; - - while(++i < input.length) - { - /* Decode utf-16 surrogate pairs */ - x = input.charCodeAt(i); - y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; - if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) - { - x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); - i++; - } - - /* Encode output as utf-8 */ - if(x <= 0x7F) - output += String.fromCharCode(x); - else if(x <= 0x7FF) - output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), - 0x80 | ( x & 0x3F)); - else if(x <= 0xFFFF) - output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), - 0x80 | ((x >>> 6 ) & 0x3F), - 0x80 | ( x & 0x3F)); - else if(x <= 0x1FFFFF) - output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), - 0x80 | ((x >>> 12) & 0x3F), - 0x80 | ((x >>> 6 ) & 0x3F), - 0x80 | ( x & 0x3F)); - } - return output; -} - -/* - * Encode a string as utf-16 - */ -function str2rstr_utf16le(input) -{ - var output = ""; - for(var i = 0; i < input.length; i++) - output += String.fromCharCode( input.charCodeAt(i) & 0xFF, - (input.charCodeAt(i) >>> 8) & 0xFF); - return output; -} - -function str2rstr_utf16be(input) -{ - var output = ""; - for(var i = 0; i < input.length; i++) - output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, - input.charCodeAt(i) & 0xFF); - return output; -} - -/* - * Convert a raw string to an array of big-endian words - * Characters >255 have their high-byte silently ignored. - */ -function rstr2binb(input) -{ - var output = Array(input.length >> 2); - for(var i = 0; i < output.length; i++) - output[i] = 0; - for(var i = 0; i < input.length * 8; i += 8) - output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32); - return output; -} - -/* - * Convert an array of big-endian words to a string - */ -function binb2rstr(input) -{ - var output = ""; - for(var i = 0; i < input.length * 32; i += 8) - output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF); - return output; -} - -/* - * Calculate the SHA-1 of an array of big-endian words, and a bit length - */ -function binb_sha1(x, len) -{ - /* append padding */ - x[len >> 5] |= 0x80 << (24 - len % 32); - x[((len + 64 >> 9) << 4) + 15] = len; - - var w = Array(80); - var a = 1732584193; - var b = -271733879; - var c = -1732584194; - var d = 271733878; - var e = -1009589776; - - for(var i = 0; i < x.length; i += 16) - { - var olda = a; - var oldb = b; - var oldc = c; - var oldd = d; - var olde = e; - - for(var j = 0; j < 80; j++) - { - if(j < 16) w[j] = x[i + j]; - else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); - var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)), - safe_add(safe_add(e, w[j]), sha1_kt(j))); - e = d; - d = c; - c = bit_rol(b, 30); - b = a; - a = t; - } - - a = safe_add(a, olda); - b = safe_add(b, oldb); - c = safe_add(c, oldc); - d = safe_add(d, oldd); - e = safe_add(e, olde); - } - return Array(a, b, c, d, e); - -} - -/* - * Perform the appropriate triplet combination function for the current - * iteration - */ -function sha1_ft(t, b, c, d) -{ - if(t < 20) return (b & c) | ((~b) & d); - if(t < 40) return b ^ c ^ d; - if(t < 60) return (b & c) | (b & d) | (c & d); - return b ^ c ^ d; -} - -/* - * Determine the appropriate additive constant for the current iteration - */ -function sha1_kt(t) -{ - return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : - (t < 60) ? -1894007588 : -899497514; -} - -/* - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ -function safe_add(x, y) -{ - var lsw = (x & 0xFFFF) + (y & 0xFFFF); - var msw = (x >> 16) + (y >> 16) + (lsw >> 16); - return (msw << 16) | (lsw & 0xFFFF); -} - -/* - * Bitwise rotate a 32-bit number to the left. - */ -function bit_rol(num, cnt) -{ - return (num << cnt) | (num >>> (32 - cnt)); -} diff --git a/plugins/kimchi/ui/spice-html5/ticket.js b/plugins/kimchi/ui/spice-html5/ticket.js deleted file mode 100644 index 96577a3..0000000 --- a/plugins/kimchi/ui/spice-html5/ticket.js +++ /dev/null @@ -1,250 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -var SHA_DIGEST_LENGTH = 20; - -/*---------------------------------------------------------------------------- -** General ticket RSA encryption functions - just good enough to -** support what we need to send back an encrypted ticket. -**--------------------------------------------------------------------------*/ - - -/*---------------------------------------------------------------------------- -** OAEP padding functions. Inspired by the OpenSSL implementation. -**--------------------------------------------------------------------------*/ -function MGF1(mask, seed) -{ - var i, j, outlen; - for (i = 0, outlen = 0; outlen < mask.length; i++) - { - var combo_buf = new String; - - for (j = 0; j < seed.length; j++) - combo_buf += String.fromCharCode(seed[j]); - combo_buf += String.fromCharCode((i >> 24) & 255); - combo_buf += String.fromCharCode((i >> 16) & 255); - combo_buf += String.fromCharCode((i >> 8) & 255); - combo_buf += String.fromCharCode((i) & 255); - - var combo_hash = rstr_sha1(combo_buf); - for (j = 0; j < combo_hash.length && outlen < mask.length; j++, outlen++) - { - mask[outlen] = combo_hash.charCodeAt(j); - } - } -} - - -function RSA_padding_add_PKCS1_OAEP(tolen, from, param) -{ - var seed = new Array(SHA_DIGEST_LENGTH); - var rand = new SecureRandom(); - rand.nextBytes(seed); - - var dblen = tolen - 1 - seed.length; - var db = new Array(dblen); - var padlen = dblen - from.length - 1; - var i; - - if (param === undefined) - param = ""; - - if (padlen < SHA_DIGEST_LENGTH) - { - console.log("Error - data too large for key size."); - return null; - } - - for (i = 0; i < padlen; i++) - db[i] = 0; - - var param_hash = rstr_sha1(param); - for (i = 0; i < param_hash.length; i++) - db[i] = param_hash.charCodeAt(i); - - db[padlen] = 1; - for (i = 0; i < from.length; i++) - db[i + padlen + 1] = from.charCodeAt(i); - - var dbmask = new Array(dblen); - if (MGF1(dbmask, seed) < 0) - return null; - - for (i = 0; i < dbmask.length; i++) - db[i] ^= dbmask[i]; - - - var seedmask = Array(SHA_DIGEST_LENGTH); - if (MGF1(seedmask, db) < 0) - return null; - - for (i = 0; i < seedmask.length; i++) - seed[i] ^= seedmask[i]; - - var ret = new String; - ret += String.fromCharCode(0); - for (i = 0; i < seed.length; i++) - ret += String.fromCharCode(seed[i]); - for (i = 0; i < db.length; i++) - ret += String.fromCharCode(db[i]); - return ret; -} - - -function asn_get_length(u8, at) -{ - var len = u8[at++]; - if (len > 0x80) - { - if (len != 0x81) - { - console.log("Error: we lazily don't support keys bigger than 255 bytes. It'd be easy to fix."); - return null; - } - len = u8[at++]; - } - - return [ at, len]; -} - -function find_sequence(u8, at) -{ - var lenblock; - at = at || 0; - if (u8[at++] != 0x30) - { - console.log("Error: public key should start with a sequence flag."); - return null; - } - - lenblock = asn_get_length(u8, at); - if (! lenblock) - return null; - return lenblock; -} - -/*---------------------------------------------------------------------------- -** Extract an RSA key from a memory buffer -**--------------------------------------------------------------------------*/ -function create_rsa_from_mb(mb, at) -{ - var u8 = new Uint8Array(mb); - var lenblock; - var seq; - var ba; - var i; - var ret; - - /* We have a sequence which contains a sequence followed by a bit string */ - seq = find_sequence(u8, at); - if (! seq) - return null; - - at = seq[0]; - seq = find_sequence(u8, at); - if (! seq) - return null; - - /* Skip over the contained sequence */ - at = seq[0] + seq[1]; - if (u8[at++] != 0x3) - { - console.log("Error: expecting bit string next."); - return null; - } - - /* Get the bit string, which is *itself* a sequence. Having fun yet? */ - lenblock = asn_get_length(u8, at); - if (! lenblock) - return null; - - at = lenblock[0]; - if (u8[at] != 0 && u8[at + 1] != 0x30) - { - console.log("Error: unexpected values in bit string."); - return null; - } - - /* Okay, now we have a sequence of two binary values, we hope. */ - seq = find_sequence(u8, at + 1); - if (! seq) - return null; - - at = seq[0]; - if (u8[at++] != 0x02) - { - console.log("Error: expecting integer n next."); - return null; - } - lenblock = asn_get_length(u8, at); - if (! lenblock) - return null; - at = lenblock[0]; - - ba = new Array(lenblock[1]); - for (i = 0; i < lenblock[1]; i++) - ba[i] = u8[at + i]; - - ret = new RSAKey(); - ret.n = new BigInteger(ba); - - at += lenblock[1]; - - if (u8[at++] != 0x02) - { - console.log("Error: expecting integer e next."); - return null; - } - lenblock = asn_get_length(u8, at); - if (! lenblock) - return null; - at = lenblock[0]; - - ret.e = u8[at++]; - for (i = 1; i < lenblock[1]; i++) - { - ret.e <<= 8; - ret.e |= u8[at++]; - } - - return ret; -} - -function rsa_encrypt(rsa, str) -{ - var i; - var ret = []; - var oaep = RSA_padding_add_PKCS1_OAEP((rsa.n.bitLength()+7)>>3, str); - if (! oaep) - return null; - - var ba = new Array(oaep.length); - - for (i = 0; i < oaep.length; i++) - ba[i] = oaep.charCodeAt(i); - var bigint = new BigInteger(ba); - var enc = rsa.doPublic(bigint); - var h = enc.toString(16); - if ((h.length & 1) != 0) - h = "0" + h; - for (i = 0; i < h.length; i += 2) - ret[i / 2] = parseInt(h.substring(i, i + 2), 16); - return ret; -} diff --git a/plugins/kimchi/ui/spice-html5/utils.js b/plugins/kimchi/ui/spice-html5/utils.js deleted file mode 100644 index 9eb42ff..0000000 --- a/plugins/kimchi/ui/spice-html5/utils.js +++ /dev/null @@ -1,265 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*---------------------------------------------------------------------------- -** Utility settings and functions for Spice -**--------------------------------------------------------------------------*/ -var DEBUG = 0; -var DUMP_DRAWS = false; -var DUMP_CANVASES = false; - - -/*---------------------------------------------------------------------------- -** combine_array_buffers -** Combine two array buffers. -** FIXME - this can't be optimal. See wire.js about eliminating the need. -**--------------------------------------------------------------------------*/ -function combine_array_buffers(a1, a2) -{ - var in1 = new Uint8Array(a1); - var in2 = new Uint8Array(a2); - var ret = new ArrayBuffer(a1.byteLength + a2.byteLength); - var out = new Uint8Array(ret); - var o = 0; - var i; - for (i = 0; i < in1.length; i++) - out[o++] = in1[i]; - for (i = 0; i < in2.length; i++) - out[o++] = in2[i]; - - return ret; -} - -/*---------------------------------------------------------------------------- -** hexdump_buffer -**--------------------------------------------------------------------------*/ -function hexdump_buffer(a) -{ - var mg = new Uint8Array(a); - var hex = ""; - var str = ""; - var last_zeros = 0; - for (var i = 0; i < mg.length; i++) - { - var h = Number(mg[i]).toString(16); - if (h.length == 1) - hex += "0"; - hex += h + " "; - - if (mg[i] == 10 || mg[i] == 13 || mg[i] == 8) - str += "."; - else - str += String.fromCharCode(mg[i]); - - if ((i % 16 == 15) || (i == (mg.length - 1))) - { - while (i % 16 != 15) - { - hex += " "; - i++; - } - - if (last_zeros == 0) - console.log(hex + " | " + str); - - if (hex == "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ") - { - if (last_zeros == 1) - { - console.log("."); - last_zeros++; - } - else if (last_zeros == 0) - last_zeros++; - } - else - last_zeros = 0; - - hex = str = ""; - } - } -} - -/*---------------------------------------------------------------------------- -** Converting keycodes to AT scancodes is very hard. -** luckly there are some resources on the web and in the Xorg driver that help -** us figure out what browser depenend keycodes match to what scancodes. -** -** This will most likely not work for non US keyboard and browsers other than -** modern Chrome and FireFox. -**--------------------------------------------------------------------------*/ -var common_scanmap = []; -common_scanmap['Q'.charCodeAt(0)] = KEY_Q; -common_scanmap['W'.charCodeAt(0)] = KEY_W; -common_scanmap['E'.charCodeAt(0)] = KEY_E; -common_scanmap['R'.charCodeAt(0)] = KEY_R; -common_scanmap['T'.charCodeAt(0)] = KEY_T; -common_scanmap['Y'.charCodeAt(0)] = KEY_Y; -common_scanmap['U'.charCodeAt(0)] = KEY_U; -common_scanmap['I'.charCodeAt(0)] = KEY_I; -common_scanmap['O'.charCodeAt(0)] = KEY_O; -common_scanmap['P'.charCodeAt(0)] = KEY_P; -common_scanmap['A'.charCodeAt(0)] = KEY_A; -common_scanmap['S'.charCodeAt(0)] = KEY_S; -common_scanmap['D'.charCodeAt(0)] = KEY_D; -common_scanmap['F'.charCodeAt(0)] = KEY_F; -common_scanmap['G'.charCodeAt(0)] = KEY_G; -common_scanmap['H'.charCodeAt(0)] = KEY_H; -common_scanmap['J'.charCodeAt(0)] = KEY_J; -common_scanmap['K'.charCodeAt(0)] = KEY_K; -common_scanmap['L'.charCodeAt(0)] = KEY_L; -common_scanmap['Z'.charCodeAt(0)] = KEY_Z; -common_scanmap['X'.charCodeAt(0)] = KEY_X; -common_scanmap['C'.charCodeAt(0)] = KEY_C; -common_scanmap['V'.charCodeAt(0)] = KEY_V; -common_scanmap['B'.charCodeAt(0)] = KEY_B; -common_scanmap['N'.charCodeAt(0)] = KEY_N; -common_scanmap['M'.charCodeAt(0)] = KEY_M; -common_scanmap[' '.charCodeAt(0)] = KEY_Space; -common_scanmap[13] = KEY_Enter; -common_scanmap[27] = KEY_Escape; -common_scanmap[8] = KEY_BackSpace; -common_scanmap[9] = KEY_Tab; -common_scanmap[16] = KEY_ShiftL; -common_scanmap[17] = KEY_LCtrl; -common_scanmap[18] = KEY_Alt; -common_scanmap[20] = KEY_CapsLock; -common_scanmap[144] = KEY_NumLock; -common_scanmap[112] = KEY_F1; -common_scanmap[113] = KEY_F2; -common_scanmap[114] = KEY_F3; -common_scanmap[115] = KEY_F4; -common_scanmap[116] = KEY_F5; -common_scanmap[117] = KEY_F6; -common_scanmap[118] = KEY_F7; -common_scanmap[119] = KEY_F8; -common_scanmap[120] = KEY_F9; -common_scanmap[121] = KEY_F10; -common_scanmap[122] = KEY_F11; -common_scanmap[123] = KEY_F12; - -/* These externded scancodes do not line up with values from atKeynames */ -common_scanmap[42] = 99; -common_scanmap[19] = 101; // Break -common_scanmap[111] = 0xE035; // KP_Divide -common_scanmap[106] = 0xE037; // KP_Multiply -common_scanmap[36] = 0xE047; // Home -common_scanmap[38] = 0xE048; // Up -common_scanmap[33] = 0xE049; // PgUp -common_scanmap[37] = 0xE04B; // Left -common_scanmap[39] = 0xE04D; // Right -common_scanmap[35] = 0xE04F; // End -common_scanmap[40] = 0xE050; // Down -common_scanmap[34] = 0xE051; // PgDown -common_scanmap[45] = 0xE052; // Insert -common_scanmap[46] = 0xE053; // Delete -common_scanmap[44] = 0x2A37; // Print - -/* These are not common between ALL browsers but are between Firefox and DOM3 */ -common_scanmap['1'.charCodeAt(0)] = KEY_1; -common_scanmap['2'.charCodeAt(0)] = KEY_2; -common_scanmap['3'.charCodeAt(0)] = KEY_3; -common_scanmap['4'.charCodeAt(0)] = KEY_4; -common_scanmap['5'.charCodeAt(0)] = KEY_5; -common_scanmap['6'.charCodeAt(0)] = KEY_6; -common_scanmap['7'.charCodeAt(0)] = KEY_7; -common_scanmap['8'.charCodeAt(0)] = KEY_8; -common_scanmap['9'.charCodeAt(0)] = KEY_9; -common_scanmap['0'.charCodeAt(0)] = KEY_0; -common_scanmap[145] = KEY_ScrollLock; -common_scanmap[103] = KEY_KP_7; -common_scanmap[104] = KEY_KP_8; -common_scanmap[105] = KEY_KP_9; -common_scanmap[100] = KEY_KP_4; -common_scanmap[101] = KEY_KP_5; -common_scanmap[102] = KEY_KP_6; -common_scanmap[107] = KEY_KP_Plus; -common_scanmap[97] = KEY_KP_1; -common_scanmap[98] = KEY_KP_2; -common_scanmap[99] = KEY_KP_3; -common_scanmap[96] = KEY_KP_0; -common_scanmap[110] = KEY_KP_Decimal; -common_scanmap[191] = KEY_Slash; -common_scanmap[190] = KEY_Period; -common_scanmap[188] = KEY_Comma; -common_scanmap[220] = KEY_BSlash; -common_scanmap[192] = KEY_Tilde; -common_scanmap[222] = KEY_Quote; -common_scanmap[219] = KEY_LBrace; -common_scanmap[221] = KEY_RBrace; - -common_scanmap[91] = 0xE05B; //KEY_LMeta -common_scanmap[92] = 0xE05C; //KEY_RMeta -common_scanmap[93] = 0xE05D; //KEY_Menu - -/* Firefox/Mozilla codes */ -var firefox_scanmap = []; -firefox_scanmap[173] = KEY_Minus; -firefox_scanmap[109] = KEY_Minus; -firefox_scanmap[61] = KEY_Equal; -firefox_scanmap[59] = KEY_SemiColon; - -/* DOM3 codes */ -var DOM_scanmap = []; -DOM_scanmap[189] = KEY_Minus; -DOM_scanmap[187] = KEY_Equal; -DOM_scanmap[186] = KEY_SemiColon; - -function get_scancode(code) -{ - if (common_scanmap[code] === undefined) - { - if (navigator.userAgent.indexOf("Firefox") != -1) - return firefox_scanmap[code]; - else - return DOM_scanmap[code]; - } - else - return common_scanmap[code]; -} - -function keycode_to_start_scan(code) -{ - var scancode = get_scancode(code); - if (scancode === undefined) - { - alert('no map for ' + code); - return 0; - } - - if (scancode < 0x100) { - return scancode; - } else { - return 0xe0 | ((scancode - 0x100) << 8); - } -} - -function keycode_to_end_scan(code) -{ - var scancode = get_scancode(code); - if (scancode === undefined) - return 0; - - if (scancode < 0x100) { - return scancode | 0x80; - } else { - return 0x80e0 | ((scancode - 0x100) << 8); - } -} diff --git a/plugins/kimchi/ui/spice-html5/webm.js b/plugins/kimchi/ui/spice-html5/webm.js deleted file mode 100644 index 35cbc07..0000000 --- a/plugins/kimchi/ui/spice-html5/webm.js +++ /dev/null @@ -1,553 +0,0 @@ -"use strict"; -/* - Copyright (C) 2014 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - - -/*---------------------------------------------------------------------------- -** EBML identifiers -**--------------------------------------------------------------------------*/ -var EBML_HEADER = [ 0x1a, 0x45, 0xdf, 0xa3 ]; -var EBML_HEADER_VERSION = [ 0x42, 0x86 ]; -var EBML_HEADER_READ_VERSION = [ 0x42, 0xf7 ]; -var EBML_HEADER_MAX_ID_LENGTH = [ 0x42, 0xf2 ]; -var EBML_HEADER_MAX_SIZE_LENGTH = [ 0x42, 0xf3 ]; -var EBML_HEADER_DOC_TYPE = [ 0x42, 0x82 ]; -var EBML_HEADER_DOC_TYPE_VERSION = [ 0x42, 0x87 ]; -var EBML_HEADER_DOC_TYPE_READ_VERSION = [ 0x42, 0x85 ]; - -var WEBM_SEGMENT_HEADER = [ 0x18, 0x53, 0x80, 0x67 ]; -var WEBM_SEGMENT_INFORMATION = [ 0x15, 0x49, 0xA9, 0x66 ]; - -var WEBM_TIMECODE_SCALE = [ 0x2A, 0xD7, 0xB1 ]; -var WEBM_MUXING_APP = [ 0x4D, 0x80 ]; -var WEBM_WRITING_APP = [ 0x57, 0x41 ]; - -var WEBM_SEEK_HEAD = [ 0x11, 0x4D, 0x9B, 0x74 ]; -var WEBM_SEEK = [ 0x4D, 0xBB ]; -var WEBM_SEEK_ID = [ 0x53, 0xAB ]; -var WEBM_SEEK_POSITION = [ 0x53, 0xAC ]; - -var WEBM_TRACKS = [ 0x16, 0x54, 0xAE, 0x6B ]; -var WEBM_TRACK_ENTRY = [ 0xAE ]; -var WEBM_TRACK_NUMBER = [ 0xD7 ]; -var WEBM_TRACK_UID = [ 0x73, 0xC5 ]; -var WEBM_TRACK_TYPE = [ 0x83 ]; -var WEBM_FLAG_ENABLED = [ 0xB9 ]; -var WEBM_FLAG_DEFAULT = [ 0x88 ]; -var WEBM_FLAG_FORCED = [ 0x55, 0xAA ]; -var WEBM_FLAG_LACING = [ 0x9C ]; -var WEBM_MIN_CACHE = [ 0x6D, 0xE7 ]; - -var WEBM_MAX_BLOCK_ADDITION_ID = [ 0x55, 0xEE ]; -var WEBM_CODEC_DECODE_ALL = [ 0xAA ]; -var WEBM_SEEK_PRE_ROLL = [ 0x56, 0xBB ]; -var WEBM_CODEC_DELAY = [ 0x56, 0xAA ]; -var WEBM_CODEC_PRIVATE = [ 0x63, 0xA2 ]; -var WEBM_CODEC_ID = [ 0x86 ]; - -var WEBM_AUDIO = [ 0xE1 ] ; -var WEBM_SAMPLING_FREQUENCY = [ 0xB5 ] ; -var WEBM_CHANNELS = [ 0x9F ] ; - -var WEBM_CLUSTER = [ 0x1F, 0x43, 0xB6, 0x75 ]; -var WEBM_TIME_CODE = [ 0xE7 ] ; -var WEBM_SIMPLE_BLOCK = [ 0xA3 ] ; - -/*---------------------------------------------------------------------------- -** Various OPUS / Webm constants -**--------------------------------------------------------------------------*/ -var CLUSTER_SIMPLEBLOCK_FLAG_KEYFRAME = 1 << 7; - -var OPUS_FREQUENCY = 48000; -var OPUS_CHANNELS = 2; - -var SPICE_PLAYBACK_CODEC = 'audio/webm; codecs="opus"'; -var MAX_CLUSTER_TIME = 1000; - -var GAP_DETECTION_THRESHOLD = 50; - -/*---------------------------------------------------------------------------- -** EBML utility functions -** These classes can create the binary representation of a webm file -**--------------------------------------------------------------------------*/ -function EBML_write_u1_data_len(len, dv, at) -{ - var b = 0x80 | len; - dv.setUint8(at, b); - return at + 1; -} - -function EBML_write_u8_value(id, val, dv, at) -{ - at = EBML_write_array(id, dv, at); - at = EBML_write_u1_data_len(1, dv, at); - dv.setUint8(at, val); - return at + 1; -} - -function EBML_write_u32_value(id, val, dv, at) -{ - at = EBML_write_array(id, dv, at); - at = EBML_write_u1_data_len(4, dv, at); - dv.setUint32(at, val); - return at + 4; -} - -function EBML_write_u16_value(id, val, dv, at) -{ - at = EBML_write_array(id, dv, at); - at = EBML_write_u1_data_len(2, dv, at); - dv.setUint16(at, val); - return at + 2; -} - -function EBML_write_float_value(id, val, dv, at) -{ - at = EBML_write_array(id, dv, at); - at = EBML_write_u1_data_len(4, dv, at); - dv.setFloat32(at, val); - return at + 4; -} - - - -function EBML_write_u64_data_len(len, dv, at) -{ - /* Javascript doesn't do 64 bit ints, so this cheats and - just has a max of 32 bits. Fine for our purposes */ - dv.setUint8(at++, 0x01); - dv.setUint8(at++, 0x00); - dv.setUint8(at++, 0x00); - dv.setUint8(at++, 0x00); - var val = len & 0xFFFFFFFF; - for (var shift = 24; shift >= 0; shift -= 8) - dv.setUint8(at++, val >> shift); - return at; -} - -function EBML_write_array(arr, dv, at) -{ - for (var i = 0; i < arr.length; i++) - dv.setUint8(at + i, arr[i]); - return at + arr.length; -} - -function EBML_write_string(str, dv, at) -{ - for (var i = 0; i < str.length; i++) - dv.setUint8(at + i, str.charCodeAt(i)); - return at + str.length; -} - -function EBML_write_data(id, data, dv, at) -{ - at = EBML_write_array(id, dv, at); - if (data.length < 127) - at = EBML_write_u1_data_len(data.length, dv, at); - else - at = EBML_write_u64_data_len(data.length, dv, at); - if ((typeof data) == "string") - at = EBML_write_string(data, dv, at); - else - at = EBML_write_array(data, dv, at); - return at; -} - -/*---------------------------------------------------------------------------- -** Webm objects -** These classes can create the binary representation of a webm file -**--------------------------------------------------------------------------*/ -function EBMLHeader() -{ - this.id = EBML_HEADER; - this.Version = 1; - this.ReadVersion = 1; - this.MaxIDLength = 4; - this.MaxSizeLength = 8; - this.DocType = "webm"; - this.DocTypeVersion = 2; /* Not well specified by the WebM guys, but functionally required for Firefox */ - this.DocTypeReadVersion = 2; -} - -EBMLHeader.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new DataView(a); - - at = EBML_write_array(this.id, dv, at); - at = EBML_write_u64_data_len(0x1f, dv, at); - at = EBML_write_u8_value(EBML_HEADER_VERSION, this.Version, dv, at); - at = EBML_write_u8_value(EBML_HEADER_READ_VERSION, this.ReadVersion, dv, at); - at = EBML_write_u8_value(EBML_HEADER_MAX_ID_LENGTH, this.MaxIDLength, dv, at); - at = EBML_write_u8_value(EBML_HEADER_MAX_SIZE_LENGTH, this.MaxSizeLength, dv, at); - at = EBML_write_data(EBML_HEADER_DOC_TYPE, this.DocType, dv, at); - at = EBML_write_u8_value(EBML_HEADER_DOC_TYPE_VERSION, this.DocTypeVersion, dv, at); - at = EBML_write_u8_value(EBML_HEADER_DOC_TYPE_READ_VERSION, this.DocTypeReadVersion, dv, at); - - return at; - }, - buffer_size: function() - { - return 0x1f + 8 + this.id.length; - }, -} - -function webm_Segment() -{ - this.id = WEBM_SEGMENT_HEADER; -} - -webm_Segment.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new DataView(a); - - at = EBML_write_array(this.id, dv, at); - dv.setUint8(at++, 0xff); - return at; - }, - buffer_size: function() - { - return this.id.length + 1; - }, -} - -function webm_SegmentInformation() -{ - this.id = WEBM_SEGMENT_INFORMATION; - this.timecode_scale = 1000000; /* 1 ms */ - this.muxing_app = "spice"; - this.writing_app = "spice-html5"; - -} - -webm_SegmentInformation.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new DataView(a); - - at = EBML_write_array(this.id, dv, at); - at = EBML_write_u64_data_len(this.buffer_size() - 8 - this.id.length, dv, at); - at = EBML_write_u32_value(WEBM_TIMECODE_SCALE, this.timecode_scale, dv, at); - at = EBML_write_data(WEBM_MUXING_APP, this.muxing_app, dv, at); - at = EBML_write_data(WEBM_WRITING_APP, this.writing_app, dv, at); - return at; - }, - buffer_size: function() - { - return this.id.length + 8 + - WEBM_TIMECODE_SCALE.length + 1 + 4 + - WEBM_MUXING_APP.length + 1 + this.muxing_app.length + - WEBM_WRITING_APP.length + 1 + this.writing_app.length; - }, -} - -function webm_Audio(frequency) -{ - this.id = WEBM_AUDIO; - this.sampling_frequency = frequency; - this.channels = OPUS_CHANNELS; -} - -webm_Audio.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new DataView(a); - at = EBML_write_array(this.id, dv, at); - at = EBML_write_u64_data_len(this.buffer_size() - 8 - this.id.length, dv, at); - at = EBML_write_u8_value(WEBM_CHANNELS, this.channels, dv, at); - at = EBML_write_float_value(WEBM_SAMPLING_FREQUENCY, this.sampling_frequency, dv, at); - return at; - }, - buffer_size: function() - { - return this.id.length + 8 + - WEBM_SAMPLING_FREQUENCY.length + 1 + 4 + - WEBM_CHANNELS.length + 1 + 1; - }, -} - - -/* --------------------------- - SeekHead not currently used. Hopefully not needed. -*/ -function webm_Seek(seekid, pos) -{ - this.id = WEBM_SEEK; - this.pos = pos; - this.seekid = seekid; -} - -webm_Seek.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new DataView(a); - at = EBML_write_array(this.id, dv, at); - at = EBML_write_u1_data_len(this.buffer_size() - 1 - this.id.length, dv, at); - - at = EBML_write_data(WEBM_SEEK_ID, this.seekid, dv, at) - at = EBML_write_u16_value(WEBM_SEEK_POSITION, this.pos, dv, at) - - return at; - }, - buffer_size: function() - { - return this.id.length + 1 + - WEBM_SEEK_ID.length + 1 + this.seekid.length + - WEBM_SEEK_POSITION.length + 1 + 2; - }, -} -function webm_SeekHead(info_pos, track_pos) -{ - this.id = WEBM_SEEK_HEAD; - this.info = new webm_Seek(WEBM_SEGMENT_INFORMATION, info_pos); - this.track = new webm_Seek(WEBM_TRACKS, track_pos); -} - -webm_SeekHead.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new DataView(a); - at = EBML_write_array(this.id, dv, at); - at = EBML_write_u64_data_len(this.buffer_size() - 8 - this.id.length, dv, at); - - at = this.info.to_buffer(a, at); - at = this.track.to_buffer(a, at); - - return at; - }, - buffer_size: function() - { - return this.id.length + 8 + - this.info.buffer_size() + - this.track.buffer_size(); - }, -} - -/* ------------------------------- - End of Seek Head -*/ - -function webm_TrackEntry() -{ - this.id = WEBM_TRACK_ENTRY; - this.number = 1; - this.uid = 1; - this.type = 2; // Audio - this.flag_enabled = 1; - this.flag_default = 1; - this.flag_forced = 1; - this.flag_lacing = 0; - this.min_cache = 0; // fixme - check - this.max_block_addition_id = 0; - this.codec_decode_all = 0; // fixme - check - this.seek_pre_roll = 0; // 80000000; // fixme - check - this.codec_delay = 80000000; // Must match codec_private.preskip - this.codec_id = "A_OPUS"; - this.audio = new webm_Audio(OPUS_FREQUENCY); - - // See: http://tools.ietf.org/html/draft-terriberry-oggopus-01 - this.codec_private = [ 0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, // OpusHead - 0x01, // Version - OPUS_CHANNELS, - 0x00, 0x0F, // Preskip - 3840 samples - should be 8ms at 48kHz - 0x80, 0xbb, 0x00, 0x00, // 48000 - 0x00, 0x00, // Output gain - 0x00 // Channel mapping family - ]; -} - -webm_TrackEntry.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new DataView(a); - at = EBML_write_array(this.id, dv, at); - at = EBML_write_u64_data_len(this.buffer_size() - 8 - this.id.length, dv, at); - at = EBML_write_u8_value(WEBM_TRACK_NUMBER, this.number, dv, at); - at = EBML_write_u8_value(WEBM_TRACK_UID, this.uid, dv, at); - at = EBML_write_u8_value(WEBM_FLAG_ENABLED, this.flag_enabled, dv, at); - at = EBML_write_u8_value(WEBM_FLAG_DEFAULT, this.flag_default, dv, at); - at = EBML_write_u8_value(WEBM_FLAG_FORCED, this.flag_forced, dv, at); - at = EBML_write_u8_value(WEBM_FLAG_LACING, this.flag_lacing, dv, at); - at = EBML_write_data(WEBM_CODEC_ID, this.codec_id, dv, at); - at = EBML_write_u8_value(WEBM_MIN_CACHE, this.min_cache, dv, at); - at = EBML_write_u8_value(WEBM_MAX_BLOCK_ADDITION_ID, this.max_block_addition_id, dv, at); - at = EBML_write_u8_value(WEBM_CODEC_DECODE_ALL, this.codec_decode_all, dv, at); - at = EBML_write_u32_value(WEBM_CODEC_DELAY, this.codec_delay, dv, at); - at = EBML_write_u32_value(WEBM_SEEK_PRE_ROLL, this.seek_pre_roll, dv, at); - at = EBML_write_u8_value(WEBM_TRACK_TYPE, this.type, dv, at); - at = EBML_write_data(WEBM_CODEC_PRIVATE, this.codec_private, dv, at); - - at = this.audio.to_buffer(a, at); - return at; - }, - buffer_size: function() - { - return this.id.length + 8 + - WEBM_TRACK_NUMBER.length + 1 + 1 + - WEBM_TRACK_UID.length + 1 + 1 + - WEBM_TRACK_TYPE.length + 1 + 1 + - WEBM_FLAG_ENABLED.length + 1 + 1 + - WEBM_FLAG_DEFAULT.length + 1 + 1 + - WEBM_FLAG_FORCED.length + 1 + 1 + - WEBM_FLAG_LACING.length + 1 + 1 + - WEBM_MIN_CACHE.length + 1 + 1 + - WEBM_MAX_BLOCK_ADDITION_ID.length + 1 + 1 + - WEBM_CODEC_DECODE_ALL.length + 1 + 1 + - WEBM_SEEK_PRE_ROLL.length + 1 + 4 + - WEBM_CODEC_DELAY.length + 1 + 4 + - WEBM_CODEC_ID.length + this.codec_id.length + 1 + - WEBM_CODEC_PRIVATE.length + 1 + this.codec_private.length + - this.audio.buffer_size(); - }, -} -function webm_Tracks(entry) -{ - this.id = WEBM_TRACKS; - this.track_entry = entry; -} - -webm_Tracks.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new DataView(a); - at = EBML_write_array(this.id, dv, at); - at = EBML_write_u64_data_len(this.buffer_size() - 8 - this.id.length, dv, at); - at = this.track_entry.to_buffer(a, at); - return at; - }, - buffer_size: function() - { - return this.id.length + 8 + - this.track_entry.buffer_size(); - }, -} - -function webm_Cluster(timecode, data) -{ - this.id = WEBM_CLUSTER; - this.timecode = timecode; - this.data = data; -} - -webm_Cluster.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new DataView(a); - at = EBML_write_array(this.id, dv, at); - dv.setUint8(at++, 0xff); - at = EBML_write_u32_value(WEBM_TIME_CODE, this.timecode, dv, at); - return at; - }, - buffer_size: function() - { - return this.id.length + 1 + - WEBM_TIME_CODE.length + 1 + 4; - }, -} - -function webm_SimpleBlock(timecode, data, keyframe) -{ - this.id = WEBM_SIMPLE_BLOCK; - this.timecode = timecode; - this.data = data; - this.keyframe = keyframe; -} - -webm_SimpleBlock.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var dv = new DataView(a); - at = EBML_write_array(this.id, dv, at); - at = EBML_write_u64_data_len(this.data.byteLength + 4, dv, at); - at = EBML_write_u1_data_len(1, dv, at); // Track # - dv.setUint16(at, this.timecode); at += 2; // timecode - relative to cluster - dv.setUint8(at, this.keyframe ? CLUSTER_SIMPLEBLOCK_FLAG_KEYFRAME : 0); at += 1; // flags - - // FIXME - There should be a better way to copy - var u8 = new Uint8Array(this.data); - for (var i = 0; i < this.data.byteLength; i++) - dv.setUint8(at++, u8[i]); - - return at; - }, - buffer_size: function() - { - return this.id.length + 8 + - 1 + 2 + 1 + - this.data.byteLength; - }, -} - -function webm_Header() -{ - this.ebml = new EBMLHeader; - this.segment = new webm_Segment; - this.seek_head = new webm_SeekHead(0, 0); - - this.seek_head.info.pos = this.segment.buffer_size() + this.seek_head.buffer_size(); - - this.info = new webm_SegmentInformation; - - this.seek_head.track.pos = this.seek_head.info.pos + this.info.buffer_size(); - - this.track_entry = new webm_TrackEntry; - this.tracks = new webm_Tracks(this.track_entry); -} - -webm_Header.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - at = this.ebml.to_buffer(a, at); - at = this.segment.to_buffer(a, at); - at = this.info.to_buffer(a, at); - at = this.tracks.to_buffer(a, at); - - return at; - }, - buffer_size: function() - { - return this.ebml.buffer_size() + - this.segment.buffer_size() + - this.info.buffer_size() + - this.tracks.buffer_size(); - }, -} diff --git a/plugins/kimchi/ui/spice-html5/wire.js b/plugins/kimchi/ui/spice-html5/wire.js deleted file mode 100644 index 7407ce7..0000000 --- a/plugins/kimchi/ui/spice-html5/wire.js +++ /dev/null @@ -1,123 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see <http://www.gnu.org/licenses/>. -*/ - -/*-------------------------------------------------------------------------------------- -** SpiceWireReader -** This class will receive messages from a WebSocket and relay it to a given -** callback. It will optionally save and pass along a header, useful in processing -** the mini message format. -**--------------------------------------------------------------------------------------*/ -function SpiceWireReader(sc, callback) -{ - this.sc = sc; - this.callback = callback; - this.needed = 0; - - this.buffers = []; - - this.sc.ws.wire_reader = this; - this.sc.ws.binaryType = "arraybuffer"; - this.sc.ws.addEventListener('message', wire_blob_catcher); -} - -SpiceWireReader.prototype = -{ - - /*------------------------------------------------------------------------ - ** Process messages coming in from our WebSocket - **----------------------------------------------------------------------*/ - inbound: function (mb) - { - var at; - - /* Just buffer if we don't need anything yet */ - if (this.needed == 0) - { - this.buffers.push(mb); - return; - } - - /* Optimization - if we have just one inbound block, and it's - suitable for our needs, just use it. */ - if (this.buffers.length == 0 && mb.byteLength >= this.needed) - { - if (mb.byteLength > this.needed) - { - this.buffers.push(mb.slice(this.needed)); - mb = mb.slice(0, this.needed); - } - this.callback.call(this.sc, mb, - this.saved_msg_header || undefined); - } - else - { - this.buffers.push(mb); - } - - - /* If we have fragments that add up to what we need, combine them */ - /* FIXME - it would be faster to revise the processing code to handle - ** multiple fragments directly. Essentially, we should be - ** able to do this without any slice() or combine_array_buffers() calls */ - while (this.buffers.length > 1 && this.buffers[0].byteLength < this.needed) - { - var mb1 = this.buffers.shift(); - var mb2 = this.buffers.shift(); - - this.buffers.unshift(combine_array_buffers(mb1, mb2)); - } - - - while (this.buffers.length > 0 && this.buffers[0].byteLength >= this.needed) - { - mb = this.buffers.shift(); - if (mb.byteLength > this.needed) - { - this.buffers.unshift(mb.slice(this.needed)); - mb = mb.slice(0, this.needed); - } - this.callback.call(this.sc, mb, - this.saved_msg_header || undefined); - } - - }, - - request: function(n) - { - this.needed = n; - }, - - save_header: function(h) - { - this.saved_msg_header = h; - }, - - clear_header: function() - { - this.saved_msg_header = undefined; - }, -} - -function wire_blob_catcher(e) -{ - DEBUG > 1 && console.log(">> WebSockets.onmessage"); - DEBUG > 1 && console.log("id " + this.wire_reader.sc.connection_id +"; type " + this.wire_reader.sc.type); - SpiceWireReader.prototype.inbound.call(this.wire_reader, e.data); -} diff --git a/plugins/kimchi/utils.py b/plugins/kimchi/utils.py deleted file mode 100644 index 2480362..0000000 --- a/plugins/kimchi/utils.py +++ /dev/null @@ -1,39 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -import re - -from wok.exception import InvalidParameter - - -def _uri_to_name(collection, uri): - expr = '/plugins/kimchi/%s/(.*?)$' % collection - m = re.match(expr, uri) - if not m: - raise InvalidParameter("WOKUTILS0001E", {'uri': uri}) - return m.group(1) - - -def template_name_from_uri(uri): - return _uri_to_name('templates', uri) - - -def pool_name_from_uri(uri): - return _uri_to_name('storagepools', uri) diff --git a/plugins/kimchi/vmtemplate.py b/plugins/kimchi/vmtemplate.py deleted file mode 100644 index 07e70ba..0000000 --- a/plugins/kimchi/vmtemplate.py +++ /dev/null @@ -1,431 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os -import stat -import time -import urlparse -import uuid -from lxml import etree -from lxml.builder import E - -from wok.exception import InvalidParameter, ImageFormatError, IsoFormatError -from wok.exception import MissingParameter, OperationFailed -from wok.utils import check_url_path - -import imageinfo -import osinfo -from isoinfo import IsoImage -from utils import pool_name_from_uri -from xmlutils.cpu import get_cpu_xml -from xmlutils.disk import get_disk_xml -from xmlutils.graphics import get_graphics_xml -from xmlutils.interface import get_iface_xml -from xmlutils.qemucmdline import get_qemucmdline_xml - - -class VMTemplate(object): - def __init__(self, args, scan=False): - """ - Construct a VM Template from a widely variable amount of information. - The only required parameter is a name for the VMTemplate. If present, - the os_distro and os_version fields are used to lookup recommended - settings. Any parameters provided by the caller will override the - defaults. If scan is True and a cdrom or a base img is present, the - operating system will be detected by probing the installation media. - """ - self.info = {} - self.fc_host_support = args.get('fc_host_support') - - # Fetch defaults based on the os distro and version - try: - distro, version = self._get_os_info(args, scan) - except ImageFormatError as e: - raise OperationFailed('KCHTMPL0020E', {'err': e.message}) - os_distro = args.get('os_distro', distro) - os_version = args.get('os_version', version) - entry = osinfo.lookup(os_distro, os_version) - self.info.update(entry) - - # Auto-generate a template name and no one is passed - if 'name' not in args or args['name'] == '': - args['name'] = self._gen_name(distro, version) - self.name = args['name'] - - # Override with the passed in parameters - graph_args = args.get('graphics') - if graph_args: - graphics = dict(self.info['graphics']) - graphics.update(graph_args) - args['graphics'] = graphics - self.info.update(args) - - # Assign right disk format to logical and [i]scsi storagepools - if self._get_storage_type() in ['logical', 'iscsi', 'scsi']: - for i, disk in enumerate(self.info['disks']): - self.info['disks'][i]['format'] = 'raw' - - def _get_os_info(self, args, scan): - distro = version = 'unknown' - - # Identify the cdrom if present - iso = args.get('cdrom', '') - if len(iso) > 0: - if not iso.startswith('/'): - self.info.update({'iso_stream': True}) - - if scan: - distro, version = self.get_iso_info(iso) - - return distro, version - - # CDROM is not presented: check for base image - base_imgs = [] - for d in args.get('disks', []): - if 'base' in d.keys(): - base_imgs.append(d) - if scan: - distro, version = imageinfo.probe_image(d['base']) - - if 'size' not in d.keys(): - d_info = imageinfo.probe_img_info(d['base']) - d['size'] = d_info['virtual-size'] - - if len(base_imgs) == 0: - raise MissingParameter("KCHTMPL0016E") - - return distro, version - - def _gen_name(self, distro, version): - if distro == 'unknown': - name = str(uuid.uuid4()) - else: - name = distro + version + '.' + str(int(time.time() * 1000)) - return name - - def get_iso_info(self, iso): - iso_prefixes = ['/', 'http', 'https', 'ftp', 'ftps', 'tftp'] - if len(filter(iso.startswith, iso_prefixes)) == 0: - raise InvalidParameter("KCHTMPL0006E", {'param': iso}) - try: - iso_img = IsoImage(iso) - return iso_img.probe() - except IsoFormatError: - raise InvalidParameter("KCHISO0001E", {'filename': iso}) - - def _get_cdrom_xml(self, libvirt_stream_protocols): - if 'cdrom' not in self.info: - return '' - - params = {} - params['type'] = 'cdrom' - params['format'] = 'raw' - params['bus'] = self.info['cdrom_bus'] - params['index'] = self.info['cdrom_index'] - params['path'] = self.info['cdrom'] - - if self.info.get('iso_stream', False): - protocol = urlparse.urlparse(params['path']).scheme - if protocol not in libvirt_stream_protocols: - driveOpt = 'file=%(path)s,if=none,id=drive-%(bus)s0-1-0,' - driveOpt += 'readonly=on,format=%(format)s' - - deviceOpt = '%(bus)s-cd,bus=%(bus)s.1,unit=0,' - deviceOpt += 'drive=drive-%(bus)s0-1-0,id=%(bus)s0-1-0' - - args = {} - args['-drive'] = driveOpt % params - args['-device'] = deviceOpt % params - # return qemucmdline XML - return get_qemucmdline_xml(args) - - dev, xml = get_disk_xml(params) - return xml - - def _get_disks_xml(self, vm_uuid): - # Current implementation just allows to create disk in one single - # storage pool, so we cannot mix the types (scsi volumes vs img file) - storage_type = self._get_storage_type() - storage_path = self._get_storage_path() - - base_disk_params = {'type': 'disk', 'disk': 'file', - 'bus': self.info['disk_bus'], 'format': 'qcow2'} - logical_disk_params = {'format': 'raw'} - iscsi_disk_params = {'disk': 'block', 'format': 'raw'} - - scsi_disk = 'volume' if self.fc_host_support else 'block' - scsi_disk_params = {'disk': scsi_disk, 'type': 'lun', - 'format': 'raw', 'bus': 'scsi'} - - disks_xml = '' - pool_name = pool_name_from_uri(self.info['storagepool']) - for index, disk in enumerate(self.info['disks']): - params = dict(base_disk_params) - params['format'] = disk.get('format', params['format']) - params.update(locals().get('%s_disk_params' % storage_type, {})) - params['index'] = index - - volume = disk.get('volume') - if volume is not None: - params['path'] = self._get_volume_path(pool_name, volume) - else: - volume = "%s-%s.img" % (vm_uuid, params['index']) - params['path'] = os.path.join(storage_path, volume) - - disks_xml += get_disk_xml(params)[1] - - return unicode(disks_xml, 'utf-8') - - def to_volume_list(self, vm_uuid): - storage_path = self._get_storage_path() - fmt = 'raw' if self._get_storage_type() in ['logical'] else 'qcow2' - ret = [] - for i, d in enumerate(self.info['disks']): - index = d.get('index', i) - volume = "%s-%s.img" % (vm_uuid, index) - - info = {'name': volume, - 'capacity': d['size'], - 'format': fmt, - 'path': '%s/%s' % (storage_path, volume)} - - if 'logical' == self._get_storage_type() or \ - fmt not in ['qcow2', 'raw']: - info['allocation'] = info['capacity'] - else: - info['allocation'] = 0 - - if 'base' in d: - info['base'] = dict() - base_fmt = imageinfo.probe_img_info(d['base'])['format'] - if base_fmt is None: - raise InvalidParameter("KCHTMPL0024E", {'path': d['base']}) - info['base']['path'] = d['base'] - info['base']['format'] = base_fmt - - v_tree = E.volume(E.name(info['name'])) - v_tree.append(E.allocation(str(info['allocation']), unit='G')) - v_tree.append(E.capacity(str(info['capacity']), unit='G')) - target = E.target( - E.format(type=info['format']), E.path(info['path'])) - if 'base' in d: - v_tree.append(E.backingStore( - E.path(info['base']['path']), - E.format(type=info['base']['format']))) - v_tree.append(target) - info['xml'] = etree.tostring(v_tree) - ret.append(info) - return ret - - def _get_networks_xml(self): - networks = "" - params = {'type': 'network', - 'model': self.info['nic_model']} - for nw in self.info['networks']: - params['network'] = nw - networks += get_iface_xml(params, self.info['arch'], - self.info['os_distro'], - self.info['os_version']) - return unicode(networks, 'utf-8') - - def _get_input_output_xml(self): - sound = """ - <sound model='%(sound_model)s' /> - """ - mouse = """ - <input type='mouse' bus='%(mouse_bus)s'/> - """ - - keyboard = """ - <input type='%(kbd_type)s' bus='%(kbd_bus)s'> </input> - """ - - tablet = """ - <input type='tablet' bus='%(kbd_bus)s'> </input> - """ - - video = """ - <video> - <model type='%(video_model)s'/> - </video> - """ - - input_output = "" - if 'mouse_bus' in self.info.keys(): - input_output += mouse % self.info - if 'kbd_bus' in self.info.keys(): - input_output += keyboard % self.info - if 'tablet_bus' in self.info.keys(): - input_output += tablet % self.info - if 'sound_model' in self.info.keys(): - input_output += sound % self.info - if 'video_model' in self.info.keys(): - input_output += video % self.info - return input_output - - def _get_cpu_xml(self): - # Include CPU topology, if provided - cpu_info = self.info.get('cpu_info') - if cpu_info is not None: - cpu_topo = cpu_info.get('topology') - return get_cpu_xml(self.info.get('cpus'), - self.info.get('memory') << 10, - cpu_topo) - - def to_vm_xml(self, vm_name, vm_uuid, **kwargs): - params = dict(self.info) - params['name'] = vm_name - params['uuid'] = vm_uuid - params['networks'] = self._get_networks_xml() - params['input_output'] = self._get_input_output_xml() - params['qemu-namespace'] = '' - params['cdroms'] = '' - params['qemu-stream-cmdline'] = '' - params['cpu_info'] = self._get_cpu_xml() - params['disks'] = self._get_disks_xml(vm_uuid) - - graphics = dict(self.info['graphics']) - graphics.update(kwargs.get('graphics', {})) - params['graphics'] = get_graphics_xml(graphics) - - libvirt_stream_protocols = kwargs.get('libvirt_stream_protocols', []) - cdrom_xml = self._get_cdrom_xml(libvirt_stream_protocols) - - if not urlparse.urlparse(self.info.get('cdrom', "")).scheme in \ - libvirt_stream_protocols and \ - params.get('iso_stream', False): - params['qemu-stream-cmdline'] = cdrom_xml - else: - params['cdroms'] = cdrom_xml - - # Setting maximum number of slots to avoid errors when hotplug memory - # Number of slots are the numbers of chunks of 1GB that fit inside - # the max_memory of the host minus memory assigned to the VM - params['slots'] = ((params['max_memory'] >> 10) - - params['memory']) >> 10 - if params['slots'] < 0: - raise OperationFailed("KCHVM0041E") - elif params['slots'] == 0: - params['slots'] = 1 - - xml = """ - <domain type='%(domain)s'> - %(qemu-stream-cmdline)s - <name>%(name)s</name> - <uuid>%(uuid)s</uuid> - <maxMemory slots='%(slots)s' unit='KiB'>%(max_memory)s</maxMemory> - <memory unit='MiB'>%(memory)s</memory> - <vcpu>%(cpus)s</vcpu> - %(cpu_info)s - <os> - <type arch='%(arch)s'>hvm</type> - <boot dev='hd'/> - <boot dev='cdrom'/> - </os> - <features> - <acpi/> - <apic/> - <pae/> - </features> - <clock offset='utc'/> - <on_poweroff>destroy</on_poweroff> - <on_reboot>restart</on_reboot> - <on_crash>restart</on_crash> - <devices> - %(disks)s - %(cdroms)s - %(networks)s - %(graphics)s - %(input_output)s - <memballoon model='virtio' /> - </devices> - </domain> - """ % params - - # Adding PPC console configuration - if params['arch'] in ['ppc', 'ppc64']: - ppc_console = """<memballoon model='virtio' /> - <console type='pty'> - <target type='serial' port='1'/> - <address type='spapr-vio' reg='0x30001000'/> - </console>""" - xml = xml.replace("<memballoon model='virtio' />", ppc_console) - - return xml - - def validate(self): - self._storage_validate() - self._network_validate() - self._iso_validate() - - def _iso_validate(self): - pass - - def _network_validate(self): - pass - - def _storage_validate(self): - pass - - def fork_vm_storage(self, vm_uuid): - pass - - def _get_storage_path(self): - return '' - - def _get_storage_type(self): - return '' - - def _get_volume_path(self): - return '' - - def _get_all_networks_name(self): - return [] - - def _get_all_storagepools_name(self): - return [] - - def validate_integrity(self): - invalid = {} - # validate networks integrity - invalid_networks = list(set(self.info['networks']) - - set(self._get_all_networks_name())) - if invalid_networks: - invalid['networks'] = invalid_networks - - # validate storagepools integrity - pool_uri = self.info['storagepool'] - pool_name = pool_name_from_uri(pool_uri) - if pool_name not in self._get_all_storagepools_name(): - invalid['storagepools'] = [pool_name] - - # validate iso integrity - # FIXME when we support multiples cdrom devices - iso = self.info.get('cdrom') - if iso: - if os.path.exists(iso): - st_mode = os.stat(iso).st_mode - if not (stat.S_ISREG(st_mode) or stat.S_ISBLK(st_mode)): - invalid['cdrom'] = [iso] - elif not check_url_path(iso): - invalid['cdrom'] = [iso] - - self.info['invalid'] = invalid - - return self.info diff --git a/plugins/kimchi/vnc.py b/plugins/kimchi/vnc.py deleted file mode 100644 index 2532449..0000000 --- a/plugins/kimchi/vnc.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python2 -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import base64 -import errno -import os -from multiprocessing import Process -from websockify import WebSocketProxy - -from wok.config import config, paths - - -WS_TOKENS_DIR = '/var/lib/wok/vnc-tokens' - - -def new_ws_proxy(): - try: - os.makedirs(WS_TOKENS_DIR, mode=0755) - except OSError as e: - if e.errno == errno.EEXIST: - pass - - cert = config.get('server', 'ssl_cert') - key = config.get('server', 'ssl_key') - if not (cert and key): - cert = '%s/wok-cert.pem' % paths.conf_dir - key = '%s/wok-key.pem' % paths.conf_dir - - params = {'web': os.path.join(paths.ui_dir, 'pages/websockify'), - 'listen_port': config.get('display', 'display_proxy_port'), - 'target_cfg': WS_TOKENS_DIR, - 'key': key, 'cert': cert, 'ssl_only': True} - - def start_proxy(): - server = WebSocketProxy(**params) - server.start_server() - - proc = Process(target=start_proxy) - proc.start() - return proc - - -def add_proxy_token(name, port): - with open(os.path.join(WS_TOKENS_DIR, name), 'w') as f: - """ - From python documentation base64.urlsafe_b64encode(s) - substitutes - instead of + and _ instead of / in the - standard Base64 alphabet, BUT the result can still - contain = which is not safe in a URL query component. - So remove it when needed as base64 can work well without it. - """ - name = base64.urlsafe_b64encode(name).rstrip('=') - f.write('%s: localhost:%s' % (name.encode('utf-8'), port)) - - -def remove_proxy_token(name): - try: - os.unlink(os.path.join(WS_TOKENS_DIR, name)) - except OSError: - pass diff --git a/plugins/kimchi/xmlutils/Makefile.am b/plugins/kimchi/xmlutils/Makefile.am deleted file mode 100644 index 207ad7f..0000000 --- a/plugins/kimchi/xmlutils/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -xmlutils_PYTHON = *.py - -xmlutilsdir = $(pythondir)/wok/plugins/kimchi/xmlutils - -install-data-local: - $(MKDIR_P) $(DESTDIR)$(xmlutilsdir) diff --git a/plugins/kimchi/xmlutils/__init__.py b/plugins/kimchi/xmlutils/__init__.py deleted file mode 100644 index ca7ede4..0000000 --- a/plugins/kimchi/xmlutils/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/plugins/kimchi/xmlutils/cpu.py b/plugins/kimchi/xmlutils/cpu.py deleted file mode 100644 index 32c01a4..0000000 --- a/plugins/kimchi/xmlutils/cpu.py +++ /dev/null @@ -1,60 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import lxml.etree as ET -from lxml.builder import E - - -def get_numa_xml(cpus, memory): - # Returns the NUMA xml to be add into CPU element - # Currently, supports only one node/cell - # <numa> - # <cell id='0' cpus='0-3' memory='512000' unit='KiB'/> - # </numa> - xml = E.numa(E.cell( - id='0', - cpus='0-' + str(cpus - 1) if cpus > 1 else '0', - memory=str(memory), - unit='KiB')) - return ET.tostring(xml) - - -def get_topology_xml(cpu_topo): - # Return the cpu TOPOLOGY element - # <topology sockets='1' cores='2' threads='1'/> - xml = E.topology( - sockets=str(cpu_topo['sockets']), - cores=str(cpu_topo['cores']), - threads=str(cpu_topo['threads'])) - return ET.tostring(xml) - - -def get_cpu_xml(cpus, memory, cpu_topo=None): - # Returns the libvirt CPU element based on given numa and topology - # CPU element will always have numa element - # <cpu> - # <numa> - # <cell id='0' cpus='0-3' memory='512000' unit='KiB'/> - # </numa> - # <topology sockets='1' cores='2' threads='1'/> - # </cpu> - xml = E.cpu(ET.fromstring(get_numa_xml(cpus, memory))) - if cpu_topo is not None: - xml.insert(0, ET.fromstring(get_topology_xml(cpu_topo))) - return ET.tostring(xml) diff --git a/plugins/kimchi/xmlutils/disk.py b/plugins/kimchi/xmlutils/disk.py deleted file mode 100644 index 126ce77..0000000 --- a/plugins/kimchi/xmlutils/disk.py +++ /dev/null @@ -1,164 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import lxml.etree as ET -import os -import socket -import stat -import string -import urlparse -from lxml import objectify -from lxml.builder import E - -from wok.exception import InvalidParameter, NotFoundError -from wok.utils import check_url_path - - -BUS_TO_DEV_MAP = {'ide': 'hd', 'virtio': 'vd', 'scsi': 'sd'} -DEV_TYPE_SRC_ATTR_MAP = {'file': 'file', 'block': 'dev'} - - -def get_disk_xml(params): - """ - <disk type='file' device='cdrom'> - <driver name='qemu' type='raw'/> - - [source XML according to src_type] - - <target dev='%(dev)s' bus='%(bus)s'/> - <readonly/> - </disk> - """ - path = params['path'] - disk_type = params.get('disk', None) - if disk_type is None: - disk_type = _get_disk_type(path) if len(path) > 0 else 'file' - disk = E.disk(type=disk_type, device=params['type']) - driver = E.driver(name='qemu', type=params['format']) - if params['type'] != 'cdrom': - driver.set('cache', 'none') - - disk.append(driver) - - # Get device name according to bus and index values - dev = params.get('dev', (BUS_TO_DEV_MAP[params['bus']] + - string.lowercase[params.get('index', 0)])) - disk.append(E.target(dev=dev, bus=params['bus'])) - - if params.get('address'): - # ide disk target id is always '0' - disk.append(E.address( - type='drive', controller=params['address']['controller'], - bus=params['address']['bus'], target='0', - unit=params['address']['unit'])) - - if len(params['path']) == 0: - return (dev, ET.tostring(disk, encoding='utf-8', pretty_print=True)) - - if disk_type == 'network': - """ - <source protocol='%(protocol)s' name='%(url_path)s'> - <host name='%(hostname)s' port='%(port)s'/> - </source> - """ - output = urlparse.urlparse(params['path']) - port = str(output.port or socket.getservbyname(output.scheme)) - - source = E.source(protocol=output.scheme, name=output.path) - source.append(E.host(name=output.hostname, port=port)) - else: - """ - <source file='%(src)s' /> - """ - source = E.source() - source.set(DEV_TYPE_SRC_ATTR_MAP[disk_type], params['path']) - - disk.append(source) - return (dev, ET.tostring(disk, encoding='utf-8', pretty_print=True)) - - -def _get_disk_type(path): - if check_url_path(path): - return 'network' - - if not os.path.exists(path): - raise InvalidParameter("KCHVMSTOR0003E", {'value': path}) - - # Check if path is a valid local path - if os.path.isfile(path): - return 'file' - - r_path = os.path.realpath(path) - if stat.S_ISBLK(os.stat(r_path).st_mode): - return 'block' - - raise InvalidParameter("KCHVMSTOR0003E", {'value': path}) - - -def get_device_node(dom, dev_name): - xml = dom.XMLDesc(0) - devices = objectify.fromstring(xml).devices - disk = devices.xpath("./disk/target[@dev='%s']/.." % dev_name) - - if not disk: - raise NotFoundError("KCHVMSTOR0007E", - {'dev_name': dev_name, - 'vm_name': dom.name()}) - - return disk[0] - - -def get_vm_disk_info(dom, dev_name): - # Retrieve disk xml and format return dict - disk = get_device_node(dom, dev_name) - if disk is None: - return None - - try: - source = disk.source - if source is not None: - src_type = disk.attrib['type'] - if src_type == 'network': - host = source.host - path = (source.attrib['protocol'] + '://' + - host.attrib['name'] + ':' + - host.attrib['port'] + source.attrib['name']) - else: - path = source.attrib[DEV_TYPE_SRC_ATTR_MAP[src_type]] - except: - path = "" - - return {'dev': dev_name, - 'path': path, - 'type': disk.attrib['device'], - 'format': disk.driver.attrib['type'], - 'bus': disk.target.attrib['bus']} - - -def get_vm_disks(dom): - xml = dom.XMLDesc(0) - devices = objectify.fromstring(xml).devices - - storages = {} - all_disks = devices.xpath("./disk[@device='disk']") - all_disks.extend(devices.xpath("./disk[@device='cdrom']")) - for disk in all_disks: - storages[disk.target.attrib['dev']] = disk.target.attrib['bus'] - - return storages diff --git a/plugins/kimchi/xmlutils/graphics.py b/plugins/kimchi/xmlutils/graphics.py deleted file mode 100644 index 2b4346a..0000000 --- a/plugins/kimchi/xmlutils/graphics.py +++ /dev/null @@ -1,45 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import lxml.etree as ET -from lxml.builder import E - - -def get_graphics_xml(params): - """ - <graphics type='%(type)s' autoport='yes' listen='%(listen)s'/> - - - For spice graphics: - - <channel type='spicevmc'> - <target type='virtio' name='com.redhat.spice.0'/> - </channel> - """ - graphics = E.graphics(type=params['type'], autoport='yes', - listen=params['listen']) - graphics_xml = ET.tostring(graphics, encoding='utf-8', pretty_print=True) - - if params['type'] == 'vnc': - return graphics_xml - - # For spice graphics, a channel also must be configured - channel = E.channel(type='spicevmc') - channel.append(E.target(type='virtio', name='com.redhat.spice.0')) - channel_xml = ET.tostring(channel, encoding='utf-8', pretty_print=True) - return graphics_xml + channel_xml diff --git a/plugins/kimchi/xmlutils/interface.py b/plugins/kimchi/xmlutils/interface.py deleted file mode 100644 index 0f3e848..0000000 --- a/plugins/kimchi/xmlutils/interface.py +++ /dev/null @@ -1,61 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014-2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import lxml.etree as ET -from distutils.version import LooseVersion -from lxml.builder import E - -from .. import osinfo - - -def get_iface_xml(params, arch=None, os_distro=None, os_version=None): - """ - <interface type='network'> - <source network='default'/> - <model type='virtio'/> - </interface> - """ - interface = E.interface(type=params['type']) - interface.append(E.source(network=params['network'])) - - model = params.get('model') - - # no model specified; let's try querying osinfo - if model is None: - # if os_distro and os_version are invalid, nic_model will also be None - model = osinfo.lookup(os_distro, os_version).get('nic_model') - - # only append 'model' to the XML if it's been specified as a parameter or - # returned by osinfo.lookup; otherwise let libvirt use its default value - if model is not None: - interface.append(E.model(type=model)) - - mac = params.get('mac', None) - if mac is not None: - interface.append(E.mac(address=mac)) - - # Hack to disable vhost feature in Ubuntu LE and SLES LE (PPC) - if arch == 'ppc64' and \ - ((os_distro == 'ubuntu' and - LooseVersion(os_version) >= LooseVersion('14.04')) or - (os_distro == 'sles' and - LooseVersion(os_version) >= LooseVersion('12'))): - interface.append(E.driver(name='qemu')) - - return ET.tostring(interface, encoding='utf-8', pretty_print=True) diff --git a/plugins/kimchi/xmlutils/network.py b/plugins/kimchi/xmlutils/network.py deleted file mode 100644 index c73aad9..0000000 --- a/plugins/kimchi/xmlutils/network.py +++ /dev/null @@ -1,122 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import ipaddr -import lxml.etree as ET -from lxml.builder import E - - -# FIXME, do not support ipv6 -def _get_dhcp_elem(**kwargs): - """ - <dhcp> - <range start="192.168.122.100" end="192.168.122.254" /> - <host mac="00:16:3e:77:e2:ed" name="foo.test.com" ip="192.168.122.10" /> - <host mac="00:16:3e:3e:a9:1a" name="bar.test.com" ip="192.168.122.11" /> - </dhcp> - """ - dhcp = E.dhcp() - if 'range' in kwargs.keys(): - dhcp_range = E.range(start=kwargs['range']['start'], - end=kwargs['range']['end']) - dhcp.append(dhcp_range) - - if 'hosts' in kwargs.keys(): - for host in kwargs['hosts']: - dhcp.append(E.host(mac=host['mac'], - name=host['name'], - ip=host['ip'])) - - return dhcp if len(dhcp) > 0 else None - - -def _get_ip_elem(**kwargs): - """ - <ip address="192.168.152.1" netmask="255.255.255.0"> - <dhcp> - <range start="192.168.152.2" end="192.168.152.254" /> - </dhcp> - </ip> - """ - if 'net' not in kwargs.keys(): - return None - - net = ipaddr.IPNetwork(kwargs['net']) - ip = E.ip(address=str(net.ip), netmask=str(net.netmask)) - - dhcp_params = kwargs.get('dhcp', {}) - dhcp = _get_dhcp_elem(**dhcp_params) - if dhcp is not None: - ip.append(dhcp) - - return ip - - -def _get_forward_elem(**kwargs): - """ - <forward mode='hostdev' dev='eth0' managed='yes'> - </forward> - """ - if "mode" in kwargs.keys() and kwargs['mode'] is None: - return None - - forward = E.forward() - if 'mode' in kwargs.keys(): - forward.set('mode', kwargs['mode']) - - if 'dev' in kwargs.keys(): - forward.set('dev', kwargs['dev']) - - if 'managed' in kwargs.keys(): - forward.set('managed', kwargs['managed']) - - return forward - - -def to_network_xml(**kwargs): - network = E.network(E.name(kwargs['name'])) - bridge = kwargs.get('bridge') - if bridge: - network.append(E.bridge(name=bridge)) - - # None means is Isolated network, {} means default mode nat - params = kwargs.get('forward', {"mode": None}) - forward = _get_forward_elem(**params) - if forward is not None: - network.append(forward) - - if 'net' in kwargs: - network.append(_get_ip_elem(**kwargs)) - - return ET.tostring(network) - - -def create_vlan_tagged_bridge_xml(bridge, interface, vlan_id): - vlan = E.vlan(E.interface(name=interface)) - vlan.set('tag', vlan_id) - m = E.interface( - E.start(mode='onboot'), - E.bridge( - E.interface( - vlan, - type='vlan', - name='.'.join([interface, vlan_id]))), - type='bridge', - name=bridge) - return ET.tostring(m) diff --git a/plugins/kimchi/xmlutils/qemucmdline.py b/plugins/kimchi/xmlutils/qemucmdline.py deleted file mode 100644 index 66238a7..0000000 --- a/plugins/kimchi/xmlutils/qemucmdline.py +++ /dev/null @@ -1,45 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import lxml.etree as ET -from lxml.builder import ElementMaker - -QEMU_NAMESPACE = "http://libvirt.org/schemas/domain/qemu/1.0" - - -def get_qemucmdline_xml(args): - """ - <qemu:commandline xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> - <qemu:arg value='-drive'/> - <qemu:arg value='file=%(path)s,if=none,id=drive-%(bus)s0-1-0, - readonly=on,format=%(format)s'/> - <qemu:arg value='-device'/> - <qemu:arg value='%(bus)s-cd,bus=%(bus)s.1,unit=0, - drive=drive-%(bus)s0-1-0,id=%(bus)s0-1-0'/> - </qemu:commandline> - """ - EM = ElementMaker(namespace=QEMU_NAMESPACE, - nsmap={'qemu': QEMU_NAMESPACE}) - - root = EM.commandline() - for opt, value in args.iteritems(): - root.append(EM.arg(value=opt)) - root.append(EM.arg(value=value)) - - return ET.tostring(root, encoding='utf-8', pretty_print=True) diff --git a/plugins/kimchi/yumparser.py b/plugins/kimchi/yumparser.py deleted file mode 100644 index 74f9fa0..0000000 --- a/plugins/kimchi/yumparser.py +++ /dev/null @@ -1,283 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2015 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import subprocess -from os import listdir -from os.path import isfile, splitext - - -class YumRepoObject(object): - - def __init__(self, repo_id, repofile): - self.repo_id = repo_id - self.name = None - self.baseurl = None - self.enabled = True - self.gpgcheck = True - self.gpgkey = None - self.metalink = None - self.mirrorlist = None - self.repofile = repofile - self.string_attrs = ['baseurl', 'gpgkey', 'name', - 'metalink', 'mirrorlist'] - self.boolean_attrs = ['enabled', 'gpgcheck'] - - def set_attribute(self, key, strvalue): - if key in self.string_attrs: - setattr(self, key, strvalue) - elif key in self.boolean_attrs: - setattr(self, key, (strvalue == '1')) - - def get_attribute_str(self, key): - if key not in self.get_attributes(): - return None - - if key in self.boolean_attrs: - str_value = '1' if getattr(self, key) is True else '0' - else: - str_value = getattr(self, key) - - if str_value is None: - return None - - return key + '=' + str_value - - def get_attributes(self): - return self.string_attrs + self.boolean_attrs - - def enable(self): - self.enabled = True - - def disable(self): - self.enabled = False - - def __str__(self): - str_obj = '[' + self.repo_id + ']' + '\n' - for key in self.get_attributes(): - if self.get_attribute_str(key) is not None: - str_obj += self.get_attribute_str(key) + '\n' - return str_obj - - -def get_repo_files(): - def _is_repository_file(f): - _, f_extension = splitext(f) - return isfile(f) and (f_extension == '.repo') - - YUM_REPO_DIR = '/etc/yum.repos.d' - return [YUM_REPO_DIR+'/'+f for f in listdir(YUM_REPO_DIR) - if _is_repository_file(YUM_REPO_DIR+'/'+f)] - - -def _ignore_line_repo_file(line): - return line.startswith("#") or '=' not in line - - -def _get_repos_from_file(repo_file): - repos_from_file = {} - current_repo = None - current_repo_id = None - with open(repo_file) as f: - for line in f.readlines(): - line = line.strip() - if line.startswith("["): - if current_repo is not None: - repos_from_file[current_repo_id] = current_repo - current_repo_id = line.strip('[]') - current_repo = YumRepoObject(current_repo_id, repo_file) - continue - if _ignore_line_repo_file(line): - continue - key, value = line.split('=', 1) - key = key.strip() - value = value.strip() - current_repo.set_attribute(key, value) - - # add the last repo from file. - if current_repo is not None: - repos_from_file[current_repo_id] = current_repo - - return repos_from_file - - -def get_yum_repositories(): - repo_files = get_repo_files() - repos = {} - for yum_repo in repo_files: - repos.update(_get_repos_from_file(yum_repo)) - - return repos - - -def _retrieve_repo_line_index(data, repo): - repo_entry = '[' + repo.repo_id + ']\n' - try: - repo_index = data.index(repo_entry) - except: - return None - return repo_index - - -def _update_repo_file_data(data, repo, repo_index): - remaining_repo_attrs = repo.get_attributes() - - for i in range(repo_index + 1, len(data)): - line = data[i].strip() - if line.startswith('['): - break - if _ignore_line_repo_file(line): - continue - key, _ = line.split('=', 1) - key = key.strip() - attr_str = repo.get_attribute_str(key) - if attr_str is None: - continue - remaining_repo_attrs.remove(key) - data[i] = attr_str + '\n' - - for attr in remaining_repo_attrs: - attr_str = repo.get_attribute_str(attr) - if attr_str is None: - continue - data.insert(repo_index+1, attr_str + '\n') - - return data - - -def write_repo_to_file(repo): - with open(repo.repofile) as f: - data = f.readlines() - - repo_index = _retrieve_repo_line_index(data, repo) - if repo_index is None: - return - - data = _update_repo_file_data(data, repo, repo_index) - - with open(repo.repofile, 'w') as f: - f.writelines(data) - - -def _get_last_line_repo(data, repo_index): - stop_delete_index = None - for i in range(repo_index+1, len(data)): - line = data[i].strip() - if line.startswith('['): - stop_delete_index = i - 1 - break - if stop_delete_index is None: - stop_delete_index = len(data) - 1 - - return stop_delete_index - - -def _remove_repo_file_data(data, repo_index): - last_line_repo = _get_last_line_repo(data, repo_index) - for i in range(last_line_repo, repo_index - 1, -1): - data.pop(i) - return data - - -def delete_repo_from_file(repo): - with open(repo.repofile) as f: - data = f.readlines() - - repo_index = _retrieve_repo_line_index(data, repo) - if repo_index is None: - return - - data = _remove_repo_file_data(data, repo_index) - - with open(repo.repofile, 'w') as f: - f.writelines(data) - - -class YumUpdatePackageObject(object): - - def __init__(self, name, arch, version, repo): - self.name = name - self.arch = arch - self.version = version - self.ui_from_repo = repo - - -def _include_line_checkupdate_output(line): - tokens = line.split() - - if len(tokens) != 3: - return False - - if '.' not in tokens[0]: - return False - - return True - - -def _ignore_obsoleting_packages_in(output): - out = '' - for l in output.split('\n'): - if 'Obsoleting ' in l: - break - out += l + '\n' - return out - - -def _filter_lines_checkupdate_output(output): - if output is None: - return [] - - output = _ignore_obsoleting_packages_in(output) - - out = [l for l in output.split('\n') - if _include_line_checkupdate_output(l)] - return out - - -def _get_yum_checkupdate_output(): - cmd = ['yum', 'check-update', '-d0'] - yum_update_cmd = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out, error = yum_update_cmd.communicate() - return_code = yum_update_cmd.returncode - if return_code == 1: - return None - - return out - - -def get_yum_packages_list_update(checkupdate_output=None): - if checkupdate_output is None: - checkupdate_output = _get_yum_checkupdate_output() - - filtered_output = _filter_lines_checkupdate_output(checkupdate_output) - - packages = [] - for line in filtered_output: - line = line.split() - index = 0 - name_arch = line[index] - index += 1 - version = line[index] - index += 1 - repo = line[index] - name, arch = name_arch.rsplit('.', 1) - packages.append(YumUpdatePackageObject(name, arch, version, repo)) - - return packages diff --git a/plugins/sample/API.json b/plugins/sample/API.json deleted file mode 100644 index 6ee7d91..0000000 --- a/plugins/sample/API.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-03/schema#", - "title": "Plugin Sample API", - "description": "Json schema for Wok's Sample Plugin API", - "type": "object", - "error": "SPAPI0001E", - "properties": { - "rectangles_create": { - "type": "object", - "error": "SPRET0003E", - "properties": { - "name": { - "description": "The name of the new rectangle instance", - "type": "string", - "required": true, - "error": "SPRET0004E" - }, - "length": { - "$ref": "#/definitions/positiveNumber", - "required": true, - "error": "SPRET0005E" - }, - "width": { - "$ref": "#/definitions/positiveNumber", - "required": true, - "error": "SPRET0006E" - } - } - }, - "circles_create": { - "type": "object", - "error": "SPCIRC0003E", - "properties": { - "name": { - "description": "The name of the new circle instance", - "type": "string", - "required": true, - "error": "SPCIRC0004E" - }, - "radius": { - "$ref": "#/definitions/positiveNumber", - "required": true, - "error": "SPCIRC0005E" - } - } - } - }, - "definitions": { - "positiveNumber": { - "error": "SPAPI0002E", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true - } - } -} diff --git a/plugins/sample/Makefile.am b/plugins/sample/Makefile.am deleted file mode 100644 index 876ab54..0000000 --- a/plugins/sample/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -SUBDIRS = ui po - -EXTRA_DIST = API.json sample.conf.in $(wildcard *.py) config.status - -all-local: - while read L && test -n "$$L"; do \ - dir=mo/$$L/LC_MESSAGES ; \ - $(MKDIR_P) $$dir ; \ - ln -sf ../../../po/$$L.gmo $$dir/sample.mo ; \ - done < po/LINGUAS diff --git a/plugins/sample/__init__.py b/plugins/sample/__init__.py deleted file mode 100644 index a3a8f05..0000000 --- a/plugins/sample/__init__.py +++ /dev/null @@ -1,97 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import json -import os -from cherrypy import expose - - -from wok.config import PluginPaths -from wok.control.base import Collection, Resource -from wok.root import WokRoot - - -from plugins.sample.i18n import messages -from plugins.sample.model import Model - - -model = Model() - - -class Drawings(WokRoot): - def __init__(self, wok_options): - Resource.__init__(self, model) - self.description = Description(model) - self.rectangles = Rectangles(model) - self.circles = Circles(model) - self.paths = PluginPaths('sample') - self.domain = 'sample' - self.messages = messages - self.api_schema = json.load(open(os.path.join(os.path.dirname( - os.path.abspath(__file__)), 'API.json'))) - - @expose - def index(self): - return 'This is a sample plugin for Wok' - - -class Description(Resource): - def __init__(self, model): - super(Description, self).__init__(model) - - @property - def data(self): - return {'name': 'sample', 'version': '0.1'} - - -class Circles(Collection): - def __init__(self, model): - super(Circles, self).__init__(model) - self.resource = Circle - self.admin_methods = ['POST', 'PUT'] - - -class Rectangles(Collection): - def __init__(self, model): - super(Rectangles, self).__init__(model) - self.resource = Rectangle - self.admin_methods = ['POST', 'PUT'] - - -class Circle(Resource): - def __init__(self, model, ident): - super(Circle, self).__init__(model, ident) - self.update_params = ['radius'] - - @property - def data(self): - ret = {'name': self.ident} - ret.update(self.info) - return ret - - -class Rectangle(Resource): - def __init__(self, model, ident): - super(Rectangle, self).__init__(model, ident) - self.update_params = ['length', 'width'] - - @property - def data(self): - self.info.update({'name': self.ident}) - return self.info diff --git a/plugins/sample/config.status b/plugins/sample/config.status deleted file mode 120000 index 6cd6b4f..0000000 --- a/plugins/sample/config.status +++ /dev/null @@ -1 +0,0 @@ -../../config.status \ No newline at end of file diff --git a/plugins/sample/i18n.py b/plugins/sample/i18n.py deleted file mode 100644 index 763970f..0000000 --- a/plugins/sample/i18n.py +++ /dev/null @@ -1,40 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import gettext - -_ = gettext.gettext - - -messages = { - "SPAPI0001E": _("Unkown parameter specified %(value)s"), - "SPAPI0002E": _("The specified value %(value)s is not a positive number"), - - "SPCIRC0002E": _("Circle %(name)s does not exist"), - "SPCIRC0003E": _("Specify name and radius to create a Circle"), - "SPCIRC0004E": _("Circle name must be a string"), - "SPCIRC0005E": _("Circle radius must be a positive number"), - - "SPRET0001E": _("Rectangle %(name)s already exists"), - "SPRET0002E": _("Rectangle %(name)s does not exist"), - "SPRET0003E": _("Specify name, length and width to create a Rectangle"), - "SPRET0004E": _("Rectangle name must be a string"), - "SPRET0005E": _("Rectangle length must be a positive number"), - "SPRET0006E": _("Rectangle width must be a positive number"), -} diff --git a/plugins/sample/model.py b/plugins/sample/model.py deleted file mode 100644 index 4ada648..0000000 --- a/plugins/sample/model.py +++ /dev/null @@ -1,131 +0,0 @@ -# -# Project Kimchi -# -# Copyright IBM, Corp. 2013-2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -from wok.basemodel import BaseModel -from wok.exception import InvalidOperation, NotFoundError - - -class CirclesModel(object): - def __init__(self): - self._circles = {} - - def create(self, params): - name = params['name'] - if name in self._circles: - raise InvalidOperation("SPCIRCLE0001E", {'name': name}) - self._circles[name] = Circle(params['radius']) - return name - - def get_list(self): - return sorted(self._circles) - - -class CircleModel(object): - def __init__(self, parent_model): - # Circel and Circles models are friends, it's OK to share _circles. - self._circles = parent_model._circles - - def lookup(self, name): - try: - circle = self._circles[name] - except KeyError: - raise NotFoundError("SPCIRC0002E", {'name': name}) - return {'radius': circle.radius} - - def update(self, name, params): - if name not in self._circles: - raise NotFoundError("SPCIRC0002E", {'name': name}) - self._circles[name].radius = params['radius'] - return name - - def delete(self, name): - try: - del self._circles[name] - except KeyError: - pass - - -class RectanglesModel(object): - def __init__(self): - self._rectangles = {} - - def create(self, params): - name = params['name'] - if name in self._rectangles: - raise InvalidOperation("SPRET0001E", {'name': name}) - self._rectangles[name] = Rectangle(params['length'], params['width']) - return name - - def get_list(self): - return sorted(self._rectangles) - - -class RectangleModel(object): - def __init__(self, parent_model): - self._rectangles = parent_model._rectangles - - def lookup(self, name): - try: - rectangle = self._rectangles[name] - except KeyError: - raise NotFoundError("SPRET0002E", {'name': name}) - return {'length': rectangle.length, 'width': rectangle.width} - - def update(self, name, params): - if name not in self._rectangles: - raise NotFoundError("SPRET0002E", {'name': name}) - try: - self._rectangles[name].length = params['length'] - except KeyError: - pass - - try: - self._rectangles[name].width = params['width'] - except KeyError: - pass - return name - - def delete(self, name): - try: - del self._rectangles[name] - except KeyError: - pass - - -class Model(BaseModel): - def __init__(self): - circles = CirclesModel() - circle = CircleModel(circles) - - rectangles = RectanglesModel() - rectangle = RectangleModel(rectangles) - - return super(Model, self).__init__( - [circle, circles, rectangle, rectangles]) - - -class Rectangle(object): - def __init__(self, length, width): - self.length = length - self.width = width - - -class Circle(object): - def __init__(self, radius): - self.radius = radius diff --git a/plugins/sample/po/LINGUAS b/plugins/sample/po/LINGUAS deleted file mode 100644 index 469998e..0000000 --- a/plugins/sample/po/LINGUAS +++ /dev/null @@ -1,3 +0,0 @@ -en_US -pt_BR -zh_CN diff --git a/plugins/sample/po/Makefile.in.in b/plugins/sample/po/Makefile.in.in deleted file mode 100644 index 52ab81c..0000000 --- a/plugins/sample/po/Makefile.in.in +++ /dev/null @@ -1,400 +0,0 @@ -# Makefile for PO directory in any package using GNU gettext. -# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper@gnu.ai.mit.edu> -# -# This file can be copied and used freely without restrictions. It can -# be used in projects which are not available under the GNU General Public -# License but which still want to provide support for the GNU gettext -# functionality. -# Please note that the actual code of GNU gettext is covered by the GNU -# General Public License and is *not* in the public domain. -# -# Origin: gettext-0.18 -GETTEXT_MACRO_VERSION = 0.18 - -PACKAGE = @PACKAGE@ -VERSION = @VERSION@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ - -SHELL = /bin/sh -@SET_MAKE@ - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ -datarootdir = @datarootdir@ -datadir = @datadir@ -localedir = @prefix@/share/locale -gettextsrcdir = $(datadir)/gettext/po - -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ - -# We use $(MKDIR_P). -# This macro uses the 'mkdir -p' command if possible. Otherwise, it falls back -# on invoking install-sh with the -d option, so your package should contain -# install-sh as described under AC_PROG_INSTALL. -mkinstalldirs = $(SHELL) @install_sh@ -d -install_sh = $(SHELL) @install_sh@ -MKDIR_P = @MKDIR_P@ -MKDIR_P = @MKDIR_P@ - -GMSGFMT_ = @GMSGFMT@ -GMSGFMT_no = @GMSGFMT@ -GMSGFMT_yes = @GMSGFMT_015@ -GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) -MSGFMT_ = @MSGFMT@ -MSGFMT_no = @MSGFMT@ -MSGFMT_yes = @MSGFMT_015@ -MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) -XGETTEXT_ = @XGETTEXT@ -XGETTEXT_no = @XGETTEXT@ -XGETTEXT_yes = @XGETTEXT_015@ -XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) -MSGMERGE = msgmerge -MSGMERGE_UPDATE = @MSGMERGE@ --update -MSGINIT = msginit -MSGCONV = msgconv -MSGFILTER = msgfilter - -POFILES = @POFILES@ -GMOFILES = @GMOFILES@ -UPDATEPOFILES = @UPDATEPOFILES@ -DUMMYPOFILES = @DUMMYPOFILES@ -DISTFILES.common = Makefile.in.in \ -$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) -DISTFILES = $(DISTFILES.common) Makevars POTFILES.in gen-pot \ -$(POFILES) $(GMOFILES) \ -$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) - -POTFILES = \ - -CATALOGS = @CATALOGS@ - -# Makevars gets inserted here. (Don't remove this line!) - -.SUFFIXES: -.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update - -.po.mo: - @echo "$(MSGFMT) -c -o $@ $<"; \ - $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ - -.po.gmo: - @lang=`echo $* | sed -e 's,.*/,,'`; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \ - cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo - -.sin.sed: - sed -e '/^#/d' $< > t-$@ - mv t-$@ $@ - - -all: check-macro-version update-gmo all-@USE_NLS@ - -all-yes: stamp-po -all-no: - -# Ensure that the gettext macros and this Makefile.in.in are in sync. -check-macro-version: - @test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \ - || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \ - exit 1; \ - } - -# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no -# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because -# we don't want to bother translators with empty POT files). We assume that -# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. -# In this case, stamp-po is a nop (i.e. a phony target). - -# stamp-po is a timestamp denoting the last time at which the CATALOGS have -# been loosely updated. Its purpose is that when a developer or translator -# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, -# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent -# invocations of "make" will do nothing. This timestamp would not be necessary -# if updating the $(CATALOGS) would always touch them; however, the rule for -# $(POFILES) has been designed to not touch files that don't need to be -# changed. -stamp-po: $(srcdir)/$(DOMAIN).pot - test ! -f $(srcdir)/$(DOMAIN).pot || \ - test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) - @test ! -f $(srcdir)/$(DOMAIN).pot || { \ - echo "touch stamp-po" && \ - echo timestamp > stamp-poT && \ - mv stamp-poT stamp-po; \ - } - -# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', -# otherwise packages like GCC can not be built if only parts of the source -# have been downloaded. - -$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in - $(srcdir)/gen-pot $(POTFILES) - -# This rule has no dependencies: we don't need to update $(DOMAIN).pot at -# every "make" invocation, only create it when it is missing. -# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. -$(srcdir)/$(DOMAIN).pot: - $(MAKE) $(DOMAIN).pot-update - -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot - @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ - if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) \ - && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \ - esac; \ - }; \ - else \ - $(MAKE) $${lang}.po-create; \ - fi - - -install: - -install-exec: -install-data: install-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(MKDIR_P) $(DESTDIR)$(gettextsrcdir); \ - for file in $(DISTFILES.common) Makevars.template; do \ - $(INSTALL_DATA) $(srcdir)/$$file \ - $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - for file in Makevars; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi -install-data-no: all -install-data-yes: all - @catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - dir=$(localedir)/$$lang/LC_MESSAGES; \ - $(MKDIR_P) $(DESTDIR)$$dir; \ - if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ - $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ - echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ - for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ - if test -n "$$lc"; then \ - if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ - link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ - mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ - for file in *; do \ - if test -f $$file; then \ - ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ - fi; \ - done); \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - else \ - if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ - :; \ - else \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - fi; \ - fi; \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ - ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ - cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ - fi; \ - done; \ - done - -install-strip: install - -installdirs: installdirs-exec installdirs-data -installdirs-exec: -installdirs-data: installdirs-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(MKDIR_P) $(DESTDIR)$(gettextsrcdir); \ - else \ - : ; \ - fi -installdirs-data-no: -installdirs-data-yes: - @catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - dir=$(localedir)/$$lang/LC_MESSAGES; \ - $(MKDIR_P) $(DESTDIR)$$dir; \ - for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ - if test -n "$$lc"; then \ - if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ - link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ - mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ - for file in *; do \ - if test -f $$file; then \ - ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ - fi; \ - done); \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - else \ - if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ - :; \ - else \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - fi; \ - fi; \ - fi; \ - done; \ - done - -# Define this as empty until I found a useful application. -installcheck: - -uninstall: - -uninstall-exec: -uninstall-data: uninstall-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - for file in $(DISTFILES.common) Makevars.template; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi -uninstall-data-no: -uninstall-data-yes: - catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - done; \ - done - -check: all - -info dvi ps pdf html tags TAGS ctags CTAGS ID: - -mostlyclean: - rm -f remove-potcdate.sed - rm -f stamp-poT - rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po - rm -fr *.o - -clean: mostlyclean - -distclean: clean - rm -f Makefile Makefile.in POTFILES *.mo - -maintainer-clean: distclean - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." - rm -f stamp-po $(GMOFILES) - -distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) -dist distdir: - $(MAKE) update-po - @$(MAKE) dist2 -# This is a separate target because 'update-po' must be executed before. -dist2: stamp-po $(DISTFILES) - dists="$(DISTFILES)"; \ - if test "$(PACKAGE)" = "gettext-tools"; then \ - dists="$$dists Makevars.template"; \ - fi; \ - if test -f $(srcdir)/$(DOMAIN).pot; then \ - dists="$$dists $(DOMAIN).pot stamp-po"; \ - fi; \ - if test -f $(srcdir)/ChangeLog; then \ - dists="$$dists ChangeLog"; \ - fi; \ - for i in 0 1 2 3 4 5 6 7 8 9; do \ - if test -f $(srcdir)/ChangeLog.$$i; then \ - dists="$$dists ChangeLog.$$i"; \ - fi; \ - done; \ - if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ - for file in $$dists; do \ - if test -f $$file; then \ - cp -p $$file $(distdir) || exit 1; \ - else \ - cp -p $(srcdir)/$$file $(distdir) || exit 1; \ - fi; \ - done - -update-po: Makefile - $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) - $(MAKE) update-gmo - -# General rule for creating PO files. - -.nop.po-create: - @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ - echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ - exit 1 - -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - *) \ - $(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ - esac; \ - }; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - -$(DUMMYPOFILES): - -update-gmo: Makefile $(GMOFILES) - @: - -# Recreate Makefile by invoking config.status. Explicitly invoke the shell, -# because execution permission bits may not work on the current file system. -# Use @SHELL@, which is the shell determined by autoconf for the use by its -# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient. -Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ - cd $(top_builddir) \ - && @SHELL@ ./config.status $(subdir)/$@.in po-directories - -force: - -# Tell versions [3.59,3.63) of GNU make not to export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/plugins/sample/po/Makevars b/plugins/sample/po/Makevars deleted file mode 100644 index 60de3f1..0000000 --- a/plugins/sample/po/Makevars +++ /dev/null @@ -1,41 +0,0 @@ -# Makefile variables for PO directory in any package using GNU gettext. - -# Usually the message domain is the same as the package name. -DOMAIN = sample - -# These two variables depend on the location of this directory. -subdir = po -top_builddir = .. - -# These options get passed to xgettext. -XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ - -# This is the copyright holder that gets inserted into the header of the -# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding -# package. (Note that the msgstr strings, extracted from the package's -# sources, belong to the copyright holder of the package.) Translators are -# expected to transfer the copyright for their translations to this person -# or entity, or to disclaim their copyright. The empty string stands for -# the public domain; in this case the translators are expected to disclaim -# their copyright. -COPYRIGHT_HOLDER = - -# This is the email address or URL to which the translators shall report -# bugs in the untranslated strings: -# - Strings which are not entire sentences, see the maintainer guidelines -# in the GNU gettext documentation, section 'Preparing Strings'. -# - Strings which use unclear terms or require additional context to be -# understood. -# - Strings which make invalid assumptions about notation of date, time or -# money. -# - Pluralisation problems. -# - Incorrect English spelling. -# - Incorrect formatting. -# It can be your email address, or a mailing list address where translators -# can write to without being subscribed, or the URL of a web page through -# which the translators can contact you. -MSGID_BUGS_ADDRESS = kimchi-devel@ovirt.org - -# This is the list of locale categories, beyond LC_MESSAGES, for which the -# message catalogs shall be used. It is usually empty. -EXTRA_LOCALE_CATEGORIES = diff --git a/plugins/sample/po/POTFILES.in b/plugins/sample/po/POTFILES.in deleted file mode 100644 index 7dbfb6c..0000000 --- a/plugins/sample/po/POTFILES.in +++ /dev/null @@ -1,2 +0,0 @@ -# List of source files which contain translatable strings. -plugins/sample/ui/pages/*.tmpl diff --git a/plugins/sample/po/en_US.po b/plugins/sample/po/en_US.po deleted file mode 100644 index 207d3c3..0000000 --- a/plugins/sample/po/en_US.po +++ /dev/null @@ -1,21 +0,0 @@ -# English translations for kimchi package. -# Copyright (C) 2014 THE kimchi'S COPYRIGHT HOLDER -# This file is distributed under the same license as the kimchi package. -# shhfeng <shaohef@linux.vnet.ibm.com>, 2014. -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 1.2.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-24 09:39-0300\n" -"PO-Revision-Date: 2014-05-17 02:08+0800\n" -"Last-Translator: shhfeng <shaohef@linux.vnet.ibm.com>\n" -"Language-Team: English\n" -"Language: en_US\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ASCII\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: pygettext.py 1.5\n" - -msgid "SampleTab" -msgstr "SampleTab" diff --git a/plugins/sample/po/gen-pot b/plugins/sample/po/gen-pot deleted file mode 100755 index c1cfb8f..0000000 --- a/plugins/sample/po/gen-pot +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -for src in $@; do - if [ ${src: -3} == ".py" ]; then - cat $src - else - cat $src | cheetah compile - - fi -done | xgettext --no-location -o sample.pot -L Python - diff --git a/plugins/sample/po/pt_BR.po b/plugins/sample/po/pt_BR.po deleted file mode 100644 index 8519d74..0000000 --- a/plugins/sample/po/pt_BR.po +++ /dev/null @@ -1,24 +0,0 @@ -# Portuguese translations for kimchi package -# Copyright (C) 2014 THE kimchi'S COPYRIGHT HOLDER -# This file is distributed under the same license as the kimchi package. -# shhfeng <shaohef@linux.vnet.ibm.com>, 2014. -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 1.2.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-24 09:39-0300\n" -"PO-Revision-Date: 2014-05-17 02:09+0800\n" -"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" -"Language-Team: Aline Manera <alinefm@br.ibm.com>\n" -"Language: pt_BR\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: pygettext.py 1.5\n" -"X-Poedit-Country: Brazil\n" -"X-Poedit-Language: Portuguese\n" -"X-Poedit-SourceCharset: utf-8\n" - -msgid "SampleTab" -msgstr "Tab de exemplo" diff --git a/plugins/sample/po/sample.pot b/plugins/sample/po/sample.pot deleted file mode 100644 index 458ffe9..0000000 --- a/plugins/sample/po/sample.pot +++ /dev/null @@ -1,21 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-24 09:39-0300\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" -"Language-Team: LANGUAGE <LL@li.org>\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -msgid "SampleTab" -msgstr "" diff --git a/plugins/sample/po/zh_CN.po b/plugins/sample/po/zh_CN.po deleted file mode 100644 index 04b2501..0000000 --- a/plugins/sample/po/zh_CN.po +++ /dev/null @@ -1,24 +0,0 @@ -# Chinese translations for kimchi package -# Copyright (C) 2014 THE kimchi'S COPYRIGHT HOLDER -# This file is distributed under the same license as the kimchi package. -# shhfeng <shaohef@linux.vnet.ibm.com>, 2014. -# -msgid "" -msgstr "" -"Project-Id-Version: kimchi 1.2.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-24 09:39-0300\n" -"PO-Revision-Date: 2014-05-17 02:10+0800\n" -"Last-Translator: shhfeng <shaohef@linux.vnet.ibm.com>\n" -"Language-Team: Chinese (simplified)\n" -"Language: zh_CN\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: pygettext.py 1.5\n" -"X-Poedit-Country: CHINA\n" -"X-Poedit-Language: Chinese\n" -"X-Poedit-SourceCharset: utf-8\n" - -msgid "SampleTab" -msgstr "������������" diff --git a/plugins/sample/sample.conf.in b/plugins/sample/sample.conf.in deleted file mode 100644 index 9da33e1..0000000 --- a/plugins/sample/sample.conf.in +++ /dev/null @@ -1,27 +0,0 @@ -[wok] -enable = @ENABLE_SAMPLE@ -plugin_class = "Drawings" -uri = "/plugins/sample" - -[/] -tools.nocache.on = True -tools.trailing_slash.on = False -tools.sessions.on = True -tools.sessions.name = 'wok' -tools.sessions.httponly = True -tools.sessions.locking = 'explicit' -tools.sessions.storage_type = 'ram' - -[/description] -tools.wokauth.on = True - -[/rectangles] -tools.wokauth.on = True - -[/circles] -tools.wokauth.on = True - -[/help] -tools.staticdir.on = True -tools.nocache.on = True -tools.staticdir.dir = wok.config.PluginPaths('sample').ui_dir + '/pages/help' diff --git a/plugins/sample/ui/Makefile.am b/plugins/sample/ui/Makefile.am deleted file mode 100644 index 37fec98..0000000 --- a/plugins/sample/ui/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -SUBDIRS = config js pages - - diff --git a/plugins/sample/ui/config/Makefile.am b/plugins/sample/ui/config/Makefile.am deleted file mode 100644 index cf9e09e..0000000 --- a/plugins/sample/ui/config/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2013 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -EXTRA_DIST = tab-ext.xml - diff --git a/plugins/sample/ui/config/tab-ext.xml b/plugins/sample/ui/config/tab-ext.xml deleted file mode 100644 index aff0d14..0000000 --- a/plugins/sample/ui/config/tab-ext.xml +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<tabs-ext> - <tab> - <access role="admin" mode="admin"/> - <access role="user" mode="none"/> - - <title>SampleTab 1</title> - <path>plugins/sample/sample-tab1.html</path> - </tab> - <tab> - <access role="admin" mode="admin"/> - <access role="user" mode="none"/> - - <title>SampleTab 2</title> - <path>plugins/sample/sample-tab2.html</path> - </tab> -</tabs-ext> diff --git a/plugins/sample/ui/css/.gitignore b/plugins/sample/ui/css/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/sample/ui/images/.gitignore b/plugins/sample/ui/images/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/sample/ui/js/.gitignore b/plugins/sample/ui/js/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/sample/ui/js/Makefile.am b/plugins/sample/ui/js/Makefile.am deleted file mode 100644 index 4d536ae..0000000 --- a/plugins/sample/ui/js/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -EXTRA_DIST = util.js diff --git a/plugins/sample/ui/js/util.js b/plugins/sample/ui/js/util.js deleted file mode 100644 index 7689a81..0000000 --- a/plugins/sample/ui/js/util.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -sample = {}; - -sample.description = function(suc, err){ - wok.requestJSON({ - url : 'plugins/sample/description', - type : 'GET', - contentType : 'application/json', - dataType : 'json', - resend : true, - success : suc, - error : err || function(data) { - wok.message.error(data.responseJSON.reason); - } - }); -}; diff --git a/plugins/sample/ui/libs/.gitignore b/plugins/sample/ui/libs/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/sample/ui/pages/Makefile.am b/plugins/sample/ui/pages/Makefile.am deleted file mode 100644 index 3da95a2..0000000 --- a/plugins/sample/ui/pages/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# -# Kimchi -# -# Copyright IBM Corp, 2014 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -EXTRA_DIST = i18n.json.tmpl sample-tab1.html.tmpl sample-tab2.html.tmpl diff --git a/plugins/sample/ui/pages/help/en_US/sample-tab1.html b/plugins/sample/ui/pages/help/en_US/sample-tab1.html deleted file mode 100644 index 7122124..0000000 --- a/plugins/sample/ui/pages/help/en_US/sample-tab1.html +++ /dev/null @@ -1 +0,0 @@ -Help page for TAB 1 of Wok's Sample plugin. diff --git a/plugins/sample/ui/pages/help/en_US/sample-tab2.html b/plugins/sample/ui/pages/help/en_US/sample-tab2.html deleted file mode 100644 index 1bfe448..0000000 --- a/plugins/sample/ui/pages/help/en_US/sample-tab2.html +++ /dev/null @@ -1 +0,0 @@ -Help page for TAB 2 of Wok's Sample plugin. diff --git a/plugins/sample/ui/pages/i18n.json.tmpl b/plugins/sample/ui/pages/i18n.json.tmpl deleted file mode 100644 index 737bb39..0000000 --- a/plugins/sample/ui/pages/i18n.json.tmpl +++ /dev/null @@ -1,26 +0,0 @@ -#* - * Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -#import gettext -#from wok.cachebust import href -#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang) -#silent _ = t.gettext -#silent _t = t.gettext -{ - "SampleTab": "$_("SampleTab")" -} diff --git a/plugins/sample/ui/pages/sample-tab1.html.tmpl b/plugins/sample/ui/pages/sample-tab1.html.tmpl deleted file mode 100644 index 4354d81..0000000 --- a/plugins/sample/ui/pages/sample-tab1.html.tmpl +++ /dev/null @@ -1,30 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -<!DOCTYPE html> -<html> -<script type="text/javascript" src="plugins/sample/js/util.js"></script> -<body> - <div id="samplebody"/> -</body> -<script> - sample.description(function(r){ - \$("#samplebody").html("name: " + r.name + " version: " + r.version); - }); -</script> -</html> diff --git a/plugins/sample/ui/pages/sample-tab2.html.tmpl b/plugins/sample/ui/pages/sample-tab2.html.tmpl deleted file mode 100644 index 4354d81..0000000 --- a/plugins/sample/ui/pages/sample-tab2.html.tmpl +++ /dev/null @@ -1,30 +0,0 @@ -#* - * Project Kimchi - * - * Copyright IBM, Corp. 2014 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# -#unicode UTF-8 -<!DOCTYPE html> -<html> -<script type="text/javascript" src="plugins/sample/js/util.js"></script> -<body> - <div id="samplebody"/> -</body> -<script> - sample.description(function(r){ - \$("#samplebody").html("name: " + r.name + " version: " + r.version); - }); -</script> -</html> diff --git a/src/wok/plugins/Makefile.am b/src/wok/plugins/Makefile.am new file mode 100644 index 0000000..21a6ece --- /dev/null +++ b/src/wok/plugins/Makefile.am @@ -0,0 +1,25 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +SUBDIRS = sample + +plugins_PYTHON = \ + __init__.py + +pluginsdir = $(pythondir)/wok/plugins diff --git a/src/wok/plugins/__init__.py b/src/wok/plugins/__init__.py new file mode 100644 index 0000000..0539a76 --- /dev/null +++ b/src/wok/plugins/__init__.py @@ -0,0 +1,18 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/src/wok/plugins/kimchi/.gitignore b/src/wok/plugins/kimchi/.gitignore new file mode 100644 index 0000000..1dae610 --- /dev/null +++ b/src/wok/plugins/kimchi/.gitignore @@ -0,0 +1,37 @@ +*.pyc +*~ +i18n/mo/* +log +data +mo +autom4te.cache +Makefile +Makefile.in +aclocal.m4 +build-aux/compile +build-aux/config.guess +build-aux/config.sub +build-aux/install-sh +build-aux/missing +build-aux/py-compile +configure +config.log +config.py +config.status +contrib/DEBIAN/control +contrib/kimchi.spec.fedora +contrib/kimchi.spec.suse +contrib/make-deb.sh +*.min.css +*.min.js +*.gmo +stamp-po +kimchi-*.tar.gz +tests/run_tests.sh +tests/test_config.py +po/POTFILES +po/gen-pot +*.orig +*.rej +*.pem +ui/pages/help/*/*.html diff --git a/src/wok/plugins/kimchi/API.json b/src/wok/plugins/kimchi/API.json new file mode 100644 index 0000000..f1f58ff --- /dev/null +++ b/src/wok/plugins/kimchi/API.json @@ -0,0 +1,836 @@ +{ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Kimchi API", + "description": "Json schema for Kimchi API", + "type": "object", + "kimchitype": { + "graphics": { + "description": "Configure graphics parameters for the new VM", + "type": "object", + "properties": { + "type": { + "enum": ["spice", "vnc"], + "error": "KCHVM0014E" + }, + "listen": { + "error": "KCHVM0015E", + "type": [ + { + "type": "string", + "format": "ip-address" + }, + { + "type": "string", + "format": "ipv6" + } + ] + } + } + }, + "cpu_info": { + "description": "Configure CPU specifics for a VM.", + "type": "object", + "properties": { + "topology": { + "description": "Configure the guest CPU topology.", + "type": "object", + "properties": { + "sockets": { + "type": "integer", + "required": true, + "minimum": 1, + "error": "KCHTMPL0026E" + }, + "cores": { + "type": "integer", + "required": true, + "minimum": 1, + "error": "KCHTMPL0026E" + }, + "threads": { + "type": "integer", + "required": true, + "minimum": 1, + "error": "KCHTMPL0026E" + } + } + } + } + } + }, + "properties": { + "debugreports_create": { + "type": "object", + "error": "KCHDR0006E", + "properties": { + "name": { + "description": "The name for the debug report file.", + "type": "string", + "pattern": "^[_A-Za-z0-9-]*$", + "error": "KCHDR0007E" + } + } + }, + "debugreport_update": { + "type": "object", + "properties": { + "name": { + "description": "New name of debug report", + "type": "string", + "pattern": "^[_A-Za-z0-9-]*$", + "error": "KCHDR0007E" + } + }, + "additionalProperties": false + }, + "storagepools_create": { + "type": "object", + "error": "KCHPOOL0026E", + "properties": { + "name": { + "description": "The name of the Storage Pool", + "type": "string", + "minLength": 1, + "pattern": "^[^/]*$", + "required": true, + "error": "KCHPOOL0016E" + }, + "type": { + "description": "The type of the defined Storage Pool", + "type": "string", + "pattern": "^dir|netfs|logical|kimchi-iso|iscsi|scsi$", + "required": true, + "error": "KCHPOOL0017E" + }, + "path": { + "description": "The path of the defined Storage Pool", + "type": "string", + "error": "KCHPOOL0018E" + }, + "source": { + "description": "Dictionary containing source information of the pool", + "type": "object", + "properties": { + "host": { + "description": "IP or hostname of server for a pool backed from a remote host", + "type": "string", + "error": "KCHPOOL0019E" + }, + "path": { + "description": "Export path on NFS server for NFS pool", + "type": "string", + "error": "KCHPOOL0018E" + }, + "devices": { + "description": "Array of devices to be used in the Storage Pool", + "type": "array", + "minItems": 1, + "uniqueItems": true, + "error": "KCHPOOL0021E", + "items": { + "description": "Full path of the block device node", + "type": "string", + "error": "KCHPOOL0020E" + } + }, + "target": { + "description": "Target IQN of an iSCSI pool", + "type": "string", + "error": "KCHPOOL0022E" + }, + "port": { + "description": "Listening port of a remote storage server", + "type": "integer", + "minimum": 1, + "maximum": 65535, + "error": "KCHPOOL0023E" + }, + "adapter_name": { + "description": "SCSI host name", + "type": "string", + "error": "KCHPOOL0030E" + }, + "auth": { + "description": "Storage back-end authentication information", + "type": "object", + "properties": { + "username": { + "description": "Login username of the iSCSI target", + "type": "string", + "error": "KCHPOOL0024E" + }, + "password": { + "description": "Login password of the iSCSI target", + "type": "string", + "error": "KCHPOOL0025E" + } + } + } + } + } + } + }, + "storagepool_update": { + "type": "object", + "properties": { + "autostart": { + "description": "Set autostart value of the pool", + "type": "boolean" + }, + "disks": { + "description": "List of disks/partitions to be added", + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true + } + }, + "additionalProperties": false + }, + "storagevolumes_create": { + "type": "object", + "properties": { + "name": { + "description": "The name of the Storage Volume", + "type": "string", + "minLength": 1, + "error": "KCHVOL0013E" + }, + "capacity": { + "description": "The total size (MiB) of the storage volume", + "type": "number", + "minimum": 1, + "error": "KCHVOL0020E" + }, + "upload": { + "description": "When the storage volume will be uploaded", + "type": "boolean", + "error": "KCHVOL0025E" + }, + "allocation": { + "description": "The size(MiB) of allocation when create the storage volume", + "type": "number", + "minimum": 1, + "error": "KCHVOL0014E" + }, + "format": { + "description": "The format of the volume", + "type": "string", + "pattern": "^(|bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", + "error": "KCHVOL0015E" + }, + "url": { + "description": "The remote URL of the storage volume", + "type": "string", + "pattern": "^(http|ftp)[s]?://", + "error": "KCHVOL0021E" + } + } + }, + "storagevolume_update": { + "type": "object", + "properties": { + "chunk": { + "description": "Upload storage volume chunk", + "error": "KCHVOL0024E", + "required": true + }, + "chunk_size": { + "description": "Chunk size of uploaded storage volume", + "type": "string", + "error": "KCHVOL0024E", + "required": true + } + }, + "additionalProperties": false + }, + "vms_create": { + "type": "object", + "error": "KCHVM0016E", + "properties": { + "name": { + "description": "The name of the new VM", + "type": "string", + "pattern": "^[^/]*$", + "error": "KCHVM0011E" + }, + "template": { + "description": "The URI of a template to use when building a VM", + "type": "string", + "pattern": "^/plugins/kimchi/templates/(.*?)/?$", + "required": true, + "error": "KCHVM0012E" + }, + "storagepool": { + "description": "Assign a specefic Storage Pool to the new VM", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHVM0013E" + }, + "graphics": { "$ref": "#/kimchitype/graphics" } + } + }, + "vm_update": { + "type": "object", + "properties": { + "name": { + "description": "New name of VM", + "type": "string", + "pattern": "^[^/]*$", + "minLength": 1, + "error": "KCHVM0011E" + }, + "users": { + "description": "Array of users who have permission to the VM", + "type": "array", + "uniqueItems": true, + "error": "KCHVM0023E", + "items": { + "description": "User name", + "type": "string", + "error": "KCHVM0024E" + } + }, + "groups": { + "description": "Array of groups who have permission to the VM", + "type": "array", + "uniqueItems": true, + "error": "KCHVM0025E", + "items": { + "description": "Group name", + "type": "string", + "error": "KCHVM0026E" + } + }, + "graphics": { + "description": "Graphics information from guest", + "type": "object", + "properties": { + "passwd": { + "description": "New graphics password.", + "type": "string", + "error": "KCHVM0031E" + }, + "passwdValidTo": { + "description": "Life time for the graphics password.", + "type": "number", + "error": "KCHVM0032E" + } + } + }, + "cpus": { + "description": "The new number of virtual CPUs for the VM", + "type": "integer", + "minimum": 1, + "error": "KCHTMPL0012E" + }, + "memory": { + "description": "The new amount (MB) of memory for the VM", + "type": "integer", + "minimum": 512, + "error": "KCHTMPL0013E" + } + }, + "additionalProperties": false + }, + "networks_create": { + "type": "object", + "error": "KCHNET0016E", + "properties": { + "name": { + "description": "The name of the new network", + "type": "string", + "minLength": 1, + "pattern": "^[^/\"]*$", + "required": true, + "error": "KCHNET0011E" + }, + "connection": { + "description": "Specifies how this network should be connected to the other networks", + "type": "string", + "pattern": "^isolated|nat|bridge$", + "required": true, + "error": "KCHNET0012E" + }, + "subnet": { + "description": "Network segment in slash-separated format with ip address and prefix or netmask", + "type": "string", + "error": "KCHNET0013E" + }, + "interface": { + "description": "The name of a network interface on the host", + "type": "string", + "error": "KCHNET0014E" + }, + "vlan_id": { + "description": "Network's VLAN ID", + "type": "integer", + "maximum": 4094, + "minimum": 1, + "error": "KCHNET0015E" + } + } + }, + "vmifaces_create": { + "type": "object", + "error": "KCHVMIF0007E", + "properties": { + "type": { + "description": "The type of VM network interface that libvirt supports", + "type": "string", + "pattern": "^network$", + "required": true, + "error": "KCHVMIF0004E" + }, + "network": { + "description": "the name of one available network", + "minLength": 1, + "type": "string", + "error": "KCHVMIF0005E" + }, + "model": { + "description": "model of emulated network interface card", + "type": "string", + "pattern": "^ne2k_pci|i82551|i82557b|i82559er|rtl8139|e1000|pcnet|virtio$", + "error": "KCHVMIF0006E" + }, + "mac": { + "description": "Network Interface Card MAC address", + "type": "string", + "pattern": "(^$)|^(([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$)", + "error": "KCHVMIF0010E" + } + } + }, + "vmiface_update": { + "type": "object", + "error": "KCHVMIF0008E", + "properties": { + "mac": { + "description": "Network Interface Card MAC address", + "type": "string", + "pattern": "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$", + "error": "KCHVMIF0010E" + } + } + }, + "templates_create": { + "type": "object", + "error": "KCHTMPL0016E", + "properties": { + "name": { + "description": "The name of the template", + "type": "string", + "pattern": "^[^ ]+( +[^ ]+)*$", + "minLength": 1, + "error": "KCHTMPL0008E" + }, + "icon": { + "description": "The template icon path", + "type": "string", + "pattern": "^/plugins/kimchi/images/", + "error": "KCHTMPL0009E" + }, + "os_distro": { + "description": "Distribution name of the Operating System", + "type": "string", + "minLength": 1, + "error": "KCHTMPL0010E" + }, + "os_version": { + "description": "Version of the Operating System", + "type": "string", + "minLength": 1, + "error": "KCHTMPL0011E" + }, + "cpus": { + "description": "Number of CPUs for the template", + "type": "integer", + "minimum": 1, + "error": "KCHTMPL0012E" + }, + "memory": { + "description": "Memory (MB) for the template", + "type": "integer", + "minimum": 512, + "error": "KCHTMPL0013E" + }, + "cdrom": { + "description": "Path for cdrom", + "type": "string", + "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "error": "KCHTMPL0014E" + }, + "disks": { + "description": "List of disks", + "type": "array", + "items": { + "type": "object", + "properties": { + "index": { + "description": "Index of the disk", + "type": "integer", + "minimum": 0 + }, + "size": { + "description": "Size (GB) of the disk", + "type": "number", + "minimum": 1, + "error": "KCHTMPL0022E" + }, + "base": { + "description": "Base image of the disk", + "type": "string", + "pattern": "^/.+$", + "error": "KCHTMPL0023E" + } + + } + }, + "minItems": 1, + "uniqueItems": true + }, + "storagepool": { + "description": "Location of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" + }, + "networks": { + "description": "list of which networks will be assigned to the new VM.", + "type": "array", + "items": { "type": "string" }, + "error": "KCHTMPL0017E" + }, + "folder": { + "description": "Folder", + "type": "array", + "items": { "type": "string" } + }, + "graphics": { "$ref": "#/kimchitype/graphics" }, + "cpu_info": { "$ref": "#/kimchitype/cpu_info" } + }, + "additionalProperties": false, + "error": "KCHAPI0001E" + }, + "storageservers_get_list": { + "type": "object", + "properties": { + "_target_type": { + "description": "List storage servers of given type", + "type": "string", + "pattern": "^netfs|iscsi$" + } + }, + "additionalProperties": false, + "error": "KCHAPI0001E" + }, + "storagetargets_get_list": { + "type": "object", + "properties": { + "_target_type": { + "description": "List storage servers of given type", + "type": "string", + "pattern": "^netfs|iscsi$" + }, + "_server_port": { + "description": "the port of iscsi storage servers", + "type": "string", + "pattern": "^[0-9]{1,5}$" + } + }, + "additionalProperties": false, + "error": "KCHAPI0001E" + }, + "vmstorages_create": { + "type": "object", + "error": "KCHVMSTOR0012E", + "properties": { + "type": { + "description": "The storage type", + "type": "string", + "pattern": "^cdrom|disk$", + "required": true, + "error": "KCHVMSTOR0002E" + }, + "pool": { + "description": "Storage pool name disk image locate in", + "type": "string", + "minLength": 1, + "error": "KCHVMSTOR0012E" + }, + "vol": { + "description": "Storage volume name of disk image", + "type": "string", + "minLength": 1, + "error": "KCHVMSTOR0012E" + }, + "path": { + "description": "Path of iso image file or disk mount point", + "type": "string", + "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "error": "KCHVMSTOR0003E" + } + } + }, + "vmstorage_update": { + "type": "object", + "error": "KCHVMSTOR0013E", + "properties": { + "path": { + "description": "Path of iso image file or disk mount point", + "type": "string", + "pattern": "^(|(/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "required": true, + "error": "KCHVMSTOR0003E" + } + }, + "additionalProperties": false + }, + "template_update": { + "type": "object", + "properties": { + "name": { + "description": "The name of the template", + "type": "string", + "pattern": "^[^ ]+( +[^ ]+)*$", + "minLength": 1, + "error": "KCHTMPL0008E" + }, + "icon": { + "description": "The template icon path", + "type": "string", + "pattern": "^/plugins/kimchi/images/", + "error": "KCHTMPL0009E" + }, + "os_distro": { + "description": "Distribution name of the Operating System", + "type": "string", + "minLength": 1, + "error": "KCHTMPL0010E" + }, + "os_version": { + "description": "Version of the Operating System", + "type": "string", + "minLength": 1, + "error": "KCHTMPL0011E" + }, + "cpus": { + "description": "Number of CPUs for the template", + "type": "integer", + "minimum": 1, + "error": "KCHTMPL0012E" + }, + "memory": { + "description": "Memory (MB) for the template", + "type": "integer", + "minimum": 512, + "error": "KCHTMPL0013E" + }, + "cdrom": { + "description": "Path for cdrom", + "type": "string", + "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$", + "error": "KCHTMPL0014E" + }, + "disks": { + "description": "List of disks", + "type": "array", + "items": { + "type": "object", + "properties": { + "index": { + "description": "Index of the disk", + "type": "integer", + "minimum": 0 + }, + "size": { + "description": "Size (GB) of the disk", + "type": "integer", + "minimum": 1, + "error": "KCHTMPL0022E" + }, + "format": { + "description": "Type of the image of the disk", + "type": "string", + "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", + "error": "KCHTMPL0027E" + } + } + }, + "minItems": 1, + "uniqueItems": true + }, + "storagepool": { + "description": "Location of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" + }, + "networks": { + "description": "list of which networks will be assigned to the new VM.", + "type": "array", + "items": { "type": "string" }, + "error": "KCHTMPL0017E" + }, + "folder": { + "description": "Folder", + "type": "array", + "items": { "type": "string" } + }, + "graphics": { "$ref": "#/kimchitype/graphics" }, + "cpu_info": { "$ref": "#/kimchitype/cpu_info" } + }, + "additionalProperties": false, + "error": "KCHAPI0001E" + }, + "repositories_create": { + "type": "object", + "properties": { + "repo_id": { + "description": "Repository ID used for YUM repository.", + "type": "string", + "error": "KCHREPOS0001E" + }, + "baseurl": { + "description": "URL to the directory where the repodata directory of a repository is located. Can be an http://, ftp:// or file:// URL.", + "type": "string", + "error": "KCHREPOS0002E" + }, + "config": { + "description": "Dictionary containing repository configuration", + "type": "object", + "error": "KCHREPOS0003E", + "properties": { + "dist": { + "description": "Distribution to DEB repository", + "type": "string", + "error": "KCHREPOS0004E" + }, + "comps": { + "description": "List of components to DEB repository", + "type": "array", + "error": "KCHREPOS0005E", + "uniqueItems": true, + "items": { + "description": "Component name", + "type": "string", + "error": "KCHREPOS0006E" + } + }, + "repo_name": { + "description": "YUM repository name", + "type": "string", + "error": "KCHREPOS0023E" + }, + "mirrorlist": { + "description": "URL to a file containing a list of baseurls", + "type": "string", + "error": "KCHREPOS0007E" + }, + "metalink": { + "description": "URL to a metalink file for the repomd.xml", + "type": "string", + "error": "KCHREPOS0029E" + } + } + } + }, + "additionalProperties": false, + "error": "KCHAPI0001E" + }, + "repository_update": { + "type": "object", + "properties": { + "baseurl": { + "description": "URL to the directory where the repodata directory of a repository is located. Can be an http://, ftp:// or file:// URL.", + "type": "string", + "error": "KCHREPOS0002E" + }, + "config": { + "description": "Dictionary containing repository configuration", + "type": "object", + "error": "KCHREPOS0003E", + "properties": { + "dist": { + "description": "Distribution to DEB repository", + "type": "string", + "error": "KCHREPOS0004E" + }, + "comps": { + "description": "List of components to DEB repository", + "type": "array", + "error": "KCHREPOS0005E", + "uniqueItems": true, + "items": { + "description": "Component name", + "type": "string", + "error": "KCHREPOS0006E" + } + }, + "repo_name": { + "description": "Human-readable string describing the YUM repository.", + "type": "string", + "error": "KCHREPOS0008E" + }, + "mirrorlist": { + "description": "URL to a file containing a list of baseurls for YUM repository", + "type": "string", + "error": "KCHREPOS0007E" + }, + "gpgcheck": { + "description": "Indicates if a GPG signature check on the packages gotten from repository should be performed.", + "type": "boolean", + "error": "KCHREPOS0009E" + }, + "gpgkey": { + "description": "URL pointing to the ASCII-armored GPG key file for the repository.", + "type": "string", + "error": "KCHREPOS0010E" + } + } + } + }, + "additionalProperties": false, + "error": "KCHAPI0001E" + }, + "devices_get_list": { + "type": "object", + "properties": { + "_cap": { + "description": "List specific type of device", + "type": "string", + "pattern": "^fc_host|net|pci|scsi|scsi_host|storage|system|usb|usb_device$", + "error": "KCHDEVS0001E" + }, + "_passthrough": { + "description": "List only devices eligible to be assigned to guest", + "type": "string", + "pattern": "^true|false$", + "error": "KCHDEVS0002E" + }, + "_passthrough_affected_by": { + "description": "List the affected devices in the same group of a certain device to be assigned to guest", + "type": "string", + "pattern": "^[_A-Za-z0-9-]+$", + "error": "KCHDEVS0003E" + } + }, + "additionalProperties": false, + "error": "KCHAPI0001E" + }, + "vmhostdevs_create": { + "type": "object", + "properties": { + "name": { + "description": "Then name of the device to assign to VM", + "type": "string", + "pattern": "^[_A-Za-z0-9-]+$", + "required": true, + "error": "KCHVMHDEV0004E" + } + }, + "error": "KCHAPI0001E" + } + } +} diff --git a/src/wok/plugins/kimchi/INSTALL b/src/wok/plugins/kimchi/INSTALL new file mode 100644 index 0000000..63bf076 --- /dev/null +++ b/src/wok/plugins/kimchi/INSTALL @@ -0,0 +1,369 @@ +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `<wchar.h>' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. diff --git a/src/wok/plugins/kimchi/Makefile.am b/src/wok/plugins/kimchi/Makefile.am new file mode 100644 index 0000000..49c835e --- /dev/null +++ b/src/wok/plugins/kimchi/Makefile.am @@ -0,0 +1,161 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +SUBDIRS = contrib control distros.d docs model po tests ui xmlutils + +kimchi_PYTHON = $(filter-out config.py, $(wildcard *.py)) + +nodist_kimchi_PYTHON = config.py + +if WITH_SPICE +WITH_SPICE=yes +else +WITH_SPICE=no +endif + +wokdir = $(pythondir)/wok +kimchidir = $(pythondir)/wok/plugins/kimchi + +confdir = $(sysconfdir)/wok/plugins.d +dist_conf_DATA = kimchi.conf template.conf + +AUTOMAKE_OPTIONS = foreign + +ACLOCAL_AMFLAGS = --install -I m4 + +EXTRA_DIST = \ + config.rpath \ + API.json \ + autogen.sh \ + COPYING.ASL2 \ + COPYING.LGPL \ + CONTRIBUTE.md \ + VERSION \ + build-aux/pkg-version \ + config.py.in \ + $(NULL) + + +PEP8_BLACKLIST = *config.py,*i18n.py,*tests/test_config.py + +I18N_FILES = ./i18n.py \ + $(NULL) + +check-local: + contrib/check_i18n.py $(I18N_FILES) + find . -path './.git' -prune -type f -o \ + -name '*.py' -o -name '*.py.in' | xargs $(PYFLAKES) | \ + while read LINE; do echo "$$LINE"; false; done + + $(PEP8) --version + $(PEP8) --filename '*.py,*.py.in' --exclude="$(PEP8_BLACKLIST)" . + + +# Link built mo files in the source tree to enable use of translations from +# within the source tree +all-local: + while read L && test -n "$$L"; do \ + dir=mo/$$L/LC_MESSAGES ; \ + $(MKDIR_P) $$dir ; \ + ln -sf ../../../po/$$L.gmo $$dir/kimchi.mo ; \ + done < po/LINGUAS + +do_substitution = \ + sed -e 's,[@]prefix[@],$(prefix),g' \ + -e 's,[@]datadir[@],$(datadir),g' \ + -e 's,[@]sysconfdir[@],$(sysconfdir),g' \ + -e 's,[@]localstatedir[@],$(localstatedir),g' \ + -e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \ + -e 's,[@]wokdir[@],$(wokdir),g' \ + -e 's,[@]kimchidir[@],$(kimchidir),g' \ + -e 's,[@]kimchiversion[@],$(PACKAGE_VERSION),g' \ + -e 's,[@]kimchirelease[@],$(PACKAGE_RELEASE),g' \ + -e 's,[@]withspice[@],$(WITH_SPICE),g' + +config.py: config.py.in Makefile + $(do_substitution) < $(srcdir)/config.py.in > config.py + + +# +# Packaging helpers +# + +install-deb: install + cp -R $(top_srcdir)/contrib/DEBIAN $(DESTDIR)/ + mkdir -p $(DESTDIR)/var/lib/kimchi/vnc-tokens + mkdir -p $(DESTDIR)/var/lib/kimchi/debugreports + mkdir -p $(DESTDIR)/var/lib/kimchi/screenshots + mkdir -p $(DESTDIR)/var/lib/kimchi/isos + + +deb: contrib/make-deb.sh + $(top_srcdir)/contrib/make-deb.sh + +kimchi.spec: contrib/kimchi.spec.fedora contrib/kimchi.spec.suse + @if test -e /etc/redhat-release; then \ + ln -sf contrib/kimchi.spec.fedora $@ ; \ + elif test -e /etc/SuSE-release; then \ + ln -sf contrib/kimchi.spec.suse $@ ; \ + else \ + echo "Unable to select a spec file for RPM build" ; \ + /bin/false ; \ + fi + +rpm: dist kimchi.spec + $(MKDIR_P) rpm/BUILD rpm/RPMS rpm/SOURCES rpm/SPECS rpm/SRPMS + cp $(top_srcdir)/kimchi.spec rpm/SPECS/kimchi.spec + cp $(DIST_ARCHIVES) rpm/SOURCES + rpmbuild -ba --define "_topdir `pwd`/rpm" rpm/SPECS/kimchi.spec + +fedora-rpm: contrib/kimchi.spec.fedora + ln -sf contrib/kimchi.spec.fedora kimchi.spec + $(MAKE) rpm + +suse-rpm: contrib/kimchi.spec.suse + ln -sf contrib/kimchi.spec.suse kimchi.spec + $(MAKE) rpm + +ChangeLog: + @if test -d .git; then \ + $(top_srcdir)/build-aux/genChangelog --release > $@; \ + fi + +install-data-local: + $(MKDIR_P) $(DESTDIR)$(kimchidir) + $(INSTALL_DATA) API.json $(DESTDIR)$(kimchidir)/API.json + mkdir -p $(DESTDIR)/var/lib/kimchi/vnc-tokens + mkdir -p $(DESTDIR)/var/lib/kimchi/{debugreports,isos,screenshots} + +uninstall-local: + $(RM) $(DESTDIR)$(kimchidir)/API.json + $(RM) -rf $(DESTDIR)/var/lib/kimchi + +VERSION: + @if test -d .git; then \ + git describe --abbrev=0 > $@; \ + fi + +.PHONY: deb install-deb rpm fedora-rpm suse-rpm ChangeLog VERSION + + +clean-local: + rm -rf mo rpm + +BUILT_SOURCES = config.py +CLEANFILES = config.py kimchi.spec `find "$(top_srcdir)" -type f -name "*.pyc" -print` diff --git a/src/wok/plugins/kimchi/README.md b/src/wok/plugins/kimchi/README.md new file mode 120000 index 0000000..0e01b43 --- /dev/null +++ b/src/wok/plugins/kimchi/README.md @@ -0,0 +1 @@ +docs/README.md \ No newline at end of file diff --git a/src/wok/plugins/kimchi/VERSION b/src/wok/plugins/kimchi/VERSION new file mode 100644 index 0000000..bc80560 --- /dev/null +++ b/src/wok/plugins/kimchi/VERSION @@ -0,0 +1 @@ +1.5.0 diff --git a/src/wok/plugins/kimchi/__init__.py b/src/wok/plugins/kimchi/__init__.py new file mode 100644 index 0000000..9330044 --- /dev/null +++ b/src/wok/plugins/kimchi/__init__.py @@ -0,0 +1,21 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from root import KimchiRoot +__all__ = [KimchiRoot] diff --git a/src/wok/plugins/kimchi/autogen.sh b/src/wok/plugins/kimchi/autogen.sh new file mode 100755 index 0000000..0f22dba --- /dev/null +++ b/src/wok/plugins/kimchi/autogen.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +aclocal +automake --add-missing +autoreconf + +if [ ! -f "configure" ]; then + echo "Failed to generate configure script. Check to make sure autoconf, " + echo "automake, and other build dependencies are properly installed." + exit 1 +fi + +if [ "x$1" == "x--system" ]; then + ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var +else + if [ $# -gt 0 ]; then + ./configure $@ + else + ./configure --prefix=/usr/local + fi +fi diff --git a/src/wok/plugins/kimchi/build-aux/config.rpath b/src/wok/plugins/kimchi/build-aux/config.rpath new file mode 100644 index 0000000..17298f2 --- /dev/null +++ b/src/wok/plugins/kimchi/build-aux/config.rpath @@ -0,0 +1,672 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2010 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's _LT_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + darwin*) + case $cc_basename in + xlc*) + wl='-Wl,' + ;; + esac + ;; + mingw* | cygwin* | pw32* | os2* | cegcc*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + newsos6) + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + ecc*) + wl='-Wl,' + ;; + icc* | ifort*) + wl='-Wl,' + ;; + lf95*) + wl='-Wl,' + ;; + pgcc | pgf77 | pgf90) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + rdos*) + ;; + solaris*) + wl='-Wl,' + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + wl='-Wl,' + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's _LT_LINKER_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we cannot use + # them. + ld_shlibs=no + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32* | cegcc*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + interix[3-9]*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if test "$GCC" = yes ; then + : + else + case $cc_basename in + xlc*) + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd1*) + ld_shlibs=no + ;; + freebsd2.2*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + freebsd2*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. +# Unlike libtool.m4, here we don't care about _all_ names of the library, but +# only about the one the linker finds when passed -lNAME. This is the last +# element of library_names_spec in libtool.m4, or possibly two of them if the +# linker has special search rules. +library_names_spec= # the last element of library_names_spec in libtool.m4 +libname_spec='lib$name' +case "$host_os" in + aix3*) + library_names_spec='$libname.a' + ;; + aix[4-9]*) + library_names_spec='$libname$shrext' + ;; + amigaos*) + library_names_spec='$libname.a' + ;; + beos*) + library_names_spec='$libname$shrext' + ;; + bsdi[45]*) + library_names_spec='$libname$shrext' + ;; + cygwin* | mingw* | pw32* | cegcc*) + shrext=.dll + library_names_spec='$libname.dll.a $libname.lib' + ;; + darwin* | rhapsody*) + shrext=.dylib + library_names_spec='$libname$shrext' + ;; + dgux*) + library_names_spec='$libname$shrext' + ;; + freebsd1*) + ;; + freebsd* | dragonfly*) + case "$host_os" in + freebsd[123]*) + library_names_spec='$libname$shrext$versuffix' ;; + *) + library_names_spec='$libname$shrext' ;; + esac + ;; + gnu*) + library_names_spec='$libname$shrext' + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + library_names_spec='$libname$shrext' + ;; + interix[3-9]*) + library_names_spec='$libname$shrext' + ;; + irix5* | irix6* | nonstopux*) + library_names_spec='$libname$shrext' + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux* | k*bsd*-gnu) + library_names_spec='$libname$shrext' + ;; + knetbsd*-gnu) + library_names_spec='$libname$shrext' + ;; + netbsd*) + library_names_spec='$libname$shrext' + ;; + newsos6) + library_names_spec='$libname$shrext' + ;; + nto-qnx*) + library_names_spec='$libname$shrext' + ;; + openbsd*) + library_names_spec='$libname$shrext$versuffix' + ;; + os2*) + libname_spec='$name' + shrext=.dll + library_names_spec='$libname.a' + ;; + osf3* | osf4* | osf5*) + library_names_spec='$libname$shrext' + ;; + rdos*) + ;; + solaris*) + library_names_spec='$libname$shrext' + ;; + sunos4*) + library_names_spec='$libname$shrext$versuffix' + ;; + sysv4 | sysv4.3*) + library_names_spec='$libname$shrext' + ;; + sysv4*MP*) + library_names_spec='$libname$shrext' + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + library_names_spec='$libname$shrext' + ;; + uts4*) + library_names_spec='$libname$shrext' + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF + +# How to pass a linker flag through the compiler. +wl="$escaped_wl" + +# Static library suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally "so"). +shlibext="$shlibext" + +# Format of library name prefix. +libname_spec="$escaped_libname_spec" + +# Library names that the linker finds when passed -lNAME. +library_names_spec="$escaped_library_names_spec" + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="$hardcode_libdir_separator" + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct="$hardcode_direct" + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L="$hardcode_minus_L" + +EOF diff --git a/src/wok/plugins/kimchi/build-aux/genChangelog b/src/wok/plugins/kimchi/build-aux/genChangelog new file mode 100755 index 0000000..803f24e --- /dev/null +++ b/src/wok/plugins/kimchi/build-aux/genChangelog @@ -0,0 +1,25 @@ +#!/bin/bash + +# This script is based on code from the Kandan project: +# https://github.com/kandanapp/kandan/blob/master/gen-changelog.sh + +echo "CHANGELOG" +echo "=========" +echo +git for-each-ref --sort='*authordate' --format='%(tag)' refs/tags | tac |grep -v '^$' | while read TAG ; do + if [ $NEXT ]; then + echo "#### [$NEXT] ####" + elif [ "$1" != "--release" ]; then + echo "#### [Current] ####" + else + NEXT=$TAG + continue + fi + GIT_PAGER=cat git log --pretty=format:" * [%h] %<(78,trunc)%s (%an)" $TAG..$NEXT + NEXT=$TAG + echo; echo +done +FIRST=$(git for-each-ref --sort='*authordate' --format='%(tag)' refs/tags | head -1) + +echo "#### [$FIRST] ####" +GIT_PAGER=cat git log --pretty=format:" * [%h] %<(78,trunc)%s (%an)" $FIRST diff --git a/src/wok/plugins/kimchi/build-aux/pkg-version b/src/wok/plugins/kimchi/build-aux/pkg-version new file mode 100755 index 0000000..749cf6c --- /dev/null +++ b/src/wok/plugins/kimchi/build-aux/pkg-version @@ -0,0 +1,59 @@ +#!/bin/sh +# +# Copyright 2008-2012 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# tags and output versions: +# - 4.9.0 => 4.9.0 (upstream clean) +# - 4.9.0-1 => 4.9.0 (downstream clean) +# - 4.9.0-2-g34e62f => 4.9.0 (upstream dirty) +# - 4.9.0-1-2-g34e62f => 4.9.0 (downstream dirty) +AWK_VERSION=' + BEGIN { FS="-" } + /^[0-9]/ { + print $1 + }' + +# tags and output releases: +# - 4.9.0 => 0 (upstream clean) +# - 4.9.0-1 => 1 (downstream clean) +# - 4.9.0-2-g34e62f1 => 2.git34e62f1 (upstream dirty) +# - 4.9.0-1-2-g34e62f1 => 1.2.git34e62f1 (downstream dirty) +AWK_RELEASE=' + BEGIN { FS="-"; OFS="." } + /^[0-9]/ { + if (NF == 1) print 0 + else if (NF == 2) print $2 + else if (NF == 3) print $2, "git" substr($3, 2) + else if (NF == 4) print $2, $3, "git" substr($4, 2) + }' + +if [ ! -d .git ]; then + PKG_VERSION=`cat VERSION` +else + PKG_VERSION=`git describe --tags --match "[0-9]*" || cat VERSION` +fi + +if test "x$1" = "x--full"; then + echo $PKG_VERSION | tr -d '[:space:]' +elif test "x$1" = "x--version"; then + echo $PKG_VERSION | awk "$AWK_VERSION" | tr -cd '[:alnum:].' +elif test "x$1" = "x--release"; then + echo $PKG_VERSION | awk "$AWK_RELEASE" | tr -cd '[:alnum:].' +else + echo "usage: $0 [--full|--version|--release]" + exit 1 +fi diff --git a/src/wok/plugins/kimchi/config.py.in b/src/wok/plugins/kimchi/config.py.in new file mode 100644 index 0000000..6ae0ccd --- /dev/null +++ b/src/wok/plugins/kimchi/config.py.in @@ -0,0 +1,144 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import libvirt +import os +import platform +import threading + +from wok.config import CACHEEXPIRES, PluginConfig, PluginPaths +from wok.xmlutils.utils import xpath_get_text + +kimchiLock = threading.Lock() + +__with_spice__ = "@withspice@" + +# Storage pool constant for read-only pool types +READONLY_POOL_TYPE = ['iscsi', 'scsi', 'mpath'] + + +def get_distros_store(): + return os.path.join(PluginPaths('kimchi').conf_dir, 'distros.d') + + +def get_debugreports_path(): + return os.path.join(PluginPaths('kimchi').state_dir, 'debugreports') + + +def get_screenshot_path(): + return os.path.join(PluginPaths('kimchi').state_dir, 'screenshots') + + +def find_qemu_binary(find_emulator=False): + try: + connect = libvirt.open(None) + except Exception, e: + raise Exception("Unable to get qemu binary location: %s" % e) + try: + xml = connect.getCapabilities() + + # On Little Endian system, the qemu binary is + # qemu-system-ppc64, not qemu-system-ppc64le as expected + arch = platform.machine() + if arch == "ppc64le": + arch = "ppc64" + + if find_emulator: + expr = "/capabilities/guest/arch[@name='%s']\ + /emulator" % arch + else: + expr = "/capabilities/guest/arch[@name='%s']\ + /domain[@type='kvm']/emulator" % arch + res = xpath_get_text(xml, expr) + location = res[0] + except Exception, e: + raise Exception("Unable to get qemu binary location: %s" % e) + finally: + connect.close() + return location + + +class KimchiPaths(PluginPaths): + + def __init__(self): + super(KimchiPaths, self).__init__('kimchi') + self.spice_file = os.path.join(self.ui_dir, + 'spice-html5/pages/spice_auto.html') + + if __with_spice__ == 'yes': + self.spice_dir = self.add_prefix('ui/spice-html5') + elif os.path.exists('@datadir@/spice-html5'): + self.spice_dir = '@datadir@/spice-html5' + else: + self.spice_dir = '/usr/share/spice-html5' + + if os.path.exists('@datadir@/novnc'): + self.novnc_dir = '@datadir@/novnc' + else: + self.novnc_dir = '/usr/share/novnc' + + if self.installed: + self.spice_css_file = os.path.join(self.spice_dir, 'spice.css') + else: + self.spice_css_file = os.path.join(self.spice_dir, 'css/spice.css') + + +kimchiPaths = KimchiPaths() + + +class KimchiConfig(PluginConfig): + def __init__(self): + super(KimchiConfig, self).__init__('kimchi') + + static_config = { + '/novnc': {'type': 'dir', + 'path': kimchiPaths.novnc_dir}, + '/spice-html5': {'type': 'dir', + 'path': kimchiPaths.spice_dir}, + '/spice_auto.html': {'type': 'file', + 'path': kimchiPaths.spice_file}, + '/spice-html5/spice.css': {'type': 'file', + 'path': kimchiPaths.spice_css_file}} + + custom_config = {} + for uri, data in static_config.iteritems(): + custom_config[uri] = {'tools.nocache.on': True, + 'tools.wokauth.on': True} + path = data['path'] + if data['type'] == 'dir': + custom_config[uri].update({'tools.staticdir.on': True, + 'tools.staticdir.dir': path}) + elif data['type'] == 'file': + custom_config[uri].update({'tools.staticfile.on': True, + 'tools.staticfile.filename': path}) + + for dirname in ('css', 'js', 'images'): + custom_config['/' + dirname] = { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': os.path.join(kimchiPaths.ui_dir, + dirname), + 'tools.wokauth.on': False, + 'tools.nocache.on': False} + if dirname != 'images': + custom_config['/' + dirname].update({ + 'tools.expires.on': True, + 'tools.expires.secs': CACHEEXPIRES}) + + self.update(custom_config) diff --git a/src/wok/plugins/kimchi/config.rpath b/src/wok/plugins/kimchi/config.rpath new file mode 100644 index 0000000..17298f2 --- /dev/null +++ b/src/wok/plugins/kimchi/config.rpath @@ -0,0 +1,672 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2010 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's _LT_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + darwin*) + case $cc_basename in + xlc*) + wl='-Wl,' + ;; + esac + ;; + mingw* | cygwin* | pw32* | os2* | cegcc*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + newsos6) + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + ecc*) + wl='-Wl,' + ;; + icc* | ifort*) + wl='-Wl,' + ;; + lf95*) + wl='-Wl,' + ;; + pgcc | pgf77 | pgf90) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + rdos*) + ;; + solaris*) + wl='-Wl,' + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + wl='-Wl,' + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's _LT_LINKER_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we cannot use + # them. + ld_shlibs=no + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32* | cegcc*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + interix[3-9]*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if test "$GCC" = yes ; then + : + else + case $cc_basename in + xlc*) + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd1*) + ld_shlibs=no + ;; + freebsd2.2*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + freebsd2*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. +# Unlike libtool.m4, here we don't care about _all_ names of the library, but +# only about the one the linker finds when passed -lNAME. This is the last +# element of library_names_spec in libtool.m4, or possibly two of them if the +# linker has special search rules. +library_names_spec= # the last element of library_names_spec in libtool.m4 +libname_spec='lib$name' +case "$host_os" in + aix3*) + library_names_spec='$libname.a' + ;; + aix[4-9]*) + library_names_spec='$libname$shrext' + ;; + amigaos*) + library_names_spec='$libname.a' + ;; + beos*) + library_names_spec='$libname$shrext' + ;; + bsdi[45]*) + library_names_spec='$libname$shrext' + ;; + cygwin* | mingw* | pw32* | cegcc*) + shrext=.dll + library_names_spec='$libname.dll.a $libname.lib' + ;; + darwin* | rhapsody*) + shrext=.dylib + library_names_spec='$libname$shrext' + ;; + dgux*) + library_names_spec='$libname$shrext' + ;; + freebsd1*) + ;; + freebsd* | dragonfly*) + case "$host_os" in + freebsd[123]*) + library_names_spec='$libname$shrext$versuffix' ;; + *) + library_names_spec='$libname$shrext' ;; + esac + ;; + gnu*) + library_names_spec='$libname$shrext' + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + library_names_spec='$libname$shrext' + ;; + interix[3-9]*) + library_names_spec='$libname$shrext' + ;; + irix5* | irix6* | nonstopux*) + library_names_spec='$libname$shrext' + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux* | k*bsd*-gnu) + library_names_spec='$libname$shrext' + ;; + knetbsd*-gnu) + library_names_spec='$libname$shrext' + ;; + netbsd*) + library_names_spec='$libname$shrext' + ;; + newsos6) + library_names_spec='$libname$shrext' + ;; + nto-qnx*) + library_names_spec='$libname$shrext' + ;; + openbsd*) + library_names_spec='$libname$shrext$versuffix' + ;; + os2*) + libname_spec='$name' + shrext=.dll + library_names_spec='$libname.a' + ;; + osf3* | osf4* | osf5*) + library_names_spec='$libname$shrext' + ;; + rdos*) + ;; + solaris*) + library_names_spec='$libname$shrext' + ;; + sunos4*) + library_names_spec='$libname$shrext$versuffix' + ;; + sysv4 | sysv4.3*) + library_names_spec='$libname$shrext' + ;; + sysv4*MP*) + library_names_spec='$libname$shrext' + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + library_names_spec='$libname$shrext' + ;; + uts4*) + library_names_spec='$libname$shrext' + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF + +# How to pass a linker flag through the compiler. +wl="$escaped_wl" + +# Static library suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally "so"). +shlibext="$shlibext" + +# Format of library name prefix. +libname_spec="$escaped_libname_spec" + +# Library names that the linker finds when passed -lNAME. +library_names_spec="$escaped_library_names_spec" + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="$hardcode_libdir_separator" + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct="$hardcode_direct" + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L="$hardcode_minus_L" + +EOF diff --git a/src/wok/plugins/kimchi/configure.ac b/src/wok/plugins/kimchi/configure.ac new file mode 100644 index 0000000..adab45b --- /dev/null +++ b/src/wok/plugins/kimchi/configure.ac @@ -0,0 +1,119 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +AC_INIT([kimchi], [m4_esyscmd([./build-aux/pkg-version --version])]) + +AC_SUBST([PACKAGE_VERSION], + [m4_esyscmd([./build-aux/pkg-version --version])]) + +AC_SUBST([PACKAGE_RELEASE], + [m4_esyscmd([./build-aux/pkg-version --release])]) + +# Testing for version and release +AS_IF([test "x$PACKAGE_VERSION" = x], + AC_MSG_ERROR([package version not defined])) +AS_IF([test "x$PACKAGE_RELEASE" = x], + AC_MSG_ERROR([package release not defined])) + +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([-Wno-portability]) +AM_PATH_PYTHON([2.6]) +AC_PATH_PROG([PEP8], [pep8], [/usr/bin/pep8]) +AC_PYTHON_MODULE([unittest]) +AC_SUBST([HAVE_PYMOD_UNITTEST]) +AC_SUBST([PYTHON_VERSION]) +AM_GNU_GETTEXT([external]) +AM_GNU_GETTEXT_VERSION([0.10]) +AC_PATH_PROG([CHEETAH], [cheetah], [/usr/bin/cheetah]) + +# Checking for pyflakes +AC_PATH_PROG([PYFLAKES], [pyflakes]) +if test "x$PYFLAKES" = "x"; then + AC_MSG_WARN([pyflakes not found]) +fi + +AC_ARG_ENABLE( + [sample], + [AS_HELP_STRING( + [--enable-sample], + [enable sample plugin @<:@default=no@:>@] + )], + , + [enable_sample="no"] +) + +if test "${enable_sample}" = "yes"; then +AC_SUBST([ENABLE_SAMPLE], [True]) +else +AC_SUBST([ENABLE_SAMPLE], [False]) +fi + +AC_ARG_WITH( + [spice-html5], + [AS_HELP_STRING([--with-spice-html5], + [Build Kimchi with spice-html5 @<:@default=no@:>@])], + , + [with_spice_html5="no"] +) +AM_CONDITIONAL([WITH_SPICE], [test "x$with_spice_html5" = xyes]) + +AC_CONFIG_FILES([ + po/Makefile.in + po/gen-pot + Makefile + docs/Makefile + distros.d/Makefile + control/Makefile + control/vm/Makefile + model/Makefile + ui/Makefile + ui/config/Makefile + ui/css/Makefile + ui/images/Makefile + ui/images/theme-default/Makefile + ui/js/Makefile + ui/spice-html5/Makefile + ui/spice-html5/css/Makefile + ui/spice-html5/pages/Makefile + ui/spice-html5/thirdparty/Makefile + ui/pages/Makefile + ui/pages/help/Makefile + ui/pages/help/en_US/Makefile + ui/pages/help/de_DE/Makefile + ui/pages/help/es_ES/Makefile + ui/pages/help/fr_FR/Makefile + ui/pages/help/it_IT/Makefile + ui/pages/help/ja_JP/Makefile + ui/pages/help/ko_KR/Makefile + ui/pages/help/pt_BR/Makefile + ui/pages/help/ru_RU/Makefile + ui/pages/help/zh_CN/Makefile + ui/pages/help/zh_TW/Makefile + contrib/Makefile + contrib/DEBIAN/Makefile + contrib/DEBIAN/control + contrib/kimchi.spec.fedora + contrib/kimchi.spec.suse + tests/Makefile + xmlutils/Makefile +],[ + chmod +x po/gen-pot +]) + +AC_OUTPUT diff --git a/src/wok/plugins/kimchi/contrib/DEBIAN/Makefile.am b/src/wok/plugins/kimchi/contrib/DEBIAN/Makefile.am new file mode 100644 index 0000000..ca89552 --- /dev/null +++ b/src/wok/plugins/kimchi/contrib/DEBIAN/Makefile.am @@ -0,0 +1,17 @@ +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +CLEANFILES = control diff --git a/src/wok/plugins/kimchi/contrib/DEBIAN/control.in b/src/wok/plugins/kimchi/contrib/DEBIAN/control.in new file mode 100644 index 0000000..dc153d8 --- /dev/null +++ b/src/wok/plugins/kimchi/contrib/DEBIAN/control.in @@ -0,0 +1,30 @@ +Package: @PACKAGE_NAME@ +Version: @PACKAGE_VERSION@ +Section: base +Priority: optional +Architecture: all +Depends: wok, + python-imaging, + python-configobj, + websockify, + novnc, + python-jsonschema (>= 1.3.0), + python-libvirt, + gettext, + libvirt-bin, + nfs-common, + qemu-kvm, + python-parted, + python-psutil (>= 0.6.0), + python-ethtool, + sosreport, + python-ipaddr, + python-lxml, + open-iscsi, + python-guestfs, + libguestfs-tools, + spice-html5 +Build-Depends: libxslt, + python-lxml +Maintainer: Aline Manera <alinefm@br.ibm.com> +Description: Kimchi web application diff --git a/src/wok/plugins/kimchi/contrib/Makefile.am b/src/wok/plugins/kimchi/contrib/Makefile.am new file mode 100644 index 0000000..5001191 --- /dev/null +++ b/src/wok/plugins/kimchi/contrib/Makefile.am @@ -0,0 +1,34 @@ +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +SUBDIRS = DEBIAN + +EXTRA_DIST = \ + check_i18n.py \ + kimchi.spec.fedora.in \ + make-deb.sh.in \ + $(NULL) + +make-deb.sh: make-deb.sh.in $(top_builddir)/config.status + $(AM_V_GEN)sed \ + -e 's|[@]PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \ + -e 's|[@]PACKAGE_RELEASE[@]|$(PACKAGE_RELEASE)|g' \ + < $< > $@-t && \ + chmod a+x $@-t && \ + mv $@-t $@ +BUILT_SOURCES = make-deb.sh + +CLEANFILES = kimchi.spec.fedora kimchi.spec.suse kimchi.spec make-deb.sh diff --git a/src/wok/plugins/kimchi/contrib/check_i18n.py b/src/wok/plugins/kimchi/contrib/check_i18n.py new file mode 100755 index 0000000..6a2603c --- /dev/null +++ b/src/wok/plugins/kimchi/contrib/check_i18n.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python2 +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import imp +import os +import re +import sys + + +# Match all conversion specifier with mapping key +PATTERN = re.compile(r'''%\([^)]+\) # Mapping key + [#0\-+]? # Conversion flags (optional) + (\d+|\*)? # Minimum field width (optional) + (\.(\d+|\*))? # Precision (optional) + [lLh]? # Length modifier (optional) + [cdeEfFgGioursxX%] # Conversion type''', + re.VERBOSE) +BAD_PATTERN = re.compile(r"%\([^)]*?\)") + + +def load_i18n_module(i18nfile): + path = os.path.dirname(i18nfile) + mname = i18nfile.replace("/", "_").rstrip(".py") + mobj = imp.find_module("i18n", [path]) + return imp.load_module(mname, *mobj) + + +def check_string_formatting(messages): + for k, v in messages.iteritems(): + if BAD_PATTERN.findall(PATTERN.sub(" ", v)): + print "bad i18n string formatting:" + print " %s: %s" % (k, v) + exit(1) + + +def check_obsolete_messages(path, messages): + def find_message_key(path, k): + for root, dirs, files in os.walk(path): + for f in files: + fname = os.path.join(root, f) + if (not fname.endswith("i18n.py") and fname.endswith(".py") or + fname.endswith(".json")): + with open(fname) as f: + string = "".join(f.readlines()) + if k in string: + return True + return False + + for k in messages.iterkeys(): + if not find_message_key(path, k): + print " %s is obsolete, it is no longer in use" % k + exit(1) + + +def main(): + print "Checking for invalid i18n string..." + for f in sys.argv[1:]: + messages = load_i18n_module(f).messages + check_string_formatting(messages) + check_obsolete_messages(os.path.dirname(f), messages) + print "Checking for invalid i18n string successfully" + + +if __name__ == '__main__': + main() diff --git a/src/wok/plugins/kimchi/contrib/kimchi.spec.fedora.in b/src/wok/plugins/kimchi/contrib/kimchi.spec.fedora.in new file mode 100644 index 0000000..0db3d7e --- /dev/null +++ b/src/wok/plugins/kimchi/contrib/kimchi.spec.fedora.in @@ -0,0 +1,119 @@ +Name: kimchi +Version: @PACKAGE_VERSION@ +Release: @PACKAGE_RELEASE@%{?dist} +Summary: Kimchi server application +BuildRoot: %{_topdir}/BUILD/%{name}-%{version}-%{release} +BuildArch: noarch +Group: System Environment/Base +License: LGPL/ASL2 +Source0: %{name}-%{version}.tar.gz +Requires: wok +Requires: qemu-kvm +Requires: gettext +Requires: libvirt +Requires: libvirt-python +Requires: libvirt-daemon-config-network +Requires: python-websockify +Requires: python-configobj +Requires: novnc +Requires: python-imaging +Requires: pyparted +Requires: python-psutil >= 0.6.0 +Requires: python-jsonschema >= 1.3.0 +Requires: python-ethtool +Requires: sos +Requires: python-ipaddr +Requires: python-lxml +Requires: nfs-utils +Requires: iscsi-initiator-utils +Requires: python-libguestfs +Requires: libguestfs-tools +BuildRequires: libxslt +BuildRequires: python-lxml + +%if 0%{?rhel} >= 6 || 0%{?fedora} >= 19 +Requires: spice-html5 +%endif + +%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7 +%global with_systemd 1 +%endif + +%if 0%{?rhel} == 6 +Requires: python-ordereddict +Requires: python-imaging +BuildRequires: python-unittest2 +%endif + +%description +Web application to manage KVM/Qemu virtual machines + + +%prep +%setup + + +%build +%if 0%{?rhel} >= 6 || 0%{?fedora} >= 19 +%configure +%else +%configure --with-spice-html5 +%endif +make + + +%install +rm -rf %{buildroot} +make DESTDIR=%{buildroot} install + + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%attr(-,root,root) +%{python_sitelib}/wok/plugins/kimchi/*.py* +%{python_sitelib}/wok/plugins/kimchi/control/*.py* +%{python_sitelib}/wok/plugins/kimchi/control/vm/*.py* +%{python_sitelib}/wok/plugins/kimchi/model/*.py* +%{python_sitelib}/wok/plugins/kimchi/API.json +%{python_sitelib}/wok/plugins/kimchi/ +%{_datadir}/kimchi/doc/API.md +%{_datadir}/kimchi/doc/README.md +%{_datadir}/kimchi/doc/README-federation.md +%{_datadir}/kimchi/doc/kimchi-guest.png +%{_datadir}/kimchi/doc/kimchi-templates.png +%{_prefix}/share/locale/*/LC_MESSAGES/kimchi.mo +%{_datadir}/wok/plugins/kimchi/ui/config/*.xml +%{_datadir}/wok/plugins/kimchi/ui/ +%{_datadir}/wok/plugins/kimchi +%{_sysconfdir}/wok/plugins.d/kimchi.conf +%{_sysconfdir}/wok/plugins.d/template.conf +%{_sysconfdir}/kimchi/distros.d/debian.json +%{_sysconfdir}/kimchi/distros.d/fedora.json +%{_sysconfdir}/kimchi/distros.d/opensuse.json +%{_sysconfdir}/kimchi/distros.d/ubuntu.json +%{_sysconfdir}/kimchi/distros.d/gentoo.json +%{_sysconfdir}/kimchi/ +%{_sharedstatedir}/kimchi/debugreports/ +%{_sharedstatedir}/kimchi/isos/ +%{_sharedstatedir}/kimchi/screenshots/ +%{_sharedstatedir}/kimchi/vnc-tokens/ +%{_sharedstatedir}/kimchi/ + + +%changelog +* Thu Jun 18 2015 Lucio Correia <luciojhc@linux.vnet.ibm.com> 1.6 +- Run kimchi as a plugin + +* Thu Feb 26 2015 Fr��d��ric Bonnard <frediz@linux.vnet.ibm.com> 1.4.0 +- Add man page for kimchid + +* Tue Feb 11 2014 Cr��stian Viana <vianac@linux.vnet.ibm.com> 1.1.0 +- Add help pages and XSLT dependency + +* Tue Jul 16 2013 Adam Litke <agl@us.ibm.com> 0.1.0-1 +- Adapted for autotools build + +* Thu Apr 04 2013 Aline Manera <alinefm@br.ibm.com> 0.0-1 +- First build diff --git a/src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in b/src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in new file mode 100644 index 0000000..e466961 --- /dev/null +++ b/src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in @@ -0,0 +1,107 @@ +Name: kimchi +Version: @PACKAGE_VERSION@ +Release: @PACKAGE_RELEASE@%{?dist} +Summary: Kimchi server application +BuildRoot: %{_topdir}/BUILD/%{name}-%{version}-%{release} +BuildArch: noarch +Group: System Environment/Base +License: LGPL/ASL2 +Source0: %{name}-%{version}.tar.gz +Requires: wok +Requires: kvm +Requires: gettext-tools +Requires: libvirt +Requires: libvirt-python +Requires: libvirt-daemon-config-network +Requires: python-websockify +Requires: python-configobj +Requires: novnc +Requires: python-imaging +Requires: python-parted +Requires: python-psutil >= 0.6.0 +Requires: python-jsonschema >= 1.3.0 +Requires: python-ethtool +Requires: python-ipaddr +Requires: python-lxml +Requires: python-xml +Requires: nfs-client +Requires: open-iscsi +Requires: python-libguestfs +Requires: guestfs-tools +BuildRequires: libxslt-tools +BuildRequires: python-lxml + +%if 0%{?suse_version} == 1100 +Requires: python-ordereddict +%endif + +%if 0%{?suse_version} > 1140 +%global with_systemd 1 +%endif + +%description +Web application to manage KVM/Qemu virtual machines + +%prep +%setup + +%build +%configure --with-spice-html5 +make + +%install +rm -rf %{buildroot} +make DESTDIR=%{buildroot} install + + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%attr(-,root,root) +%{python_sitelib}/wok/plugins/kimchi/*.py* +%{python_sitelib}/wok/plugins/kimchi/control/*.py* +%{python_sitelib}/wok/plugins/kimchi/control/vm/*.py* +%{python_sitelib}/wok/plugins/kimchi/model/*.py* +%{python_sitelib}/wok/plugins/kimchi/API.json +%{python_sitelib}/wok/plugins/kimchi/ +%{_datadir}/kimchi/doc/API.md +%{_datadir}/kimchi/doc/README.md +%{_datadir}/kimchi/doc/README-federation.md +%{_datadir}/kimchi/doc/kimchi-guest.png +%{_datadir}/kimchi/doc/kimchi-templates.png +%{_prefix}/share/locale/*/LC_MESSAGES/kimchi.mo +%{_datadir}/wok/plugins/kimchi/ui/config/*.xml +%{_datadir}/wok/plugins/kimchi/ui/ +%{_datadir}/wok/plugins/kimchi +%{_sysconfdir}/wok/plugins.d/kimchi.conf +%{_sysconfdir}/wok/plugins.d/template.conf +%{_sysconfdir}/kimchi/distros.d/debian.json +%{_sysconfdir}/kimchi/distros.d/fedora.json +%{_sysconfdir}/kimchi/distros.d/opensuse.json +%{_sysconfdir}/kimchi/distros.d/ubuntu.json +%{_sysconfdir}/kimchi/distros.d/gentoo.json +%{_sysconfdir}/kimchi/ +%{_var}/lib/kimchi/debugreports/ +%{_var}/lib/kimchi/isos/ +%{_var}/lib/kimchi/screenshots/ +%{_var}/lib/kimchi/vnc-tokens/ +%{_var}/lib/kimchi/ + + +%changelog +* Thu Jun 18 2015 Lucio Correia <luciojhc@linux.vnet.ibm.com> 1.6 +- Run kimchi as a plugin + +* Thu Feb 26 2015 Fr��d��ric Bonnard <frediz@linux.vnet.ibm.com> 1.4.0 +- Add man page for kimchid + +* Tue Feb 11 2014 Cr��stian Viana <vianac@linux.vnet.ibm.com> 1.1.0 +- Add help pages and XSLT dependency + +* Thu Jul 18 2013 Adam Litke <agl@us.ibm.com> 0.1.0-1 +- Adapted for autotools build +- Split Suse and Fedora spec files + +* Thu Apr 04 2013 Aline Manera <alinefm@br.ibm.com> 0.0-1 +- First build diff --git a/src/wok/plugins/kimchi/contrib/make-deb.sh.in b/src/wok/plugins/kimchi/contrib/make-deb.sh.in new file mode 100644 index 0000000..5a6e56a --- /dev/null +++ b/src/wok/plugins/kimchi/contrib/make-deb.sh.in @@ -0,0 +1,15 @@ +#!/bin/bash + +VERSION="@PACKAGE_VERSION@" +RELEASE="@PACKAGE_RELEASE@" + +if [ ! -f configure ]; then + echo "Please run this script from the top of the package tree" + exit 1 +fi + +TMPDIR=`mktemp -d` + +make DESTDIR=$TMPDIR install-deb +dpkg-deb -b $TMPDIR kimchi-${VERSION}-${RELEASE}.noarch.deb +rm -rf $TMPDIR diff --git a/src/wok/plugins/kimchi/control/Makefile.am b/src/wok/plugins/kimchi/control/Makefile.am new file mode 100644 index 0000000..33118ca --- /dev/null +++ b/src/wok/plugins/kimchi/control/Makefile.am @@ -0,0 +1,27 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +SUBDIRS = vm + +control_PYTHON = *.py + +controldir = $(pythondir)/wok/plugins/kimchi/control + +install-data-local: + $(MKDIR_P) $(DESTDIR)$(controldir) diff --git a/src/wok/plugins/kimchi/control/__init__.py b/src/wok/plugins/kimchi/control/__init__.py new file mode 100644 index 0000000..4ad9459 --- /dev/null +++ b/src/wok/plugins/kimchi/control/__init__.py @@ -0,0 +1,26 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os + + +from wok.control.utils import load_url_sub_node + + +sub_nodes = load_url_sub_node(os.path.dirname(__file__), __name__) diff --git a/src/wok/plugins/kimchi/control/config.py b/src/wok/plugins/kimchi/control/config.py new file mode 100644 index 0000000..15df68f --- /dev/null +++ b/src/wok/plugins/kimchi/control/config.py @@ -0,0 +1,57 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import Collection, Resource +from wok.control.utils import UrlSubNode + + +@UrlSubNode("config") +class Config(Resource): + def __init__(self, model, id=None): + super(Config, self).__init__(model, id) + self.capabilities = Capabilities(self.model) + self.distros = Distros(model) + + @property + def data(self): + return self.info + + +class Capabilities(Resource): + def __init__(self, model, id=None): + super(Capabilities, self).__init__(model, id) + + @property + def data(self): + return self.info + + +class Distros(Collection): + def __init__(self, model): + super(Distros, self).__init__(model) + self.resource = Distro + + +class Distro(Resource): + def __init__(self, model, ident): + super(Distro, self).__init__(model, ident) + + @property + def data(self): + return self.info diff --git a/src/wok/plugins/kimchi/control/cpuinfo.py b/src/wok/plugins/kimchi/control/cpuinfo.py new file mode 100644 index 0000000..31f316c --- /dev/null +++ b/src/wok/plugins/kimchi/control/cpuinfo.py @@ -0,0 +1,37 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +from wok.control.base import Resource + + +class CPUInfo(Resource): + def __init__(self, model): + super(CPUInfo, self).__init__(model) + self.admin_methods = ['GET'] + self.role_key = 'host' + self.uri_fmt = "/host/cpuinfo" + + @property + def data(self): + return {'threading_enabled': self.info['guest_threads_enabled'], + 'sockets': self.info['sockets'], + 'cores': self.info['cores_available'], + 'threads_per_core': self.info['threads_per_core'] + } diff --git a/src/wok/plugins/kimchi/control/debugreports.py b/src/wok/plugins/kimchi/control/debugreports.py new file mode 100644 index 0000000..b5a3072 --- /dev/null +++ b/src/wok/plugins/kimchi/control/debugreports.py @@ -0,0 +1,61 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import AsyncCollection, Resource +from wok.control.utils import internal_redirect +from wok.control.utils import UrlSubNode + + +@UrlSubNode('debugreports', True) +class DebugReports(AsyncCollection): + def __init__(self, model): + super(DebugReports, self).__init__(model) + self.resource = DebugReport + self.role_key = 'host' + self.admin_methods = ['GET', 'POST'] + + def _get_resources(self, filter_params): + res_list = super(DebugReports, self)._get_resources(filter_params) + return sorted(res_list, key=lambda x: x.data['time'], reverse=True) + + +class DebugReport(Resource): + def __init__(self, model, ident): + super(DebugReport, self).__init__(model, ident) + self.role_key = 'host' + self.admin_methods = ['GET', 'PUT', 'POST'] + self.uri_fmt = '/debugreports/%s' + self.content = DebugReportContent(model, ident) + + @property + def data(self): + return {'name': self.ident, + 'uri': self.info['uri'], + 'time': self.info['ctime']} + + +class DebugReportContent(Resource): + def __init__(self, model, ident): + super(DebugReportContent, self).__init__(model, ident) + self.role_key = 'host' + self.admin_methods = ['GET'] + + def get(self): + self.lookup() + raise internal_redirect(self.info['uri']) diff --git a/src/wok/plugins/kimchi/control/groups.py b/src/wok/plugins/kimchi/control/groups.py new file mode 100644 index 0000000..649ff09 --- /dev/null +++ b/src/wok/plugins/kimchi/control/groups.py @@ -0,0 +1,28 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import SimpleCollection +from wok.control.utils import UrlSubNode + + +@UrlSubNode('groups', True) +class Groups(SimpleCollection): + def __init__(self, model): + super(Groups, self).__init__(model) + self.role_key = 'guests' diff --git a/src/wok/plugins/kimchi/control/host.py b/src/wok/plugins/kimchi/control/host.py new file mode 100644 index 0000000..0a40f1b --- /dev/null +++ b/src/wok/plugins/kimchi/control/host.py @@ -0,0 +1,157 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import Collection, Resource, SimpleCollection +from wok.control.utils import UrlSubNode +from wok.exception import NotFoundError + +from cpuinfo import CPUInfo + + +@UrlSubNode('host', True) +class Host(Resource): + def __init__(self, model, id=None): + super(Host, self).__init__(model, id) + self.role_key = 'host' + self.admin_methods = ['GET', 'POST'] + self.uri_fmt = '/host/%s' + self.reboot = self.generate_action_handler('reboot') + self.shutdown = self.generate_action_handler('shutdown') + self.stats = HostStats(self.model) + self.partitions = Partitions(self.model) + self.devices = Devices(self.model) + self.packagesupdate = PackagesUpdate(self.model) + self.repositories = Repositories(self.model) + self.swupdate = self.generate_action_handler_task('swupdate') + self.cpuinfo = CPUInfo(self.model) + + @property + def data(self): + return self.info + + +class HostStats(Resource): + def __init__(self, model, id=None): + super(HostStats, self).__init__(model, id) + self.role_key = 'host' + self.admin_methods = ['GET'] + self.history = HostStatsHistory(self.model) + + @property + def data(self): + return self.info + + +class HostStatsHistory(Resource): + @property + def data(self): + return self.info + + +class Partitions(Collection): + def __init__(self, model): + super(Partitions, self).__init__(model) + self.role_key = 'storage' + self.admin_methods = ['GET'] + self.resource = Partition + + # Defining get_resources in order to return list of partitions in UI + # sorted by their path + def _get_resources(self, flag_filter): + res_list = super(Partitions, self)._get_resources(flag_filter) + res_list = filter(lambda x: x.info['available'], res_list) + res_list.sort(key=lambda x: x.info['path']) + return res_list + + +class Partition(Resource): + def __init__(self, model, id): + self.role_key = 'storage' + self.admin_methods = ['GET'] + super(Partition, self).__init__(model, id) + + @property + def data(self): + if not self.info['available']: + raise NotFoundError("KCHPART0001E", {'name': self.info['name']}) + + return self.info + + +class Devices(Collection): + def __init__(self, model): + super(Devices, self).__init__(model) + self.resource = Device + + +class VMHolders(SimpleCollection): + def __init__(self, model, device_id): + super(VMHolders, self).__init__(model) + self.model_args = (device_id, ) + + +class Device(Resource): + def __init__(self, model, id): + super(Device, self).__init__(model, id) + self.vm_holders = VMHolders(self.model, id) + + @property + def data(self): + return self.info + + +class PackagesUpdate(Collection): + def __init__(self, model): + super(PackagesUpdate, self).__init__(model) + self.role_key = 'host' + self.admin_methods = ['GET'] + self.resource = PackageUpdate + + +class PackageUpdate(Resource): + def __init__(self, model, id=None): + super(PackageUpdate, self).__init__(model, id) + self.role_key = 'host' + self.admin_methods = ['GET'] + + @property + def data(self): + return self.info + + +class Repositories(Collection): + def __init__(self, model): + super(Repositories, self).__init__(model) + self.role_key = 'host' + self.admin_methods = ['GET', 'POST'] + self.resource = Repository + + +class Repository(Resource): + def __init__(self, model, id): + super(Repository, self).__init__(model, id) + self.role_key = 'host' + self.admin_methods = ['GET', 'PUT', 'POST', 'DELETE'] + self.uri_fmt = "/host/repositories/%s" + self.enable = self.generate_action_handler('enable') + self.disable = self.generate_action_handler('disable') + + @property + def data(self): + return self.info diff --git a/src/wok/plugins/kimchi/control/interfaces.py b/src/wok/plugins/kimchi/control/interfaces.py new file mode 100644 index 0000000..d698b7a --- /dev/null +++ b/src/wok/plugins/kimchi/control/interfaces.py @@ -0,0 +1,46 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import Collection, Resource +from wok.control.utils import UrlSubNode + + +@UrlSubNode('interfaces', True) +class Interfaces(Collection): + def __init__(self, model): + super(Interfaces, self).__init__(model) + self.role_key = 'network' + self.admin_methods = ['GET'] + self.resource = Interface + + +class Interface(Resource): + def __init__(self, model, ident): + super(Interface, self).__init__(model, ident) + self.role_key = 'network' + self.admin_methods = ['GET'] + self.uri_fmt = "/interfaces/%s" + + @property + def data(self): + return {'name': self.ident, + 'type': self.info['type'], + 'ipaddr': self.info['ipaddr'], + 'netmask': self.info['netmask'], + 'status': self.info['status']} diff --git a/src/wok/plugins/kimchi/control/networks.py b/src/wok/plugins/kimchi/control/networks.py new file mode 100644 index 0000000..fd92111 --- /dev/null +++ b/src/wok/plugins/kimchi/control/networks.py @@ -0,0 +1,54 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import Collection, Resource +from wok.control.utils import UrlSubNode + + +@UrlSubNode('networks', True) +class Networks(Collection): + def __init__(self, model): + super(Networks, self).__init__(model) + self.role_key = 'network' + self.admin_methods = ['POST'] + self.resource = Network + + +class Network(Resource): + def __init__(self, model, ident): + super(Network, self).__init__(model, ident) + self.role_key = 'network' + self.admin_methods = ['PUT', 'POST', 'DELETE'] + self.uri_fmt = "/networks/%s" + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate', + destructive=True) + + @property + def data(self): + return {'name': self.ident, + 'vms': self.info['vms'], + 'in_use': self.info['in_use'], + 'autostart': self.info['autostart'], + 'connection': self.info['connection'], + 'interface': self.info['interface'], + 'subnet': self.info['subnet'], + 'dhcp': self.info['dhcp'], + 'state': self.info['state'], + 'persistent': self.info['persistent']} diff --git a/src/wok/plugins/kimchi/control/peers.py b/src/wok/plugins/kimchi/control/peers.py new file mode 100644 index 0000000..21e9f13 --- /dev/null +++ b/src/wok/plugins/kimchi/control/peers.py @@ -0,0 +1,29 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import SimpleCollection +from wok.control.utils import UrlSubNode + + +@UrlSubNode("peers", True) +class Peers(SimpleCollection): + def __init__(self, model): + super(Peers, self).__init__(model) + self.role_key = 'peers' + self.admin_methods = ['GET'] diff --git a/src/wok/plugins/kimchi/control/storagepools.py b/src/wok/plugins/kimchi/control/storagepools.py new file mode 100644 index 0000000..e5f264e --- /dev/null +++ b/src/wok/plugins/kimchi/control/storagepools.py @@ -0,0 +1,116 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import cherrypy + +from wok.control.base import Collection, Resource +from wok.control.utils import get_class_name, model_fn +from wok.control.utils import validate_params +from wok.control.utils import UrlSubNode + +from ..model.storagepools import ISO_POOL_NAME +from storagevolumes import IsoVolumes, StorageVolumes + + +@UrlSubNode('storagepools', True) +class StoragePools(Collection): + def __init__(self, model): + super(StoragePools, self).__init__(model) + self.role_key = 'storage' + self.admin_methods = ['POST'] + self.resource = StoragePool + isos = IsoPool(model) + setattr(self, ISO_POOL_NAME, isos) + + def create(self, params, *args): + try: + create = getattr(self.model, model_fn(self, 'create')) + except AttributeError: + error = 'Create is not allowed for %s' % get_class_name(self) + raise cherrypy.HTTPError(405, error) + + validate_params(params, self, 'create') + args = self.model_args + [params] + name = create(*args) + args = self.resource_args + [name] + res = self.resource(self.model, *args) + resp = res.get() + + if 'task_id' in res.data: + cherrypy.response.status = 202 + else: + cherrypy.response.status = 201 + + return resp + + def _get_resources(self, filter_params): + try: + res_list = super(StoragePools, self)._get_resources(filter_params) + # Append reserved pools + isos = getattr(self, ISO_POOL_NAME) + isos.lookup() + res_list.append(isos) + except AttributeError: + pass + + return res_list + + +class StoragePool(Resource): + def __init__(self, model, ident): + super(StoragePool, self).__init__(model, ident) + self.role_key = 'storage' + self.admin_methods = ['PUT', 'POST', 'DELETE'] + self.uri_fmt = "/storagepools/%s" + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate', + destructive=True) + self.storagevolumes = StorageVolumes(self.model, ident) + + @property + def data(self): + res = {'name': self.ident, + 'state': self.info['state'], + 'capacity': self.info['capacity'], + 'allocated': self.info['allocated'], + 'available': self.info['available'], + 'path': self.info['path'], + 'source': self.info['source'], + 'type': self.info['type'], + 'nr_volumes': self.info['nr_volumes'], + 'autostart': self.info['autostart'], + 'persistent': self.info['persistent']} + + val = self.info.get('task_id') + if val: + res['task_id'] = val + + return res + + +class IsoPool(Resource): + def __init__(self, model): + super(IsoPool, self).__init__(model, ISO_POOL_NAME) + self.storagevolumes = IsoVolumes(self.model, ISO_POOL_NAME) + + @property + def data(self): + return {'name': self.ident, + 'state': self.info['state'], + 'type': self.info['type']} diff --git a/src/wok/plugins/kimchi/control/storageservers.py b/src/wok/plugins/kimchi/control/storageservers.py new file mode 100644 index 0000000..654ab47 --- /dev/null +++ b/src/wok/plugins/kimchi/control/storageservers.py @@ -0,0 +1,60 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok import template +from wok.control.base import Collection, Resource +from wok.control.utils import get_class_name, model_fn, UrlSubNode + + +@UrlSubNode('storageservers', True) +class StorageServers(Collection): + def __init__(self, model): + super(StorageServers, self).__init__(model) + self.role_key = 'storage' + self.admin_methods = ['GET'] + self.resource = StorageServer + + +class StorageServer(Resource): + def __init__(self, model, ident): + super(StorageServer, self).__init__(model, ident) + self.role_key = 'storage' + self.admin_methods = ['GET'] + self.storagetargets = StorageTargets(self.model, + self.ident.decode("utf-8")) + + @property + def data(self): + return self.info + + +class StorageTargets(Collection): + def __init__(self, model, server): + super(StorageTargets, self).__init__(model) + self.role_key = 'storage' + self.admin_methods = ['GET'] + self.server = server + self.resource_args = [self.server, ] + self.model_args = [self.server, ] + + def get(self, filter_params): + res_list = [] + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args, **filter_params) + return template.render(get_class_name(self), res_list) diff --git a/src/wok/plugins/kimchi/control/storagevolumes.py b/src/wok/plugins/kimchi/control/storagevolumes.py new file mode 100644 index 0000000..bbe6627 --- /dev/null +++ b/src/wok/plugins/kimchi/control/storagevolumes.py @@ -0,0 +1,83 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok import template +from wok.control.base import AsyncCollection, Collection, Resource +from wok.control.utils import get_class_name, model_fn + + +class StorageVolumes(AsyncCollection): + def __init__(self, model, pool): + super(StorageVolumes, self).__init__(model) + self.resource = StorageVolume + self.pool = pool + self.resource_args = [self.pool, ] + self.model_args = [self.pool, ] + + def filter_data(self, resources, fields_filter): + # filter directory from storage volumes + fields_filter.update({'type': ['file', 'block', 'network']}) + return super(StorageVolumes, self).filter_data(resources, + fields_filter) + + +class StorageVolume(Resource): + def __init__(self, model, pool, ident): + super(StorageVolume, self).__init__(model, ident) + self.pool = pool + self.ident = ident + self.info = {} + self.model_args = [self.pool, self.ident] + self.uri_fmt = '/storagepools/%s/storagevolumes/%s' + self.resize = self.generate_action_handler('resize', ['size']) + self.wipe = self.generate_action_handler('wipe') + self.clone = self.generate_action_handler_task('clone') + + @property + def data(self): + res = {'name': self.ident, + 'type': self.info['type'], + 'capacity': self.info['capacity'], + 'allocation': self.info['allocation'], + 'path': self.info['path'], + 'used_by': self.info['used_by'], + 'format': self.info['format']} + + for key in ('os_version', 'os_distro', 'bootable', 'base'): + val = self.info.get(key) + if val: + res[key] = val + + return res + + +class IsoVolumes(Collection): + def __init__(self, model, pool): + super(IsoVolumes, self).__init__(model) + self.pool = pool + + def get(self, filter_params): + res_list = [] + try: + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args) + except AttributeError: + pass + + return template.render(get_class_name(self), res_list) diff --git a/src/wok/plugins/kimchi/control/templates.py b/src/wok/plugins/kimchi/control/templates.py new file mode 100644 index 0000000..fc58815 --- /dev/null +++ b/src/wok/plugins/kimchi/control/templates.py @@ -0,0 +1,58 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import Collection, Resource +from wok.control.utils import UrlSubNode + + +@UrlSubNode('templates', True) +class Templates(Collection): + def __init__(self, model): + super(Templates, self).__init__(model) + self.role_key = 'templates' + self.admin_methods = ['GET', 'POST'] + self.resource = Template + + +class Template(Resource): + def __init__(self, model, ident): + super(Template, self).__init__(model, ident) + self.role_key = 'templates' + self.admin_methods = ['PUT', 'POST', 'DELETE'] + self.uri_fmt = "/templates/%s" + self.clone = self.generate_action_handler('clone') + + @property + def data(self): + return { + 'name': self.ident, + 'icon': self.info['icon'], + 'invalid': self.info['invalid'], + 'os_distro': self.info['os_distro'], + 'os_version': self.info['os_version'], + 'cpus': self.info['cpus'], + 'memory': self.info['memory'], + 'cdrom': self.info.get('cdrom', None), + 'disks': self.info['disks'], + 'storagepool': self.info['storagepool'], + 'networks': self.info['networks'], + 'folder': self.info.get('folder', []), + 'graphics': self.info['graphics'], + 'cpu_info': self.info.get('cpu_info') + } diff --git a/src/wok/plugins/kimchi/control/users.py b/src/wok/plugins/kimchi/control/users.py new file mode 100644 index 0000000..756a2f7 --- /dev/null +++ b/src/wok/plugins/kimchi/control/users.py @@ -0,0 +1,35 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import SimpleCollection +from wok.control.utils import get_class_name, model_fn, UrlSubNode +from wok.template import render + + +@UrlSubNode('users', True) +class Users(SimpleCollection): + def __init__(self, model): + super(Users, self).__init__(model) + self.role_key = 'guests' + + def get(self, filter_params): + res_list = [] + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args, **filter_params) + return render(get_class_name(self), res_list) diff --git a/src/wok/plugins/kimchi/control/vm/Makefile.am b/src/wok/plugins/kimchi/control/vm/Makefile.am new file mode 100644 index 0000000..b17c68a --- /dev/null +++ b/src/wok/plugins/kimchi/control/vm/Makefile.am @@ -0,0 +1,26 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +vm_PYTHON = *.py + +vmdir = $(pythondir)/wok/plugins/kimchi/control/vm + +install-data-local: + $(MKDIR_P) $(DESTDIR)$(vmdir) diff --git a/src/wok/plugins/kimchi/control/vm/__init__.py b/src/wok/plugins/kimchi/control/vm/__init__.py new file mode 100644 index 0000000..a311045 --- /dev/null +++ b/src/wok/plugins/kimchi/control/vm/__init__.py @@ -0,0 +1,26 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os + + +from wok.control.utils import load_url_sub_node + + +sub_nodes = load_url_sub_node(os.path.dirname(__file__), __name__) diff --git a/src/wok/plugins/kimchi/control/vm/hostdevs.py b/src/wok/plugins/kimchi/control/vm/hostdevs.py new file mode 100644 index 0000000..a43b9d8 --- /dev/null +++ b/src/wok/plugins/kimchi/control/vm/hostdevs.py @@ -0,0 +1,43 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import Collection, Resource +from wok.control.utils import UrlSubNode + + +@UrlSubNode("hostdevs") +class VMHostDevs(Collection): + def __init__(self, model, vmid): + super(VMHostDevs, self).__init__(model) + self.resource = VMHostDev + self.vmid = vmid + self.resource_args = [self.vmid, ] + self.model_args = [self.vmid, ] + + +class VMHostDev(Resource): + def __init__(self, model, vmid, ident): + super(VMHostDev, self).__init__(model, ident) + self.vmid = vmid + self.ident = ident + self.model_args = [self.vmid, self.ident] + + @property + def data(self): + return self.info diff --git a/src/wok/plugins/kimchi/control/vm/ifaces.py b/src/wok/plugins/kimchi/control/vm/ifaces.py new file mode 100644 index 0000000..ac957fd --- /dev/null +++ b/src/wok/plugins/kimchi/control/vm/ifaces.py @@ -0,0 +1,45 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import Collection, Resource +from wok.control.utils import UrlSubNode + + +@UrlSubNode("ifaces") +class VMIfaces(Collection): + def __init__(self, model, vm): + super(VMIfaces, self).__init__(model) + self.resource = VMIface + self.vm = vm + self.resource_args = [self.vm, ] + self.model_args = [self.vm, ] + + +class VMIface(Resource): + def __init__(self, model, vm, ident): + super(VMIface, self).__init__(model, ident) + self.vm = vm + self.ident = ident + self.info = {} + self.model_args = [self.vm, self.ident] + self.uri_fmt = '/vms/%s/ifaces/%s' + + @property + def data(self): + return self.info diff --git a/src/wok/plugins/kimchi/control/vm/snapshots.py b/src/wok/plugins/kimchi/control/vm/snapshots.py new file mode 100644 index 0000000..dd17b85 --- /dev/null +++ b/src/wok/plugins/kimchi/control/vm/snapshots.py @@ -0,0 +1,58 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import AsyncCollection, Resource +from wok.control.utils import UrlSubNode + + +@UrlSubNode('snapshots') +class VMSnapshots(AsyncCollection): + def __init__(self, model, vm): + super(VMSnapshots, self).__init__(model) + self.resource = VMSnapshot + self.vm = vm + self.resource_args = [self.vm, ] + self.model_args = [self.vm, ] + self.current = CurrentVMSnapshot(model, vm) + + +class VMSnapshot(Resource): + def __init__(self, model, vm, ident): + super(VMSnapshot, self).__init__(model, ident) + self.vm = vm + self.ident = ident + self.model_args = [self.vm, self.ident] + self.uri_fmt = '/vms/%s/snapshots/%s' + self.revert = self.generate_action_handler('revert') + + @property + def data(self): + return self.info + + +class CurrentVMSnapshot(Resource): + def __init__(self, model, vm): + super(CurrentVMSnapshot, self).__init__(model) + self.vm = vm + self.model_args = [self.vm] + self.uri_fmt = '/vms/%s/snapshots/current' + + @property + def data(self): + return self.info diff --git a/src/wok/plugins/kimchi/control/vm/storages.py b/src/wok/plugins/kimchi/control/vm/storages.py new file mode 100644 index 0000000..f502caa --- /dev/null +++ b/src/wok/plugins/kimchi/control/vm/storages.py @@ -0,0 +1,45 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import Collection, Resource +from wok.control.utils import UrlSubNode + + +@UrlSubNode("storages") +class VMStorages(Collection): + def __init__(self, model, vm): + super(VMStorages, self).__init__(model) + self.resource = VMStorage + self.vm = vm + self.resource_args = [self.vm, ] + self.model_args = [self.vm, ] + + +class VMStorage(Resource): + def __init__(self, model, vm, ident): + super(VMStorage, self).__init__(model, ident) + self.vm = vm + self.ident = ident + self.info = {} + self.model_args = [self.vm, self.ident] + self.uri_fmt = '/vms/%s/storages/%s' + + @property + def data(self): + return self.info diff --git a/src/wok/plugins/kimchi/control/vms.py b/src/wok/plugins/kimchi/control/vms.py new file mode 100644 index 0000000..858b23c --- /dev/null +++ b/src/wok/plugins/kimchi/control/vms.py @@ -0,0 +1,67 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.control.base import AsyncCollection, Resource +from wok.control.utils import internal_redirect, UrlSubNode + +from vm import sub_nodes + + +@UrlSubNode('vms', True) +class VMs(AsyncCollection): + def __init__(self, model): + super(VMs, self).__init__(model) + self.resource = VM + self.role_key = 'guests' + self.admin_methods = ['POST'] + + +class VM(Resource): + def __init__(self, model, ident): + super(VM, self).__init__(model, ident) + self.role_key = 'guests' + self.screenshot = VMScreenShot(model, ident) + self.uri_fmt = '/vms/%s' + for ident, node in sub_nodes.items(): + setattr(self, ident, node(model, self.ident)) + self.start = self.generate_action_handler('start') + self.poweroff = self.generate_action_handler('poweroff', + destructive=True) + self.shutdown = self.generate_action_handler('shutdown', + destructive=True) + self.reset = self.generate_action_handler('reset', + destructive=True) + self.connect = self.generate_action_handler('connect') + self.clone = self.generate_action_handler_task('clone') + self.suspend = self.generate_action_handler('suspend') + self.resume = self.generate_action_handler('resume') + + @property + def data(self): + return self.info + + +class VMScreenShot(Resource): + def __init__(self, model, ident): + super(VMScreenShot, self).__init__(model, ident) + self.role_key = 'guests' + + def get(self): + self.lookup() + raise internal_redirect(self.info) diff --git a/src/wok/plugins/kimchi/disks.py b/src/wok/plugins/kimchi/disks.py new file mode 100644 index 0000000..eb40e3a --- /dev/null +++ b/src/wok/plugins/kimchi/disks.py @@ -0,0 +1,196 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os.path +import re +import subprocess +from parted import Device as PDevice +from parted import Disk as PDisk + +from wok.exception import OperationFailed +from wok.utils import wok_log + + +def _get_dev_node_path(maj_min): + """ Returns device node path given the device number 'major:min' """ + + dm_name = "/sys/dev/block/%s/dm/name" % maj_min + if os.path.exists(dm_name): + with open(dm_name) as dm_f: + content = dm_f.read().rstrip('\n') + return "/dev/mapper/" + content + + uevent = "/sys/dev/block/%s/uevent" % maj_min + with open(uevent) as ueventf: + content = ueventf.read() + + data = dict(re.findall(r'(\S+)=(".*?"|\S+)', content.replace("\n", " "))) + + return "/dev/%s" % data["DEVNAME"] + + +def _get_lsblk_devs(keys, devs=[]): + lsblk = subprocess.Popen( + ["lsblk", "-Pbo"] + [','.join(keys)] + devs, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = lsblk.communicate() + if lsblk.returncode != 0: + raise OperationFailed("KCHDISKS0001E", {'err': err}) + + return _parse_lsblk_output(out, keys) + + +def _get_dev_major_min(name): + maj_min = None + + keys = ["NAME", "MAJ:MIN"] + dev_list = _get_lsblk_devs(keys) + + for dev in dev_list: + if dev['name'].split()[0] == name: + maj_min = dev['maj:min'] + break + else: + raise OperationFailed("KCHDISKS0002E", {'device': name}) + + return maj_min + + +def _is_dev_leaf(devNodePath): + try: + # By default, lsblk prints a device information followed by children + # device information + childrenCount = len( + _get_lsblk_devs(["NAME"], [devNodePath])) - 1 + except OperationFailed as e: + # lsblk is known to fail on multipath devices + # Assume these devices contain children + wok_log.error( + "Error getting device info for %s: %s", devNodePath, e) + return False + + return childrenCount == 0 + + +def _is_dev_extended_partition(devType, devNodePath): + if devType != 'part': + return False + diskPath = devNodePath.rstrip('0123456789') + device = PDevice(diskPath) + try: + extended_part = PDisk(device).getExtendedPartition() + except NotImplementedError as e: + wok_log.warning( + "Error getting extended partition info for dev %s type %s: %s", + devNodePath, devType, e.message) + # Treate disk with unsupported partiton table as if it does not + # contain extended partitions. + return False + if extended_part and extended_part.path == devNodePath: + return True + return False + + +def _parse_lsblk_output(output, keys): + # output is on format key="value", + # where key can be NAME, TYPE, FSTYPE, SIZE, MOUNTPOINT, etc + lines = output.rstrip("\n").split("\n") + r = [] + for line in lines: + d = {} + for key in keys: + expression = r"%s=\".*?\"" % key + match = re.search(expression, line) + field = match.group() + k, v = field.split('=', 1) + d[k.lower()] = v[1:-1] + r.append(d) + return r + + +def _get_vgname(devNodePath): + """ Return volume group name of a physical volume. If the device node path + is not a physical volume, return empty string. """ + pvs = subprocess.Popen( + ["pvs", "--unbuffered", "--nameprefixes", "--noheadings", + "-o", "vg_name", devNodePath], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = pvs.communicate() + if pvs.returncode != 0: + return "" + + return re.findall(r"LVM2_VG_NAME='([^\']*)'", out)[0] + + +def _is_available(name, devtype, fstype, mountpoint, majmin): + devNodePath = _get_dev_node_path(majmin) + # Only list unmounted and unformated and leaf and (partition or disk) + # leaf means a partition, a disk has no partition, or a disk not held + # by any multipath device. Physical volume belongs to no volume group + # is also listed. Extended partitions should not be listed. + if (devtype in ['part', 'disk', 'mpath'] and + fstype in ['', 'LVM2_member'] and + mountpoint == "" and + _get_vgname(devNodePath) == "" and + _is_dev_leaf(devNodePath) and + not _is_dev_extended_partition(devtype, devNodePath)): + return True + return False + + +def get_partitions_names(check=False): + names = set() + keys = ["NAME", "TYPE", "FSTYPE", "MOUNTPOINT", "MAJ:MIN"] + # output is on format key="value", + # where key can be NAME, TYPE, FSTYPE, MOUNTPOINT + for dev in _get_lsblk_devs(keys): + # split()[0] to avoid the second part of the name, after the + # whiteline + name = dev['name'].split()[0] + if check and not _is_available(name, dev['type'], dev['fstype'], + dev['mountpoint'], dev['maj:min']): + continue + names.add(name) + + return list(names) + + +def get_partition_details(name): + majmin = _get_dev_major_min(name) + dev_path = _get_dev_node_path(majmin) + + keys = ["TYPE", "FSTYPE", "SIZE", "MOUNTPOINT"] + try: + dev = _get_lsblk_devs(keys, [dev_path])[0] + except OperationFailed as e: + wok_log.error( + "Error getting partition info for %s: %s", name, e) + return {} + + dev['available'] = _is_available(name, dev['type'], dev['fstype'], + dev['mountpoint'], majmin) + if dev['mountpoint']: + # Sometimes the mountpoint comes with [SWAP] or other + # info which is not an actual mount point. Filtering it + regexp = re.compile(r"\[.*\]") + if regexp.search(dev['mountpoint']) is not None: + dev['mountpoint'] = '' + dev['path'] = dev_path + dev['name'] = name + return dev diff --git a/src/wok/plugins/kimchi/distroloader.py b/src/wok/plugins/kimchi/distroloader.py new file mode 100644 index 0000000..0032737 --- /dev/null +++ b/src/wok/plugins/kimchi/distroloader.py @@ -0,0 +1,67 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import glob +import json +import os + + +from wok.exception import NotFoundError, OperationFailed +from wok.utils import wok_log + +import config + + +ARCHS = {'x86_64': ['x86_64', 'amd64', 'i686', 'x86', 'i386'], + 'amd64': ['x86_64', 'amd64', 'i686', 'x86', 'i386'], + 'ppc64': ['ppc', 'ppc64'], + 'ppc64le': ['ppc64', 'ppc64le']} + + +class DistroLoader(object): + + def __init__(self, location=None): + self.location = location or config.get_distros_store() + + def _get_json_info(self, fname): + msg_args = {'filename': fname} + if not os.path.isfile(fname): + msg = "DistroLoader: failed to find distro file: %s" % fname + wok_log.error(msg) + raise NotFoundError("KCHDL0001E", msg_args) + try: + with open(fname) as f: + data = json.load(f) + return data + except ValueError: + msg = "DistroLoader: failed to parse distro file: %s" % fname + wok_log.error(msg) + raise OperationFailed("KCHDL0002E", msg_args) + + def get(self): + arch_list = ARCHS.get(os.uname()[4]) + all_json_files = glob.glob("%s/%s" % (self.location, "*.json")) + distros = [] + for f in all_json_files: + distros.extend(self._get_json_info(f)) + + # Return all remote ISOs arch not found + return dict([(distro['name'], distro) for distro in distros if + (arch_list is None or distro['os_arch'] in arch_list)]) diff --git a/src/wok/plugins/kimchi/distros.d/Makefile.am b/src/wok/plugins/kimchi/distros.d/Makefile.am new file mode 100644 index 0000000..684fe60 --- /dev/null +++ b/src/wok/plugins/kimchi/distros.d/Makefile.am @@ -0,0 +1,22 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +distrosdir = $(sysconfdir)/kimchi/distros.d + +dist_distros_DATA = *.json diff --git a/src/wok/plugins/kimchi/distros.d/debian.json b/src/wok/plugins/kimchi/distros.d/debian.json new file mode 100644 index 0000000..5d6a313 --- /dev/null +++ b/src/wok/plugins/kimchi/distros.d/debian.json @@ -0,0 +1,9 @@ +[ + { + "name": "debian-Wheezy", + "os_distro": "debian", + "os_arch": "x86_64", + "os_version": "7.7.0", + "path": "http://caesar.acc.umu.se/debian-cd/7.7.0/amd64/iso-cd/debian-7.7.0-amd64-net..." + } +] diff --git a/src/wok/plugins/kimchi/distros.d/fedora.json b/src/wok/plugins/kimchi/distros.d/fedora.json new file mode 100644 index 0000000..bce72d6 --- /dev/null +++ b/src/wok/plugins/kimchi/distros.d/fedora.json @@ -0,0 +1,30 @@ +[ + { + "name": "Fedora 20", + "os_distro": "fedora", + "os_arch": "x86_64", + "os_version": "20", + "path": "http://fedora.mirrors.tds.net/pub/fedora/releases/20/Live/x86_64/Fedora-Live..." + }, + { + "name": "Fedora 18 (PPC64)", + "os_distro": "fedora", + "os_arch": "ppc64", + "os_version": "18", + "path": "http://mirrors.kernel.org/fedora-secondary/releases/18/Fedora/ppc64/iso/Fedo..." + }, + { + "name": "Fedora 19 (PPC64)", + "os_distro": "fedora", + "os_arch": "ppc64", + "os_version": "19", + "path": "http://mirrors.kernel.org/fedora-secondary/releases/19/Fedora/ppc64/iso/Fedo..." + }, + { + "name": "Fedora 20 (PPC64)", + "os_distro": "fedora", + "os_arch": "ppc64", + "os_version": "20", + "path": "http://mirrors.kernel.org/fedora-secondary/releases/20/Fedora/ppc64/iso/Fedo..." + } +] diff --git a/src/wok/plugins/kimchi/distros.d/gentoo.json b/src/wok/plugins/kimchi/distros.d/gentoo.json new file mode 100644 index 0000000..2c0f012 --- /dev/null +++ b/src/wok/plugins/kimchi/distros.d/gentoo.json @@ -0,0 +1,9 @@ +[ + { + "name": "gentoo-20141204", + "os_distro": "gentoo", + "os_arch": "x86_64", + "os_version": "20141204", + "path": "http://distfiles.gentoo.org/releases/amd64/autobuilds/current-iso/install-am..." + } +] diff --git a/src/wok/plugins/kimchi/distros.d/opensuse.json b/src/wok/plugins/kimchi/distros.d/opensuse.json new file mode 100644 index 0000000..f51de97 --- /dev/null +++ b/src/wok/plugins/kimchi/distros.d/opensuse.json @@ -0,0 +1,23 @@ +[ + { + "name": "opensuse-12.3", + "os_distro": "opensuse", + "os_arch": "x86_64", + "os_version": "12.3", + "path": "http://suse.mirrors.tds.net/pub/opensuse/distribution/12.3/iso/openSUSE-12.3..." + }, + { + "name": "opensuse-13.1", + "os_distro": "opensuse", + "os_arch": "x86_64", + "os_version": "13.1", + "path": "http://suse.mirrors.tds.net/pub/opensuse/distribution/13.1/iso/openSUSE-13.1..." + }, + { + "name": "opensuse-13.2", + "os_distro": "opensuse", + "os_arch": "x86_64", + "os_version": "13.2", + "path": "http://suse.mirrors.tds.net/pub/opensuse/distribution/13.2/iso/openSUSE-13.2..." + } +] diff --git a/src/wok/plugins/kimchi/distros.d/ubuntu.json b/src/wok/plugins/kimchi/distros.d/ubuntu.json new file mode 100644 index 0000000..161fbc8 --- /dev/null +++ b/src/wok/plugins/kimchi/distros.d/ubuntu.json @@ -0,0 +1,37 @@ +[ + { + "name": "Ubuntu 13.04 (Raring Ringtail)", + "os_distro": "ubuntu", + "os_arch": "x86_64", + "os_version": "13.04", + "path": "http://ubuntu-releases.cs.umn.edu/13.04/ubuntu-13.04-desktop-amd64.iso" + }, + { + "name": "Ubuntu 13.10 (Saucy Salamander)", + "os_distro": "ubuntu", + "os_arch": "x86_64", + "os_version": "13.10", + "path": "http://ubuntu-releases.cs.umn.edu/13.10/ubuntu-13.10-desktop-amd64.iso" + }, + { + "name": "Ubuntu Server 14.04 LE (Trusty Tahr)", + "os_distro": "ubuntu", + "os_arch": "ppc64", + "os_version": "14.04", + "path": "http://cdimages.ubuntu.com/releases/14.04/release/ubuntu-14.04-server-ppc64e..." + }, + { + "name": "Ubuntu Server 14.04 LE (Trusty Tahr)", + "os_distro": "ubuntu", + "os_arch": "x86_64", + "os_version": "14.04", + "path": "http://releases.ubuntu.com/14.04/ubuntu-14.04-desktop-amd64.iso" + }, + { + "name": "Ubuntu Server 14.10 (Utopic Unicorn)", + "os_distro": "ubuntu", + "os_arch": "x86_64", + "os_version": "14.10", + "path": "http://releases.ubuntu.com/14.10/ubuntu-14.10-desktop-amd64.iso" + } +] diff --git a/src/wok/plugins/kimchi/docs/API.md b/src/wok/plugins/kimchi/docs/API.md new file mode 100644 index 0000000..fca424c --- /dev/null +++ b/src/wok/plugins/kimchi/docs/API.md @@ -0,0 +1,1116 @@ +## Project Kimchi REST API Specification + +The Kimchi API provides all functionality to the application and may be used +directly by external tools. In the following sections you will find the +specification of all Collections and Resource types that are supported and the +URIs where they can be accessed. In order to use the API effectively, please +the following general conventions: + +* The **Content Type** of the API is JSON. When making HTTP requests to this + API you should specify the following headers: + * Accept: application/json + * Content-type: application/json +* A **Collection** is a group of Resources of a given type. + * A **GET** request retrieves a list of summarized Resource representations + This summary *may* include all or some of the Resource properties but + *must* include a link to the full Resource representation. + * A **POST** request will create a new Resource in the Collection. The set + of Resource properties *must* be specified as a JSON object in the request + body. + * No other HTTP methods are supported for Collections +* A **Resource** is a representation of a singular object in the API (eg. + Virtual Machine). + * A **GET** request retrieves the full Resource representation. + * A **DELETE** request will delete the Resource. This request *may* contain + a JSON object which specifies optional parameters. + * A **PUT** request is used to modify the properties of a Resource (eg. + Change the name of a Virtual Machine). This kind of request *must not* + alter the live state of the Resource. Only *actions* may alter live state. + * A **POST** request commits an *action* upon a Resource (eg. Start a + Virtual Machine). This request is made to a URI relative to the Resource + URI. Available *actions* are described within the *actions* property of a + Resource representation. The request body *must* contain a JSON object + which specifies parameters. +* URIs begin with '/plugins/kimchi' to indicate the root of Kimchi plugin. + * Variable segments in the URI begin with a ':' and should replaced with the + appropriate resource identifier. + +### Collection: Virtual Machines + +**URI:** /plugins/kimchi/vms + +**Methods:** + +* **GET**: Retrieve a summarized list of all defined Virtual Machines +* **POST**: Create a new Virtual Machine + * name *(optional)*: The name of the VM. Used to identify the VM in this + API. If omitted, a name will be chosen based on the template used. + * persistent: If 'true', vm will persist after a Power Off or host reboot. + All virtual machines created by Kimchi are persistent. + * template: The URI of a Template to use when building the VM + * storagepool *(optional)*: Assign a specific Storage Pool to the new VM + * graphics *(optional)*: Specify the graphics paramenter for this vm + * type: The type of graphics. It can be VNC or spice or None. + * vnc: Graphical display using the Virtual Network + Computing protocol + * spice: Graphical display using the Simple Protocol for + Independent Computing Environments + * null: Graphics is disabled or type not supported + * listen: The network which the vnc/spice server listens on. + + +### Resource: Virtual Machine + +**URI:** /plugins/kimchi/vms/*:name* + +**Methods:** + +* **GET**: Retrieve the full description of a Virtual Machine + * name: The name of the VM. Used to identify the VM in this API + * state: Indicates the current state in the VM lifecycle + * running: The VM is powered on + * paused: The VMs virtual CPUs are paused + * shutoff: The VM is powered off + * stats: Virtual machine statistics: + * cpu_utilization: A number between 0 and 100 which indicates the + percentage of CPU utilization. + * net_throughput: Expresses total network throughput for reads and + writes across all virtual interfaces (kb/s). + * net_throughput_peak: The highest recent value of 'net_throughput'. + * io_throughput: Expresses the total IO throughput for reads and + writes across all virtual disks (kb/s). + * io_throughput_peak: The highest recent value of 'io_throughput'. + * uuid: UUID of the VM. + * memory: The amount of memory assigned to the VM (in MB) + * cpus: The number of CPUs assigned to the VM + * screenshot: A link to a recent capture of the screen in PNG format + * icon: A link to an icon that represents the VM + * graphics: A dict to show detail of VM graphics. + * type: The type of graphics. It can be VNC or spice or None. + * vnc: Graphical display using the Virtual Network + Computing protocol + * spice: Graphical display using the Simple Protocol for + Independent Computing Environments + * null: Graphics is disabled or type not supported + * listen: The network which the vnc/spice server listens on. + * port: The real port number of the graphics, vnc or spice. Users + can use this port to connect to the vm with general vnc/spice + clients. + * passwd: console password + * passwdValidTo: lifetime for the console password. + * users: A list of system users who have permission to access the VM. + Default is: empty (i.e. only root-users may access). + * groups: A list of system groups whose users have permission to access + the VM. Default is: empty (i.e. no groups given access). +* **DELETE**: Remove the Virtual Machine +* **PUT**: update the parameters of existed VM + * name: New name for this VM (only applied for shutoff VM) + * users: New list of system users. + * groups: New list of system groups. + * cpus: New number of virtual cpus for this VM (if VM is running, new value + will take effect in next reboot) + * memory: New amount of memory (MB) for this VM (if VM is running, new + value will take effect in next reboot) + * graphics: A dict to show detail of VM graphics. + * passwd *(optional)*: console password. When omitted a random password + willbe generated. + * passwdValidTo *(optional)*: lifetime for the console password. When + omitted the password will be valid just + for 30 seconds. + +* **POST**: *See Virtual Machine Actions* + +**Actions (POST):** + +* start: Power on a VM +* poweroff: Power off a VM forcefully. Note this action may produce undesirable + results, for example unflushed disk cache in the guest. +* shutdown: Shut down a VM graceful. This action issue shutdown request to guest. + And the guest will react this request. Note the guest OS may ignore + the request. +* reset: Reset a VM immediately without the guest OS shutdown. + It emulates the power reset button on a machine. Note that there is a + risk of data loss caused by reset without the guest OS shutdown. +* connect: Prepare the connection for spice or vnc + +* clone: Create a new VM identical to this VM. The new VM's name, UUID and + network MAC addresses will be generated automatically. Each existing + disks will be copied to a new volume in the same storage pool. If + there is no available space on that storage pool to hold the new + volume, it will be created on the pool 'default'. This action returns + a Task. + +* suspend: Suspend an active domain. The process is frozen without further + access to CPU resources and I/O but the memory used by the domain at + the hypervisor level will stay allocated. + +* resume: Resume a suspended domain. The process is restarted from the state + where it was frozen by calling "suspend". + +### Sub-resource: Virtual Machine Screenshot + +**URI:** /plugins/kimchi/vms/*:name*/screenshot + +Represents a snapshot of the Virtual Machine's primary monitor. + +**Methods:** + +* **GET**: Redirect to the latest screenshot of a Virtual Machine in PNG format + + +### Sub-collection: Virtual Machine storages +**URI:** /plugins/kimchi/vms/*:name*/storages +* **GET**: Retrieve a summarized list of all storages of specified guest +* **POST**: Attach a new storage or virtual drive to specified virtual machine. + * type: The type of the storage (currently support 'cdrom' and 'disk'). + * path: Path of cdrom iso. + * pool: Storage pool which disk image file locate in. + * vol: Storage volume name of disk image. + +### Sub-resource: storage +**URI:** /plugins/kimchi/vms/*:name*/storages/*:dev* +* **GET**: Retrieve storage information + * dev: The name of the storage in the vm. + * type: The type of the storage (currently support 'cdrom' and 'disk'). + * path: Path of cdrom iso or disk image file. + * bus: Bus type of disk attached. +* **PUT**: Update storage information + * path: Path of cdrom iso. Can not be blank. Now just support cdrom type. +* **DELETE**: Remove the storage. + +**Actions (POST):** + + +### Sub-collection: Virtual Machine Passthrough Devices +**URI:** /plugins/kimchi/vms/*:name*/hostdevs +* **GET**: Retrieve a summarized list of all directly assigned host device of + specified guest. +* **POST**: Directly assign a host device to guest. + * name: The name of the host device to be assigned to vm. + +### Sub-resource: Device +**URI:** /plugins/kimchi/vms/*:name*/hostdevs/*:dev* +* **GET**: Retrieve assigned device information + * name: The name of the assigned device. + * type: The type of the assigned device. +* **DELETE**: Detach the host device from VM. + +### Sub-collection: Virtual Machine Snapshots +**URI:** /plugins/kimchi/vms/*:name*/snapshots +* **POST**: Create a new snapshot on a VM. + * name: The snapshot name (optional, defaults to a value based on the + current time). +* **GET**: Retrieve a list of snapshots on a VM. + +### Sub-resource: Snapshot +**URI:** /plugins/kimchi/vms/*:name*/snapshots/*:snapshot* +* **GET**: Retrieve snapshot information. + * created: The time when the snapshot was created + (in seconds, since the epoch). + * name: The snapshot name. + * parent: The name of the parent snapshot, or an empty string if there is + no parent. + * state: The corresponding domain's state when the snapshot was created. +* **DELETE**: Delete snapshot. If the snapshot has any children, they will be + merged automatically with the snapshot's parent. +* **POST**: See "Snapshot actions (POST)" + +**Snapshot Actions (POST):** + +* revert: Revert the domain to the given snapshot. + +### Sub-resource: Current snapshot +**URI:** /plugins/kimchi/vms/*:name*/snapshots/current +* **GET**: Retrieve current snapshot information for the virtual machine. + +### Collection: Templates + +**URI:** /plugins/kimchi/templates + +**Methods:** + +* **GET**: Retrieve a summarized list of all defined Templates +* **POST**: Create a new Template + * name: The name of the Template. Used to identify the Template in this API + * os_distro *(optional)*: The operating system distribution + * os_version *(optional)*: The version of the operating system distribution + * cpus *(optional)*: The number of CPUs assigned to the VM. + Default is 1, unlees specifying a cpu topology. In that case, cpus + will default to a product of the topology values (see cpu_info). + * memory *(optional)*: The amount of memory assigned to the VM. + Default is 1024M. + * cdrom *(optional)*: A volume name or URI to an ISO image. + * storagepool *(optional)*: URI of the storagepool. + Default is '/storagepools/default' + * networks *(optional)*: list of networks will be assigned to the new VM. + Default is '[default]' + * disks *(optional)*: An array of requested disks with the following optional fields + (either *size* or *volume* must be specified): + * index: The device index + * size: The device size in GB + * base: Base image of this disk + + * graphics *(optional)*: The graphics paramenters of this template + * type: The type of graphics. It can be VNC or spice or None. + * vnc: Graphical display using the Virtual Network + Computing protocol + * spice: Graphical display using the Simple Protocol for + Independent Computing Environments + * null: Graphics is disabled or type not supported + * listen: The network which the vnc/spice server listens on. + * cpu_info *(optional)*: CPU-specific information. + * topology: Specify sockets, threads, and cores to run the virtual CPU + threads on. + All three are required in order to specify cpu topology. + * sockets - The number of sockets to use. + * cores - The number of cores per socket. + * threads - The number of threads per core. + If specifying both cpus and CPU topology, make sure cpus is + equal to the product of sockets, cores, and threads. + +### Sub-Collection: Virtual Machine Network Interfaces + +**URI:** /plugins/kimchi/vms/*:name*/ifaces + +Represents all network interfaces attached to a Virtual Machine. + +**Methods:** + +* **GET**: Retrieve a summarized list of all network interfaces attached to a Virtual Machine. + +* **POST**: attach a network interface to VM + * model *(optional)*: model of emulated network interface card. It can be one of these models: + ne2k_pci, i82551, i82557b, i82559er, rtl8139, e1000, pcnet and virtio. + When model is missing, libvirt will set 'rtl8139' as default value. + * network *(optional)*: the name of resource network, it is required when the + interface type is network. + * type: The type of VM network interface that libvirt supports. + Now kimchi just supports 'network' type. + +### Sub-Resource: Virtual Machine Network Interface + +**URI:** /plugins/kimchi/vms/*:name*/ifaces/*:mac* + +A interface represents available network interface on VM. + +**Methods:** + +* **GET**: Retrieve the full description of the VM network interface + * bridge *(optional)*: the name of resource bridge, only be available when the + interface type is bridge. + * mac: Media Access Control Address of the VM interface. + * model *(optional)*: model of emulated network interface card. It will be one of these models: + ne2k_pci, i82551, i82557b, i82559er, rtl8139, e1000, pcnet and virtio. + * network *(optional)*: the name of resource network, only be available when the + interface type is network. + * type: The type of VM network interface that libvirt supports. + It will be one of these types: 'network', 'bridge', 'user','ethernet', + 'direct', 'hostdev', 'mcast', 'server' and 'client'. + +* **DELETE**: detach the network interface from VM + +* **PUT**: update the parameters of existing VM interface. + * model *(optional)*: model of emulated network interface card. It will be one of these models: + ne2k_pci, i82551, i82557b, i82559er, rtl8139, e1000, pcnet and virtio. + This change is only on the persisted VM configuration. + * network *(optional)*: the name of resource network, only be available when the + interface type is network. + This change is on the active VM instance and persisted VM configuration. + +**Actions (POST):** + +*No actions defined* + + +### Resource: Template + +**URI:** /plugins/kimchi/templates/*:name* + +**Methods:** + +* **GET**: Retrieve the full description of a Template + * name: A name for this template + * folder: A virtual path which can be used to organize Templates in a user + interface. The format is an array of path components. + * icon: A URI to a PNG image representing this template + * os_distro: The operating system distribution + * os_version: The version of the operating system distribution + * cpus: The number of CPUs assigned to the VM + * memory: The amount of memory assigned to the VM in the unit of MB + * cdrom: A volume name or URI to an ISO image + * storagepool: URI of the storagepool where template allocates vm storage. + * networks *(optional)*: list of networks will be assigned to the new VM. + * disks: An array of requested disks with the following optional fields + (either *size* or *volume* must be specified): + * index: The device index + * size: The device size in GB + * volume: A volume name that contains the initial disk contents + * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc. + * graphics: A dict of graphics paramenters of this template + * type: The type of graphics. It can be VNC or spice or None. + * vnc: Graphical display using the Virtual Network + Computing protocol + * spice: Graphical display using the Simple Protocol for + Independent Computing Environments + * null: Graphics is disabled or type not supported + * listen: The network which the vnc/spice server listens on. + * invalid: A dict indicates which paramenters of this template are invalid. + * networks *(optional)*: An array of invalid network names. + * cdrom *(optional)*: An array of invalid cdrom names. + * disks *(optional)*: An array of invalid volume names. + * storagepools *(optional)*: An array of invalid storagepool names. + +* **DELETE**: Remove the Template +* **POST**: *See Template Actions* +* **PUT**: update the parameters of existed template + * name: A name for this template + * folder: A virtual path which can be used to organize Templates in the user + interface. The format is an array of path components. + * icon: A URI to a PNG image representing this template + * os_distro: The operating system distribution + * os_version: The version of the operating system distribution + * cpus: The number of CPUs assigned to the VM + * memory: The amount of memory assigned to the VM + * cdrom: A volume name or URI to an ISO image + * storagepool: URI of the storagepool where template allocates vm storage. + * networks *(optional)*: list of networks will be assigned to the new VM. + * disks: An array of requested disks with the following optional fields + (either *size* or *volume* must be specified): + * index: The device index + * size: The device size in GB + * volume: A volume name that contains the initial disk contents + * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc. + * graphics *(optional)*: A dict of graphics paramenters of this template + * type: The type of graphics. It can be VNC or spice or None. + * vnc: Graphical display using the Virtual Network + Computing protocol + * spice: Graphical display using the Simple Protocol for + Independent Computing Environments + * null: Graphics is disabled or type not supported + * listen: The network which the vnc/spice server listens on. + +**Actions (POST):** + +* clone: clone a template from an existing template with different name. + It will provide a reasonable default name with "-cloneN" as suffix + for the new clone template. The "N" means the number of clone times. + +### Collection: Storage Pools + +**URI:** /plugins/kimchi/storagepools + +**Methods:** + +* **GET**: Retrieve a summarized list of all defined Storage Pools +* **POST**: Create a new Storage Pool + * name: The name of the Storage Pool. + * type: The type of the defined Storage Pool. + Supported types: 'dir', 'kimchi-iso', 'netfs', 'logical', 'iscsi', 'scsi' + * path: The path of the defined Storage Pool. + For 'kimchi-iso' pool refers to targeted deep scan path. + Pool types: 'dir', 'kimchi-iso'. + * source: Dictionary containing source information of the pool. + * host: IP or hostname of server for a pool backed from a remote host. + Pool types: 'netfs', 'iscsi'. + * path: Export path on NFS server for NFS pool. + Pool types: 'netfs'. + * devices: Array of devices to be used in the Storage Pool + Pool types: 'logical'. + * target: Target IQN of an iSCSI pool. + Pool types: 'iscsi'. + * port *(optional)*: Listening port of a remote storage server. + Pool types: 'iscsi'. + * auth *(optional)*: Storage back-end authentication information. + Pool types: 'iscsi'. + * username: Login username of the iSCSI target. + * password: Login password of the iSCSI target. + * adapter_name: SCSI host name. + +### Resource: Storage Pool + +**URI:** /plugins/kimchi/storagepools/*:name* + +**Methods:** + +* **GET**: Retrieve the full description of a Storage Pool + * name: The name of the Storage Pool + Used to identify the Storage Pool in this API + 'kimchi_isos' is a reserved storage pool + which aggregates all ISO images + across all active storage pools into a single view. + * state: Indicates the current state of the Storage Pool + * active: The Storage Pool is ready for use + * inactive: The Storage Pool is not available + * path: The path of the defined Storage Pool + * type: The type of the Storage Pool + * capacity: The total space which can be used to store volumes + The unit is Bytes + * allocated: The amount of space which is being used to store volumes + The unit is Bytes + * available: Free space available for creating new volumes in the pool + * nr_volumes: The number of storage volumes for active pools, 0 for inactive pools + * autostart: Whether the storage pool will be enabled + automatically when the system boots + * persistent: True, when pool persist after a system reboot or be stopped. + All storage pools created by Kimchi are persistent. + * source: Source of the storage pool, + * addr: mount address of this storage pool(for 'netfs' pool) + * path: export path of this storage pool(for 'netfs' pool) + +* **PUT**: Set whether the Storage Pool should be enabled automatically when the + system boots + * autostart: Toggle the autostart flag of the VM. This flag sets whether + the Storage Pool should be enabled automatically when the + system boots + * disks: Adds one or more disks to the pool (for 'logical' pool only) +* **DELETE**: Remove the Storage Pool +* **POST**: *See Storage Pool Actions* + +**Actions (POST):** + +* activate: Activate an inactive Storage Pool +* deactivate: Deactivate an active Storage Pool + +### Collection: Storage Volumes + +**URI:** /plugins/kimchi/storagepools/*:poolname*/storagevolumes + +**Methods:** + +* **GET**: Retrieve a summarized list of all defined Storage Volumes + in the defined Storage Pool +* **POST**: Create a new Storage Volume in the Storage Pool + The return resource is a task resource * See Resource: Task * + Only one of 'capacity', 'url' can be specified. + * name: The name of the Storage Volume + * capacity: The total space which can be used to store volumes + The unit is bytes + * format: The format of the defined Storage Volume. Only used when creating + a storage volume with 'capacity'. + * upload: True to start an upload process. False, otherwise. + Only used when creating a storage volume 'capacity' parameter. + * file: File to be uploaded, passed through form data + +### Resource: Storage Volume + +**URI:** /plugins/kimchi/storagepools/*:poolname*/storagevolumes/*:name* + +**Methods:** + +* **GET**: Retrieve the full description of a Storage Volume + * name: The name of the Storage Volume + Used to identify the Storage Volume in this API + * type: The type of the Storage Volume + * capacity: The total space which can be used to store data + The unit is Bytes + * allocation: The amount of space which is being used to store data + The unit is Bytes + * format: The format of the file or volume + * path: Full path of the volume on the host filesystem. + * os_distro *(optional)*: os distribution of the volume, for iso volume only. + * os_version *(optional)*: os version of the volume, for iso volume only. + * bootable *(optional)*: True if iso image is bootable and not corrupted. + * used_by: Name of vms which use this volume. + +* **DELETE**: Remove the Storage Volume +* **POST**: *See Storage Volume Actions* +* **PUT**: Upload storage volume chunk + * chunk_size: Chunk size of the slice in Bytes. + * chunk: Actual data of uploaded file + +**Actions (POST):** + +* resize: Resize a Storage Volume + * size: resize the total space which can be used to store data + The unit is bytes +* wipe: Wipe a Storage Volume +* clone: Clone a Storage Volume. + * pool: The name of the destination pool (optional). + * name: The new storage volume name (optional). + + +### Collection: Interfaces + +**URI:** /plugins/kimchi/interfaces + +**Methods:** + +* **GET**: Retrieve a summarized list of current Interfaces + +### Resource: Interface + +**URI:** /plugins/kimchi/interfaces/*:name* + +A interface represents available interface on host. + +**Methods:** + +* **GET**: Retrieve the full description of the Interface + * name: The name of the interface. + * status: The current status of the Interface. + * active: The interface is active. + * inactive: The interface is inactive. + * ipaddr: The ip address assigned to this interface in subnet. + * netmask: Is used to divide an IP address into subnets and specify the + networks available hosts + * type: The net device type of the interface. + * nic: Network interface controller that connects a computer to a + computer network + * vlan: A logical interface that represents a VLAN in all Layer 3 + activities the unit may participate in + * bonding: The combination of network interfaces on one host for redundancy + and/or increased throughput. + * bridge: A network device that connects multiple network segments. + +* **POST**: *See Interface Actions* + +**Actions (POST):** + +*No actions defined* + +### Collection: Networks + +**URI:** /plugins/kimchi/networks + +**Methods:** + +* **GET**: Retrieve a summarized list of all defined Networks +* **POST**: Create a new Network + * name: The name of the Network + * connection: Specifies how this network should be connected to the other + networks visible to this host. + * isolated: Create a private, isolated virtual network. + * nat: Outgoing traffic will be routed through the host. + * bridge: All traffic on this network will be bridged through the indicated + interface. + * subnet *(optional)*: Network segment in slash-separated format with ip address and + prefix or netmask used to create nat network. + * interface *(optional)*: The name of a network interface on the host. + For bridge network, the interface can be a bridge or nic/bonding + device. + * vlan_id *(optional)*: VLAN tagging ID for the bridge network. + +### Resource: Network + +**URI:** /plugins/kimchi/networks/*:name* + +**Methods:** + +* **GET**: Retrieve the full description of a Network + * name: The name of the Network + Used to identify the Network in this API + * state: Indicates the current state of the Network + * active: The Network is ready for use + * inactive: The Network is not available + * autostart: Network autostart onboot + * in_use: Indicates ('true') if some guest is attached to this network and 'false' otherwise. + * vms: all vms attached to this network + * subnet: Network segment in slash-separated format with ip address and prefix + * dhcp: DHCP services on the virtual network is enabled. + * start: start boundary of a pool of addresses to be provided to DHCP clients. + * end: end boundary of a pool of addresses to be provided to DHCP clients. + * connection: Specifies how this network should be connected to the other networks + visible to this host. + * isolated: A private, isolated virtual network. + The VMs attached to it can not be reached by the systems + outside of this network and vice versa. + * nat: Outgoing traffic will be routed through the host. + The VM attached to it will have internet access via the host but + other computers will not be able to connect to the VM. + * bridge: Aggregated Public Network. + The VM that joines this network is seen as a peer on this network + and it may offer network services such as HTTP or SSH. + * interface: The name of a bridge network interface on the host. All traffic + on this network will be bridged through the indicated interface. + The interface is a bridge or ethernet/bonding device. + * persistent: If 'true', network will persist after a system reboot or be stopped. + All networks created by Kimchi are persistent. + +* **DELETE**: Remove the Network +* **POST**: *See Network Actions* + +**Actions (POST):** + +* activate: Activate an inactive Network +* deactivate: Deactivate an active Network + + +### Resource: Configuration + +**URI:** /plugins/kimchi/config + +Contains information about the application environment and configuration. + +**Methods:** + +* **GET**: Retrieve configuration information + * display_proxy_port: Port for vnc and spice's websocket proxy to listen on + * version: The version of the kimchi service +* **POST**: *See Configuration Actions* + +**Actions (POST):** + +*No actions defined* + +### Resource: Capabilities + +**URI:** /plugins/kimchi/config/capabilities + +Contains information about the host capabilities: iso streaming, screenshot +creation. + +**Methods:** + +* **GET**: Retrieve capabilities information + * libvirt_stream_protocols: list of which network protocols are accepted + for iso streaming by libvirt + * qemu_spice: True, if QEMU supports Spice; False, otherwise + * qemu_stream: True, if QEMU supports ISO streaming; False, otherwise + * screenshot: True, if libvirt stream functionality can create screenshot + file without problems; False, otherwise or None if the functionality was + not tested yet + * system_report_tool: True if the is some debug report tool installed on + the system; False, otherwise. + * update_tool: True if there is a compatible package manager for the + system; False, otherwise + * repo_mngt_tool: 'deb', 'yum' or None - when the repository management + tool is not identified + * federation: 'on' if federation feature is enabled, 'off' otherwise. + * auth: authentication type, 'pam' and 'ldap' are supported. +* **POST**: *See Configuration Actions* + +**Actions (POST):** + +*No actions defined* + +### Collection: Storage Servers + +**URI:** /plugins/kimchi/storageservers + +**Methods:** + +* **GET**: Retrieve a summarized list of used storage servers. + * Parameters: + * _target_type: Filter server list with given type, currently support + 'netfs' and 'iscsi'. + +### Resource: Storage Server + +**URI:** /plugins/kimchi/storageservers/*:host* + +**Methods:** + +* **GET**: Retrieve description of a Storage Server + * host: IP or host name of storage server + * port: port of storage server, only for "iscsi" + +### Collection: Storage Targets + +**URI:** /plugins/kimchi/storageservers/*:name*/storagetargets + +**Methods:** + +* **GET**: Retrieve a list of available storage targets. + * Parameters: + * _target_type: Filter target list with given type, currently support + 'netfs' and 'iscsi'. + * _server_port: Filter target list with given server port, + currently support 'iscsi'. + * Response: A list with storage targets information. + * host: IP or host name of storage server of this target. + * target_type: Type of storage target, supported: 'nfs'. + * target: Storage target path. + +### Collection: Distros + +**URI:** /plugins/kimchi/config/distros + +**Methods:** + +* **GET**: Retrieve a summarized list of all Distros + +### Resource: Distro + +**URI:** /plugins/kimchi/config/distros/*:name* + +Contains information about the OS distribution. + +**Methods:** + +* **GET**: Retrieve a OS distribution information. + * name: The name of the Distro. + * os_distro: The operating system distribution. + * os_version: The version of the operating system distribution. + * path: A URI to an ISO image. + +**Actions (POST):** + +*No actions defined* + +#### Collection: Debug Reports + +**URI:** /plugins/kimchi/debugreports + +**Methods:** + +* **GET**: Retrieve a summarized list of all available Debug Reports +* **POST**: Create a new Debug Report. This POST method is different + from the other ones. The return resource is a task resource which + is identified by the url below + * task resource. * See Resource: Task * + +### Resource: Debug Report + +**URI:** /plugins/kimchi/debugreports/*:name* + +A Debug Report is an archive of logs and other information about the host that +is used to diagnose and debug problems. The exact format and contents are +specific to the low level collection tool being used. + +**Methods:** + +* **GET**: Retrieve the full description of Debug Report + * name: The debug report name used to identify the report + * uri: The URI path to download a debug report + * time: The time when the debug report is created + +* **PUT**: rename an existed debug report + * name: The new name for this debug report + +* **DELETE**: Remove the Debug Report + * name: The debug report name used to identify the report + +* **POST**: *See Debug Report Actions* + +**Actions (POST):** + +*No actions defined* + +### Sub-resource: Debug Report content + +**URI:** /plugins/kimchi/debugreports/*:name*/content + +It is the sub-resource of Debug Report and the client use it to get the real content +of the Debug Report file from the server + +* **GET**: Retrieve the content of a Debug Report file + +**Actions (POST):** + +*No actions defined* + +### Resource: Host + +**URI:** /plugins/kimchi/host +Contains information of host. + +**Methods:** + +* **GET**: Retrieve host static information + * memory: Total size of host physical memory + The unit is Bytes + * cpu_model: The model name of host CPU + * cpus: The number of online CPUs available on host + * os_distro: The OS distribution that runs on host + * os_version: The version of OS distribution + * os_codename: The code name of OS distribution + +* **POST**: *See Host Actions* + +**Actions (POST):** + +* reboot: Restart the host machine. + Only allowed if there is not vm running. +* shutdown: Power off the host machine. + Only allowed if there is not vm running. +* swupdate: Start the update of packages in background and return a Task resource + * task resource. * See Resource: Task * + +### Resource: Users + +**URI:** /plugins/kimchi/users +List of available users. + +**Methods:** + +* **GET**: Retrieve list of available users. + * Parameters: + * _user_id: Validate whether user exists. + Essential for 'ldap' authentication. + +### Resource: Groups + +**URI:** /plugins/kimchi/groups +List of available groups. + +**Methods:** + +* **GET**: Retrieve list of available groups, only support 'pam' authentication. + +### Resource: HostStats + +**URI:** /plugins/kimchi/host/stats + +Contains the host sample data. + +**Methods:** + +* **GET**: Retrieve host sample data + * cpu_utilization: A number between 0 and 100 which indicates the + percentage of CPU utilization. + * memory: memory statistics of host + * total: Total amount of memory. The unit is Bytes. + * free: The amount of memory left unused by the system. The unit is Bytes. + * buffers: The amount of memory used for file buffers. The unit is Bytes. + * cached: The amount of memory used as cache memory. The unit is Bytes. + * avail: The total amount of buffer, cache and free memory. The unit is Bytes. + * disk_read_rate: Expresses the total IO throughput for reads across + all disks (B/s). + * disk_write_rate: Expresses the total IO throughput for writes across + all disks (B/s). + * net_sent_rate: Expresses the total network throughput for writes across + all interfaces (B/s). + * net_recv_rate: Expresses the total network throughput for reads across + all interfaces (B/s). + +* **POST**: *See HostStats Actions* + +**Actions (POST):** + +*No actions defined* + +### Resource: HostStats + +**URI:** /plugins/kimchi/host/cpuinfo + +The cores and sockets of a hosts's CPU. Useful when sizing VMs to take +advantages of the perforamance benefits of SMT (Power) or Hyper-Threading (Intel). + +**Methods:** + +* **GET**: Retreives the sockets, cores, and threads values. + * threading_enabled: Whether CPU topology is supported on this system. + * sockets: The number of total sockets on a system. + * cores: The total number of cores per socket. + * threads_per_core: The threads per core. + +**Actions (PUT):** + +*No actions defined* + +**Actions (POST):** + +*No actions defined* + + +### Resource: HostStatsHistory + +**URI:** /plugins/kimchi/host/stats/history + +It is the sub-resource of Host Stats and the client uses it to get the host +stats history + +**Methods:** + +* **GET**: Retrieve host sample data history + * cpu_utilization: CPU utilization history + * memory: Memory statistics history + * total: Total amount of memory. The unit is Bytes. + * free: The amount of memory left unused by the system. The unit is Bytes. + * buffers: The amount of memory used for file buffers. The unit is Bytes. + * cached: The amount of memory used as cache memory. The unit is Bytes. + * avail: The total amount of buffer, cache and free memory. The unit is Bytes. + * disk_read_rate: IO throughput for reads history + * disk_write_rate: IO throughput for writes history + * net_sent_rate: Network throughput for writes history + * net_recv_rate: Network throughput for reads history + +* **POST**: *See HostStatsHistory Actions* + +**Actions (POST):** + +*No actions defined* + +### Collection: Partitions + +**URI:** /plugins/kimchi/host/partitions + +**Methods:** + +* **GET**: Retrieves a detailed list of all partitions of the host. + +### Resource: Partition + +**URI:** /plugins/kimchi/host/partitions/*:name* + +**Methods:** + +* **GET**: Retrieve the description of a single Partition: + * name: The name of the partition. Used to identify it in this API + * path: The device path of this partition. + * type: The type of the partition: + * part: a standard partition + * lvm: a partition that belongs to a lvm + * fstype: The file system type of the partition + * size: The total size of the partition, in bytes + * mountpoint: If the partition is mounted, represents the mountpoint. + Otherwise blank. + * available: false, if the partition is in use by system; true, otherwise. + +### Collection: Devices + +**URI:** /plugins/kimchi/host/devices + +**Methods:** + +* **GET**: Retrieves list of host devices (Node Devices). + * Parameters: + * _cap: Filter node device list with given node device capability. + To list Fibre Channel SCSI Host devices, use "_cap=fc_host". + Other available values are "fc_host", "net", "pci", "scsi", + "storage", "system", "usb" and "usb_device". + * _passthrough: Filter devices eligible to be assigned to guest + directly. Possible values are "ture" and "false". + * _passthrough_affected_by: Filter the affected devices in the same + group of a certain directly assigned device. + The value should be the name of a device. + +### Resource: Device + +**URI:** /plugins/kimchi/host/devices/*:name* + +**Methods:** + +* **GET**: Retrieve information of a single host device. + * device_type: Type of the device, supported types are "net", "pci", "scsi", + "storage", "system", "usb" and "usb_device". + * name: The name of the device. + * path: Path of device in sysfs. + * parent: The name of the parent parent device. + * adapter: Host adapter information of a "scsi_host" or "fc_host" device. + * type: The capability type of the scsi_host device (fc_host, vport_ops). + * wwnn: The HBA Word Wide Node Name. Empty if pci device is not fc_host. + * wwpn: The HBA Word Wide Port Name. Empty if pci device is not fc_host. + * domain: Domain number of a "pci" device. + * bus: Bus number of a "pci" device. + * slot: Slot number of a "pci" device. + * function: Function number of a "pci" device. + * vendor: Vendor information of a "pci" device. + * id: Vendor id of a "pci" device. + * description: Vendor description of a "pci" device. + * product: Product information of a "pci" device. + * id: Product id of a "pci" device. + * description: Product description of a "pci" device. + * iommuGroup: IOMMU group number of a "pci" device. Would be None/null if + host does not enable IOMMU support. + + +### Sub-collection: VMs with the device assigned. +**URI:** /plugins/kimchi/host/devices/*:name*/vmholders +* **GET**: Retrieve a summarized list of all VMs holding the device. + +### Sub-resource: VM holder +**URI:** /plugins/kimchi/host/devices/*:name*/vmholders/*:vm* +* **GET**: Retrieve information of the VM which is holding the device + * name: The name of the VM. + * state: The power state of the VM. Could be "running" and "shutdown". + + +### Collection: Host Packages Update + +**URI:** /plugins/kimchi/host/packagesupdate + +Contains the information and action of packages update in the host. + +**Methods:** + +* **GET**: Retrieves a list of all packages to be updated in the host: + +### Resource: Host Package Update + +**URI:** /plugins/kimchi/host/packagesupdate/*:name* + +Contains the information for a specific package to be updated. + +**Methods:** + +* **GET**: Retrieves a full description of a package: + * package_name: The name of the package to be updated + * arch: The architecture of the package + * version: The new version of the package + * repository: The repository name from where package will be downloaded + +### Collection: Host Repositories + +**URI:** /plugins/kimchi/host/repositories + +**Methods:** + +* **GET**: Retrieve a summarized list of all repositories available +* **POST**: Add a new repository + * baseurl: URL to the repodata directory when "is_mirror" is false. +Otherwise, it can be URL to the mirror system for YUM. Can be an +http://, ftp:// or file:// URL. + * repo_id *(optional)*: Unique YUM repository ID + * config: A dictionary that contains specific data according to repository + type. + * repo_name *(optional)*: YUM Repository name + * mirrorlist *(optional)*: Specifies a URL to a file containing a + list of baseurls for YUM repository + * dist: Distribution to DEB repository + * comps *(optional)*: List of components to DEB repository + +### Resource: Repository + +**URI:** /plugins/kimchi/host/repositories/*:repo-id* + +**Methods:** + +* **GET**: Retrieve the full description of a Repository + * repo_id: Unique repository name for each repository, one word. + * baseurl: URL to the repodata directory when "is_mirror" is false. +Otherwise, it can be URL to the mirror system for YUM. Can be an +http://, ftp:// or file:// URL. + * enabled: True, when repository is enabled; False, otherwise + * config: A dictionary that contains specific data according to repository + type. + * repo_name: Human-readable string describing the YUM repository. + * mirrorlist: Specifies a URL to a file containing a list of baseurls + for YUM repository + * gpgcheck: True, to enable GPG signature verification; False, otherwise. + * gpgkey: URL pointing to the ASCII-armored GPG key file for the YUM + repository. + * dist: Distribution to DEB repository + * comps: List of components to DEB repository + +* **DELETE**: Remove the Repository +* **POST**: *See Repository Actions* +* **PUT**: update the parameters of existing Repository + * repo_id: Unique repository name for each repository, one word. + * baseurl: URL to the repodata directory when "is_mirror" is false. +Otherwise, it can be URL to the mirror system for YUM. Can be an +http://, ftp:// or file:// URL. + * config: A dictionary that contains specific data according to repository + type. + * repo_name: Human-readable string describing the YUM repository. + * mirrorlist: Specifies a URL to a file containing a list of baseurls + for YUM repository + * gpgcheck: True, to enable GPG signature verification; False, otherwise. + * gpgkey: URL pointing to the ASCII-armored GPG key file for the YUM + repository. + * dist: Distribution to DEB repository + * comps: List of components to DEB repository + +**Actions (POST):** + +* enable: Enable the Repository as package source +* disable: Disable the Repository as package source + +### Collection: Peers + +**URI:** /plugins/kimchi/peers + +**Methods:** + +* **GET**: Return the list of Kimchi peers in the same network + (It uses openSLP for discovering) diff --git a/src/wok/plugins/kimchi/docs/Makefile.am b/src/wok/plugins/kimchi/docs/Makefile.am new file mode 100644 index 0000000..679aa18 --- /dev/null +++ b/src/wok/plugins/kimchi/docs/Makefile.am @@ -0,0 +1,28 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +docdir = $(datadir)/kimchi/doc + +dist_doc_DATA = \ + API.md \ + README.md \ + README-federation.md \ + kimchi-guest.png \ + kimchi-templates.png \ + $(NULL) diff --git a/src/wok/plugins/kimchi/docs/README-federation.md b/src/wok/plugins/kimchi/docs/README-federation.md new file mode 100644 index 0000000..c184f4f --- /dev/null +++ b/src/wok/plugins/kimchi/docs/README-federation.md @@ -0,0 +1,60 @@ +Kimchi Project - Federation Feature +=================================== + +Federation feature is a Kimchi mechanism to discover Wok peers in the same +network. It uses openSLP tool (http://www.openslp.org/) to register and find Wok +servers. + +By default this feature is disabled on Wok as it is not critical for KVM +virtualization and requires additional software installation. + +To enable it, do the following: + +1. Install openslp and openslp-server rpm packages, + or install slpd and slptool deb packages. + +2. openSLP uses port 427 (UDP) and port 427 (TCP) so make sure to open those + ports in your firewall configuration + + For system using firewalld, do: + sudo firewall-cmd --permanent --add-port=427/udp + sudo firewall-cmd --permanent --add-port=427/tcp + sudo firewall-cmd --reload + + For openSUSE systems, do: + sudo /sbin/SuSEfirewall2 open EXT TCP 427 + sudo /sbin/SuSEfirewall2 open EXT UDP 427 + + For system using iptables, do: + sudo iptables -A INPUT -p tcp --dport 427 -j ACCEPT + sudo iptables -A INPUT -p udp --dport 427 -j ACCEPT + +3. In addition to the openSLP ports, you also need to allow multicast in the + firewall configuration + + For system using firewalld, do: + sudo firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -s <subnet> -j ACCEPT + + For openSUSE systems, do: + Add the subnet to the trusted networks listed on FW_TRUSTED_NETS in + /etc/sysconfig/SuSEfirewall2 file. + Make sure to restart /sbin/SuSEfirewall2 after modifying /etc/sysconfig/SuSEfirewall2 + + For system using iptables, do: + sudo iptables -A INPUT -s <subnet> -j ACCEPT + +4. Start slpd service and make sure it is up while running Wok + sudo service slpd start + +5. Enable federation on Wok by editing the /etc/wok/wok.conf file: + + federation = on + +6. Then start Wok service + sudo service wokd start + +The Wok server will be registered on openSLP on server starting up and will +be found by other Wok peers (with federation feature enabled) in the same +network. + +Enjoy! diff --git a/src/wok/plugins/kimchi/docs/README.md b/src/wok/plugins/kimchi/docs/README.md new file mode 100644 index 0000000..f400333 --- /dev/null +++ b/src/wok/plugins/kimchi/docs/README.md @@ -0,0 +1,247 @@ +Kimchi Project +============== + +Kimchi is an HTML5 based management tool for KVM. It is designed to make it as +easy as possible to get started with KVM and create your first guest. + +Kimchi runs as a Wok plugin. Wok runs as a daemon on the hypervisor host. + +Kimchi manages KVM guests through libvirt. The management interface is accessed +over the web using a browser that supports HTML5. + +Browser Support +=============== +Desktop Browser Support: +----------------------- +* **Internet Explorer:** IE9+ +* **Chrome:** Current-1 version +* **Firefox:** Current-1 version Firefox 24ESR +* **Safari:** Current-1 version +* **Opera:** Current-1 version + +Mobile Browser Support: +----------------------- +* **Safari iOS:** Current-1 version +* **Android Browser** Current-1 version + +Current-1 version denotes that we support the current stable version of the +browser and the version that preceded it. For example, if the current version of +a browser is 24.x, we support the 24.x and 23.x versions.This does not mean that +kimchi cannot be used in other browsers, however, functionality and appearance +may be diminished and we may not be able to provide support for any problems you +find. + +Hypervisor Distro Support +========================= + +Kimchi and Wok might run on any GNU/Linux distribution that meets the conditions +described on the 'Getting Started' section below. + +The Kimchi community makes an effort to test it with the latest versions of +Fedora, RHEL, OpenSuSe, and Ubuntu. + +Getting Started +=============== + +Install Dependencies +-------------------- + +**For fedora and RHEL:** + + $ sudo yum install gcc make autoconf automake gettext-devel git \ + python-cherrypy python-cheetah libvirt-python \ + libvirt libvirt-daemon-config-network python-imaging \ + PyPAM m2crypto python-jsonschema rpm-build \ + qemu-kvm python-psutil python-ethtool sos \ + python-ipaddr python-ldap python-lxml nfs-utils \ + iscsi-initiator-utils libxslt pyparted nginx \ + python-libguestfs libguestfs-tools python-websockify \ + novnc spice-html5 python-configobj + + # If using RHEL, install the following additional packages: + $ sudo yum install python-unittest2 python-ordereddict + + # Restart libvirt to allow configuration changes to take effect + $ sudo service libvirtd restart + + Packages version requirement: + python-psutil >= 0.6.0 + + # These dependencies are only required if you want to run the tests: + $ sudo yum install pyflakes python-pep8 python-requests + +*Note for RHEL users*: Some of the above packages are located in the Red Hat +EPEL repositories. See +[this FAQ](http://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F) +for more information on how to configure your system to access this repository. + +And for RHEL7 systems, you also need to subscribe to the "RHEL Server Optional" +channel at RHN Classic or Red Hat Satellite. + +**For debian:** + + $ sudo apt-get install gcc make autoconf automake gettext git \ + python-cherrypy3 python-cheetah python-libvirt \ + libvirt-bin python-imaging python-configobj \ + python-pam python-m2crypto python-jsonschema \ + qemu-kvm libtool python-psutil python-ethtool \ + sosreport python-ipaddr python-ldap \ + python-lxml nfs-common open-iscsi lvm2 xsltproc \ + python-parted nginx python-guestfs libguestfs-tools \ + websockify novnc spice-html5 + + Packages version requirement: + python-jsonschema >= 1.3.0 + python-psutil >= 0.6.0 + + # These dependencies are only required if you want to run the tests: + $ sudo apt-get install pep8 pyflakes python-requests + +**For openSUSE:** + + $ sudo zypper install gcc make autoconf automake gettext-tools git \ + python-CherryPy python-Cheetah libvirt-python \ + libvirt libvirt-daemon-config-network python-pam \ + python-imaging python-M2Crypto python-jsonschema \ + rpm-build kvm python-psutil python-ethtool \ + python-ipaddr python-ldap python-lxml nfs-client \ + open-iscsi libxslt-tools python-xml python-parted \ + nginx python-libguestfs python-configobj \ + guestfs-tools python-websockify novnc + + Packages version requirement: + python-psutil >= 0.6.0 + + # These dependencies are only required if you want to run the tests: + $ sudo zypper install python-pyflakes python-pep8 python-requests + +*Note for openSUSE users*: Some of the above packages are located in different +openSUSE repositories. See +[this FAQ](http://download.opensuse.org/repositories/home:GRNET:synnefo/) for +python-parted; and +[this FAQ](http://download.opensuse.org/repositories/systemsmanagement:/spacewalk/) +for python-ethtool to get the correct repository based on your openSUSE version. And +[this FAQ](http://en.opensuse.org/SDB:Add_package_repositories) for more +information on how configure your system to access this repository. + +Build and Install +----------------- + + Wok: + $ ./autogen.sh --system + + $ make + $ sudo make install # Optional if running from the source tree + + + Kimchi: + $ cd plugins/kimchi + + For openSUSE 13.1: + $ ./autogen.sh --with-spice-html5 + + Otherwise: + $ ./autogen.sh --system + + $ make + $ sudo make install # Optional if running from the source tree + +Run +--- + + $ sudo wokd --host=0.0.0.0 + +If you cannot access Wok, take a look at these 2 points: + +1. Firewall +Wok uses by default the ports 8000, 8001 and 64667. To allow incoming connections: + + For system using firewalld, do: + sudo firewall-cmd --add-port=8000/tcp --permanent + sudo firewall-cmd --add-port=8001/tcp --permanent + sudo firewall-cmd --add-port=64667/tcp --permanent + sudo firewall-cmd --reload + + For openSUSE systems, do: + sudo /sbin/SuSEfirewall2 open EXT TCP 8000 + sudo /sbin/SuSEfirewall2 open EXT TCP 8001 + sudo /sbin/SuSEfirewall2 open EXT TCP 64667 + + For system using iptables, do: + sudo iptables -A INPUT -p tcp --dport 8000 -j ACCEPT + sudo iptables -A INPUT -p tcp --dport 8001 -j ACCEPT + sudo iptables -A INPUT -p tcp --dport 64667 -j ACCEPT + + Don't forget to correctly save the rules. + + +2. SELinux +Allow httpd_t context for Wok web server: + + semanage permissive -a httpd_t + + +Test +---- + + $ cd plugins/kimchi + $ make check-local # check for i18n and formatting errors + $ sudo make check + +After all tests are executed, a summary will be displayed containing any +errors/failures which might have occurred. + +Usage +----- + +Connect your browser to https://localhost:8001. You should see a screen like: + + + +Wok uses PAM to authenticate users so you can log in with the same username +and password that you would use to log in to the machine itself. Once logged in +you will see a screen like: + + + +This shows you the list of running guests including a live screenshot of +the guest session. You can use the action buttons to shutdown the guests +or connect to the display in a new window. + +To create a new guest, click on the "+" button in the upper right corner. +In Kimchi, all guest creation is done through templates. + +You can view or modify templates by clicking on the Templates link in the +top navigation bar. + +The template screen looks like: + + + +From this view, you can change the parameters of a template or create a +new template using the "+" button in the upper right corner. + +To create a template, you need an ISO on your host or using remote one. +If you are willing to use your own ISO, please copy it to out of box storage +pool (default path is: /var/lib/kimchi/isos). + +Known Issues +------------ + +1. When you are using NFS as storage pool, check the nfs export path permission +is configured as: + (1) export path need to be squashed as kvm gid and libvirt uid: + /my_export_path *(all_squash,anongid=<kvm-gid>, anonuid=<libvirt-uid>,rw,sync) + So that root user can create volume with right user/group. + (2) Chown of export path as libvirt user, group as kvm group, + In order to make sure all mapped user can get into the mount point. + +Participating +------------- + +All patches are sent through our mailing list hosted by oVirt. More +information can be found at: + +https://github.com/kimchi-project/kimchi/wiki/Communications + +Patches should be sent using git-send-email to kimchi-devel@ovirt.org. diff --git a/src/wok/plugins/kimchi/docs/kimchi-guest.png b/src/wok/plugins/kimchi/docs/kimchi-guest.png new file mode 100644 index 0000000000000000000000000000000000000000..2ec8fea930b71c0e03a40700d79c4bbb63bf54e6 GIT binary patch literal 192281 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 P00000NkvXXu0mjf{F7R- literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/docs/kimchi-login.png b/src/wok/plugins/kimchi/docs/kimchi-login.png new file mode 100644 index 0000000000000000000000000000000000000000..66387fd70adebc3b20b9520974a127ea7faa52ac GIT binary patch literal 318041 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%0A&`9-9b?c>R2A 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⪼mDSr{tK2+EhOBG_{{`e&G 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 NOI8XjSt(%@^gj?LcDMil literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/docs/kimchi-templates.png b/src/wok/plugins/kimchi/docs/kimchi-templates.png new file mode 100644 index 0000000000000000000000000000000000000000..ca3ba585b02668de97015bdd9ec4af64265592bd GIT binary patch literal 329678 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%0Ad3dx|<q`n;0ZSQ(k06~bLzVbUVbpXVB!PYn z9Frfdx>ffN+&t<;+=Mb>$|BSs>}BgrCXaa^9%Qz)F&)R&yP}{CGE}o=3p0y@$R&&T zB|x7kM2>tT%>1@GGX*R(ZtpjLe}8WuL>Wl23+|#5`231D9Qb3Mda-^3D-ND6J*I9F zAt9b*2(8MNdN%O8@PJ`W6P}S@pA|oyFlLCy9a*WRy($eIvqnJAhs;G_kI5RBZkHTl zv#)oMr%&(6?+@5*;WBo`qsF`{4Vq^&BN7qUoo4W(@V|HLnUYSlW;+Gm&}Umv0|0`I zgN8zV@Cas7G`2Dc^blj7cd$8IPo667Xd)LM{Kf5&IG5`)h=nP3fZhK$fzJ?jw0-*Z z%06F47HeCRw%{q}Q)jzt$5eacvln;Xe!#TOm&fuJh2#-qkJ^`ZCYM2O<=q#358#w3 zu389x$~&b;zDZdg;j($l4(~xZ+~CO+2?gK)40&&FQvs?J%6RqzeBK27xg&-Bux49A zK+is<jtd0HeSmyyu{B{678ecNUcf8#CK{F<W@_jlY!Gqi4ujUXl}GV^Jf^iVokqre zJYye){@9LmSHG+sV>%IddziY2Q!!T9|Ee1wDO1E==MP0z2upQAV??FP8XG5~yl`5v z<kT9)``Ga())dw}IF6beXoj(~E5Yh26X>2@M^;AeII~Q!V$8N#J|zb02ITvQo)JHA z-?$p9BxMHa$hlRmD^TSs@bglY%u4al(UCl|mV2-^UC(mfKV-Q!LFX-9B$6s%AKi0& z@fVNfJxk=(DVaYnt-TF?T+-9Yfi81+oVBf&IS#`9GvhJ?8CY-<5rp)$ZE>f*sFrZp z%;SF18d%_@+G5@O+eW<N&e~9Y^QmVjSd=Plc2kJ#L34%CnSFV^!9`1!V<kgCQs}Ky ztjzy@K+v*Gv#gA-L7D4$$E5XcKZ5ssj}!vR>iEviJ|SQP6UnrXjP5yXn38$Zse&ca z9314tJxaeTjs(PxqJBk%#O%mC64F!O2wc8!ccY`C7HczEnVT062~$r5zvEC9A`qov zl=1k$Q@m?i_g(D3go<Dv9n|gF7`So{RL_T?%33dX=o{kSo?6_QT~66VmsxuaTC<9e zh@;cil22A}e0=)97U2F2fq`W6bb(s}q#kR!_e+LOt9)<<nr1U;J>giL;Luav{bW`m zBR*-5&6wQ^D2qY50n$ZSTAq@`K)wWDoqZ6ZzSL$~%tK1%JQR$&$!IP_!$(Orf0QEp zw1{Sbwf5=R(-gP*qs%Yqw-4w1B$2z0;y84p-P9$-4vl>my?}3!b(-d#ETf@uLEBk@ zDn`=F{7V9B7N1tEvzKj4PEa)FH@3oo6jpfabC9YY?K}ykt;US07tHtas2Jm896fSQ z5U55Y+RFqtpZ!n3szEbqu-Cw5YQt?xx%gKG|Kzzsaqr(CwmH6oWa2vMUK{eA8jv+u zE8Nn%ovO-F3EXnNRFU0Ea1ZwbXN`Yr#m;OVN<`N@a4$pqAfX6cxM|&9%f@m#$8<r- z1@UdTp4zbuUJ<t7MSzx6BB}aeY8&xFg}T1c+zk8fyg#7kpm0Z6O8Mlm<AHuNg$IAl zC0^TVjTS!Wn1M!7itmGKwQ@=TXz9VSY4!0~t*dlAOz(LcBi#uid5tdLDEzX)Q_kHc zG}q*ox>@eBQXydD0(7yQ^b4HS9uZ9AVVO3HN<i>W2GC|G-FEuUqn$Jr$7vMSG4skB zl_Y99jwqKwRjJaBh}Nw+(?;`^y&=EiUrriEQX>S=e7cgon2M;rX=9+SEQ@@tU@HBr zE6PY@V8T8cUOvP6Kr3r0F*X>vfVqQUInFO``rO%w4&N0F@p_pM>nc^@jZ2Y6PwU85 zE}QpYX95%(Hxqt_Cb1uK|69Is3n_8Ra;#T65?JPcn@kZCfd!8<$J7w2R&cI9%1p>u zj79z&jS`e(erl)#PA4l8z0$3N!GE?dz4DLT*c~X8UP4s7k-g9>9J&Qk?_<Ouvn=8q z;Y$8|(YaUB5Pb)yF3PD?Aj0F6=+Ff>!gltT;607(Y&n54OE550WSwu=jYXj%RA}v@ zPvxf+N*sbLwFxANc**^+uCG_5A6fc_Og}KpYV0ER*<GnNH-|K%FK;6Z&H!8Jk63s- zHRXIjFp+PjRS>)E-|Fp-{z-HTfTB&>#)LopNKK}|`+SwlRGI^6mQh1^&<i3OpJ*OE z@Sg7lTfL`X1HI+&l=GkaV{6Lv!-Zlrna9GkP;4(3tHr@>UGK6hXD<QhV?=c;$pE=} zKN(|yNWEky<{Do9L`tHF!i4iMI*HjR3N~%fmy&PxssRWc+ELG>d%J+Pe;X9%o2Zx| z-F$aNR5F*Z5(oKPO!o$-F4Jq%zFc&RHBUqdUEH6HG>aEW!)(B0d7pUO{7$jiN+LdL z#8k>w5tS-k31mpLVhsfJ9GC&M^Gi6wjMJBmg@2!9edQvIb3h8!d7ydR%%2$n#rZ;t zb9uNfGS(%-W74xI&$E?CcgX&Be{c4e%8QXo2mrZtKD@>v>cAkK+)cEuEXjhvpSgco z5ANM6XN#h)C-P5XBYLhWQjxJ-?V_g3)0~t;3Ci`lUWM3p462eFV%Ucowc?$_keM-L z;Axc^-1K?c%${KI7!3b$qN{+E8r|j>>11DLx<oE8(3bKepD(W$VqzfBT5u?;CJBWR zR9E@o1k(TrDcL@J)T~Hcsfbj~@+w@&@QNjA@(|TQ{T#b0Q)CYxN3%F2(gPQuZFqcq zEp&qvDyFeJ_6YdQat&27jLAeAuYPIgK24Y~otMRP>TRVy9;Z&vH(8E9W=HPES)B() zhue(8REkQsIfQ7h_~r!P)PK4n|H>wZfVZ=05YksWcaLhXw@N=^v>gIIo6WQvyktro z*<YGfhiyiG>5nfp3FJXXcfbv7S2_PNDqcGZKn9n@?r;F;bNH6Lv(mk<UiIM#Xwky? zE3;#Zh=L{1t_&%o>L@!+uhW*%DBO18#`C*RekpaW`67DQ3#IFjU$jX)P%Ng7gl173 z{SKE+_uqvhEb#77TQ<1l5Vxd=Lny8I!5g$#ZGjK8D9C5_dmkv2-0WBwlp*4<Kp_#i zftAt4BRJTXA<_+&HR?Tg?U@W*RQ0XvSiN7<(TL2&I)%L%_D=VRmgxacgFq<sR3b0j zW-pyS_af0(kd`Ojwg?Y<;A`@wxc*ovckmqJVK?G0Cs_oaZFH&{#7ONZpGj;M{rf+T zX5kpvaDOsDqugmEJCS%Gc}W0jCK=*cy8pM^80bX^=pXtHv7$`!KVlw{qySLtezU~i zTnu9Rf3V&n{pXgz9gl?{oC{ep@W=EN$8IhyNP11=hS%O}TR~vaw4dTHA1oeRr}nV! zyY1J^nDjrPbiSv}n6A~c!_M24V_Tc(9uszhf!E+cKs?ji{U&-Q7WStQtJEJWOYX4X z%GAjHmJGQf!IT<oy)}hrGm>{;_K;FszB%(<5m{$=IYE7gvphJhHmGW$0@%V_Vl0VK zg|ncOOhyl*%n#Ajx<e^q03+rj<z(ve;5B<T1|r6TdP;7SSlzrLuVZ%H078EluN0LS zmrLWAyR9M_jjA_okJaXI%DZcI9&0gON@3+)=DOTLT#6%I<oM=~mcTTrvNA9ow8&>b zzn4r$wb`&%gjaJ7e;r$QR$#nEj(dq1ZQ@k;dkPro{gf=XpV9kBaM&<fAw73+3p6z{ zD46)pwAa8A<034R4h)|wh=j&-BqqlTud@EntK@D_3QLfLG#-&CNswIu)T}eSU!N zmQv5oYKGU3%xj{T0)FryKS-sMN7VFTE>xRl2)~h6(s|Ya$K;k<o`!zb{_88VvgB-- z^lkLue>8n{RFvQMwMvQ74N^*{q{PtON{4{-&<#VUN_QhYLw8DtbazVE&;!!_KA-P; zfB#Odb)S3hIcJ}}_i?!jM2`U(9TD~9n*N(M?GHe2PY5kS?N@lG>2;&R)HF2qbG~(+ zXLdpE_#DBz(|gv7;O!eCq479X`@<7NR$<i-FCyq)jNHTTLQXZnWXAp1^rd`YYQhYC zLisQH4|5Iqjtf7Nm){2oN=GtS96zWt5_oa-35Ad{co_ETz7z3wC%kFVMZP5CIH4|2 z8s|ob++;FrVD%9yX4l4#HK8-~=_7>x%Ci8BfwuZT(Vp=oWLAzn;zu|fA|P>d+yn}K zB7?M^8Zq(r6hw556$y^A@i(v6Bzbb_PjVvJ6R<_7h`tEV@92WoTJS$_Vh#PSwd{mN z@Ek0>chR1|LWQYRmx@Q;$~mDC{*~)>W>w6SQ0wB^#KMMid%7<FOM{dCVjTJNJray@ zrh8Fqe9b&G=<*r=9rrHh3D?=#c{TM5X<I<ufeiYA4tS*6a#kF+oBb4z!wzkgz~XmO zmo;tJ^E>Poa*kds`0(O7h~8m=Z`QirYe>tG5tZvnSbhc%%|uJY)3T-BI;$QrKTA#- z3QLR?m2>RR83f~-8x7Xe*>xMm&0=9C$B6>k*-{bP%bJ!hYn022Tagd3TrsJLBtllL zC&pmKCZm6K!l__FEUj=-j@vc#H}d1uIuV24V5Vm+!s_crQeH|*OQtM~HtEN1&mb!* zA=qO5dEn+Ph8A_v#TIxS@rl~i=qx+oO`p*qf|Q(G2^N1!#>9hzNnA`R)$Ulv(Ncq- zV9eYtRVA7EEXQXol%wQuQEs$u_9E)oQ%zCHdn;EiT+en?7H*<8^dTx(UKyrVO_l<i z>N}xka<ASKH&ym$xGoO#*2hN9gC(i1@_Ln3z3oSQ051{f`hj^`Xm^5LG1SiXzIID3 zBc`rx&NbXiZj?xWTSY2Vjr%smiY8vWUhEjjvNQ+wA5{5g$;XZJ1I>p1NA_ZUS!*!C zWDcXG+HZzCvFdkyw`6OTZ&9Dxj@of>WW{l(n(~<VTHdH?#s#F0M`!WlLRh7?BKv*= zULxY1QlX8(gjU3rfROFTRUhtlHWJf0KE8~iQ7PIFlWQ_@mL$W0Z^#u!GzO#a01|4L zvlAQhp|ml2jZmuCb<tVqM$a308~#nKK5O-)_@b2R($VjUJer$Wro!&k#Ut)OD|XzU zNP+kdg^;=rWfe|m8c7yQ3;{&y8JMs$)u}(A_=iGY9cZIu%8u=--GNGKaI<kCr%U`F z37kSI>Bfx46fNW!TpV}l704PR&``L&EXp-l*WX67?{Ox;RJDZkJv^q#W7sAv-w+D4 zxcZv!l9ehseMw~lp&GH&Rn?3d$&iuV4xX5#E#V3LNMtcXiA%Ga!l@BQz0LLcr22~U z->$Ce#b&h7Mq?P10cFKcmkBQB#?x6#Zn7<1Q;O^PS4Gapzl^;~?=v$onw2LuOt|k& zP&QivwbsI7uUX5?c*eu?f{De>Y8WMEQ=X}l{<x}8;9>fTLXd6{-juTCQ7=;DHB}dX zFbjouTY>W1Q|~Z4n>+qfF^fN=-7znc(YTlh%c8mL&&Dxn7YR+&a0M=T;<r}e2vhMt zn!L}E2pX+hIVz(KYUf>FY-Dm3u2dtbAu=n6vN6@Glq9VwK9e8W_sK}laV%q4Ezh#p zQH&V4`(-{d$lNNMzHF_#3(~Y}>EQ|)#p~2O#r$PK(*{}a55hDz513lmGCP2oP-jA4 zd)!Z4cxvhb*$Y)Ax;{rT!*dG9$At3O#1}fGBLT@_45oBZx=c(X;h(xhnO3XMdpq#y z908N%arzCc{+Hpuq;`?!_cwrHFQ_#vKnac9lz|zRxePGVs-f*TCq}<ho%%RA!bQn3 zAg3cA+)^oCtNp<uhMcC|dwNWO)Xuh!ED6@B*LhE<={}Z>_mWBwMYd{LnaF=@q+J%@ z5%0@kY~Ap7nG7Nc;!H=aoy15uFOzSiA==iNFvcAh{q-GGv<yVuP~p7I5BcTTKS2+X zA9gs<A+%#7rv)Yj`@w%HaM?F4C%VykJyFxm&L9(n8HA=<lq3s}AQP0N)(!sU-XG(^ zT=Xwsg4O5ZR_Ycvu;8BD6Azq8^kjwi+YSHL3pdd^f>jofCtPb{<jMHnn`2Yx++>Z| zf!{9H(R;B;%{!oyX_?4LN7VQz{gk5%3wmpK3d?phn(A6gsvG#Yn>)r#*Nf@%txUm@ zLUktu!L4=w`ZPX3O5<BZxsTSO?pY|C$yipeK<H}?-D=*`a2Fo^UqY!K>r&z5*m7gG zy^q}jC|b8gSAAgVI}C8-0<Iay#q|w!jHV+osm>+PSn`cNuHGaq?Wxx5P3E)0R%%^9 zah1UTp_Org+lnK`&14Z0g@}<%rd&7Ui$K@Qurr$KB~f@1FfHjaf3VM@h{Pl~Fv63y zCL=r>=#9ZbI6Z~-qK>U{;L_`u;|97o`7})Oq`xsmwnr9f)w*-Sd97B}DT?6DH2WtP zY=l61wpTRcrUYTBh6~VpA4N(vLo(>Xe+Fk2Um$kMSil+--25(m;s`lYGZP82<Y!^Q z-{-8`dZE^~JrqtBaVT0|CekI_xsI|Ik48J0U?Zi8rs()Yvc<ElOFYxqtR5Q%;ZTEi z*&xv75qE-u*K6F2Yag`WG<LA$ayi50{Gr|ZW#f@Sm*l}!i7X{xXSkcnKbxL?+Qb^m z!GZ8E7E*o5D72^!Kp{s&dDuIzFl<EA_73v*EBX+&D8(svZL<)uB{+uY;sDTb>bBI^ zuu#zE!`Q}pbg0v=o5iLh3vt{_B!>^q4^52}b(Y&nJQ;(^+eW0BItdw}TgGyCLBTJ; ze3l1NUP#=+sDKG|o;p9+dzbWz`im1sc<a6;&+d>)S)Ef(qMf+HJDGD<mUjMtbH9Nf zuIn4QD!Sssl{J4TXA^WD!6uzru4NT!PqT;sa$EZY%c-Gok3?IuU%#Al%f<xc-W}nw zs$u&X8RdLrti2zoz(g}oD4Crxyf&(tkGVa`=%AJksU?xO+mt(xEWhM`p@^f5g8xce zkyN%GbfVdCEigh7CF~2BV(oZGj`xqx^1N-AHRKEFV^SR@=>cyaUfgpP<*HH$oNV9V z6V%d>fOx81HU)SfFgfh-5IN-TCx<NE&{>@dSt>3dj5}}$r>k<sQ5*1|9H-(qAv_C$ zxRp?0sB}EIm(MN~UcOu>&5Heq-DXpu<g*)2mpx0eEE$wcT%(w0eXFMrH^hb+O6Pob z?5`afA3R({{N)_5PKQ0+tVqkA>KOb+&%V|n_`WX4NwVptHWT<qn4PsRnjHQ{zl%O1 zSY9;Yz1HkL*0^tv3Sd){ImPC7DBMfZ2HZ6tl%0sRb{;_(tc#e`glY0`ozUhPuU|N! zB>=R4x$?pX5fqw?3_K}%&3T#=xx734FY0#A@0Yt8H%XMd>P%Tsz7M>hK3ON1?xA>k z1j3SQ8|`w}m?!yBp(9=dj~P`j??7!dBA|1{n-3l0xZ+(9v3m|Xpu~VwnJQab15Lx` zy)H*I!V4_G?K>CDDnP!xaTz-!ZvK*ieg^otKkqc$wh`G3FFK7zBfzNr$=X6Wjqi_E zN31`5oe+7QX7%fp7!u1=OzL9w5?;PQF?(0{FUc#vstSI`gle{aY1udLSo$#s_!6!i zjJk(j@u9TvE{hdxR!wgp6uhvPJ<1|`#3W9M&}4KM*BvRv1@}pu#1;_K;;UUe^fpII zvBXD4q$^R2CD$P1zmq<mf~U=+c9pmd;Y~98zG8-aEH98NHO`H><SxsLVB2DZAhEKs z+I$5hzBPw!sdr`0ud`RAwWR?=re>0B^dxPcFJ~gciN|l6MoZ&iwTnc%8`57!j1+je z8y=y}`mjnz;TpU{UowyhP_L}w%Tq|xe^Sj#oYB^5FGAhA+(u$_et4{C8}~>R?7YV@ zV_;R7tXb;c2D!iUV4P-5aK&fNQpF5+HAyG0iP(Tpg20m(i5l4Sg%4T$M-)j@a)Y_B z!fV|~sxsGqj=LjbN`JNj<(HyOal}Q$Ia^RzfA-olf$WuX<b(4xyjep922ErG#Xgn1 zu5la?7-CfG{17~DcJeNKSZb-@B}as*$mfG9+R$?@T;Q?Fo(0e@Z-^H5%PJ8-(>U=D z_iTE{yz#yi_%8yW0YM%x3D5${l{U|u;GHgm2a!Uzc^(4@+iF=0ZVG=Wj{4YUaKoMM z)`CH;DKr4uFb908uNLOqt3x8K6soykp!A1A30Y`-_XGJBIj}W%fiW(hi6Z{tLcXwu zxqK%`+{peFh4Z+-pji;cxwB$g$lRAiyKL+u&TaTiNpF+E3kwJtAL#C-aALQj933GA zp*hD3z1CSY$H^1G8y&vk$P~N5Ig8>P=<^J)^e}hqxqan)Yr+>)K5F@i__FaaV8H*A zbhJjWWhB8YO}rR!$SFw=hO6$zmVQ*W8xK#O4-FbQW*$=+4hzM_na&=CT3@oY1I%dR zI7366od+rNHIGMZJoj-4P3f-ukggD8-f#3-XUo0bH!q4=D)MS;lpQeXr4z+3jJpH2 zXtRRQ{8kABbDHr&k}-Kqe{f^f%M2+eUPMtaKC>F^q2Ck>5tYsyc~wbJvdAZTZD+{F zZ({6YI4#V2_x8T36gQ+obBF#>5i)wjB7Ljl5vCv$w@FAR04@9YQacg<iW1(*Y4xg_ zYkWZ#U)24(4hq=ER`M=$kPIBx8e-5JZ6xRwG#MKkmViwK*%yfE8p;4>NWY|9h+CCj z<ppQytne8@sW1siZz)7<7GA0_S5;HvGUXzZNAe2QZ6Tr#>ByA(q~gM)kn^e~Wla?j z%KdZ-qzS(3B|O61{GXGM{Y;z>UHVwxWGOrCrL6z(4o>nOo9lUFOF$HwN!2I3mXK`| zZwt5*nW6TW*tSw(9m$pedx%CsNp=|*G)j<d<d)ezSBC_o;jZ-bTd>UPO@|ygdB|9; z(`PQG^(v9KBJCnr|J18C<2IxBxUvCc_5FsI5qK4mLH}FzmNk34RG)qPaIXKh%yPu8 ztXC?bv3p+ZAsuL2eC$8L#}{+gZX-$)!+})k;1nCHst6Dr0Q6zFxIB8)xfttRm8HzI z;U*RXNFzE*x<7a$+LN1`A=}6K8w-nb=@!QaK1Fhj4~5zBj%AEG`}D>C`l7l@LIN$y zwbTKsSYb}06rZkT0Q(SD4clk{fiN?M94Z=`HvziySAhZYkaF~%g%ysdE~7wAV>Gt0 z7dH@mm^71AiMRB;Z4eTfDXwFB{7yKbfw_Rxkb?UKB#him3q^ROKRN#qf1oK^-h!uL z`@Kp#L(5N?c6I%z0^v&z?9Rrg{d7t?!{dZl+Kv%g?jbR+w#F&^N3r-ws>dgC0+SjA zUJg;k3I_m)LsQ~5?T@eJD0@{?)g`911uCJDrh>@{(1_6=#~y}#cy-jAYQI<CdyD^y zK^;lo>gsM|M9!5ZCcX$c;9_aR=dF3M?+edzb%78x==>Yd6b~i0Z`463?no~d{$ov^ z*Sl+!m4T*JlKWH)b-{$6anYkrKVzz?gOVHBNn{sC*M%|>^?(*f)w<|lAlKU+qxh5v zRCU3dR|6AInCA=(EY<?#YWpAMgAw{P$inURZ)I=@;!14p-fX=<Vc^duxV?E|*BX6n zjp*GJ>Sh1dQ5lx=$?HH03~}Cp!Z`4e!a1wFDO%9pqWe$avkS%o8>%w<2RnVE;q)hM z5&h*ZmvOK<a;IxGSe(8BX!iBn8robuLQR;QWXB`Po#qD>GYXC8znk!CJ#Vt2L?Bgj zj3U#IIXA00d_i1;xVfhfB}iHSgClkrRY!uz_6_wN^b1A2qi_N4Dx<f`*SC5|9QML^ z%ecMtI#m`aA&o#sivdWwCad|!d%9<87m`E?PSzJB6NSP3u|MY{GlA=^UEq$A4k#Kv zjOkywSu~!Z`z%OAAWb<{1T6B05YT9g{u;ds;Q9Lv<{BF$b!uM0PiURT%8EqDQu@Fi zq~?$V)AA-iGRt3>Js!}t_}9~&eon*Vn+Ib7%kwwd;gDgzY>IuIlb4S37v7Gru3yro zGg3PUPL%moMsRN6%)x&*>bTW1yo2&ix$;5ZQ&~PBWe^wSHTn0)b$#pzTj|zhYq-%s zt=dd<VNfI*LWeMyrxZ=alrJ{q-8?$J6jqB2f(+Hxy@!N94;vewnrzHjSs=|kzc)mK zCv4l;q62w~C$q<e{l~e)B!7ga-BjJ?y0dHIHLG-nsqtiINEEj7SnT9S>M`##U#aoe z^iQZ_C(hN9e>|h*FmtVqx3$i1@pEX;>YxNZ8i`?IoY~{oStuai0=3v=NkYC3;^q`@ zHjke%2IeA?71I5$h@4-CdUPB$%6O4=<(1ASj_lr<{0<t*MAbmOh<q2PwhfC`>pH5c zkyKE?MJs`}GMWZnXTb;a(7so$+(!j0A)@j~IIY6hhr%#+egZSE5t(<(k<>v3awae6 zpADyx7c>IHo%=%mP@J*K0r5&lV0g1OyOtUm#?IXI1?Y=zW+|(E2f`hz9}eV86m!LX zD2V)57$|j_ZZxOH<3Lz!WDDGNYe5tZ_)h)+npto39NU~zGaG5h`t?++wMs9GX{RhR z6|4a3ca>1nK-0R)X%tNeX&7kp)Dwn;2h@iE2D&h;atkC>PGrReeH5zfONX7(fbC76 z65?>-@%=E(W+o7Jr*<r*6lvy2rbER6|5ftrG?}-+oIZ8;`g==@lMzQp-k}fiLp?{L zVSmROsDdePT{SSnRvDcd`Q@Dgn|Ex*<6cSl8E-G*wmQBJOXRhvKaxAc36K9l9=;_c z-uiP-YRvmzCsnX7xn;zx%_{ajHmp$^{WEjgnWWx#@zT;*Ath3yJ!P>s5&kjQgKEVy zg(}@D1axs}9GqhRyaqRR&!KPYvDHedzX*pcJ2cO`2)o1zhl}tpno9pHH$qL}cT@_* zq!iQ$cn=m0`pKU&B-u@fO@*B3cOe4a9QEGCsh!8VJyFg7etgc)Ek;K4EbMN{FDKuD zSz)8*(MsPoP9cUq0(DSSs%X{TYB$NVwpQ8x3(6u*RaMK><mq_l6%lJ8-rdVsJ+}Bx zYr@w<^`DS?Q`<KhF{OC10-knkKZO&SCH+L<C`$fG#|gwIh2p;Jo;UADL*@T+@H31K zYr0VWIZ}`w)X_2@jJdw2Q>K3sFfTKGA6gy!g1TZ~4m})QAi;oPL*oy$BkdZ?H?gt6 z>b3k5MIhJ9veJ5|-R}hF1JD?*3VC!n*j07J`Wk}2M?k9&?QSskPHH)hwp<ydUPp&^ z4>pD8g!cA3Yzep@Dr*7ofB<jvx|$y+-`=ym%6qp_;t<XKO|jU3?#Bvgz<EmvKoD>a z&mto={qHiQmc@_uF6D{30kE8*>?q^Ee0*!<5vUE;0CP810F89Z0Cs9$g(@Jes{?*p zo@Y5U4f@In@5HEo$EY!wB=CN%1Mp>?!fWaS5QJ10TEM*~_Rv-EF_W}e(mOcrUpKYH z&M%L1jOD}zXlKB4J6|4l@g5m@$nUhBIQw|Bn?AGeghL)WKqLF&j4chLX-GnZiY0qF zvii@iSns+#&IvPT;EUT(<npp)&RA(l(W!Dq&f#Q>WgT0JK8Ps??wVqJvVcIft1v^< z&ja^r6T+rVCrK^=$NX>w^LD=UG_Ek`(#)FhY8J5{BJ|{CuM$4s6KdYv=RL5Mh9IM0 zHD(;HThP6ZiC%W1=FplEuvA=+9p2GkPr2Wd_OmZ*?>+e4R4z0i_swWM1}_O28+k%? zEW^in`khG)0le=6UsmmV5u>)XJTorOr6WA<0Gau7Mu<wgFcU4zu~#6RABq=+)#g{s zAxphyM%^c*wcZGc|E_<-jl8QLlHq3RmULhl`CchY&MpT7tl^SZ@--eHRwAoXX1-A` z@RAAHle5Yn%4Mk)!rxQG-O2Erkoip8=i+>6YJ&5_!Nd2cNL6GNZkHiStvL*ats$+^ z?UWZY%bdP5McYDy^X*6dp$+2UqIXdhjzcN6TvA%@@>H7o20SQ6ItoychBrV0^G*bs z(VLF!ObRpVyP06XXsE(aU6=(OGU1^-naTQpTmb$%AKV+RF=wrCAX0t-X1J{FG5xtW znh)ayy4k_=$F*tamOO?#E!8$YJru}eld|JKGJy(^-3NBo`>4!pL%w|Nm3x;Lp?k9D zoYl{{bpPwxCbILs;I+n)HIQVjt29CU8MY*WP4}ht?}!e-D`6$VANt`a%i0LQU$OrH zK(y<R77sXEmYb#{8;u&fRt^OUVq#%j<*C=RTb0ZWLSo6s_;MlsKL5L2AOG(S?8{@{ z*D^G1w9_i6covNqFAOybWSve^LVjY;N#su4w>%g&({tx=3TzsSXK}M|RCFd#$s72( zlY4ml{%fbnoYcOqh!Vl?I1+dai&}rNot;mcjhMAN<M)9dyb^b?U5RfH7vV$_1o<d& zy;k5S?rCU$i5ZL~4m50mDjyr8H+O$e;<KmhKVK*@Dq(Hj6d6AFu3$nsgFyEDiAFP~ zJMKTWk$et*l8&Y+?+^jGv$4Q*FE7~+1*y({%}6w6W?Wj)-Tw%;!QuvOhS~rhih`Br zEOM1DQXIzVeC#Ny1`BR=(K^8-Uzm$A#60tZRw8#~dw;+xBTJ0C9tR%_bQg{F4l!qr zZjtLuP1umf!qay-_*u^NMV+cv{8MC-<M78fNkT?x%tsM_$Fs@rim2s7Ao9#f3cjL> z-$)UhTDQ<vPP!7^(VdA;^Vyl(=yR#aHy8keP<U4ipfD-oY#Om*-!-}~yf^zDQ{cr~ zB`x#P^yPdmJ_FIM9C299QL74lEsPMjRXi|Rfo|~=6)*uHNV<~<u!aO?xA)jC<L*?^ z__CuzV!0G(4EvgZL>eHMbyGa}E+aTss|OUa8A_Br9R#vGVs1fEARWd{a@d(tzS{ny z_l1Y<YlsvoHZZ$bmw?B}IqUn!s9}?M`N3Vrx=!w-#%|8wUN(TwzkwyH4x!BJ;mHn$ zx5>HC#DYVTe*lG}2W9`_RVc`ZB9Rto2Kq$~qO~l^1GWax=f8k{g6hObz01GffN^S7 z-ZQJvqE7+&FH|+*uhI8oZZ*1A&yv{#p>qyxviO+}6BZGyr?Xgdkf0Vh3C=#wkocn| zWzX2lmd_QAy~KTU9vUT1I4(&&FVhmS@2abs`^_fCp?c+G)5KuH=vHOQ*6n{Fk9q6* z_AZGa_vT7jmyx1^Eip>oznC=-M>@Ck#PLb(3nrIq=4u2?=JJFLV+2*ais3K5-cb6S zdsC2;AN?ApE=*caJ`gy%n~;hKu{b*Ya!kwYa0Yr9*SL$gz|_7mp<ch=B#ZFlRAmPJ zvmYFeIT!Ou_OYLIVZ_Q;JSgt#S>$#9$S=FYOp@SL`7t~U$Mw#UCLpG-cry2I#co** znWZ}C=sZ4?==Nngu`S2C|J6n(vnbjp-^N~h=4@qso2N&^>2~(?S29Cc37JKdyTZK+ zCR3Dj%25=VKQuxY%xQc>HO1c4;7s(S4l3|@?j1GXjO$Kpum)8A(7^om7JkUzLLw|M zu;DHthvgYL85g3``S~E7WjeAux-`SnSetQ3GocwDbQE1FB&%N(wuvPaqa<$n-q^yT zz=1uSg1cgz7TvY)13e$IZ-&+Ij&qxf2s(tHvg))8iyo0Slh#-OMfOR2;RgduY?<$r zfk^3oNW&&@!q#pBh){k|K+||!vVpC_QcPOM^*&0iy@x_0eMc#=gT<@(2JtWQ>uUhq zIAtw3eOn!j=$9vIk)A|OtF;3#(>`UrXdvcUrc)LNPj1JD!vL^KT2T$2M=nB&)gujL zff^&w%NJH7xDctqtHy%Gs4c|Ko*Yk@h5dTa3-H83Z<xVZyBYluV@*)!n~#5$GK@Fg zZ$-|`BC83vzG%`dmOMUq^R;8LBls=--OHPn!Q$QFNH*3fGZOOG6Ax`=SsdJMgx}Ld zULv!|Y8;tdrY8Al8HV?oWCx*ePZf2H9nhnVd3MG-jCU%lGiZ&c>Qu*%c9mI9^o27A zs_|Tz+VC>(NEbSO`|X+O_i5WV;Z;v}92$KkQ#xzBB3b<+pz+f`@V7t<5D``t_$k7o z8Wg*HKwGR#@4ubFC3eb@$I8J%hOD7_93J+%^bxg96*DF$n>jSG(=2~5uo@`hG}&~+ zA_+DBS?dn03#&e|jFm}sywi%3d%4r9hkU~d1I#KX<fdh`Mrgp9^E(1K%vy_lVgC>W zuZ&-jMPTTo@t`QjS6u5^y#FJ)9+?8ma@NV3r(EMq;MCfo>ByLR^jU=oNNd}ri`CF{ zyA1~#{hP@oKR4jSYSeQOMLLmXpn@@|iTtX2kCpk(=Tz8nA$2_n%=Fel$luht*8{h- zGJ`if+`XDi<um4qqQXo(>L7T)qp#w9uWkmiw4O$yZxq)aGMIC4bG#~`?{eggK+@aA zYA_xyxZH#eq##-Qiwb_zcnyW<PDRpH{>ZGN#ii>L3%2R=86%G)?UMTS3RiWcYsgOH zT|St+#Z|*#YgrdI+#l@{Pv8(qq0s|9#lqhhs0*V&QmbTiBX2=9d)2G*X%RVJtvH1z zAx<pZl;E2Vqf<2A*^!d>T2;cJ3hq4W7F9ON7T%fjg@IXF)H%>EsXia!J?@b8dXGXn z@P)d<WPZMS=8y+~S=*yDRxc0dSrqMUHTupZf2F2QthRaIH>T^0O(HYO*VCsTN}u<? z9$?&0yD**`^#4qz5EVU+Oow()q2zPpy}715^!*kd7fc?~M&w0_<~?@?f<oOeBF`v# z59OQ3V31Dg3%S*K2?Qk94gc%OnaEasKO(}PPhK}TL{0<ytEDnSc}EdFVP+rpRV45W zX9iM(<FIRwB6t>Tig><`<&H(GY!BrN{j!iPziihlY4()qi;FsXdU~(G{V&(47k*d` z?s=>?5;ipZ_e5&CVK#S;bLSEW4ki`a74O!H*SkdFZ{?ZY-u4DJe!?b%5;s5ps1UY_ zp=%q4!6}l0HtQ)4JU<dZp&_bMEuRHhHbJ4$GjE0e-ms@K_P}va@bkJXTAy!}u<Hwm z!@tTS=tcMx1Y}*-VPK0+K7g=%cIJc$5G>V-FJ79`ODY`@FC8MgJDo&ww`y$LeEQ{k z{!uAF9{S<OXo(!M9*jG_fjA8vH9l@t-jOUqjn&9mCG3LQpNeojPdm9Ifr8KdM_P_! zn`&>wxu%K=f1@G5mkT~eZJ87ankP~&Eq30$cezfbUZN01vLIrLw`_<5$PV95r2T(e zDf#$MA|kw#;^%jqn_|Xx;ri?;-a#}+b$z4<jEdvDqxNzaH8h#43O1AX;bA06h&MkZ z5Seq<^{eA9C!EDd@+`@;ntVh9d7kW6{z9^H<7OK_Hw|FWT1U8viW<YuBh1ZcfP;WN z`qt-gt~?$FjTS74`PzD;`@rh=1R&8-Kj|45E+-_ht!7I!h3_b^jj`4^tIt>$li9w` z?7P-kjFMquVzTu`_Kt7DJ5CE1ZLOW1)!u!worsgAES{X4Y&Q!c5Y>WP(c$cCRO=m< zRQit%zHWI}fJYe7OW8;-9K!AP)b=C*SsEla@}WtEak0RWJViCqT(qY}CFz<pm}k%5 z44QGZVQIzl;p}@IWjH^Lh2>ZFa@}SG@4E_?Xq5^#h{0L}!%pix<^m-bcx+(vxTX69 zzIn|bm<(8dN`D#KUJ0WI+pZ9n0TONzPP4RBi{0<AFN_!HxRV5_8ZITx(&h%!TO$gg zsK*+|AATfddW&Ma%d{5gvKsv!Qh>2ze6gEH4@IOUjxP*ew8g6_2I6?>I(cMs+f!cs zzB51ilQO)s+VWrWG~c5_uIZch;6yL%J|XZ;!8VRAG#4)xKMmMVY~R{_45b~<YJs(V zn7`k47AV(mQX5YBINyyex}1;#BsXpE%^Ko$2}j}QOAU6vfE6w{J3H%5t^V&Dcs@0Y zWm;uAxz*L2b_-SF@qh+(2EHYwhehXv`E$S@;*=DB{oqj$IAn7%@&3oen)FjU7{@kr zkTxO-JaxdR(Q_NYs5tD&Gba9Jz4sioU1WS(T2MK$hORB%fH3_7NJiEh_3oR%t<jW} zuD6%0^t25`=Rw7~UN2kpwQt^XaZYEjI9DkG^)8M`MI6-~{gKs&t)0rhQoM0Z7|v<= zLh1a#q<SF*2ef~72iva7uFPh*4oryVAD4aO!t)F}<F>lbfYeu^Yfd~E3V=qgab~xC z41cvBsZjhPhOM6q2#{W6t=rPgQ}+wW@t&{!UaU@FkCC`B<S*TW9P;iy^dNF(tuNhH zyqF4!o2VY5DL`I17Pzsjeng@jLR4tE&=?WD76{@bEmKCN9a{>mPx;p;D<2>It*xyH zPE%mnZ|NdPi!~HvseJ3MPFDUhEW9sH@%VxgBabXzBF=_l_fV^Kz!h-D(dhpP3l*P7 z0Zs4&L3(H=@hfAjf3li208Y`Z%o7Kbst|8VAW9eMTkK=BQMvr|?bkCq3Q`%FO%+@5 zb%w9+iGpK8;DK%iL#`_aoP^EGq)ORQWvCi4DVAdG=XY|VS3Uh%;E9oJ%O)pMkkDA* zohkJQDdSko<hz0Om7y4w_%@<P^1YSq>mG1-&*<idj58XPiCVoZ^M7uFi@WL3D-uMn zp*U})wd8i714R4z88puSY-g)1iAG^5D_ToAQkUG!G-_8F;ol8y>i8_{_5M2|JF+L= z)}WxIqo;h*$UVv|Kw9g%KP4?z^WWBr4@&S6shpftRaR2EU_=M1lQ#EOd{X9z|9`Ag zu1%LYczI{}6lKYX1g?;+kEC!2TqagU2w967gKT5X((w{7`e2r{iu(p{IB;5>t_Eih ztm{kk%I8vSC)e1m3>U=WoSQDa+R)Yoyd`SCU^%KAj2VqzP$QWJt7#uHA#4v418WlK z+o^)>AW+L_+f%CiHRvQgA=AoE4j0KNfffJ0O>TAlI5{(hpnweznKciYu$!2uKZ9p7 zp+(Aw{0s5Ad7Sc(jII($n#2CnwjyJHr#=Kzi0EmPG;%vRPua-3Gbj+$7&%Kc9n0-s zxLoiGo;e5MGWi1q+vgo%Zn@4z^m(7kn2+#Dr01h*X55UDVQKdM$jC@*P_QNjpl%Q@ z|Cr{)F}UMgqQOi?N~#+<5|Q0I{?Su{TTrmX_x@^B-PQ%AREL#0d)#KN-8X{U?Z5X; zM)v5qc|>8bYF~NAwa@2z!8T*%Bs!k%!Lx__McE4Z8pRsBX;ow|-VHd7b#@NS@DaNe z7xcWe4_5Hc#z%F}#0Wqq(%qo9`#I|e;R49Li*C<Y4DSoHIZ4g_P|J6BcLPMX|DG?C z9TH?J2FU)tZORM2V|gf$td6JDY>^XyN~5gNweTvPKKNwlNY_e_-Q0kIkFB+^B`J^r zC4@Jh3cZ!6Ns{EZ-w6t8m#wRoQuZ%I`S}+V4;EBi{&m)m(5B?!9r19a<vD+?UDN=I zKR1VkMYDLxuP7bb>a>f+k=%?KDesda=atXx8JLxpppd-mV0=7L#r{_j4j!M++SFgu zY(`7u=BO3Jfbv^gY46f8bGC_)C^LXq^nZ)E)~^;;X1UlC9`Yzr)BN8{oA8uFNm84B z4CYvYu2A|viD$f3VXLY<J-l+<Re5T^5-35T(=X!0{)&weI%!|;vza5PribDa#nW(f zRp!OM334z<<O{#Sa9sF19>PuG(;)B1`$VClks+6?kiTk+^Rfu#Mcyd#ql^!QhNDY7 zczx`p=Wsfx>FgZl!vnU;<076N*~3Cy;tM+qQAxxIjkW2NM-S;{WS@EErljH9KeK|} z9x^hFWS+SdS`&t3p-x`wjpv()->ibZi9&l0>xeFoU!R)~rAu<~f8N+zO`MFy+ex?5 z`>w&DO^Vwc!=ywINMlx0VOnS0Qy=mt`u27$2%+ys0MN)<WSUn`CQK^osRGWX5D~L) zMD}g=^T4D0;41C8<oQ=()4okGrv+;tMhDWX588SHj7ps<F+AA%e<lCCXa_vX7_BK& zKkbBdcPk}g*rV5BTrt|bdz{4R)30`SN>Q8Rd5qqznRJN`_~=!9o5o=rN*|SRzW#tq z=k<tDgk_;OF*2fr-5BrHKNhy-`9Qi>>QBt%^^{t%4G|Ad0GWJBiK=VjcRfKw{EYL% zQo3S<AKn|+$Qq;Exp~?-p@#DmGnP|<>@U#65%Y&3Kidpt+bJ24MlEVn82O7$;9O(< z6Dfo9e-0zY<NuvpIET~M`=t1_tJ<d>Sjs2A@+oYOSwQ($f72$2n=8eiAWDxoNxvOu zNmBTDyRT^RfH(5)@i+2NKXa-sxy;izx*XBk-;Lwn&!N6>>y&4Kp+fd;|5_4mBGKnb z`H>EDHuk>A?B{;Gu8UvQOUWR<Xo?E{`*F)DJ9#~?oT_QlFmq7ZyU1omapp+SN7SEM zumkrNVMj9@z_!8boP^w>aFMojfyc-dp8iCRy4C6sY|ZR5dAUqzrFF>UpmfS!Jg(l~ zkzhas;ac!L<z9EmD>h4fxD*NplVD89N8~Z&f@EOmH7q*^&1-2dIcK}}zDh9Jb(oR` z$?Tht6E~fA!Hp2_yjB|j_R=~V8Hrtb830EbxM6%LXzwS#&;}sg^qQyw((`frK~WG8 z?+df~7in2u2pSthA`Dvjm&Z4u34RLNpr$<i-}o5x6+V7X0t~$>{PLgAL423P^LrI! zqf5$2ZZ#*o%7c~+w>=~mPvLJMzC7ID)@cMVe9rLk@tISGefz{?eyke+#uk7|(|kDj za&V8$kFq5j)^Pu!Dg#@=(&y4L7~ff!M!Q*u)!NJJ4%e5;^k?v%>CWQr`K{rI(GK|R zzg0Kw+wjjwB!M}pSOB^t>`-phMyOGMvNZG1Hre*1dSB-fxT7m00dG8u1X=Js2k}~G z7WxagAAe=1H8+Tb@&F>S<tFf-w}#Fyi=2XIv)V<GFmvrD_2R^2R^2=RAM*Z$goGq~ zx(64ByG6WNAnsWQ)TQHn@`Qx-mIVigIcpL5PMBGlwrYVR=;is%$KH}l8cq6h6B84y zZ`u=N)FU#?_|q<hCujx+NoVUU#YVay<Mm(I#{B!RLbLt<bE_!-5;f|_>_=Z9Melax zV*o?_2Pbb~v>EfHgg_r6+X~WrZnGF|H{hcuCW%8=*#e$s@z%zu3hBSB;oe5z&`e4Q znq7fnts11b@!LZrkP|u-gdKRZmo$5WfB^DS5x&qZfZ=|$kn7b}0Yuz#-P(fB2J6*d zih-!M^xGl(lf!Bm@cMtrVzu)%No9re0{bAkH*PBIju9Q1IcAPw3PWEyj3>0)Q?$kX zSgl@fb}C=7-s|$9Ut@&h_1_Nvjt1MsynMx!tL=Sa(U_IgjqXH^(B9Ouh$zy6U{Xex ziFD2%=*iENRxB4x8%<(g2=d)A^W;pSu#Zg28igNHⅅOnbhWduq*EF?|q_xg7h<I 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⪻gYAy<i$*4^-X7~$4F9lRG_zXCwb znrID+%ApASbPNf;305f+WAtA$KjD3gpV9gxmE?tGU<8tm<DjLbrJ*6Hx~cIRm~BzX zQ`qTCuTlHMXq|>;?RY*OVG_gf2-kCt*85Cli3;?!zDBb<D%s*VXf{q8m8yJ7<%T5i z;eJG#K~Yeygfm<d!}X*F8yxG=*0eUDRGAqMwHsH$p!G9+1~jv%YiDPp`<)p>UDIl| zplc+on$md-yVp^QsF~03z8=iBYTNduW~L#vY)24p8xP+dcB!x|<TgJAAyzk)TG# zvdpk`vIX0w%fj&YfRiE?fjiH#+iP%K7e_ChiF7L7ESGtiy@;C!Ub3c{x=C_lr;b*8 z0gO3%3j^Ckv9SFVJT>?~=&d}5UvIb?@0xoxmJXbWs#m~*wo~!wwmVU(<S;og9|pjL z)NGtJ{R_xX?uCIhVm~m$)@EJldAMl)^;k3T0G{l*2TLZL0oz1?eIPT<<K>Z&Xa+%E zJZY**bO-<mdiifEX9~MEX~u(pS9u!Gp;2CSr3%+*r~*an0~7#;qsOcZ)ZQWLNXE=X zSW*`NtYHAF<E=F~%pA40wl+lfxwjHfhMQxOAn{(<lu*IE5<W_wbT6mODV&|6n-|Fu zo1C%{YuJ^I?*m<Dnh9feEgp{t<b={9m2zoa4(F#(C^TfT!p^iRlT$*=wV_Qt)lG{4 zU7I{=c7p_p(kwcbsgoGrc?9qL9yLQyqX{L<;XW|TV5qgS_SDfe9kwD5t0XkLp&3$M z6UTuG3|d5Uy>Z>^xG3S#o=Zx0)L4Sqw|qVykPuzdDy5{60OfU@H)aF1o}bw|o|h!N zfy_{I$@JF?*fL>7;xKj;20macIF%A=g+Un09+g-a@mi&KKwz=Fm%Sd0F^EMYIA+NV z#A6XO-(`pH5tfKF2~A_PIlR#w=(%9JnCIp}{px6uu(90Fyv`G`XyDCQF>n_ieEw!^ zFRa1wQ!YTl8i$9r-hv0W-i(SV<J1KoM$N0%+i4mLZSg6)4QyD(g714+*m)`zkAD+f zpUzgzO`%ElUs;D1#=jV3MrA(X`Xz!QN=)bkMcD`?NZL@7pD7lL4cQCFaZoCi(9+V< z09w@?KuHnL$%wJqDeIo5awAH?lF1}8nM^~!4Pd97j5QM~d(te85<8XO@V*Gvip63> z6koF|YMrZDnsB6?q)*+^H2c6z0zq>)JHr5#c5P=p3&|(5LF^Ai62&?uCA5_7sVkc{ zOC{LWc_YzazZ#WOshg&PZi0E9gL4#?rl~qWWqRR$cIvRk_btJ-I)G{RP^DPB9@YWT z`HQ65_x*<X=KGZLLd`%ZK_v;``XQmx`!^vI6P0^$PUG=-P-{i9!KSKw4m5kFMgzL9 zXpn+)p3mn;%%#c{bsqG()ec-q9_wrP9VFu;GBaVF>OMlAIvcU9;lBgEW#GHDVE|!9 zp+10T49u{c%me_*f#><K%--qTjWL)zYZ6{}?EJcnt(lfN<OobS<*N}zec`-PfttGA z>`zP8-5u)luKgRrQnP)TZ}`C9%)T6%?r~T?@C!VX`z=;JeRthz+p^G^o{lpnd>V7w zk3-ch55GKY_`bKt=i3--*uAVNHF`Pk8R1M!nDoEW_Y4*XYXSO;5s1=8gam*J^a+^4 z{ZTYqqeZ|9tOy!;Z|u>+?@(DA@10{okjsd$UbjlN2*R|PqFU5yGfH+n*XVS(7mfCz z;qMTTYDPgDdy*h&eIl=)|IcW)5*J3U)v8z<X!0{WAA{Ni$?62hLVS&`Yn=|=!+1>u z<T@7N%$sFdNG6jb0+w1IqAqL-x>bUuy=R!|p{+01h{{bhL#SC8&1k8UnGzMw1<9c9 zEpE`neP^ai*SNaiX;x4PKJS~vkHkWq!8GfrCJSN5I3*71h{y3$qX-f<evX+LbqUl= zo7S9ZHj`t-xeCiL_4+wB9B+=FHUbTgAJ?y9#1UjBtXbR}{ky@=o)N|jlNZl}Z`*+H z!j7k5MWXQC8hqbs06>w5jZ(IPxw9q*nHk^rF))-zwN^vKj_(EFGVl?>d2cxy6UViV z>fPV0nK`t;2_Hljh`o}53D<0`Rzs;&LZwm(q9LP2rT5o48A;M!4*GMxjK{KPj81&& zwR5LUyA+GZoq<i+$I(|^56iNUw#H+2+wqu^S%j)v9>aI-;yzwLHm12}9C}#@f`R6q z;WuP3%H{HiPVf7BZI4z95tiMkbuIs$plCFiJ8LzP$z%iR&}eQv9*66?0jXeyfY!I+ zD0-N9D0v9?C{j?UGAG^-A@K3d9KnG<|hY+uiqcp=fa_?q1y8S|~21xVr}l?ox^s zcXxMp*I>cj-QArx&-b0*41bZ#By(;)_ny1EXLl|`E^p;nuy7~)9=s(?#z`~zE|3bG z>X5azi_iaSliNUE_{WTxG=a}j2st!@n}-_FL|m7+M`|QK-Qtq*wT=F2Cv~cmD!$4R z9L66PGxqI$S0F;co!%9h5Ds0=I!+N&y7Fu6@3R-oO693L?Xo$DU*eyGzb~o~n;DMY zPI0O&k1Bo=E0oF!#b&s~hsp&>3fYE0nZ5YQ8%LQT&NlJha!vjO*wV8`Zd_HPyhx`l zXZaMOtcnn35?eUW4)<YwFJ(KT{dmU^v%wxmVvQJt>9_;(HXlBUt9(HN9Qp)$Ev@Ot zBD8dJLh{Q;<+M#tJY}=MSk8qeRyz;)anBQAF(23mBbXwTeCME0G{UAv16jvLuf%0V z#tb4emnrxiaDOXGvYOsd97h$TR8liE<^rEAxG~T_3vepfpY^R;7cK3q;*=J@!RyQH zX&62T=wMCtl<=O|bUVxhl4UVL6C`+AQi=``6C_Xdx|nG%0?><j6n4!ap$1|BcF>ku zDAr(Pw2^+!>G2y{%urEKRm4|!Tbo1BGw$(QgJ`;z&w8DU*Fq-;Rnn_#Y((|XI!qLa zCwF0Rw*^k<rY@6x!xT-GVix5eaoFB=o{^Ax^)J@IUT;&noZm({l?GO*qTORJ6uh)- zWW{sOaS-bN*42=k1~4N}Q5J;kB)-!g?N%!OE2GQJw&G}u00|2kQwMfgD=c4=s#0Ey zr;OSm899da$UGrE?pIkkGvrv@5&d1orAa@$yKJ%<Yn=OL??g(y^(BqzvSl`vQ1`<s zkyT5P2r^Avg6(SG5xDjw5shD4gM06Qzs~sFM7GRNGRSe6L9m?>Os+YUTW##<t;`0e zH}_Lp8*bzM0WG_(LeIi<35Q-4{z0f2dTMC#6Tw-MfWYtO_fb;69d2ss;N!3)G*NAB zNWRCS-_I}{SQCgWBRqt;Jyw)3&)93TMN@(TBb-#^-7hoiS+_IX{oMXw3)dsc&;P>n zPHyCqQ+v=#m<Vj#<QZhDX<=#k-PM%`0>A|bL42LMav#F&y@~znY*z3@d|si5apwj8 zu0_o5g&63)M54QuevX&vq&uQGG!gp4Z*3VwixWnk2IjuyB99@HqUBv6K#Qnl(4bA3 z^1+?5z=jYgP`{KZiZ*p1_URX?TuNkwaA~Qg%9hdd?dVRW<VZbDGOO{t*96i;($kzb z1s#A}lG#YD6VYDVq;}j$qzMQ|f+7aV?EM@=8B#zcU+3}a-3c!Z^F*vAXBQ3;rdZnF z{a#AINsn`~G*&o6=?BhpVc0$vcPwz$<$K~zfDe=rNvk5ngB(X%z9q=?colQ;omf7O z0d*jN@n@)c5A6hx5;22hvYV%EuNc;tWQPtm>mdR!6uM&0$mXC1<>yyctU?rllokS} zfR$eyd8aN_Jj{5=Ct!mmrFi&8ayB2hQx%5ri{6qs)(ch1o#GP7yjVi<f_;PKeAM*2 zL3QKjU7&L|TsJoy&)WN^`O1}lK;jf3oJ%y>^QrmR9@Q*iQsTb+Voe4|i%zc=oFavc ze-Hy>qB6CLAOB5UJxY5o>RW!I)<GDNpS=<MPtgHi?-DenEALyT=izG>6kd~h#*hZm zJH!7pIX4%0w$fw_iHNbVvqKZLDp9dI$FDVKEp2nV+WyQ>LjRS#d#YC-c1!DU{KWLr z&x*edK)vQkJ<4tvbt<u8liD1+h)l&3rDS=-{lA~$HwLU}Qz+OdifIs3rUywF0o=v; z;ZzFLvWB5wyTb6P&0-%p{>)SZWCIKca%eGrujn+8&~)!P1G^5mtU4lOz`Z*qfm{C= z`XbN~{ZxMxXDt9A{f`xy$1!rzQlY&F(K>t`(%7VhM7T4F4CCzIAMzBv#AkdsuNl=N z-*k2gOtLOiiIu7StOCGnN-yS^(bZT)2Wn|XLDYI<)5YMHdoPM_CNvV(EswACz}>n^ zt_CV|dRWyzz2<TYaWZGOn)@0zd=>~e_SLGLbw$iQd6q*$8%R_}eInwWFP8OSAsiCq z-@^!<?++j&4|TXof!AvBpoXH@XRpgD>nku}Vosh=ha`ouCS2wLB}UkeBdHJ}sKbhe zXd%F6?q#YQzTFHwM(!?7fkEWH8*_MmKG^Df5<PM75b%9ql=2JM8RBQkW;sp8sMCy| zk&ywP-`8X{sOpjpuH}5J;qe^IK|o0J9PH^ZXVh)Q)@}s!Jl~zfjPB`Oc}lpUNK#-x z<XnbZy@AQBhW`ySg)m?z)3X_vXnAVTxv3f8pDSTihLQE)S2X5nFj8bF@I*t~z~C_> zA2iVUeZkc&`<xj2)5U%P5PyFG@$H9_rZk*PB^Zf}H#y9d{Un^)9**&3FF~$jmnWn@ zs~Ns9h9F#(k<GDM9uvzsl7A>J85(1@0dYGnm#-5`<wAaN*m}e)Dy^5E$P*{S3Cn?8 z2k_8-73QZPMP_irp-i;lWUA9Ae98_!1I_7t=U}n=M$$OBzX*J@B2N0_dp6h4n9AQ| zIS6rNuufeVuwKXxFe93S&Tts}kGVt`5!$)pg*3UM+$kxP-;_1;?j?SU(XQtS+fn_1 zD8gI_2Z{3tJ{3#YXHl5+`JRTr8sp<_{81+Q;j{ClzmTzK^&4^WRKj;KFyNiN@?h@n z@)D!QM(}x7LdRnuBIIZA+T^{ciI>KZ$#(NO(#1f&G!_u7Yh7bt1s5lPRc$bt7@Auq zG{tEoB(C2H*|qA-CkETyZ(KC-mdA|FsPLZ6eMwiVQ;g77Dms5#V?qQU4d#$lA4})M za@-%YJjZWa<k2e^63a;7Z2KWvGGz-3IQ}wl$kt<5qaiLUi{#LvBbN8$ow>k7OG-Yv z3XC94gl*3zyZs^zp{9NrqbCkwc&X8U&7V1fqexaL3h-cpZikEo8r6hAJ_WnP+9_i} z?nmJrm!W}Hi3)*Kpv+W#x86&^-wJzao!TXUy-xzpx02m148O9L05f+46E5SQpDM1o z$5}-BPShXR6UtgD3DLigtMmS-I(LBtSV6U$LsS}6z;sK>ij-`KpNXG+B*Vlo8`6U? z1sk$<nB!YXM5C4iR`-p8*&p!;Yo-_}81Zz++?|Ss?>Y;miJM$kDWfLrJ+E|{5UFgc zb~G7v+;C7LQ#_FaQ_;*(x0;T;ATQ+PN#&b<rt*g43K+LmUhT0)(-z=~#-B4im+e9@ zW~9Pmlgn6)L`iEx8wFF)p#cKanGBtsh2O7Fy@=|v%W@Xv8uqh`Sc3J}9$+e4j?SO^ z@czj}Gb{au`*h_7ElDg)to}NqnJidCd?_@RlHMDeV$=M7&UI)Jx-({6#3^2%2Fh_i zq?t|!O?^+t4Erpf`51eE6s6QgV-Ep9XEJl<OTjw@OB@<_irvK+0H#wlZL_nt9sm^5 z72>t(bb+l_X^}a0ifBBBe!_?q@n4A&ME<YYC3j49R4|b+x;l1LKg0RURKA_QiW}v} z(%q9xNd(J?H(2PUi9j^?=b$kO3or&q1!<XY{mXvKM4SoTWue?Z40mV0ne&^}f^9y| z(Lyr4Is*v4>b7A&)?kNtVj(zzRI8Udpw#kJx(%m4&SDZf8v<eeJcVr7&bSd0F%Yl| zIDBv;RWySFdp7n3DC8)An0}OOeWUCguZ*7|gMbw(J{cCe^WCA+J1{w7Hd97NKxR_K ztT<LaQd>C7?(nY9T`eVlp3PEC(z?ExMn!n}5I}?<Q!_Vag6G=51Kf3JiGk#hWpIO5 z()wy4+arXAKNS>g_xdc@1pS!|Gpwfqo3;KN_}Vqfv$eakZ@h1a1v$sWKSW8&7HkG~ z6f64%&xs-2VF)Ofvb7x=t`bd!0o6!}uu8;*eElgg54c@(W2gx?ml_sg!&<`xwZhG7 zrbioYI+^;9`%}$6(4y1c8Ov^buM%`5Dw92X^_PX*8PgIoWgl35hQG>?>N$A0lkcDV z`MU|HRpr2<6SOR(7S718>D=Ftc}6KMCp{5%zGligzijCdP|3fh&r=q|gijN_3-3vd ztru6+-Gk{Mck#FH_4azYV+eE&W<SpY`izV5u@bnBnz7J>5apU<^4Di9gyd$&wE|XQ z%AZ|fYsUzRO}iu(r8Rh6=|M77nEu|)W_E5J^hvwUadIWP)!cSeHL9T6YH6s2=#isd zoSo&Wpx7UnTGSR}WLI_Z1(rDU={ZPMB9)YpEtnFKZDs^qLqjKXnZLIHB%nlgNi)n8 z`Po!vZW+~YMAU&gAMx$qu4Xn0IOS1j;+@Kfl%#17Qa6hFrRs!HOo9mia@Q><p`4!C z2@|ZiAa6aBevsxWN$3E&@opc?fuJf9e;!6Aj=^qrIEW9DRN+>iBpCJ+L$$H9E^elF zUv7)C{V`(j&h8G5;q$CQer(MatU3>ry%1@bd1DVdoSmS@?>C7Ed{v|Q*$&dwPX+Gn zPLdF^ZyFTd&YG|e69&$MxXDCa=Ge;7Yfejb{lT5Pwhj{aFEU%HhstYRwp0tuj+4i2 zI0*S;1v|W~9Mm`+4@Qr!+5dB}d12{|?%x0{ex^~igtSgbTyk5N`jeu#;4=}39@1Bn z#c+{?k3eGF{K&pVFO1<->DEbZxo-)5i<$OZFpm_?WT*S1iAeyh0=-sU5+O5<U~tDz zSM!^_yJf2*rW{I?J^{j*+EttGKRqhU^xn7$3R`_v0;3iK1LnPfI?nP|B2;=JAo-K| zUKFaYo7QT7cY4S0r1OOdiL5JdDMAe=2r_9Qy6C0vdP)3;M;?=dsn27V2EfjFLZICC zm7AC^RRS^n)Aj*mKfiqO>?OvCFe_&0$wdAnVVw<<ep}q=#J3Z)WFvVUB>=2(SJ%B3 zWSW#Hq96Yqe5g?tpy|R5TY)4pvUxs>GbVH3*P*2$;8{JqZAGp}@NlG8$NJt$CL_@G z*>;|$O5WgU!z6hI$WShRkOO*J7!2}Qz+y+gqNi6m{(F%yCO=)gEiO*{m+<G)cu^<; zfu)&ijj)`)j!Nt>3vrE%?B2i`0w{HLF4%(hdmUz;+<i$Vv$-ufe`YAIm*+{n#AIpd z;LNm_{8+&TLN&w;nOcNg%`VZnPk%Hc%1>I{z=EW{ihHVCmDgjemN(<o+8JiC(?^_; zu?EP26A;KP{db(aiWU$E-cXg!z$u9Ho4S%?Dpkdlq!8_{y!$@3%$nC%QxN)zgTX0w zW|?dp|00kE{ndy6=<2ORD6C$oES8*_oqlWjuH64q1={RsTx%pmyp(KxW}TcKbT-uz z)Ib~CNjgl}3s!t$gd`1|$}AGA4zpWNJAwaNA36!~+@@@ao_@O<3(jaAy+rE#U12zt zUczhCW5_x$42|2B>3k)KR(a3|<g>h!8$V3R8T=qUGr%g?pAv*fjfhu&wZtevXJeGE z5zDdFS=|3>F^7)*|F2;Y!fL_%h}Zr$Pxfg+;vWIymTNIGt&VIicgJ#hG&>PA7qqv{ zW=SlQL{h_K`W+zwA5Dm<t|H{t%-DknoiKFO+JK)k&xkHa?`KRC_H#`ODfir_KG=-g zf9E$NPQZ(qlV`miv6VnM3a2!llr46*^~P5&*-fvnUts%<YO+H%YRfkXR58C+exD{F zvym#Pw4;LGT4o^-MvuNBB9h$}F+)^oEVlm9wt%HmMwnSCVv|`a9+*W=zSpMgiC*#= z{(w$XYDfuX_QJcMm74QV+Hs`fQPiMd<&(1yZB+y&iEp<{xB=>3Wj5f1WT8N;n>YlU zBAe!WEYVd?qTN{XV)1bn5BF=@P)hUiK6i9<B(oV0A{ZEj`|o(z>pZ~nh2lS@vH96_ zvFdi3YC=>By}QG4X&Cd6>fLW=?|jLVH+*Y6E_Q7)KV7W(4AH&hnK`4WvCnL5Z2a%H zyC}(?w}d8RgWZ4GC5<`@mg_0LANZxM&%|4l9=a*TfgR6NvMWibf{AVIC~W4L%!Ob~ znUH|djp26WuDR3w7P}w^`WB%UC;s;(=kH77Ut*>dFvYLAKQ^(%)L~ZQ+0H*<nyo%% zKZp)1E-J~qtgvp66X3xf!`v@VWuV$G+XY^HrKYsnD~}bTrpWWAVO*I;M)|DDKd2Q_ znL?%8RQhZBG;f?MP3C%?i=o&03(w(fH~A-s>5eExp^4bbroEmNoU;vms49fD-6UHL z^6wY-Y`r9yjnz6?Bm!C5!_JaOSzY%4HxKH4!i~Q}4+9T8ws^0-pgIrqbEhnR^>g5` z#|@hptZ>7@!%Mz-b1>4@>2+sil;q=fmMk|$KurEAQsmAXTE5>{kW}3U5aQ^UmwKvM zcAwuPw|3v&-4SC3K{eVKuQb{~P($#T9OP{;=z_B$Oi*8XsJ?Rp;e8cNnW$)MG|F>C z!tRO4i;)%z=?<y8XN(@iDf}%smkpT8uJhz*u+S+Jz!>$l!H7^5IF<}jGiH4R&S+^W z78@95yv-Mru>Ta)TB}N(qQrw9s)R&%amz;yozjeRm<?Zr;969*Aeni8HWP8o8HTrs z%2ew|ZZ#bHA40}GA@cK~RytAh099%fs{|sr0eTPxqH^}c$)u4}B<w^E7s2uEXgEA5 zbP1-Cfr~P9z=(2?pCl^k(;X))LYitZQOwTIlqR!$y045lVLco<Cc1T`>9pW^V5bU6 zp#*9?w!>-z&OZ~qg<3eYSrh+<bVyJ1OpM|~H$_?Ud(_?rM&Qrb;XuT|R{w*yTq-A` zn3xzuO#^RZ%r1NiDO$iu>*4XSm4rr`<jvx!*xOmda3YRM<ep}_pga42wjJ>BXwO1< z5Xn}9R>gk@-F{7!XAm@7!Z7+I2F#REQjEi&R7il{X75j<zA<?>G{bC&kr>Q@`nROz z*Vf7~NH?9{2Du%5V#mZA5Z5{_ueA6w-S8<D_I1jlK1VpPJ3L!8Y+jm*PTlza2j#}A zE>3Bk#9uPiI{11Jjp!~O>q>s$T6rkB(ysX|ub<j1%%s(d9B!3;oRS^~NbRf~qC7R2 z055+VS>dcJ;G&Ixx_W^?bekFy6uCjc95|}~rv-pb9o{;Sik4<=(X(*rqfC*5g9*J5 zu~{79Cr(fWdhrP#%Shzrq}1Ar5GE*Ge@N3yk2R~+voTe%B*^4wRlo^3-+DlPr=Jm3 zzv(usV=QC~gRGh$7(Zb?km$f(BKCJbM7K3GW61&z$2d?w2%Nx0#5zbgQOWuU66V-K zF;Zl)H%5j`u>S4r>?D%`R)2k{U4*108XnJ<1c$d5xN}AYz%E*IhOoHVWEW_r*7&^- z$I<3hRk2Jukd}K&a1so}e^X8+-u-Wxf`!Ds=eNdMqWm4n;57IVt+**mhE=IMx%t^w zAqD9p0_8)4OcC8i6X!ny#SZ-s3j{(Q-HVo^2}tF`Ime=`+0@CK{8ykN199tyo)(Xm ze_)bHk}~3y?Y91nWP$m8<PagdA%%+al8T^RBvToTrcova{S#1B2%9Ru;{y&)Y|XPo z36z0T#VLA>p^7rlviZlgJkiiUVOjW{L+;s5&<!OW33gy>xwJYUHL?VgGU01!N?;@7 zB=obr+IL`MYtj{oG@TP;y<#l)yGkssZQ=;mh`E0)lMiVq&&I`;MEUYB)e}9sqkP2A z!y)&bTOM0P(eZJ~tPl(&(-C5TK%lYNI%^&?p&*Wn(*>~WhQua)S65fxbg*abc;tE; zJN$1KfDrp=-rq{s(?!J!P(1k|W;6YvSOMS*1Bl+Iz}^18cjU#)TGV(qGc<3bzPH_P zPkO}IH#yrBgSuvXQpi#;bpD8fTP^gXS;-dGSz&7P=1z*!<&jDeb?~K3*ASqJ=AkUb z6k&Ux+giJ<#4|-T_iVP{;$gz5`~{2tc!P1Se3F5a$WfSFe`G5P$a{=TG7Wf%#8F4D z>kI$ARF5Rgy7^g4?wP~vX#uM8gEzo;`3*n#gNa<tLYy+J6!WK$scutMnF}JAK78-j zZ-yfogl=97+T6X}<Ke%MP>K4%Ag1ChDg2Hy%0HV^pmU*BBi&zlCw>7*<=9bLy0}Qx z5rB*5m`aG5q<X&s-0doPQd&rDg_7*3KgF(n8RtxU5NAcmw%rqQA0Ot)S`eII2nLsW z441g6%_zs*-L+Z4Ft8!L@QwP`=&+2w)x3Vo5D=nupl5;~q%T;CWj5U^SEd6ElwvP4 zDz~<)JebH*S40QsmK|)Ng13@6@{lb2edcnsnybX>Em+}<S$!ImsurRWe$dtC;x1Oj z=_*AV{_o!}L7xh0(;I==6pzrdy~NP@iQTqs|Fm=Kjt{@)s3Inu#)r%t4F)>|&3g9J z|NKV4C~8hjFU#DtC(6BISQC_c0G-sxm+b?(Z<9tMC}vck)`ZT6E~g)u-k`<>aBx3& zb&fjll~dJ<?!UkLbfuI~Pp*u`<!&cZv8Y18PDH@69&e&Z!A66(eED^vXnA*YC2e%s zOSR_LlALdpIb8GW4O&c)Tr#%l_C4LBF|A;^1KES_(yF7iBIkKwtro*H`D)bk&KZ8g z#G<(I)?uh$G!if62H7&G0c6=~Wp@)%l_dwG++p$$iS?+};A#uvc($o$OD0CeQTlpK zs84(nR&)$4Rsxb~<kNa8WphO;V~ppM@5GK~PD8sHD1!#bg9a8F(CySSh05mvY<Q4A z0_c<N-w2zUWX6P-OR+VaLkVIAd(KQ*0}^+zr#8MAKV4Nv3Sv3<WE#t5v+E#PLZeQz zVT$;~qrl0I<;sghUkXo4!p~OYiGDV)YARaBo}F|8MtsQ7W86EGtZM-7mjcn&Ad0ib zSE<^k0i&8OTQxOp9Zc`wvm=TU(+)H$d;oQ|O{j|28~xhd+P|N4o`%$EHm;tgqvZru zL~U|3j^#^ru#1+fW!@@q;LaIFv|)aHhktuxN63ddC+lbHnzilEm-(to0DZC*KqI6^ zBIX(DEAg{tleaI8@rt=n6>29MpOvqQrybVr<roA?$}>=)HBx|W=85f96DM*fo?o3N zy~<P5ANg=x7qk7qBdy&3a^>qCJpZfD6_{8}VMd~?e5)ol{eK0k#&@94P9nz$!DPj0 zR%(g$G5gv8L-4b*QO39tKYQ=E<gbJXR&&$u#t|#2uX2%Le$5qoP3>s@;{Ht9BPM&1 z15X(CjhM|xG?|TC`9z!yc7Q$Sia0~+RA&?*J}2WrUuniSO7fz~#F-^zB`p#@rgj6w zixEr<`FQE-SNs(^rO5ET)kBZvzWT8`Rx5~xb?`gpWP@k<b%~Sm@3TB2s5F$R2`1dW zYw?PmJU)$c6)m!!d$rmWkqlC83Dbwg>qY>U^62Nfj-=ZR%(7_8g76@55+@e540%t} zgz@R|a+_UxNv(s4%9efGg82$cqbH5jHk*2zstOLPmlZFJ^Fwp9T)OSeO~0+Jt)kme zcw<($oirhA-5N_XLWGza{KfDdyzrjtPlGaxTEc;!-g|nWAYB6J*}S-Y<Q`P*ZH3)~ zYf+0iGG9}p<UlwDTdY?0CRGR9*oZu27IN##z{DU*Z^}w2)L0-uKj5t<={m~Q_-TqC z^XN1R{0V_|B`CWwCNE-t1v%lXA^K4Kj)83CZHp5NF<3oY(=*P8WypV4*aD?IHt|f; zn8U?mLqpR#fne!wPFO=y1s}T1zVK-|D33e9XcVczTuqc5d=(pCkNvotUFzBKD9~DX zuJi(UA+lU-Das&bXg7Xg)l`BLNUGOy&>|oIhe>ChA1idyt_d*<J_lUjoxrRh=c~@w znR;@U8P!#(K`Cm2oVo}yR2l4{XgGFWgadzUA*F5n@4@4-JA^f%)SWlbq}cuMIYbVk zmJO@R{$LcvIIk{XY@DS|0}I1;157ljt)PD|0q&FIa!;d1mQc~qN)}GMGlNCryA#hg zD=#n>8*-@|FT!Oir~6G9YOH(m6JT)Ao5n-GGWktBk7=;CgHcOf%g|2cW(Anavfv`< zt7?~^PKYccRQb(c1~hux_nIt-zs@C<S3fe(OD6;v)j1>vm=Kelj2(CGQI)k<Kt7x> zy-@n(=v`pD$HJFd3_xsr7Z4-YxIcU50{Jp;7xNxw>?xfb*&GFL^IrXIP54+RzqCNK z2!A@$Yv1K3#EC$VIbp~*hfMi{YE>JH;?AW}BhR`hBO}r|5=fUxI7Z%=$o|ahqjtRm z3X*N~X*>%PdLY;vXnt1sg+5De2bD0rdi;isi(_TgY;*E|<&tQf=aXM0;${EuIW!FR zD~*6diY`i%D#b?hz{gs`gEC%O5RVLaXIV9pZ2^=-K9VO|$En@aDug8jHlhaFl$TVV zKg;o3rJoa0O3K_Ucpy;8GKx~`Yay*1>3mwa=d1DlUaw$TO$R?VKDX?&<e<Be$g3$F zY*Kos3Epr>gc)ZFs<+a$I!tz9W)zWJ`s#12O>glezb$d(cr;COVlecigrAsBKk8W% zyQW22kv5*`%*`~sVP<#Rrq-eOP%fvmoKx)`ed}0J=Zp#9Ry6&~{n?z@<SKDjWAO&? zlWf|2JkkH?;;2>u4B}sj6<P4MwsDpy_sH;B7%5)?q@W}g4t%+Na1zNhwlcf!o@oF; z_9sG_CDg%B(L=nWq6armJ{J&Eruxoz17yIUfmfYP(5HWXF@6OUL(u)A`WbS4*EfJX zaeqN1=AR=A4_YbONb%)56@JwSgN+Bl2~jwHGUn_s?SKp13~$01oJveTtn5a}y4f;! zmz^wFaY2mV*rHR<x0yGqUK+bs&DzDA8w*?#9VzUq*agZ~O-IKWCwkv?Ps%sslW36I ztv3K5cTWYt2Z?D&ekC=$8kxvjhnf^QQ~jg`XJmrG(lsNW^oZQzX|T)<0B+)smnp!h z3n$*%2S;(GlXYHtzG3dy^u2g(1fz|+rdG(04VLj=TFd<4of?HkCZ$=vMujq_sJbN? zX}wWjsVr9p35YL@CN;k|B<AvT*|kmgOW+TEn4ay(P7WKC=(%i?a64|gr_rw0(eGIi zJ#JsJ7l$(Rq`0T~>`gjTC=sCFpQ}DRqNhm1i-P=`5-b}E3>!~}=<SCy5jY_xK^sX- zR@`ZdP&WR3P6zhdRV<$h$v3HgnLY{86aQX{U?;^{EmawVc4LrcYS5?%6lU0D%w`}f zy=csLSefYiBMa7_vSW}k7<DVxQf)OX0Shk0GMN6@m9j#E$+v;o80V9}ZK77tVo6g~ zy45?Wa9@;2Ze&RT?_1bhKY4XwD}0zONJfU)gadk7MO`7=e&KE5OSO<PC#e8WSV2W! z?EXK5a&1#?Q&W{h^9)!9Is@6se!?0@`3L)2>JW!N@zkm<X_?d~ZpX{~<__Bxy&Bj* zLF4u5R>M*&GzEzQW*iM_v6`L+d@7Bgu^W33o4G_>ZAop<<34J^Gh~nV>-_yMLH#Q) z9%nu=G6)FAZOoeKU|)brBbqx_S@DF67yEg~odlv6)nCpJsjOv%j)vB5WGl3KVG4=+ zjQ&$8i!^(hc4bn@PceIq|7Rkh(dY>Foo&;~tW|@tw@f*^R)?NQqUw}4WWcT{KX0!8 zmt*Z8s5_6hWa#9x46Gn>2-p2_;Ucv62~lpjxWl;|TNm<lWW^I#?|q-ILAP(3?n_M@ zDJ*9%6i%yzu5B-HqExsFif2OC7ne!Xf*&=6q}qFLmXmOBBQ02PT5zX9nxpq+jTk6h zefANDe4DByj}8S$kYg4u;wOzj{!xZll}6F7^)iR{UB<<R>bGQ=cV|5a<M^>b7%|9J z17+xG+IY*iGCBY6+mL0nhyg5CeqzzxypWbZlu#5su9q5q4mg@S4eVneHXc1M+s-}u zd3sq0$@Nz3LW_*4mgFzXzxl#pn<HPvk5l)q57XA*B5G3j9bcdN_t8^F4-Mn%vQyLN zHsK4w*HTAW{n2+J?+m+RJq9b90P|51pA3$hlmE`y#c+S{qX#l!1dc}SDw=kziL8ps zmt9^|NZ~YGJ!MZ5jSU4_v{$IA&4w4aa~Zdr$CGlm?o*E^a;(dchwq_l`t9B{yVaHw zjcVNFYUHvXGz;|Add9fb>i2B89rF$1_7F={WH-!BBUSg!6MD-7@;Mk1c+2d~s0#v@ z>S?u%{a@=HQqG$45ZYvJX7wc>68C>Bkq9&<MebK|O}{T<{!G)Iykis@ltHqNIMs0$ z+4j>&;MRt$;8Z)HBp-ISLF-Jz;8%x@*TzMbYen5z6lEaS5<#2#vMd8;PMzgm%Rt1` z`m&EW#m-7BkWeZ*pumx(Xy9Gv!3dW8cFn~OKr`pC>ZEq&KHq{1N#1MT!84agGZtv@ z$;`1L;aUg&f}clU09rPzaBABS!MEpOYtmeHKb6Cf|D!mLfCHwZn?YZ<MDqeOJv0|_ ze^#h{2IZ&>Io>Y2ogZ|aBH6O~yfs*HYjbMLulk^vUKn2Mpk+eAsAMex8m_#felUma zxKZglpb2E4-buuHF;iW7r&f$leNN}&R`*scTRY0?VT~h4@WRxYPP)LF5{zQSLYHK# za3P#{Kn(CxXcDWNgUCCgue>ocQU3bqM&CIv`u-Gy5eG0eFg-oCza0C=;H(wDq<|4P znlmNK5*qQLQXs_myYYKD*L%D3hx7fezQ@~v|DIhe_^I8~ra_A{l}YEIF7*bG+;j8F z(ukiaDNMS}|DM!{FEo%Naj}E~omzn!c@mAn(G4sT+lceAqjsC9!MD+wI9m$mJz9wd z(1;bS6f9ZAp?qflei>1Z?*N^tI$|0+)VM0mEnc9uZCElZp%5S%mD`WAsfiqSzGf&J zkF7a>0QmU2!Z-!-2msdT;F_Y9kHjYE%?mAJk|wkuB3RjAmo&X5JEf$<Ms1T6Gqf_H zs3%HpRAp%!RGEvT2CA0MdNJwumlhoHRc}}lH*ng4TymTGy|w>nRH*&e7K}%TwhD<g z0>IqsDxpblU7zYRs`kK(jQ`%jG921dfsh!4Is!SZ=*o_1O)E|UZ*o|^_+{+`L(LjE zKJ3QTk?W>%lNutJ49l}5p_ymYx5)U>e#ze)<G)L8Rr<6}cC91g$)}$!E}YG5s>sg@ zzFz!F1e>+qUL>X&pZ&d;GH;vcsDbY<<nKa=S1DCJPOwoUWvs1Lrgr%;crboBy>~+e z=7+a-ZGJF_=u->NVzR#;5oq^l6>Xav1nQ=Oao|@*1)E)y&iZhkLd(1!1aN_oxrmLf zf%|jC7neth8%3!C0}t<W)-Yf=C7Hnf`5Dcf6mGeID;7^n8qp%%y>-uvnp*v{iYi=o z&W7#?b^UB2HxOzANq(P9;2Mah<;5h;L$Js7<L-j>m|9$Ny@@2;iDz^DDSUCG8NA`! z3=ZVkFkqZ9u(pgi-4!e{Q`}4&QmarqFgW9WASqY2q=jk0L{i__-&1zyKRd5^-cl&) z>v_k~W+22i$H5~VQ5IS>vUX0(dE$_Zzag?+-L~6U+dX#e0uOJEDRY&~)2)!es*y|) z6jiO@*YjVq3pTz#hq<{ZVJnrWl&HIEc-lwpoqf?|4+k?|PS43UpTPxNyS8}x1_qdg z<L;-ly$ZDZRLZ>!SvIi1zc?sXd3q=UP%7tzgf{Ap!p|o%L7Y<3lKwV3JOYX@7aJyN zP?MGm?w3<9f=kP^3YeGd$QiuD)>WND_IQE~nLr}t6164IYc^LB8>KKww-<OjM+&FT zc<`YUC2G^f^}|I)-R1F#9IgOBNRt{b%h1p#wfhaZUDeu|{=~J}^W(7ND-Q3|^h&!+ zp?I73YN9j0E-G5%qLv=50N=!}MauG)%SMn~WMawL>fVJ<Yj0rF#{Oz3bPf4}k1`<0 z8JUrE;KAFfVVNyd|HY?Ltqep&a25mhDPCW9NmRUng*gO7p?fE(YR0}+*gVs|l20bu zmLKveh@@tyVb<M$e+}cL75(@oX2Kz48OV)<2m1{0C2oUwP1pOa-n+yQ*O6&h16t@C zdrD-M%Eb(A^1<i@b9>lV3tZ(^>EJ&awjp1wCp!<l7UdG|SKl*L!FArhIpI5ab^(PM zlnhVlwyl;NDy`-fNir}tN15r$-dWgNj3Pt#UKsCcngx678iAr^zs!h<GeA1bl8{y- z5o)G$7+9kzS^<$S3gU=HQ!>BIT5v)pDM2#G6_@^J111yxnPMkiS_h0-6Qpr2jSq!& z#Rt>tC(0@K#9p$+?&nA)GX-;tJ5w)Ro6@eybq7_O>WR&+AI1d4!3;>uO}4_hs_EO) z3EzqV4vUbDv2XpHyBUg&%`?p!V7tHvyyMbKPs#0UlC9G#A{;R3WgIYyu`QDCP$U0G z7D?#DZ^Q2+&hxMM;$jNW5P~&ic7u$9hT$wgbb2v;PGurSN)&>b)I39@fXQx{n3I!} zH?(T-`fOL4DTXCUyj+nSr(U%QV5zx&6no!zL-oCEV~J5g^?1Hkf&ls3@KE4o?y{)) z&@VIXE_d`xws9F9Uoz-=Z@j(~ursqYjF2z=NRb;nu=hn1K^We@p#q8*&B#j5YYPar zx}tTRv#Zdvva9rej)lpcCxB!^{@~>7L&BwzqEAz??nv5ve`n5c38qs(U?<N!_${!y zzm?&+%MUdcIaOkFvw5!@v<6L%)vxEj^dv2l1M2A^iSWRhcnHl4VNEI$<P>jO%hlq` zUWt&lx0f2il`-k{(`xupv<3&FPGb2*pM)s*U|qNN4^XHI$Y-bMcsnq6pwt3;llWdb zk~GSs3%dpayaNY7O^=!kTgQQdkcG&{iFDk$X4JEZ>yWs3_7qrg^9j-^5ie6Km^xev zA&biq<doZNfmC)1(D>{bJG_raKtgj|?`gepgiaehii^+}t+nUpLfd;ov`t5&PZz_o zYsqcJX~mVx+cRN8mly;*{LQyWi-j}1Cx(i4Z%>@{qeQ$;FK-EePTRr%Iz36pj4?N2 z$U=`Z@OO!5&%xcmG4c<Y^lZV}zm%?f%=hyzqq3woS@-;}Jr`Z!%0k&d6OKP}i*Y>_ zXVuRZ5iVxw>UusY&^9hE^iHip)yi~<S31RNs0fbKwM)psFP_bMqLsg>q_-*4rV8}d zcCNOCwgZxLa@dW<ehR{462;!bLDoo)!}m{^dLghZ?Q{W)Unwczt>fLttd}GzTW@J^ zYR&V}8J;JF!s-?v)k%oy!OX^Iwoi*cZptgTn5Sngc;lspigxId*9jil3;Wv={XB)= z3mo3Rjvo;-d98{9S9h;Nrfe#_AbF7iz!N$;4r5|r?R6{vbibOj0>jV?HI42>pQZgM zOC{*Ck)-pZT&YgcluuQDjVSSluH|B8gpA9`A+_?{{B{NQ6*{$|#q2-1SB!rm<&T>Z zYLBEy#Vy$k$DV!UW(vJ+c29Yio(?AtTAn4a)%AOLOK2j3CnVOKqjLH33F(jJEWnJk zlxNu1AJhwgI$IZoJC6?EL`L}jM9y#8*`E^Dtf71oC{a;Rh?W1=MM@BXc5j|K<?0er z8@~YQzhjX~cBq%n))8?N4o!JYn~N_AtNzkxG3U$Tj!PUiDW0=>WBdo5tQ8F4UJ(I} zoLY31NBet6GIq%x=tNeZUFCaEx;KosgUdrbUBfA9`;48Z?y^N#mN97&Gu}XqbI>@I zYnv-}nTEbMRJJ=J*H`n*SG`n`Y0=HXsLYhKRrbz4$;GNg_lGnh?@md$K9@oSC)!TL z!EXgGUMdgCqjnAtJ#e-(R90L=iu${+PTkW*JeuoabP<V`k{x|h#U#~thd2+Ub{N5$ zt!K<LEbZeBfrc*Xwl_T$#1cgk*@Q~TsfBed67UxD$H-YNBiak&aX`2|vybVm=;(ev z=JtCy<2hxo$DNPyvjzdLTer-VK?+wA+pQpSr7~&5eIl_r+EW)Hi&Mv!bs8Q$dWVa= zv{{`b+m0VR0t0g=xJ#{fj<#nCH+`g?z3<PuK37}hT{m6tB%L!a^Ku9)O^L+<B<ttw zA|D_cyVosO-Yut4!KfeH0XzLvdR6T}z!m{ZCf)C)HKVsJCX#XzOcM?#E#g6itUhhs z+#`1<o}?D<=D>xDnR}u8L|k`Q?<i$+9TFznUwX}=EiL^M?_1nGi!hp2rz)7^Iv=RG zH2meOZy_%X@Fu~MQpcXBJQ7duq+J8=0cg!_>xC)^((OdJl^p{qSi(STU!nUYarT*` zJC=WA54nF4*8->$OG)Z*t8Uipy1KXK;l7`IYz3_8F0UC)n7QHWfDGNv+12+YrI+PX z8JZr0(bQTlgMG(#dnnIWeZ<$0ax`fLykizB_41Xq_svB*<yqOJdu*yZ7Pe+(d3bq_ z>KrbxNNjk9f=D8`$Mie`Ll1>TUIsA5X5y&sh*4XqD?6T;26Ih?JwCXdtK`_Qwj%Wp zz_|Yag0FrLq_~d(q@6#FFW5xh4!%~tu0P;et{wy^W=8*|{=q_%?jE3yV{kJ}jFa?m z*%xhFCjB%k+wORVOoF)KR<=XcuaxMxuwhW!BK@A_(_a*Iaov*#i_?nM?CeWS8%J%+ zGnC2OXW^NV5h<Il((G!NaV^`&=yQvq3ZgDmw+zN=zdbfZz33Q~w9b2-LbLm|)H*TY z(*lkVdDgwYrT@x-zvx{r4!*KSU3eT2advw{>jcN+Vzn?oRhx5M{#p05e*eNEmr!zk zR(<uz{h)q-)rY*MmX;G|j@Xp>%T=g-P4%4f{xX-JX(F%fD&)bnj4}Pj-OD${{+@_7 zUDfA3FA5k0`sN|uh{m7ZeoxFiK~=u?kvu>vU=kz&Oocz4lks}+^$cF#Nn6#bRAw~k z8MS{Nxv;k!q<v0ZMAoLKGO$XhV2sArsMSnz5?9AZT*CIp^A{wHz<r!QU_$GGHW|gQ zF_2mK>b_1N{B4xdkKq$Qdb#nYg=wMz!#xeC)F_aFQeB|=?-3~tG5*V<>@U$29KyRs zeCiWc;j)d;?p)QkS|U_a8bH0?c=CP)COsd`JYW5uj@oLsS;#In;v@ZUI}Tb0g$C3{ zme4&dgqh=X%W-IkiIj%HM&|>g`m7q&Vo<f(zm-f{u&k#YG202cwom-{-?Om16K&8O z=4Qo=Nm(i<t#&I-L*qP#ytpP^g>2i}x%oGnmb~;U^E+D^9`?BhEzl(92NT-9yCCsd z0iXwW3w6OZHN+;1c6cSqtA4pZGb{_ya;|jNimBH~YSn7ztK#*bb`@(vnf*!M!{e}` zPyfdIBdV^5$@8@H`zD%i7831Xa%$ROlpwR$$%~FQf~LO5kAn4cQ~hP<#B&iN&pTmR zPhGRh_C5xd@tkgzrbh7eHT~M~3FLmTvAt{2y@MuVC~|e>jW&Up+;z{i?semA7A9=C zIeF$1vV(eJO*qRxo`gw^7k-fO`KK1KeYUFI?-FM^6Cr!zR8M$7Ig_%bm58-qOPid_ zmLQgooZ&XIU57hVQQ9v$6Z>3dAaq55DT&>^9w0@|FDzh3rgZ8e*p;}d`?SC@KJIT# z9Lsfp$TM@Cza#eAU%4YHp7r)Yar^Fyhm9Rtk$2Dc_o4?2PE-xewd|?$$+P++&U?*Q zr+^rw1G+&(<%6oLvkRZ3uq1`J6PhvI&Yq^O7kXGsqKT8M0G+6AG`ti(knBPg>$c0H zre2=rnxUm*)a5K;yYmivUtqKxdh~?(QDZ45WfTAylCq>(C{ZiPv1k2R?i6XAzG{(w z?O+*sg4(hvR0p0VE>F4YR~gq3c3uA&s;y7Z!ba=3PRV#il<+30?=|K7Xq4^LJ%?Oo z+u+5=$;N?6Vc-4rXO~yL&bx6}x2s;x;HdMu){Re~fd`Ioxvaf{1zY>ZS<}5M??#tK zxAsoi6FT;dk~904eadA$zl%UQ{pOL(5?bj0(*nq<PsCZP@(Py6Ij5bfwKb;@^%>9T z@N$I*2b?^cunVtGy}x{i^c-XdDvM=5AD5tw<Lc7W7$z%-Yg=0-D%_n0Q@@`3I%Ito z^z!|+Ei-+?tQ7&5V3npb*mp&g`tp@~A(6M(H4-2Zu=gVSSXab{LA49<F}cxBx-zE2 z`LWt88!!4|5Ey)NHUS9AoRSmWgx}<)LgdxUJd!=YqcF5M7VP@y@`^etm;4iOB3j4^ zir~>V<JaFCpYlApc)#L~Pz#)ExXXJxowOvm-n{4Eb2R@(i?~z7d^7&gIf2BINl8j8 zm*JaY=X(M76PIYA&rz3Xf%@`u5Djkg^|9*UpX7{!giN93#lf_;o{M((h^gOFoA4dy zw;5j|DrGh3ID|MrV;bkyrW`O*fTwT>Qi@&5DVc(K2dFU>gl@;_*6yzIRc=Xw?Me-M z_8;<><^ieXYdO}Zka$;}=~Rgz4J{33C5BPjhS_jh_-B9}w0#1p`&K3xJZu-#N_CH} zX-&<`vCN2tPb}zn4BYWreansuExeXB6Y`9Q_q7B}t9Au7Y~%KXG{*ncqG`!yAeK>? z%N}#;^9>$zQGz57er!~9OfS`>V`(><5sGX3*)8;QJJ0F;yS4M(;OBl;C_6UGpg(zC zycPgUms-xVNo84{glkJ`DukWSnJv}d-<!`LsRx~E;<q{t=Xpm~q}LK*pD5=Ocm2q* z5AQRD6`bygFiydDH&%;0bDvV%c=#5Mg5~tEwBgpjd`JW=lQFJ})K90d<O#i|ZFV|? zF<*gSec5{{uM#w?1EvCYf059~_CsnO*xxf@HatioPP{sWq|?P7kVfV9J#l`yjVdw# z_wn(25PERr&Snd$H0I7Ti8N6Rl32TK*pLu~hx<<&N!iCcZh<Jfn%VT-V<cRQDz9!@ zcs5kj$`hiU1?0h*_4Au?(OxAXb-M<>)%E_1^BTv=KmDdAR>}7+@UFWQReC9d)IAfs zWR-O%L>;@{Q6nQv=amb|!k&Q~=j<07YZQ@~L<>Ek+Ox-8xe5meAG{sxU%Q<JU*$x9 z{J;c>LM|#C5=ul$Whzo%l-n<_IS;g6R-Xo502Nh}ye*%klQ#QJ_1ZZ9#rcu$hPG+< zQ&9o`?ubTTMU5O9NePGH4TpshM*%wJ@aC_8hpmX2Gig}|FK(H#*{6lL4#$BDz$CTB zrM3O}X#%FA{xTN1x4}3M(-4&nTS_`L8!5~CgSDuGCv1t};r<nsMv~fEsCp~Td#lGl z@<W$HGur0IX<l<?wdRla7sd)fqdH)u7f+4`GbYGpyEtseQ#=E8$tzQi2;(8vxq|~! zlB(I{?Jt#r6sA;c^6QwXZ8{UNH(h?GZ*V{2x35Sr5$IVk+sxyOVeK~(iL_-a0LHb0 z_Z^z9hu{SuG1>XAs=1J58_Xhg=C5*k2WRS}HMKQ;({HLIRpRY$72ndE14Mjc)b-Q5 zrO6N+!%aOJkDHW`H%Ax4ePA%`)00Q;aSWZh*A3%%9q?1|0~Pt3`^??<3N!`D5bB~i zOPc*=>hR|pR#r9F%wKQ6>LK$yZQg%TiuXGaT`gR1!dJKeCeVFm{=QFFOZt#`QcR3N z>i<ux;75Gg=JcHOcs-h?*Mqm(LSjjVXH8QU7OwkQAfgo6&@TD<-c`&SkZ8!n3v-rD znEn3h&~F=aKWNCz7#fsw)-RM6L)HA<@8n0eXzmW1<Gb_rDf>#Bz-mj24A;obenVWz z$@_jLY(ky}Yz-L#1cAp68|XZ(7;$3s*Vv<LWC;X>tBhshLN)#Sg;V|I6+r{(a)qvW zX#2O<v{$?(x<N#4h*g6}xr(Hp(kdcYdZE@^AV1tRbn>5r^|}M^^ea6dH~o#$UwzDu z#N8@uhEiKXqmio^<?NFsgie__fU(lg?L8?e<|RnC@>aX+!2nzC+f?AwiVLOD_5o_P zmo)FEPb&D@29a$zBUfbmCG0nL0B_G{oMA7SCdBc30NnqDotrDw!~KV?7xrEc_EXoG zuU(tpwp-ZDiq2d+09w-0<)j@~7$MxWRl{?nP2Lp5|M@lxpPJ+L^qBF}8**YgjdV#F zk%FUTgBJFeK;exuO$r<}wqFWm&h}1?y{!3D7PlYigTx*_0PgCGF^wuM`1ckiEl`f& z9j3aX?e*5O(0Z9&+}U}ZCIj#);U?Vt;jzm1h9o|S?oqcfjqT}*ZxD%u;i3cN+gS%{ z5P8QM{E<Z!3Dk`;a!)QfvTQtOs%hS3-{xMlLcSU)fR(@zF*$h${WV5>QTiJNx}0T< zGd32~c=kivQ6gCJ{9B}NOmk3!=|&|D54uC(AU7NYSyDFx0|GkW+?bI~^gjakOrwWk z9xFf3x?gUwxT}a{PyfRg{vci#<mov(vz)(R2HFi9_E*$tl5X#n(Ow<`W!O`YTOeFt z$u_Sp{Y%68=Qt*|V-zewO=BRNY;A`u?YFIGVMFf24E%|rc+%YTfV&1sFE@_SJzT{Y z>K>pV`!Ki2`-|dLP|#2tapN*#!LYjmc*5SzH+*0YewD?EZV<k_>ELPpj(rc%yFX2l zMZ;XQA4IojG*7bDW1VSO8&4kUVa|p7%nO8$lw`);reWJu7GxW+0LDZ}Ufg`I6K~L> z%?XclT3XU5Bssv#!Yk-(irjJMt$b<t#uwZ3`<6~V^OeGsW+HHUH%v#MVf=*w&HVw_ z6FXLnyVQMLud~~!q}TT)Eeq?b4EAeshez<~5D^w^)?FIUQ(D@I&il?s#*#9v=KCfF z>4p`?{Jcff1kk7$#&Z+Brr{pFX}`MjfX!u}>R=+uvHAAz+}uwRGxMQF7mX<9%i|wG zyhj-cI>P;-n3y0?33E-ep1GUF-+awHO+|$3pAr&-Lu<Z60q|&us5}-Jkl5O*p3fu~ z{o#?3(|m%vla6!|itIvM!|QpHjLZYbN`@V5Jr|KtSeU+fXA(3B2wu49aA+dW)UseP z)Dzv2gY_+KbC6p#&*(@I10%D0_%l<ZH6OEnN}r+;CfN|oZY_Cc+$JyETwf;Gp5v#) zP2S&!tZKI|zqYoYX+)6+aT9ldpq&@&FtPX>RM{0-uSdhs(ImwfSKeCuw%1)ro|lV? z3<+_cQ>r4fB8yDkp7%J(RR)qXbH{%?`ow&-B504CL-x-m6F~qbCI^N;OH=C)+t0h~ z!u@QUv7^t;K)F~qY+4$8h9nKhDD8!7kOh&7^w4&6b=TeBKHJ2aP^DwfGTzGIofazn zxXk%~^GF(6?_m@bYU1KCPEdUQ)Y`wzU@;iKYfzc`|9sQ=u;U~E$*koUQ%R2e@hp>~ zo1`+ZlwB&9^4qUE{kMm>)N)J$L2l=NYSNFs)F^~gTk;S@2p`7ZQ2JFOkDL2bU1;q0 z{Qd%<T9X*D*}(Vz1*MUuTT>w8;IzBC$j($YuS%cr+^vb~KOR6ttcvjMhO9{9B3X`R z27b3Saqs5<P_9DF*v;(`k1k1!`T#Ofx8l8?DgPGPA);+-TF|g3dPt;wAbw&iTMa0b zf3fnV0m&aIn2&ssUv#ZeMXZa=UQ^HT6+rXWJ5X4{Gxa=uotel2`;4@p`$~w+)R{8~ za-tD_`VW%nXwo4KV>#_8lwI%ey|H@-e|TSQ4;XVLv>x8bND{&8@EC0GLdWe98FJ^d z3W5ic^!7)d@S#}@nsvysz_CooY~I&`RjbWo(JNu%UnLY+U9B=}v(WcP<-ilsj=Di0 zT0GM6AF-Qe|KzgL%{}(9Z+7?u7pQr-M^6vwux4iD6cpJw*v5X5_utiqPw4J~)mfrl zdv1to12N3Z6w#lV_hOX(>4`IZWA`;n-P-zANF#x;x+{xF;xz;5dso}t<I2>ld~Eke z9t6D>@&ttk?MwP67qJhRyC49~ehwC!Aa~EBy<2@2wV47FD~D1q$kfd$F*FAAX^Tyw zFZ1>2ag~#@Z)a?b$=<^wS%+C{^B{%aJ1BGu!)(8h&Wva^d-lbVdE!tiQV#u(_GbSW zop48aTGlWJ_iu_Ulwq9U6h3GFBz@1A+ygcrqx2jjIEd*|Upl{I>~IW*L{P2CE3(_q zeVly=Z4z?@oo*2F6qon+drV3T{)jso2+ScQGOEEB7UveOFu}^sFUM^)>8uOAL2Wf# z9C)+p=I$@o^u25imS=Q#3AfqloeDp9<MHNz7qzXeZES4pHbSvgI*}qmf7X7%`SYM6 zGb>j-?O4!ma8a}U6M?!uuk_(F<R~7EWr|Np6#(7w=ot;2b?n}V8ILig8+ic!gvJnM z?kMA>9W0Nsu<6~Fke1iAJ9Xb4-K67v<KT8oEvwSWA=*#=e>9zUINR?R_d988by3?_ zThvy2k5;L@Y3v$_k=T2-)l#*Jnh~Q`?Gd83Qq+vtF>8wmHIg90li%}P&voUm{E_SW z+_~@1xz9PT_j%{C7H3k%(dLVdVvcBZ(<Oo;lF_HG+HwptbXhr2P?)UFg4_LGdUP_s zZ4l0kl9r;a-}~_Y4ut2(hUX3xaF=WXnFm`Mppezy#j?REf;H{k>Z2e(aD4JO3e7My z3{&n6k|UXlrY`eB4-Wddd^ZNukV+FBTdS?gl>a|^h$mX3RQ71qzXN~BpW~q(?35F` zBBY=4_v|LGL9Ro9Pv(`Ff&qYjJY6yutFt6FYE4{TYG8X?b^=~1D<MIVDslhw(alxv zk6n3NvQ@(WNu=7s9_W#6+|jlDI#=w^YLFanN#E@p+m0EUqxht6Nuz)7n(!eH2C*6Z zp(2G3)@UE~EVXrWZ|dhc`GCKnR)n(t`+Yz&oSVJ%+bgjP`IpLhbF2S0`P#&h1nr}6 zcA25c1;w=<xt!n5ej(AQx_k9Tsnu(De~Ngw>QCjZ^a+Cg^a)#5(Z{lhd!IcPwU&Q5 zjk)Oa1zOKI2L@&w92|5Ma*Me@Vm4}LH$SA$_*C`~jfwzQCe!87w`y7S%h3fmUXLj~ zMhs#@o9SE0sVL&yR@E3;f71d%9EK0J2xWdtXbcAmfzah%0M1x;7POOl2INs7lv_&^ zJ3*h+flO~k@9kRJ$#DqCq+EC4C~jzhn!ST_EH>5*dI4_RFJ@?Gj~9<3-FQ+uJXF}g zU9|*T{S-#3*Mj_(wI0NoK|S|TrXN=KJ92Jezge|GdIf}3o(bQ{7s?A~z=ry#?<&n2 ztJus?{U?m<m8T-W36|!k1}wt!ntfE)8~6}*DP&|djNRQES$QWrV!1j{-h|p~Ym_5L zg#=g8i8$%uA}Gx~`!YK>w-dNbe!Tk8b7w2{Dfdo5tgemY+=CwPTVZ)mV`INRNs`gp z_G^85Td5<iny)b6Mve{f2Lb)wqm-y*?k1KPA^_65ruH}asWFrHt!tf^q_1~h9hmg_ zh$#<^lTY(5<s#2YBSYe8iEWQExQ=%wLm6CjClfxep2(3{Qf2?PiYz{pm%q;0K?HPW zJ&na^Xx1l@vmHKvU)m4NjiU&5l)n(<6JJi^IB}Pt#g8fqQIE0sh<+m3R=72JpDeUG zX0kkf9vYeCZ9|>%(c|Gth{#^Db;DXqP_<6$g#GDa-oL#yrPZf>19^WN_rqdn9J#B^ z*^mlfUVM>dCU0i2H&+j>u0FP?vBhPG%sxx8%_WgY>PG5yZ_c}OaswNdU7;)NxWG<x zxi8zyP?TM$2@>|3LKI|dUX-5qcb>ib<av3|(+>8*Bj%ZWN_(+I#}Nxk>hYKRipcN~ zmBK>#<BsH{v#n90N@(5Mv38oD$eHM;!tew~{5LPs(QdYJ)UpQj;8Enkqx1Plk|)W2 z)fW<dm9ITe%@daTaq^TBx-}CGo90P5%112XpD~I(z~4s5^kc&Ni=)d8a32U%OC%fY zmyV`aGqOSN`8%?EEBfnOXXwjxdvk=%6fe5gpRK4I4N+V9r80LvukJjuvCSODpUtwv zgcAorp#c~f(s@vBe|sn~=yW54q-v2E)$(~>=!0r=!tUI=@)4KWl>aLJ6_0c1_#v)X zT`^1!o!?SV_P5e5wiTZ~rBFVStO*fv+2VJv{WfP+#EIRe6*Nhvf?fMSh`4zyWcMef zyeht`HvU}+du7A#CbQ{!maK;LHlA<pBaq1Z^IYnoE;FY3F~VGMXH5Ysru@dI;Z^}a z*u8sG6!@p}w{F%0=Rni@&cUyJQY5(q(O|3KS#edlS`05tKFX)|sc)q?KUN69@8Ml5 z57X~#6I`V4m3KodejaV`_o+H>6!wI#QX~A|=khpnn=Ju3Y+*wb?ugO{0$uK&rhN3V z+(BRHZuleK|46fK!n)^yM$Cw162PH<l~FD_9G5+jCk%OMS<Y}k`IOt`RWrXenlFw? z1HI_vJ)%Qo|Fw0=HxWztIpn}y#r<BiM}I#vr`?S~>b03I(}tw+pGa1u5|`bog!e;K zc;7|e!2x_Mgt8NewAU8(WA=O_woaBQoP+04Mj`1y_H>RYOEULz`Wix?X?$P@3Q3>x zZz|H(`F5Vdh*#R$U?IWOQSiK@ZzHuF*(8Gd$^FZ%OaHVkqN^0tfP4-J=#DUx|8Y=x zszl7`L+-&RZ~@x^)Y7Y2(rdoE2S=kZ;SckOSv8YDMUaY>-5l^=)<~@LbsL~<M2t%F zLDtCFnYvNNvsD^c52fAzHjm@|W1V<<N^h}hTJ&@P2saf-b5xxPux$!|qwc}9tvjS> z6$_jveYdP4{7S*LP?XlnV-4Ec>1>a^+=5vUqF)BnZ~PMyWBS*S!!Xa#KX@*H{k92z z^CF1#E6uk#aGdZ>cs{!P1v>uA(@e<2rE5C@t&0|ODdfg>BXEi8398)8HOWjK2)}FG zXfj}A8LxUT)a;5A9DQ*)v0*tUdLU$3WzO|*o^ny72Ry$Tx{R<E6n2IXrM`Uch`Of4 z)1+POBlO^VXv0pp00(@0P~O0tdjvQS9!MkTbu(Gc+g>Me+Tq@Cr56Swrh9-&m6ZtG zMp1a(`<oPEkA0_Yp0<RYK`V8>t8PTmm7^CqZp+W+tg~9#V%MTMUZ*TkY>atBUY03y z$J=`e-9M~UVd#6rFwZ{3imV|4f^v1s!rxvXl|=;vS!Sy#$e3l7%|q0ga6Jn`sNY9O zD0U8b=P6bGcKf@x?ET>>?bsGFC;zJFtrNf%PqV?NZbk05-_e-T7=8hJZshmc7%6q; za9Pzm1<S4m6~PV6PY2U6+Z^16ycdZbNO|?g7FLbbk}+yTP%v_uzb@yd9E$)Bo;MM0 zRUNbW);SR}kOa{#Uv668qa@WL8CV6TL1UMtx&3Ef&d_2Nb0voYa(56Pb@CM#B?0b5 zq{hS_jJGK^my*zt(h#zX2coQW$=}DP>du?Ffv?APvW_kN9!(VC7Wb_W5zzy8gtt|& zIa+iEzB88C^MSHDiu}ofIXYa87Hf$1Q4Ni5V4~QZT8jk6zbqVA!xi|qj5~jkruiWO zp#Wt{^}*&JtY+%IUnijJL8ot6%5PqiE|&hEOrle{RtLKoxfm0Uv0~A%iaUqa?sZl< zTSq;wWwC2Qfu&t3)X@jTy98k<3Mr)8kl!bN&4(VG<z9%A?YmbOE(DJ85@djRjPd;g zo3-D_=D~o2h0{$OVf<-qx796gzkUBI)DGjZhdH9Kv1iumg8N{d6XDL+EWATgb=t;= zm^ecJpt_)-lbkG*`rM(YV5*>3xzI<#?1%M`_NBo4rmIEnlUTg6ONNO{urfl8vNaWX zHH8-33dv0G+#@I=2xeKtjyvm_4fbp4CvLwIJZW$jP^zIHePT0>Hk#H`G04N1S4>f# z5pw=u8tBw`q#(h3h^?=qo!WxF&DNJ~v*1$ya>z?dITQ2YE3%v0ZV6yOmKgw^=tOCy z%wLDztVfnk+p?5M?v24gLp*stK(HS^m`>vV2?XRGPSqJbn)e0%RsFv(H%IyrH?#o! z`Q~r)J8uA~Am^LEX$)_tcID<UzgI}>_+h$q|KH7cp|_mdAgUX-6C<?#Tt4(p```in zmdn_YZ_f@z^IdSokSnh58<lIoiP|3Etw0)8EIwrU{k<zyGgyOzdk>wP0IWAF*K2Pv z4`sn~_!cX=JhF*zIYeky8=D6IK3j9(DTBo3`+vT%gwJDqGBzi0J->OD{`jnQ!|Ka} zYEm7K8-W7^f8+`>B|0#+t!LiJpZ5_bR}+dTd_1hNVKsw2Xy{4(j_sX@*KXE{vHn5p z!{~Z-tm%A&%$a`Lr(zgK>t%pmm12W1Y%<p}nYJRkGThAIzwpk7BPmZQBd;pE^KsbY zg_5jtZhxx!-v5iWM-NI>62dJ5y#FU>qUv$DbCt2e!wJeT$Xz>Vf^d3m|7zVy=L+JU zYZ?F`5(VLX<`7h7D$jdfxUa9-HL<?_zxPa3{_eYao>hAQqX=7-IhEGmMM9-31+~TE z9qH7BKb!kmE<6~qz?Ro@<C*Vin&_(+qPCHO&=Jljhm?|=xS_O;{fsd>uc18sUAdY0 zgcQUzXWA5-j@%*<xobVygzp$qNb?SpQgDiDjdp=h=?nT)M)A8YGy8+T#>iHs^MhXV zzzhL=>Uo1OG{poofJvWtyU~RU^WV=d{m9)AfoL!~GK)4zOfXBM41)n)zAF`1rd)H# zxngI{{-1a8LV-G2Dsn~X6Q%#XA8plsS!MX4x<+b(;*p2GX#f0#;uUp<tsxmsAC~36 zyRc7_9UqC>eVy`Azx5^Gmp`9atdTs44=BtX1#_h7v8#v~0$Cn>rMrG6F4oyMwu13% zd8&oX{Fp_XISF`(pLG84-*(w5?G<!Q<0wqOv~;Ji<B3{LvNIe_mEu^RRgFDHY7w^I z$v`QL>JwUte>WGaLXC>)jV8&ugD77u=G{dLrAo!`w4ZrKOWfn~{PpD*KU3&SqV@Nm z#O|KcjJbG9J^n#7OHR!npkJ%a9E@IT!Q{`*tFKXxTV{lc`GhNJlTKcXYU!jb>;jGe z(YSj<_Nk;L<aOo9zogeF3bk5~uDz^22us?{Xkcm20Pera9H9sIUH*9cr2EUN<yR+( z_G_8a<DM$1ls^a+EI3e(og0qdO^(ia0Oh&+p9Lmi(9x;qcV4ZtsyV+73)7I6QAyX} zVhImO_@rK2PkObQWV&vNjGETGMm5OE-{MI+y!Bd;WM3Q!$;#QNeQl=SW%bTl->$%L zyQZ+70U;B&=?dq<&?bQ2$#M~34g*9t4gQrYxH6pJb+4eHSv$KSy89U~u`X~^#O?sl zr~zaNdJl5etW3367#|9T176seJPjBUu506cPj1l8?l1s69;zD$nN_>$T>7O~dA%p- zxEK7V${bBrYGQweE6(M>ejDURwG=nQTdGIf)7~_(h&gj^s8_61m|kPd|0>}K7h7H7 z7n~Elty}tO<8)_Ci7fuXW6}w;2Hj2GSZK6h36M9fXa$RijI%2A#)0%#A1J}8jG$nx zmhk(A*ss)0d&c<E=7Tf2wt!MTwA*pn#7upsr-{+xj~+s5t0H=VkGE&HcPK~MsAS5` zL}B5ryMOFR6mQll^CJ=4ZQ?s-+C&!ER#j}5Rh4aFUF+yhAAMthZnfm-Zq`lNH>(GQ zbS?VVey&IJ%KC;}ErpNt7;xRw7xp?krp34OEp&E{oM3cvvbdf+ml`GP9v41KxT6yn zI1BOn*DfyFhG#AGP*<F7sW}$<!;BUgGk1NZKC(3*FD=;QQNMT~dvu76549<u3P&*Q z8w(;2yFbA{`b9cJQ4ouuAQC-w&fh+^NB<N!93BjunSnJP`lD@Z*AM#WjqZ#26YhgR z8khhDb_)G=>;$t^c$_K<_u9KA;aD6YLy*<q4!{a6cJ!XTrLj&L-=@tF$t(V=dPpb7 zhYa<6Q#w5t?<V-zirtwo?Ao>?ki=Oz?tR6&zSu}VPcDuNcld9DI>^yCM<Mdd<}dNM zI4JE%?pAk}R*J{g5kv#tcen~cxI+}1eit`+i0#pV`z*qlo=&-6>Y*SsUcz!{joFRu zJC)dAa~54z^&u7`CceeiSMSik599aince{aKsg0zc`#{aR+*Ve3>&g)_6Jb6xKZ`H zHit=0z}(i-r|&Fq{-*7{a6y@zJzi1cmQ8!O<e+s?=-)r+<U8qUM^oXm%T4>#f_)A{ zmp8(0{={?E>1U)pMvyfcsC^!<$Ct3lSpB*-1h2iKqSemVuysG>-rw}WoLw#DyhwpK z5Jw=af)X()_Qh&8MCPluS=2Vm@(-lfO2eD9gQm;sq>=I|1OR;eFQKw1t#4evX0$>0 zQ^N-qX{cN8v*R29^-TGKmKuOX)XKaJ>9Sun2kYe+0m6wKNbwhoNYn#=_J2`|pK5=t z@eL^g%En_IzMruYGZ3x_Yl?!r(Gq6as7-qPYxQ4k_uGxHZjBo4wuQ!JoaAQx(naNQ z)IOg1&zA399ty5ZnNpdi{mHyS%g5<6J%b>{kCI-HkurS}rVo9J@eivqt$6CKn|bir z-9Ovt_voMiHSR{gw`<c*rAo(06^ZnaQuc=|tbn*g$3N$&H4oQ3EHiLHWV0(a_l9yU z16|>--a37D*}q35aJ$aTTFw_i`IGSql?$gIiF?ARJ;bby9muza-j=FGN_tv)cFEJw z6Y;~ef};FbdYSV(9G?WN_=Hu>^mdWSo+J<fwo659>t2^P@16cSIqVTAo7JuUla>dP z`0$?&H@L2$VYr8n+HWoMXWb~dSlEp&L%$UyL3x-e^VCFe-wOAX+th5lTj$drZtgD+ z6qlc5AXlE=p0Z5n>B+Tmkq(tEoWLAIG>VN2jH?K4WvQ8#Rikf<Lmu`Xy=J96{_x%o zYbahMm+Nn^2yRDY>X}aS!&=gba%Wp`Mo(gB<)|E+yq^O7X#sazz$eYXrM0a%6w7P# z|IY#le;DIp&n+bCz^B&jPet}4!{Ykg{SSM3o>J>9%<H^v@kh)^yOM%^)G``-=i35F zR}(y-?Fn?!2*IZjw-)80?pQExs;tS<v_gt9z;nNNx{1Y%b!0Pn#0xXYI?2EQ0L<k- zIL;Ph=(A7&FDLjN&mOwm$QG)zOt!oF^s4ClFlh5VX5(X9XRSLw`R`_r0RN}f!+yz! zoHASsd<?Ss(5zaon$4pecQj6s<}NT^m8J0$X80p7P+x$ktgx*ink`Wh*UJttRloMD zd3?S82X>`oRIv!}{hwwj^+zeUJ`Bd*uogZ+@aUUATLElDFjda)>r`X{Vj*%)gY|#z z)v@1Y`&*wfu{ty>E{gM{^vvvZ^6FA{DeiX5?tcXS7Q?L&SuU(9<rVEXBS)RyN>hZA z4&tNk5n_<yS}iD3{ong~o@wqWB`ez$;VC#B0K%(>1W+z03U&mE>{kDEDX#oT4=@Hm zx!-QuQ%2T1x_!c=$XCVYXbaM(^l@|~gbhxde($(fjWy0z=-FNjL@x&Y{<W<oP~qOt zeXTc{n?7B6W4fKE9Ct%hVYt}Bwq)`r(jb!Xapi%tTTG18mcg2*qC+QLV%}TAATijx zZG<o<0M$=70cn<bC_5bNy+p9xOU$5zl^IzTrQa)k!Vwo2@@po}^nrn~K72uBToVi3 zW2VbJ&!C4Q|5{Z}=zV9F{%i71B2EW-D{>);-mzsCgl&4e)#Gz5X*PqPOBC-E_IB_x zixa3rQIgw@v$mn*6<ngb^DHp3`^8xC15Nf_uEP_Nr*-`&0}{hP%Nvc6_TDvGfh~bS z95cW03(B)MW6U9Op_IPgj@qMs-)A{tu;q4TJ$KJ6uFDBc-OIlQLB4JubZQp6E;m$s zOIQ9<UG?aH|NhFdg*>>3XOTrN4@oS1f^1|-)Nv(9t~E8y+J$y4O$NJFxJ#aY&5HFd zA8Km$Cq9qCG0T{2b~k3QB;@`>Ui#&&{=QYUb2Y13;v+O^7Q!nV(X}48yf$Z=0mDm~ zw<yzW@%`{rTKTm|0#CNe>i@wA&NR!aXh60^R7j`ydrW#JiA0y1Pud8Cz|6sZ#go>~ zx6iXyLnBYF1FIMQYsJ4KN+T#sHgk0A!&j4xrS(ag+Q?divc_IfqWsgJvWfMtZr|o% zvTYe&+2f>M3`fvs(<U$-aAZhFMN3>Us_5S7qiO_ZEt3K-skeGQ2e2E-$*vEOb4QqA zN+V^)FAx_`Ja94?zav?C*=l#N27_z^RzawPC^8fZVMlVSgu?bar4343MpekAcH(D? zDx0`dqtWFcj?1XL1J_0ha`7{n2G!*fme!-uck|iJk5kqL$v$aGvA2X&%a<hF2p}lc z+-o>H9ki-0i;-=`An?tjpC(6Y&_%d$TXuziG#H(g*3$?83z93FZ;MH@(hY9-Tn0`Y zHH?VA`fbr*scN_JCjGT%GyPfo#iF)V#j*C$#N1$qyUM!y+=ZyXQQgs4E`U)Cdi!2& z6Dj~|R!%wV!!c(36OHTkF4Y2>^`rH;14kWrJ$m=~FRH7K&N<&sDFb@R^$Lrr{_?x+ zZ*tRbQ2QmW2hACa$bB1>oeQN{@nE|E&tv`4-lvHmvRs{?^?KLSm;Am{DUn&-H!k7I z2AgxEYTutyHOZq~HPf{F*;&$z-A1LKI9<Qj!r<Hw*65dpO$Dl$j0~4}cfJNr`Tv)i z=MW)a9~c@pcp*Oo6|VpEAl{kqGkohFqxSHy-o1dPAmU<-pCZF@thWYJ(2>HjW3HLB zg4`z3c73qecR1mr><_lGmrcQ4Yos{v^B%V4h!~T?+j$+N+a#OP8UBUXKf1PmcXVie zrrAhK69$+Dbz$;Dr=R2w-#?aX-$QA!uU(<^CQx-oIpqF@7GLPp2$lZA_XOYg8?wxK zcH-j-k{ol3(g$PwyixSjF^mE+?LPuve8BdCmD_rvdKD^n`QmlsQ$~W?Q`nLZ5=Hid zIMv)!ix+u&(QxbFgZo>cm;vC6!6$1u%|Y+cD`A&vajQ?Ru=LXg>{f7@|LUVs1>e{{ zie7t{r||3C@6XBwQ|LUl5-fGAK2?`VV4<D#j{LLhcvte&DT84tRCUPvwzb!wMB4>! z-?z`ov5G}3l<?TXR<?hjPAGAW!0tH1<7Nhk2+C;OyKNgun$MA2@ur}xv#x~t`dsMU z_`H?kiqZiJmS=_LHF+ixyhFQ%%q_|^8tj}wD``2%hM*?d=mG)|a@L*5wGk0MB+Q{G zQ%-~$_s$@7L!qg;6Jd}8wJ*7alF{9{I2s)O{A7;e)P4F?B8#3B6Jts**pNtR>h^+F zn){<d1B2=xNk}TcP(DtYr-kv)JlWo@Z?oc)36B;OwO#FAxOFO4q$t^kp?Q?aB~194 zvbdMLpK@38`sv=~y_a1UU3wpP{F*|C<cwy#(U0agY!l<n-0H`FUmHk|EclE7XX1=f z(gBF^S@YmQ!Us93+{CVoG$<lmfBiG1zURo}BA}My_(Z%t;f<B6y^Y0@MS!)>pn1fM zj|$i#5X=57l&7nDm!fh~n3hCU$DF0j(x&BTIwz^0nah<CY7L*UW8I&4BoXxY{pNi& z5<mERfMZQ56E=N4ZUmX7IO{A3CGodMB3McYy87<_tI-C4Oa5q^552FepUZ}B`20al zZdIAQh24^SFYsv+?!Z>P(+2RSk@H5ZkNbeY(S6D<ktrqV5*I?$wjfjA8EeQBGw+!7 z_}Q)xxMnBka)_Mu{~%Ny|B{LO!%TsSCRbErl*r4zzY-paDMo(r!gISbKzIEg^N!jA zp9Q~`iM>6z7N4}q%m(}W!Q!{p^y?gU8j!w(R4>Yt{Pg(0M^H!l94#m91>y%ay+h zW0;0peWfgdo0#~-d&=md<e(c*f9ofsv-t0f@NyfxP7z7aP(NK@)KCA?U}d%w{fvnt z?fc4^u88#-ew?>8#^%cdXK5(+sjg~@Ung@{<n>>Fj;5caj@&z8S=bS0m@#<%Q0CwR zt=7U5wbZ9USzjH3zYR=SWM$<Rg`eEb_!v;3(P-SOC$IkVXQC!>m%XNq8Q#*~6Gg4J z5H`HN&gf9{rx-gk;Cx@8Q65&v8l3adqvGaLzSb%w3vd#G^hgT!ySjf>nE~d=>jhv$ zunha&V>^Z&XZN2}qGDTb6hH6Nq=`?8_Z}5pm4iOjk8Vx{W#$Sb2iADYg$$353d{@I zL{|iBKcdloxEe~oX#OD5DW%Rh*C{M#p~smu_T@dw@|l>Je9QSLl=OO)K0za6HEU=% z<BOlA6g^aLwMdg8sg+~(r^Pj+3W`i%os)sf)41gy)pASNozg}7%fEMLd<THy4e~ZQ zPy0_T>_8r%WV?vtcX^#n!wW<MwegFpfEHooo-afrljqOJpCrKrJC&X{<K1-EQe@?Q z-gFH)J)=*P^*(%60xF4hGw^zEUaG%Q`+|4x?$tzWDhuH6#v^DY7<cej?K<E5%5T%G zk3w5^&HBoIWs^G%3X95}W%F)oVwB<|9#D&NVl!%_6Nd1ARZY0*?}~96qN&aQbI8#x zwwpnXP6-~;xl5U|^BA2ggD`1l7nK7siOspRq`hL&vi{HR-OS;~%Hb+Tp1XOy0w%?B z^euLR-@kf%E5lkweA@j<c;VYLn)t3*xk9O)r_aZ-=m$`(YFazrgoWolz*!R<o0;|! zVceTu!Oiz8mvLUqWb{2deN~~j5$4MiISu6M>THS|4w~~4`WCMLPWTgi$4Ma2lvlSX zz<bb71D9o>^BC)k*pI_iIl`k_(sA=emEU-FtqQJSC+AaMS49aYn|i%yYxKKa?B8Wt z0^AqH(OSh!Qz>)^?F9))6vkkNq;Wnr8QuScOkUoD&NHq$<z(3A6iF(+cs@L~IA6RG zeF9VB^lTW2i4av}BeoGXSEP*s;y+FJK2(sR2-UcUSLNyd8ZmP^ySRKFJ?sw)x#Y%T z-6b`Faz=l?-VQ5rcyNQ$<JwdD+j@KCZIvU7NRkO6`*~v(qjVF)c8gc-MP_J{^yhay zWDY{b^V8a%(LrU$QUmd9B(1GSXSbJ4#=_Wbk<q-aIGI!QGWj~!az{_-<-ewLaFvb- z?dK;+&5vwX`tTWYk#1kw^6su{WU&RJmn}E;O1XTAqXI^}`F;*}N)aO-d`<xoxdSQ4 zUuRVQ{e^W$nU`n#mnnH7T;mX#Su3lJT6C}XoRH|!TgRH`hJ~arG4I~RfB#;5)=4|R zl@9w!-+U+pFT6e9$~d=ZRBe;>{S9YH&Jc>SLYR*?P}~O6mQE6y$l#PQjGrqf7&RDQ z>lKpdvtS?U_(&X}h>kzJ)$^oKy`t&F>3|z6I5ZhkB4;$5G7zLG-NSvW?Fn|}8iey= zz4PDx<wO#|vu`qRn$pTG#L1c>(g9&VH53x%7J~k?$5b@LrG8se@>p!?x2@8fTw2Sx zTweY+F<;TZuzxgR7dE_B%#)rG7_tK?EOb)bV)Ip2NebL<Q8K<fJ!PpMrB}IZjr?0U z9~gAWcbO1r>yb<oo-*rvwqRx(if0tb$t_@hdINn=KQYvlKoP|b=<O}o7GQ(Fl>iTR z6m}8UOSU$%SZ>QL%;raHV(rr|FDxPlRFoHr=UwYN5yNWjQELc*O<T{7KEz(4W0m`z z8{4h9ah9u~t9}%T!yT>k_39rDx4IFP+5q->t6u4=5C5dJeB*(J=4y&$Jjocscbd?D zeix*C32>%t^<>C5pG@sEu<JKQhOgaeBhO}UwNyXJ=TrW&r$?*_g=fY1@#k)Uwp$Ro zv%m#h1jhF*Gi8V+31OQ<@zIXl?O4B26nimkG`Tc)A!#09F@pfTNPH(N6^?&d7*eu7 zVcnoI_;5D&1%U|R`maK_q|qcwbHpxzk5UBZ`s<$HFS60)CUWf%)A!BNvt6O;DFWyJ zwC;*v<$s#}_jh?ht3szhl*0b<b3|f!j&<5^0B8CQnaSUi@@(m;&ZPOGp;uLYO=jYg zik6zzAp<g2jH=M^alG(et(%WLykA^G{tBi6ePpLg|7lf>4=G}3v(TLt4r|uUu=L0d zTndhY%Iw#M?bF-xA}1+Vz64p?G~&PwWi{TH+>Z>~FF)d@m_7a8TPz1fm928>ynHDM zyY@EXBUWbVKhgo8P*vsXmcc=k=d!(G-Y+gr2bUkOl%dYD%-<DFOTHqF1ejO^80Bc= z9uD0UXfj97?tNur<1PdHYz6$;&2rT)=!vRwo_35mY@P`wPYK@ehMFt>D7Z*tXYF@9 z8?-vNKjF+15~*u#)O(Y&GQJ?&gI9`<89Kk*Z3m^=Y^4=9S2xApxPL|M?tizn9>QK5 zJ>1at(5@=a#^k!`sgI~ns*|%%pPv~Tap5183^kPP+~-gEUV1C#pNK?F;1RbkhjQS` z(<_6&Z>=ib`|q>lR_;+Yxw@S==N`yPP2DrOuxe>#NB(8^<7}s*CFrPxX+-mQe5hu- zSQIbSF>VeyDOhTiPut-L$MLC5t}RA;KsY9*&F#n$c8k;1R2eGMKjx+n9*idtm(3~= zRWMktIq}(xW$R9^uY-HtiF5H9Pv~NLNOxQ)bsqm#tB_TUD3$=tXb3r;5Bc6c=@Ov5 zOu8T*pVcf)_V0HTTNV~-=7yM;8b~&V?`F<bT`$+JnV&pqj|(A<8&5fI;RgddYv5!h zo4KXwy@pcrP#w{>LmMf}8cdH)-j8Yd(#wAn``ai-2rePXoiy7K0z)Jcn;OHxIyhTR zvaMY|;%v^6V>bRk!NTu!$B;72WBgyq(wV<i61hKPYF~OvA>c(hz5m9c>d~1sXjG+a zZQe?LdcOkUuiI}B;NKQuW})0(XjWA$+J2sKwj^WVF3k#Nx(n{h0(BO5Dk2K)+DQc- zHm%jb{d-Ej7YzYS*CC!<CQX1Du(Zm<06>{71T&;^LStqdZpLNXS>{SE>L9dx?m+Dp z$JZ@&8c}rZksBsu)6;O3i-O#3sm9RV%tQ!&YI&z(2Il6s;fSlTl<$}r8(~;BgG|ko zP4qWh8*%U@UtG7nF=6@y>nHz;{H|~?K$lsF`^xYTJ#}bPW`<`i_%vua$|zLlSH0N6 zXiQ!&3ZkuM!Yu$3(L`m{iES6(VSYtVJ4pM^q$6wfhACd$Ii~lhGAZBJsLH&twUttd zu~45zpMN#-1ddssKtL(=T~z7A|D6&udk>aP3&l5`$SM5^`&)J5T{4CU_(tUiEX4-N zc;%~~&;)r_DDCmx>Wl;5W>wg$J;g^^JgdyJEDq8iefv8E1597vcItB#W3EIEKl}Qt zvN&%fZv#HJ))il@lIpk~To5lmWcagWXs7M<qL9h`;)&O#-$t_{)7OS*fAGNKHrrG# zPmvZXBs6k5=pBVq5pF9W+2BJ=VEQ_ZgW6H3_bsZ$mL{!>#&FcvhH(e!38#R3rlKkB zwE@#1vsbtPlY|f(Mh<ZPfM2y`dvyT3<RGXVy_z4X4o4XlKOQMD(JPUtGH3Lc*Q-j` z(JS$l%BGvDNQ;WN(U?6q(!!fs##CNDai$w(UGYhya9}RnVyNd&zhCu+Po0sZLcBVe zynNYyvA2J*_dfga^bTF4mGBf+N=tBr_krFc!A46uvvi#VUXvnci*i#pw?->!sLi;~ z^BEUKltY~{9BoMXG#aBQ-vo(Ig*6+OPMAA4j|E9vv@aP}oC4J5!laeX$-Pu+=U1-` zP;-UlXV`|6iA_%K6aClv==69WQ1r7TkjoC8zdU5BLXa-zfgVW0Ou(#B0oPMm(U6Ih z%o3S$nKtDIM^Ab*PP$B*$>k6a{36DDivTlD;uC%m_6=4e*P+kzM!qcL0xV+)ppp=H z0kG;jDoDW0eMgevVen?fm$?z-$(E(C6l+4`8*QAv2|l|Rn31i|o2|R$hRAj^6{JQQ zSCpX@cMsdGT@<sb{p&AG5G<Gf7%uZW$@87Usyk#zbgO2KBvfAtCd>ft+mV2Jdp*-B zH=S~8WZ1%wNyqbLmyWy{mC9v5?r>|GFLy0Q`2_@3OMdB4i96NpK?ONVT)dNBYu?Hg zBqYDjE}TaHOQcxQ{-7-q(pKMkkN=NK^2R{ov();YRX@!+x^CKw`}r(}rBQ1ApA*?& zoP&l6JCOVlk_kSpYt9a|BF8~Dp0rC_m)iczc~F;RqqTVW^ZCDTQoj)-@Xl+Er2d=+ z1^IVn%6+!N)ejEN><d&B&>-M2fN5H*PV-Bz>$%dP8Jy~yK0RCO8JhpxK7VhkXrlMv zJG^hR=35xA|8wU)jO^@b!IO2;8CrMi$k%62DRAil{gtov{ba1vSMvKXm2t^3*?v|w z>6i@#aUEd)EGboup<>-gI-CA`zi-`}?MIy_y`U@>fjfr#<Os^!1r?@jqr+d#<V#2G zn;?KT)pviOz&a|`-A>O7EWxZxWc@;UReLXJrVxmrOkL*wQ(ZU)lvk$$UBC}lOlkL= zRt9xYW0L>9YT;}EmdrN5%Lt%}##aGj*8cU<%X#GXF&EiM=HA?kr65Jh-sr$$qsV0B zW+>%IS)W=Xe>O)nHLB*q>Eb&3ZSOOPGaR8!NiqHg6f?(Pe><cdWpkDrN5_Hjnn#Uz z3Qv<+gO1noUe4N_Kt@E0LDLhXaMlrv(mQY|>(lP4p=IburrzGQo74{8ItiLR<H1UU zKw1VGPl!ZG!Ox~TmdM#gdw!=VGobvNpI`yXG%afrRek`|bGC=5rP;S{i)L7EUA7gT z1eE`9>g#x3G<*_~I-pLDh!h?liB}EqCNAIjJo>oKN`aI(EB8m)lT)IT?^h6@^8w-7 zTTf<%rx8pF8sAueCBwvG_(sk17SDq#k?9zn>WcjDX?duvSh)5Di%JxS+I7Df+kX+& zt@cdOsBndEe%ctrv?;ZF4HLJWAYWi2<v!1K99bM{xIl5w`1UM|0$OdHK;taFxJR%n zH86HIVDYoWl`Wr6Hu?J=+OEY?pn1h=zwX6`^l-cLFu(6wM#ozu7P3DT-Om!GlJoGH zuICb(_wM9!nX%^E)-<If&K3JA+5k(7FRq<lYLbVIR01d89_QzI*C5f>oh0snn$w7{ zd6$Yu<o{kULa{_&BgpT*Vd`*#{K?C?_)zljzMI5-^>rmm(!WPUL){%EI$l2tjrEg< zNoh00{Q*S2{qGO(9r{*sxU#ON)OJ%y`qk(Ba=R94{sNlcZvV{~Dkd;ocNzAot@}@H z#!FTxBxAPjwLfKUJUZ)8-Y@!BG7zY-(B3}$cJQ+tzu}GO%DA`vAs;+-7Ug?ZNkKUj zgstGsG+25H7hqOpPQ%#Xcja7&lL1((dx<5I+?9N8eb*9{2m(&%$g>9Ana2@WnTfL^ zOf+~B*<nG~=zG-afe)}^9#`$mL>2)bZWHUT<K*hr-22C+9v7{h>N?YXHXHfL#G0V7 zqMK=nshMyEmJAsG>F6ZpE>Ap^Uq)iz3j|OrEh|@S9sc}UpvKB?wl!-#wT}x#MD+;W zr@1V%&iEM>p5GP|K9yB{kRW4PLDwZ4e7L^ZwQQZoa%Y>6q*3^o71I^->(A!d>Rdd< z_a|Xw);drwg-W|<!7v~Tz@*btumAfS@1r~L3@SL+#gdDpWkr(xG&hH}W)naW8PX*r zS+cek!WQK^ZNseIdeM&@n9JHtA9Yb-gwp=UAKleqn>gM219};t9wDCfP*0358cy{| z|0_nx+=#MBy&&hFez2F@e<Prh`{}<ZRE5nD_yn$G8}RgpSbBXw=gTO+Yc3$eH!}`% zZ(A2do<)v^@!-Bb<dYU`>{&sso{6U=0}|LJm`3+;xGFi!E^+NZx+*E$`hMYrx72K) z`8RUh8%;;eWqlP1-i4T=TR^4>>=3Do_%CSg)M@NpH~r|I*o0>PSAS<siaz;?nZ)7F zx6w_*vsGI-T33aPF_8J|=Ua94=8&<m^f=Z25fCUnlb1X4KY4O}nHt(U5KX6WOY8l2 zT46RlR<RU~ZkKj7A*ii!OY@W)W56I~;=>Y$Q2<2mgJhJ*^|$l#nlU_#y?+DPZ*}*r zd8@&W;B$b#q&gXT=%f3F_ivccau??+!1S-~Zc8%zu@0X#XH6Z#CC+dkB9k6)=qKIV zAF+K(4`w-@NPfHdOJ!ef<U%Y0RFNasswTJdFw@?5$fL=sQbnO8CsZ0JnMstW^M3YT z-o5sac)nn}wOiUV_mBxEF=XHW%ML^}2zXq>D8S&Wf4+z2igxclSt9<+nJ;Kc-N(yh z=}K}Y(S)!u_HIuaqvOeMU-vwr$ewOj3KyoZrrk{H=J>Rx+0&z8%<^m2+O9Hg=N_>o zWjSJU=Hjwr@VgI@wA3C^x~s&MUUvfdUIDJ(kW_+D@!y4F<FI32<&SFT<3p8Z`hW|| zK*RTfFzdr}6PCgJQT-2vb?DGf<rPJrljl9(fos)40%qMs$S+g;#k#EbUEf|bNr<)E z)_57p(icUb0Qph9BL9|NQuU4M&tklkZeR7gb4?7|6a5Xbvdh!cp}=`PF#)bYbrEJe zD#)QHO;ddR*Tv&pE1>bL!EcraphiUz=k^dG)xXWew5scwR|}jZ;KpEOifxf3GwmIK zhrrV5QlIwjNDmkayActc*Y6(fulg|k?>S)mJ$BOJN+si<cZpxqOd;FHxw6J11GgV4 zN#EoNHs4=Bmw%y!k{CH8tFKOD$1npIdZr-~dw;{8OSJM{>3WFf?M5{31sYAj+!z<` zM$)1}JRfT!Shr2o!y^SMzFunM@3Q$^=02e^-N@Hhq#<%{4&N*mhx{Q|Cwf7uNASTA zN-Yot?ih1;ep!fM39A-|*2(XFYOoZRk-q*n-FWZfrIzzVrZrrxn8(<HFICHENNule z>+_)YjUs;Q?(B!i+gShIKX>oSi|hY~&1SylW77FKPuKae>ISF%+N;6U`m$n36~7-R zwSwECN7E08mzo^ZdybzasecC_;x0uiv_s6Pn~8({E;2LXkNYKb=O$&ckAJHT4u@mR zpYW3bS)b=9o9zA!ft+;YKDc%wUYeH`)$3r?CJK$M&+Q>4I@}pfc|N4dD6PV#A~7RP z^Y>J_+72L+@o6qQZ$|pV+V<{~;#mHmU-I{Bq>Rz$OA#KOO?eY|2~IwOe_f&D)~`m* zT~yB;rRyGSbL74h8YVq`S&JBv(hIPRRoGS6=dQ8?ee34D>`O*lGx+H7KCx*H15EU4 zlX04UXOrnvQ8tS$A$oC^CVX6S6>C-;w^0qGS0WNGG^>vm1vK+sUD@|v#`t|-WV7%O zjV!WkFN0|!G3xuOgFdngGk-@RxTF%dhF1CT&G<QdxkeA=*SvMs&@b>BCi8sA?c>-E zzn=yKVqjw+DO~{H!5O}qW1d=9ZP#3R04~_8)AZX+c4Va`_+balM%?{jvi{}@{h{TG zzwcRS+uy(2Fb~1)?RiN5-fY>If+hNs56_fY=mY(+gN;4mhd%-kq;a>?P&mu^B6TAR z9BtYvQ@u02WH@DMq5v9o165R<hLx<?+eIzT~#7diwjFB}?o`Vp)>{{IPv{2_?Q$ zJ9?0P#qXN>oT>Cr(n+M&xmN#|6_$2M%E9_+81<PNTa=5qS!<*v2$?(P^|QvxqT0>8 z40AHd0#j_pkIm73cw4R|SMk=%)9s<V*zEfp)j#&n3sF>?HzPTd7k6*>_@i(EG-s7@ z3mo{SiQj+fyzjfS(O#pg#RZ|Ra(ns0)CA&LK8^?1ne@I^iHh-fHW2u|sG6~l_H+N5 zw^6D6S6BPYPup_TiPxE$MgKnwFgEWk`44a1Qr)vA&rB;RYx?k52~CSytF^3ZplEr_ zZ+K*XgISwka*Y0kwumM~G32U92Ru!SE%yq@&QvSZm4quO@4ty!Yc5f}0TUfxd6xaM zbkM!Op|A4#Q8q7QioOmN!%qV4>l?EKpRruuX-zEwcISzwT3e5CDF9Z`${WXTYTWzo zHEasTeh%BZCi08YEwq7|eLpvc#hl^yuFhIBFtz9G?07EC^g>(9@thM)k>@sz1X1iv z&7~zNuBGGL*iMvSnVr~IZZ24ER^cX1&$_Ay@}&d{;SA#{bF)|D;5x%XN@4_<3F{aO zk~b-SY$nJk#ZZ_<eV7Pe4J=OE!S|`<C8N*tu^|-&7{8J<fgS%jw?;Qs>$BHf3+yhJ zo3HIo4_sl2(^F272CW$?;|lv>KQPmY<s=zAr4MpU&d4=}M40Wj;p;5>E$7-pOs3XA z$A@|3*C0z1y;2FfnvT+$rSsQ41K#9b69ZTG`ck&M3ypod7Vbt)RA9u}6aN?sJfX&J z2IgwEMbYh(N)243V2a;-A!}RLyTi;W>TJpj%3j*B1e+K3gF$53v^ZR2`GP^kG|<b; zv-321Z@4_<9F6D*t}MlP6}c6Ex5U}+Be!VuYWHU#8a7qHmvOynk*xFa8imy%Rn-`9 zM9@hDP{Ix0B0tjiek4<P(nCfPI@)0PimY!n0@N!M<ihq~Ls=Ktw-5Hg*!2TpJ*v>T zc0%1!I5s>Xl+ToHVT?4BJCPT@29Qdh!H+_@%9|HaON~(DNKL!Ti#%*tU;!n0K1g6V zo^$7NiS(g_{X+}CHt|WE;3NE~rbWY#{cVLv`~wJG4R*0<X{>6%I7#tTk9@Mr?<yYg zY%5#puAk&>0d(s}`!PiBBnL2%_Vc+vVdB5EKUW62^3Wm?=~rbXxG#jRcbk4+J!0{i zL)jBP`^iT2*7qewL`+NGr6skaD|*UZcH3WEy{1APN*W7(n$~~xwm)VxdMl;zMNtk4 zQz+?=ioR~MgxMW`z9#=~Hr0INpgy(hPy7284x#HFK-)}i=YYv03=*gr3Ir&npDSG? zE)VGQWpP{p6aw5+y7OJQUJVT6cRTqbM})HSQXgtoKUdHTXgl|{<zrg-XSp6E7u84m z%(;LiKHqonj3ueAKi*HrWWKF53@N_w>q;Pu^Wj7a)ZJG}wbHiH&1}k22agsG_c_Sc z-?g18nl>`gF*8HCNRBV@d17!xm8lEUIr$^!_J8MVE#zMnA*8iWoJ!AUirF5(LRPi# zeKUBdd#HTGo}3bKl111f>_^}d`Lzs{ZzE!Kn{D|t8c`t;ezqivALWyPDKw7vX9P4F zzbdsoskRL&Dum{B6wEBy>|mEq%LDAlk8ChXW&7d#Q2EQ%z{!@g4qH-&T?I<fbT2c( zA9u#rVoOfBIO`Y13_>qoT@ubnEk~;s_}Mbhap(C4JbQ$<<!Dc3Cr{;PRfP;l-rKEu zW4(Uq@^4FvLXwL&q+oM}O#fX)Sjs%`7)lhy)}2ZvOqs)_EecVlRkjo7+z{DOAYcOH zmtefo6VQSw>1gKc0zM=;1zT~2djUYDGm_;EQ<b8oRi=`xNs=eWkaqG#e~U!&S!v#6 zoM@O9=}}~{j0!V$cvRcMBfcSg?>6ksA}S`sqbzchrTyQ6oUmtD5k<yjI70xr5ezWc z<q&{ELR$6trWE<CCz(^h2E~^_sXB~G)NJ?mC%O^`Yw$yMN%)1PT-3?PWr@KK2*1b` zZjls@vvRY&G^`;{V9RBo<)(t!$dZ=eHAfp8*i7X4fnW=MPX!x!e)w|nY;GdNXRG4u zz)q={5>6EMFXJvwVe>6vkP?Zl^zq{_OQEEcxzbTL@8C)ec-i1jpS$a2jg#ej7;=*+ zW+;J;RfNrLdb3=H{&DZoz)Sgwn7{K`48}ovSH;6W-^5WlRGI6n9sD$WE<QWZLd_It z#S>=~8YLBFtwGRQE(l3~&k22+?Xw1sSL@_|4^F}43Q%=dK0lCXU5Y|qcX&QsX{`3e zD46N(1gf4^6zl%R*FiG|z;x*W9DM!2p(+}FN91FmdF(26z~@~*O8NG&iMkd9Xs%fE zkow=rNtRy1p><I8)={vUBmDYi=vh4C3Fh?pr;ol(VQ;pfbnr2#1yGiUMBhzfn}Mnf zxrL?+5#{q)q019%j`Ef@Ggd>BUduu3Wq13dGb8qaaKLAk6F{>;rTAuL8Hbn&OS?gi z)GFuOfKPO<$t)36z^i3m+h7O6mBXOBft2Uf85xF-(?lGBj$%*^^(u^7j8zSm5bVGa zWbtgBQa=qZT6;8F0k?MRc;n(j3MZ4?J5iO9wn%0C4~>kavB*$dOFE;gbX$qSNdNJ6 z-6!P;lCaH$Hw;(hhfgK?ogVVEUsMG8hx=F~+y2F~t|j3wFV+;Y&9RokkFptRFd^jI z?dQ0R<Jqig<#5vX06s^YO-IogTGM|IWwIk#UOvU@CJ8leEFXLei$C`m`UEVjD{pt) znG`IaR&W!dnuAq0lut^*Xr)+|Ch^#pQVRXYf3m89sS0QRreq{T*MngyOW(|OMoOiZ zbc8MX{Z?MswNg$ju^NY+P2HNbs%kKPRguOy=dUVKU1*x9YQ#lZ3`dDQBKeECWi`To zWuPNKCHUpO4Vw$8TMnPDGxA7Bj}pluBXQU1=94hZrAXHR9E3b1TH|V#yxD_oS(Gh= z_gl1_FDbN0;xMR)S27~)g>iYdsG8+4D~o8Wkj>t$sVtl6$kWm$$+GF9jTc8NbT&1) z6GJs&FOyUd#e(}0l?rQh1kuRvgBTO}z`gjEgzWOh7S<6aN;$6!$S%E~L#J8p*ECsW zW>ytA^@hGt2H;YbU6PvI*8^?w4$lv9*GbCVcbD!cWUvdj=`pdJ_>`)rMKc15IZmI_ z9@<Fn@Ox_&WnecGYO(j@@*^a=VZ5i6zCMyhA*&VG?Z;^Rf!5Hvv$eh5=E|Oasfqe2 z-RAA`BrX+O*~f{Go91z=fwb9kxPSw2QF2yp1LfA!*=cvh2<T3W7zTPfElKhyyrfi1 zuhbU(zITh_rT8=HwOt{tq*>v1*H~S_8KbNI|IVAW@0Bk`es}KFBJ~rS&DK~Gq6tJ| z+yzg7H6T(Q#XOPQw|0<y62&2AoR~RaZ**=i_NIdC`B&oBNk@Q_ZrS%6UZoTK(>!p4 z2$iHb4l|R@`huqzs|Y^iJ?DYNm>*~`1)5@X)S4^!r6}PrKR^G;MD>+|j;O)}C?>hx zU3`KfC;S3VlwhOyRh?u@e6wAnzZO&zr02Wzj9%UBSAC`F-pwS~OgZrh-1H&*-z>bq zBYEX<!pH2tl)$sNZ>eSM%v0qikDuBy>+}aSS%8i=CiH~UjT_CU&PO47?u=C>q?U-# z^3)`yY6;jUriwJCsfn|`A-f6mgq1O_C^wk!N-4OyX2YR)0A`c$NWxz<%*Mbj$QqQG zXNa3FovT2YRtZT>xROu!mQfQ1N~NWoDm6>%j^SRXCN}L8W1oDtOaZ2TE1H*Dk>ssq z)4=Bx@RRt!-Fr5?!?vcvvcgRY>LSL@@$cBoq{_$ZD{iT+h-gbL7OB?XfvTMQhL?3t zp3hN-><8#A?r_+&H}g&Lg<MX_G&Yr2SSFhfl?Qa3eGiFpZ+R|PKvOzzDPqwJQmK4I z_cK8e8vVcAuNmB5{vB4+kw5x3+e0_dZ^e|<1vIV5-p9FFR=qxYU%kwZ`JHtnKM!;7 zNMV{vJv-A8-CoFon7Pe|>|h?@i~EyYn=4&fT1yYW-wCOrI~bZR{PsYq+d@a>qP9-j zptdh=n_A@}F*o=O5WaE1*U)%k%4K_@p5bZkzqk9qO{n-t<-`sjdA>pP1Ivvcj{!|h zQ9cJ*tY(e2Q*O$r3$JHYOyiUjLrZlXx7hKW!8X*aGYf(#=DPTli?(zNSbNeQsIwzQ z@Y|THHpgcv2jTS=0aIpWuPciERxvf$ljD-=J>v0i%--9!jTHn73tGmI_p`(DJ?)FR z0x?xxywG)hnPmyDV`OT}8kkOkqdHKG@V2f~EwAuc<W0cCrIE*Uf3z5n;P<*x`!+y4 znI(g)QJO`fa%;cn36%`uvrmf?vV_JXPH0W(jyg^7BaUu&wKYMFmaekwZtm_CnG)mK zVaTE}wCnSC&T8#5U;3lF?+J~A%!jdGqzo>CLEYzVqup<4yH#GIZYFZ^hx&zOsyT$G zZ*>vZT2B@McB{z3&r$o&+39KebERHVIsk8CI30n;iq*NAGX=A6oux;wJv#Lr)-al$ zQ=>xG-4xShfWwBfA1&u45-C+kil7-sUZwgGtMFQ(xW>42r4H0skOirxZg!jcQl9q3 zJS`1j5UwTK=J!hG4C&H(P)8qx(Syl)8#m6>luyeS(AdfG&{gjYu4m2-4H-9954!Q2 z2^d$EyE*fi6{VH$z+?+HH?pa?Itz#j^DXUxniEx}4HM;Vre&`iTg)fQcqd{l`Sh{J z1X9b%FHJXsJ{AS%lVS<`zI=YT+%T_HTB97U2Dh4NXjK@me~h#1EE0s3C*lzelpy?Q znWVZOF=>kLW7I<+cT8KW4;m{%_7i0M9hXoK?34?4U~w(Ra)nEya!QwA19-1>6AV*k zYF060R>7|B-IS<O_Q)>6mJe$;u1}1<c=+P_E^uU3Tl(g_H540R(HNpym0~_8@2w^p zu@(&ThyW<S+*8cUr`hDaLp1TH{pHdK{JI6FnRAd?hQ|M)=_;e5>c6fCf;33SAT1yu zFysua3?U#bEjdF<cQXP?Hw>*b(j!QRbeA;JAzjk--e;}%|Ah}T7Z!8p-1FOKpMCb} znJiu!Ez!`l1b~S~92bro`2HQ@rmlNBz2Ry*-P>U|@8h5PGQ|hn{U0R_I%P^Vp*rYd z_V2~C1~1Nfzhp_?9<fZO&wH=*$qUha7<ah83-}8^C6&0lozP!sD2Fz_9(p;xyh&js zIW_Ly`aLsq!lvmeZn1Gjdw0q*>Zhu8;r!J4aH03ZnTV_X)bA^N#N<qC(Yx=6-%ux= z5sCTVt}UYnK|vEG8bFuweVP84(n~iWZ&kFO2-&|H*>(;1@cb5cPze9tNWo4X+10kW zlRg)(#YBk--mz!2G8ybn##WB@PPjHVQBEq^n`{quqokWZHv5BVEvuKinr%v`qA?U% zUleT_n9?;h_^iq}2+s$53Om@nuGAG?_(|O{+>}}u-W(HD1(L*^@NaFM68WShJ>{TA zI_x4R-LFprXVw@s7o?>y-{Qu|y)QWM%JMUw1>A(-nCg^An(e?|8yj&3s@-0f>224k zHxx4qV{0n<6w?g5PP&Hgb{O@D?*Xhd;V5eOvi5@Blki$h<6~O<ioeGI>;}a-wIb0I znTlp9z56OH7wrPS*emifuD|eo4(T(T=meG0nct1;4-rT-57hu%S&hDmkSzrd6~&~1 zL}tK&fw!^{Ao@^@$k!?^xtMu--FLBhec0+N|8N`Q@O@IE;Kc`D{k!9!Dw`kBxt%G& z58RV>7e6M8ZK`yO-FB?+t}arp3m>ju-i-v@=<e^kTz`M~2ig}zG|ZOR){Ezu3~sro zP^m~9Uq(ybPqLj2i&vlxv<azHwujw}(z8aVYp-eVMm}uUyfxQ;`7&zpDxdcbUetOo z)mm5~{t&-85ipq!=*_j~px5`rtz{E;wFf|bx|vx;8CCCpI%RuZIsQ8&<z9Bl|5~xx zaYs@6<y*gh-yceB-+$ai9X6FtB&0V?7FpNp7Ejsjj#adLn<%m7pL=gv_4|bB!YcKk zP~G9@ylvdq|89*nI8CKySDS}Qqj`2}c%tGj>7?NE1BSWC@P?R{BB=-Tm;0O6*1~|R zo{QgmcH74l68U8|Mgv`MqIBekJ{p~Ny%}<UKR=O18IhmX)0+3(FCahQdh5eZ%ENVW znnBD?;lsR#TL~NC93c;tOBoUI#%y(g%a+H#v7wmXzUxmUs*ENbwclGFhL-C<yjzwg z_9jLC&2<HF>Dyek?>0C)<vrXzT(@NTUhk%<+-p~~-oGubFLUsF@PT-I`+m2gAmR{H zV>Re{ocUpUwNXgo`u4+){44SDiv5iD`PJk3KOeN;OEs4wTF$B&jP|TYOKrunOQx)> zw+3GAek##d<t?e!wW=?f(ezOOP4DQhXLNN8Qi|FP2b;Z&pedypRHI$2>r!`ixmWzk zzbw?otR^7MLJ{#Oyhgk>0NcHMjei+IOiTHzF*!C6>f>DHn4ZXml;-+3JEmZ%7z4s! z@R^+9H^VvKGg?)~1_>eI5MMEbjzjJs_{o!7m+};*vo9zTs8q5Y`=6-sIRgU&U`Axe z6*9N9^eSV#w9%P8YL+0_3F?t2Qa!VvDnzkR)QJci&X!Bd&wRcZgJ+)gLW4b_#9o^p zK_Pay2ks;w&W~<p5M8pH={vJ596H?EvgjT*U+1QreljgQE!ZVI<0u#+tXya@@tc_} z+8FGQvqr>K2)NRoW>@&1qqEC6`3#%AYf^KD&bpfS>X-0~rs!1c&l=NI3TP<>ytLhX zKtj7hgrO_|XsVc2M~{u#)c^LCoUo`>EBrI+TMN)m?|)AG241vkP%HGRRPUKUBEL`C zDd<~6P*#Fj3P~l`&9#)L`5%|+a}A~?Cu?Gs#u}$}uFnJR4J0P%tpY@KzE9{}RDO1C ziEr4a6diXVJP%7#M%dKq@3_tZ!&7Oh#F8B&3!JnyJVM#3HB$7Tk3Yh9qC&6lqA4fp zv2&}qCQE9sK|=+n$SPf4V&?8Y(fUIT*vPTh@&hG0fWqhao3YnM(y!6V<?+znoyqSZ zZ`L-inQ=t*Z9y$DwKQQj>uMmy68gEwhR}|<&4DEEKjmpduPqB_zYbY}0;|R>%0J#L zn}AfPY(#8JlxS79Y=r3m)K+4Z-)B*BZ1HWf<ePCt*`#yvyobBn%{7}*^JVm6z4*ky z!_~u-OJ>|THjB`_{TYNurQ3WcS)*|BjS;mS4DDqCF3}!>YZA(v^CZ7KYsg&9F)B+2 z3T#>eBRVzpGUNBHOOrM&qb7ooN=x9gqU%F*k5{rFl{EYC*T{CYgs|W6rlVi@wp|_3 z^yx%!17)%IFsIpyJOEHHhpBd02yoi)?VMfflV`SNK0}ux`8>^aLb`U5?IvXk3uE3I zJ-V+<V*Bqw{;E*&(ibMR>C#hcZ_+4ageKYcpRxjRN{5u0zD)hL)$(eOc<XO-Kv+9h z$y@%@)j@Kfb&^}~yk!qF{vC?bROJbX75d)&*UYClRbnu7aEhYz8Tlw0DKQ-gW*pWj z<3yO=0XQC5;cCl9m#twJbl49oai0+-&U&da#F4Xn>`XZ_q9o6?5mPKFA2#KKbQL%^ zt4^%XbUk<vR}_bnGanh(X0O~Go-O;WdgY&bksmlx?)|?UV9}M#@{eI;?^1#iU;57Z zzFt)zad}86G6=>u>eHB={|BG<^y~Uxo0{<hI}Kll!=pXpGMzM)7qqK1O|gdyC=dfV z#eeKnL(H~;l&9*u3k2=K2y2-jO_U&1YaUpCGMBD09oZ<-=PCHxRlqpHU2*(=(GXAq zG<xgOH*K|}|Fk@@KMQfaIrr|A)wdR;w-NWQYxJHku8I5k^~dqTzk)f#>}mKqz{rR0 z3Y$Az1lf1rW6nex&E)7bm)LAYwp<|*XA4#Jp*IuAz&=l{r{1MHFL{2!XCxzgSX9`v zC*kD6<^io7<h*DaKw{uAwdlw2a6eH+Q%f8<J~x*Ci`>>qL1JJqQik4^#qi&tnH}7g zgJmF#%9lM@%bigq^GkJ)-MUrm{uVz+{sNzNgTl%M8bZ78Q$vhI5b?Ua<NxL`Yl_g? z>s6;jRS)<Q9YpxIey|wYJ5ra6tRX8013TnGXp^&pB&;)>MBVpNv5_)gV>fQp+J}Z8 zp^03rbgfihjOHYNdzwWCWi)=3I5xb8wGnnVycg1OO^xXTk>{@7GQ4z<Y7B@O`6Vfx z^?ZV@m~w0D?S^2uCZ7+=7DD&MyA*Yo(*z91aGk%}r%HDp$IV^a6mzHSihKnrN{nG| zj?{ZE1#W$}&@Qp&R6e0;8UE1)0JzQlM1}=p1NTPfKE%%1x8C_0ljo=&w;f*qM9X#D zwa;AxvnKLJmP^nbbU^xr?~I&KwRH;q6Yw0mUU(Wg7kRUvAeAvxR1~n2VJz;m;!#bL z_u9^``%empO4x^0l%=fSBwFIN0@TGQNakxhvs?s0-9kX8G>V)%m>W`j-~6AxfqU?{ zFp@jFCufY*T7GEXs?uBnta2~mpG`xDG#Vefz0*SWmp;uDnA(b+0@nB8%lDhhN!u`v zMEqIFTshuC=PVs=Dzu;tC_yI8m`hRQEW(=qMg$t(ZS}3K4pIS)L7um639HF%>C1mc zh8oC)C;m06F=v>Owh(tcQC3t|N<)8kjcuZ;`;Z|vz)g$EskraVqulsMr*LA-gpUL7 z{4R@AvVD$csl!#g91J<3e54>B_gffl26k+-;{;6&QiDRE;Wry*XUt0gWHzn08-(RL zksbqrilqqkq{xLzjOooeL*fu{4WL3fig<E0v8|OmR`h5#TA^_>XUwYfETnJqOCl?K z^MG`raRpWDJ4d@l%eEOi;fQXZ;&{s!1I$mb4D^~D^eo?!(S1T&&Htc5Lg1Df{;B<j z*xOox&Y^86x(EW2KzLb1?hM10dt(_O_Rx80%9VkS{(>O^FI_vntqg6S#e(-`gt+XJ zY$FP+cqs9sV7ao@Gv-5APK4x^1+&@Rfpg}Av@B4j0-<YgX1(dxW;9b4*%DNHQ#r`F zmHOPuRHvUPGV`0^gmJ6ktJ{X@Mi6m8?e3TApHUz@Y;5t7^7qb^151d4@iVa`B{{&1 zz>&QvMfbG2wY4>w=j~S3tWC^IOdR8E<HK&E;m%9{JvNJlI5#MFh#uJ^M{j#F(?5ps z2L`Xu^(~?)gl=Uz6N`(+$2F>jXdSi2`j(mLyB$m6X{wjKZ<1bM%8mOHN=HFcN%_>y z4=as7B}!qcVhY0F67(wQnT4XbbPA5uwEN=Bprl$>=45gY<q-?BETM-hvTm(~wj5E- zGoMD+UY~JkF5R~5shF9(<@-oWVN0*zWA@Vx>Uu8*ucZzuWQmo<@|SO|04X58kIPtI zcw=f}nj<e)9Cb%G6?!acM}i;cwRrte-;NMib}tq8&qMIz1J&nLHSK*yVsXKB+Vt~G z`sjD(lct$(&!3oujt}$PEI1DKbND1eF0L;iuJ(~2^$JDdT(@^jQ1NDC2bHh96zdsm zr-un<TU&YNn{zDiou;g27%-@|@<uNw(0R^wn4r<8;?zTAnhFwJuZNj_CDr76blv9K z*%!6}Zw7inv@?cSD%gD3&e%0txZnemk?=jCj>pH7Hrj#LI^VU`^6L(C8CCn!T6+r8 z^6b>@qvAda=l*j^kW7|aRg^G;BS$*taG~!@yG#NDLk<|ex0|Smf@XcXb0$=i+FQZG zd6%NdUv^ZPV#8(Ifwgzs_rsyZ_u|7iEdR2|vUyxT`VmiI*Wdr@Hy9MSlDs#9NHh36 z*wbcgYv#$(Sh?^nkSD1|XZP*K3kj5J9xojEm$swP2n-Mx!04q3^ek<q<(Ob*dbN^8 zoS=i)Y(uNxk;oBhnDW|Maipj`5gUnGn$?np#Jcayv?bW4MMIwOHn~rw!65>b|CQ_j zJ{Rb>VLABwj;kBE7d7?5R6(zxUJ1X<(#=fP|CY)SM|=i>3jUSmUJi4pX%{QA4Kem* z53u{@EmFU!iep8y4zsGE!n^ttEmd)iFyCTYPrauey`m}BnA$zV^Rh<n9D6pMOSmf` zh@VTfVsNpQaHh7=QpZTpS$QktGVf!hVs}HRM|d(Zps%#5nH}M;dj=QkPn(v;qS$5! z#{_x^%ALwcO%Nao%VIQdCk^13t0n%NqPKK;`vPvC-1EscWn{GiwX>D>5=xZy904wh z-Gr6+4|884?8CPtceO9;UG26j`ES;1HYHZYT>YLs5x6B9{;eifzH~^{PB=k=gAB5% zN%L+tj*~H8Vrd0qvNn}qz0@+BF$4%bd)^PKG!v;;l}g^dKu!W)p#gRd9exK8&v0l^ z1_l+-HP-0~6L`qurg@5xsbg8h*2GROCu1_Q<)bE74bQ|APPORq(1h<PlbT$4%{GmL z22>82b=jJGNiX5(;&zkD0=^A}8xy|Ryl;9h@-vMl*3!sha)VftzTes<R-NhA%<n&@ zZ$K41*at!xVx}MKx-&-6NH7drT)OC`m{#ua7p}?3$DfS*s|pj;kSPfXmSbw({T;n( zNo+i)cQmR@?vJMKS%}U(K6Vt<0{Q~G(;W@elr2!Qc5c+Pkalk!EW-=j6)h+Xt#uc` zLAD#I7&P<lOMAb%WZ0{C-6c9w1CpJBs<0=RDeGphA8)%i%Be)%;cDE#a^wEfeMM@T z4zJSr`1o`+oZQS7zvah&$fyvqhV#Y~YMTH@=8)VZIfM6lFGLA$8u(v)O;cS6Q2!uX zX13ybUxi}c<|<I0ZJDVu84AfvO7yh+5MJuXzg)XYZEZR%JWA^5STMb-s1aAp_cxc7 zAOBZoKHpO?$BWo}B`OdOrZeViShixEIr3f1bNe4lNfNH21&L|3WS!U%+`|Q2DN+&9 zfQ1ZqU~}<nciu=A6*>WlK~>C%J<hLob4eqVP<!5|udL)A?G0nAg{S+O>{$WAyqZCV zq;~NvW2)g#Gsnlix<_rQ`7%DjviV#fkP4*C^%*MZM4VN7WOttYH6m04W5lIv@2hs3 zI2FMojEwI8X#tcpc>kydKV;8}NaZf2&vGBC;A?yOrsn^n-(WatQd8)SezlwN8LF(v z^NH>6U}fDfW|NbR@bu=jnX#nkU{HP{M}$G~PIVR4e?e#$iXV>KaQ9Hlxo3+&nM`S> zhW=V)Deb6gR#YO(?FM{Snx!=gE^oPW;Bi$T#(oC$IZI<cTJP(P{beTMjNY<6UAhoQ z-XKkprcLUPLf0MLgf~uD(Ks>?Xa`y?OYZON%Hnv>@FLwzt$taJJ}4VR{{kwtXAU3T zzc9s+IF#8!y3v=`n~^DL9HwfUyN8&OVNVTXi#3||nQP4KRnB@LvZ;mJT_2eH-)l;@ zUF1$EQ-~re77lxM!?<xNZ_u!=k!9}qOnk`M9!`fdS+v+iknI#TK@Qmnchb_(+IB=~ z%!*?jdq>utEj0<>WVI&@X40G!4RjXXn27ub20kp<Iyk&5RL$gyq|4=ucGu>j05pn1 zSy%r(l)DjL`-g|SRXq$70RH&PJ@_ki(Za-P!E~#K)bl|qs3^BPF)*JSjS(BP<SA~P za3|!EJ>~>~Y0;avw_q5ZuYox%$<)SIxho7Rrtx=Xoa=wz-{0$F4%$6d7{h2uX*cc{ zNx!zF8+s}c@#~JLU`@<?*<)zL{3v|Qf$y-Ch7*ygiYU|RT%KRE#QU1b1c@08zd{wK z_9-V(4F0{0)k)#fr_`tf!xSwvXeEdV2CF`HA1e0DtHLX$U)t#DYOX8CS|*~C*&`0_ zpbR2X>9#f*nauW4C?(0(fRyn;a##-8;mtA4tZ0(YZ&!u>4>vU2NR<_Wa%&}<MvU)Z zb@#f|cEyGEoKB-*f|~K&vxeHAKizK5_oFNqfxCn6O^A&NY@yE-_i|Qg7@vFCyBoC= zcDucF`cv<M06PK^<|p%NTDFd;efVwRgkEk-rS<b-aqdAx;G`D05<T5Q<w$sYECxD= zfz5?56g7z&f_scv5N6mN0;YsxWL<J|?$z}6FF<|STeOb@3NoK_rP7e2g+gWWK@d#H z)Ql%L=VKH3el4N#UgcKjb7Z(313r}9E>U^;-5H-ooHzqu1!X%#Z*;L@7vmFid6&@) zOgu=K$Iw-v`YbdoBz%D!$o$%(Cz{Hq%5#r!aTXc6^C9D%R7~q4!0Kg~P2E?@u+yme z3&YKC2kWspoc8x3FCK^BH=S>1%m+D@QCxgks+ia&mpZ(1-i-K0XS_7{##`maMWV%B zw)#2wbTWwP@CDao+%vA?oDouw8P0!*Q52`MgjOoBsT>k;-^6R&R5bt7p~CO7Agm3D zxPXQfLKGNH#cQYwt)n(Q-sl}efe}9pc}0ZHft2?ub;xnur`~X9Zx(I)n{y4ngu7}O znG;Jy!1*qrFV9hJhUF7u%JMYhAmdOXQ^_mZ41w?i2tJqCtfGt7+>^nAUzHAcEE~gG z2C6A~VTpR@%^dG+eFpTgFV6T#UL56<rMjo6J_n@Hx(~d?ULPM>zo;(N=^9Z!15X9U za&_9pFa1G5F9?tQ_D2DYN)0S6aVb>{s+?Q;bhdSX4y%9C5@AjIngpBhqw*gIGiO zrm3@|B)nP6&JvDC>JL8G2>T!I#jQ*Er|hk*`mJ46X=Jvl9%Bms`IqVr0Rhcwp<?^2 zGrQO!f<%zkAz_8$%`;<zEF5fxneW{rYiIF(PNGxB)5UNdQSjz9F#EFJmjI~pXo<oA z(&@w7!&~9^Hti3*(}!!uts`4rx>+kRE14pP7d?#yATcrj+q&yJf73vaUd>ll50pk4 zVmL#+@y`@cs@cJ4&h}#3DM$G}mP-xZUl|=<@a=C&g(8N8?!x@pF?A8}n>&B?x?NdY zOdWa6JD*~cE@PJ2#CRb_tOH!TqV=wCj+m?neS%1W9F>3*bR|djKWYR*A)9{`K`Q#> zsqWD`j7OL<m<m(w)Q(d&LjQfz2C95#y;rLURW-%Y5oSB7bc`QcA<fQ!1>fAwTYVSm zJLUU^VneKKJ7%SzN0iP!2hFN8>7SnsxBR?8dD>UOyB{r`+R4{&(;>nFC1P*6fm-Iz z#|vIW0Z_QO$QCY)9H#M4={vO)<@DI4Ze_U1-5L#-fo)x-w?B`@Db<Knylg!Ls00(f zx?Qn)VLvJ8$)5W9S;vw~s4IXl^ymT#4rTfadP44YGFF<Y4j5}WGH86J1<6$_&TsC1 zHRd)M2oHQcdE6{ulac=2dhHFNx6j8t?}4ZCz>|LZrtENkDc`jEMXxL9th^bQ-g@O% z!3%{Xl2-&fUeIRckx6684NOg(3^_!>UTnbj6Zv5$R5FxKx$5n!o=j;sQF=<!F938B zM4Y%Jxhcand1IQjmF-yn3i)tLh(wpFwZxJ7!EmYfFMO*bs;3|0lN1{r{(VeXKV3Zy z;HY3p+5nqXaQ|l1P!V<`BiMPh9-+=eSHfR5cX)w+cRg!Y0O&P^(jKSBT=@(0MHhHV z4sD##9$mX_S)DXAGjO;mqAcb0GyE?aevsz-GDE@8{@R+F8u!b~*rSFOrVidAe<|9x zE+fSW?{YTzM;3{(JQ)H4q6sDIceGSZMI29#?oi^tGp^4~huH&_k*6f)uG8*)cw#Me z?>u{t_zGzgv(bS1UG6pKsx)8k(^BFiAR#po?>~YD&EJp0pz#X%&ykFpoKIan9nKdk z?a!Mfq<Gye(K7P1S3>3XQa`i1Oy;yW=8ZILnqc+sL>-JhYFTP0u4sPH>{<Q-cL~Q) zEe*_Km9ueutl~(~VvdfmjJwNVFqcZ-niZboQqp>MLeFQm>$h>Y<K<zIj*zgg!q2&L zSS5-f^U1mtYo3~Y7ZS2aPc=tAhY7cOdfwX#u<jv4XcfkgP(jYa*Cpo1E)um_Qot{; zL{yw+How31=iV9qTz^67gu|~7SDA_FK{!12sZf!^&(z{Fu!OOp^(9kgJLBt+TUgWS zmcC!0fRmJZVfzJFN9J&+r^EH`LN>24BD80D)_vd<Sf#kNHU~V|U1`;_G$5;~U}_If z@l=qKDc+%h*|V5{aEVLsj8*bK+3^j#clPEnAZTrJ&5yzQtuCT)`%~bwJ}>T>u0v8M z&C+X}_}*8GBxH}B_xb$siB}3)93fcveZT2&zxm*`i9!JGQB&cIPaEv^iil(m=hHud z5O=1<GMNi%kEvb>D7~nD$u~(a9;@2dKtt8+>YyR@N~o^+_{!xs%f;i12Tc&NOMl%5 zZj%8rA*}PYB2!S}B6{}9J*HVCHk%E<`j#8mB!hnOlt1Ui<%(G$ypE6>zvY(On8h`t z2>0Nkiu7C6dE?C;3hzS3+`NNX4(4=Qx_LiGV;V#oA<Ow*A^dT!^Mai+nyiwPS~Iiz z!bC9IImn;)@v~OCjZuR#o%R~b=bywQX(laP1Rq+bNprOrp5G5$37dS2`<h_GxFVz& zxQWa(`f``0wf7aRklT&PNau1*3{}<C3neXzRLcKFIO!>Vp2)r-K1Xxhaw>jwlZ8*` z$q*lzb0Y1i&K8t2-LUj!M|x57hhh`X1#C{Zyftrf#*3e0H49N__51*fJnwmBqgXL$ zapFGB8nPH8X&{Pd`M~v*KQ*p4*w9J%WPqdjf-WK?fy`mvA~udxvo)qCIxr4{Gs`JY zX{PT*8{#=(|G0O|i%|>dPc>M^2+4GN96xsSsc>!{!L8TOP0L<jmb&(17}YL#;unO3 zD!kETW~;uP)IJI$YJ~idWopuqkoskvaA$4EEX~^EId|-j)Un@IQ%1C~ubQ4qNEuJK z!UV?msy2*G59uKPIzJeG*Mj8sKC&gd9dy+dFDySix^-5r|7b^SA7+PN_aHh=B+G}6 zuTk6X6=;NgeGECR{p#<ZWm-E>y2~HR<QGE@Zf$hJ10hP1*+P#F$#&I^(})T|WY9AL zVG^H8_kmQd?I8CYmDg)&&T0U3+5PEBq}iPo&7TQ-!JV4JSibD7)Ig8S@8lhnBsCbX zI%$lh?YS4Wqt;KZsR~45ia0c%O(BLOMN}TM(^<mWQs<5_6hG3{2ldTcz=JWBhVx%! zOBZlI>)4e3H%@K25^DJ-iBtMjn{p2rZ=i@oMk@E4cyDpU$Uk^Nt%R4bj`G!<wK-&{ zRXzm&RVV<5lbIZyG7q~xKPF~U(%Gc0u8+@7DE>(62g~6E|GheS@F@lFD5!NPn9#m~ zB-ldML}Rz5Nj`xEvaOwA^q~5qjM4VDTc6i@|4QYOa%QI{V$hPndQ;h4+uAQy^er~W z)SqGcExvGDso%sU+7FDaP|?$>C>&fKGxjWVRB3#nQm}u;yC5H#Ax77ACd;WaLWarX z@4>*k4nmVMP^5_C7<=T+T$5b*5hmJq6kWZmlnqBB$s>CO%vGe@Y82%svwMX4v)?wv z5z}MZ!l~m2hTZy_2S0<oR`uR?Nj{cjQCK@Z^=SO_OMRK9y#pmzu*a*S)-UuH@0r+~ zdua1L2chzfjE};NA|eBUnG{g{S3G@Xb{MTYea?qIXmQX8P^drgQUB7rMZ6I*dpm3^ z6cjV<D?IS_${c>@^^uQJI-Hcv0Q_>@uh+?vOyS^5qGYXkl8_)4iok@wsNE@Nq8q&_ z<A{SSl(dch1;PrwzryJPp~}uq1uB&*0W>WU7w44a<Qn{UZ=$c)4loRX<C1xZcBBcx zzCa0n0rMrsH@+|>CLadetS`{NkB$sY?jkPCs%3#cR^AA~^Y9!>Ss^mBo+z=JD3*O6 z3XNav(tkNum1k10Cfn3@hTx7v2<^`LN<rm0L$d0Sl34S<EJzlGL+g+}<5HTU;1S82 zJ^g>biB;Fu+u;q-!%C=fh>T<|4c5<pq1$EPsD1^rmQPa1P-GaN1O!eg+Ly?hXTf0o zTrdz<p`J-G<@B3L6(jmF>Z=)L5T_^{Tf8<;hCjD+NX0xgeVUXA^YJhlOGp!f@~Jn5 zfcI{fLkE2MO&1xgr+TeIDrR}ccI*NEDN@`#n6Nc>nw149n00FxOgYR0qK1585RvCb z@tgh-jhLn0W@n2XnoJcanE0!JeL<6nQ^9inbopzi*gBJPpas_l_;9r%s3$fvkj8J- zbG`_yCR>>zoymyA5d%G=)eU~5G2N7cD=c<V`{Gt_f>B&2vcQ?h+F<W<yz1YYwpFbW zOnZ*@Cuod32Qf|Ax#u@{j*@>3C&b|Y7N~sKQ<J;ylB4$H4^<#fWI!zKkvZUT1;(~O zlAbKaAoceZcVkvR3b^I?2Ef54Ul=E3=rpqGLUHq~a?wuA#mvS?-xpcWGguyT2Y(`< zCC!UVOSu#HOMfb<*!YhoL2ezZeYQ6mrSe#EF=h4xoI@jeYNR{V)9{^T9kN|xT=&F| zHAm0~Nn<^A&3cey-udmqm0%_(u9hv`9X@?Rzb3G-BBZh)!>H7gsmeIrobDOl@*x!J z*}`vCH)RCc{cIv-Jqk>8O;G}DIJIkzEOqhqJ&i`T=*Lb_-im<QPR&T$mwjO;98jCU zLfl~*a3I4pqMu`V@CCKCVWy|YH@7PT?_xSy)blO(xTSiIphU_y@;u^=q!D4%pSGY* zVM|G<9`2;x&AQp?k38Vl_2R+w#2g@!=S_JQu{*Jg{8x_Amz6GDgjmE7-edtDN0%GG z=qFN~pr2e+!8#Yb5~NZX72>$}S?NoM;4g7%&@rQECI1F9OKUuii?i*Oa_Ng4go;v- z2xTS~?cLxw--*gKR&G%=Upg5ydjuaRmR!ai<jx+MBVnx|$c&N|$uWn&w8R5-UEDfJ z-U>}gj}~d-F9|Ww+wQc|X^pqDS;n>15~z8)(7n;X_#F2VR`-;)X!AAE%VLz>GkIz0 z<+pPtB`KAQ!A-{F7|pO$iErk8yn_V6v6QmL-1xz`(llSputrCuW7CL8axJa3XvR(? z&%fGms!hd=&G_s!6X7~m`v`-JOYay>&M&<xNMc!I*Y6qCHYM43CN7>6VB0PawN1Ie zq5IMVGM44-)j|hXUwM|9Z0798|9GaJ+)@*T+5T%R%`{`;C05hWp0!Um33c;!m24hv zYAtqrQ#s%V+e%%!(9gl*1S{-eXNRjVQW043C-menfy(kk_>Ve5UHqlE1gq8{oIxm+ zuQuc(q!%7v{aBJhwZJh;$Yr7_`DY${qn+K}1f$Nw2O-e$#aQ0GiUhCrJsHT?*~UC> z%_JdGAZS`}_HlaxeZCQRcoG1a2&Fe{r-$7|EqG%O#EW|HnZSa~y!3+UHI);NeY8}} zWyGU&<)`6VqdH_Bmw!CFuTCSO)IbO4z=X1uz=Kc0Zb7EsF?t@kN;KufKbkuD96sg$ zybf8{eaXD*5BwXqSEVERE^tp4n47?Of(<iP1ooBWQQ!MK4^<io7)Te|k*Ha)O9OhL zdn{|2HkIC%#VwX>`1>CR8uhGQG?U%CWN)<}nPo#vj=_kN95Isf#oFjY`4>}++@6Rr zFcrnbC~2GJj=1I|xAAE~-l-U%z$E8@o(nwNcNK^*M-PYUaX&U-D31$r}x_AdfsV ziaa6+>!|5K70;1dGKS5s_5Do%5yRq!9BO0)I83_()AqM35!eahH@SbI(T|+7nsD^? zQiM1cSq#4`gTc%exk{L@GJlxDtvF}#-@7c^Iam3L=MVu&N17_3nCw5nWNjym>prYJ z33A=ofAr`&ORKE${6CKT%=CKhK3j$QO(>lDGQyBQ*dZ*u$>9Kls`>_vYy1?OlTImp zODHoa;zu!7-F9c3^Bd{c5P^Lq4Wp;*pt5`ud5F!eq#mZBCf1-KF{hn5>7!tC=XKmq z0}ZYdUL3i)TUiKA1<a~FGY6CQwkKDoipS=RQ7Fpb<Gh1$MZS#$8tK+BkQH`H{I{-0 zn&CM4<H`0R7xfo(xwnJxWVhFa`@FfE)!n@K$J@H`J3Yr&_D=G8Do;o5s?F>c(F7ij zgvk`QWFAN2xtY8jpgo%SI+k>cYqO;kAYL+(YE%hAPv`^G7TT2wyA-RxH)mpv$C7zC z65+;!Q@8jp?ld>PN8%}mgPg*u#+w~+b_=NqF48trXFswX<bd1f@^RWh^kF_LMA&J) zbEZ)PcfcjKeLB6$<lqBW-sWy<!G-}8Q$Pl%?Rb|$-w8g+C-p8Suk3#(+cfbm+0vQA z8t%7)MRLyPO-IFt2e`~XGqDpxgQ6ehYDU`JY*FW%T7(!%L8P^|j?wYq2{>;wo{oPR zgwRh#@m(wQW2K9Fp)L2HB}r&7#I3;^Fr{K}TBUMJsU;i7o?*rLzvg-*M+3YytZ0n& zT5Dnj9k*tUX(?^&?#Q<@LQ6(DY54(zvZksiLu$)s9v40OBv(<qQrENRF$AWqU|M~= zJ`#@}6jHGi9mf>dP=?TOzEC7Hb45vq{$q>rbI%?2VD9R%O$@n+G(2$}LWb0^4XT}- z-Wv0E<|&cqsuLtybSA2dP}^J7rq7a4`cBk;wIB8-n_`QVU$UtQhZl)!O|kOIbbU3t zXfVl?o04%RgkJt?{wpNw#??v}0aLV9xHc()R87SPeNL3z!05Mv*kjs9`gkAxsb=`i zrExD29PpSCw!3?FP0PXgJ!M(U#zvSTki)y(57o{eQ=i$DHw`a{->1=Ne}$Rlnl>=S zpIJswH%7y5`B~)!imkW6UrQR?_O(Ni)(7%>yJ?BogKyW7{4}@@`9l?9L&&RGsF<uc zH$}d-a+RPPbskz%kd5PU>BpIxXv<bbm7fOYNJ4dXf{ekIbu1UEbDV2LbG5($NB~BI zz3we)1Bn74pE*Zk&pANKa7(hcV9&%-{E-)6-A<6<QoZ|tqkIXaX1nn5m!9rm9-!6x zH|b562I9-@t=>ERP$)IQ#$40$14jFlGa-f)Aw;Mk??-okD@qK~NK32{y7>OrIsloB zZ95*RJS3+7ItB&%gp&{?8gXoxySnPJla6SA**srLXu_IHK#g_}QYUa1%#Ty?yW{R< zU&?~jmCi(VXLdEYOVU4aPmBpES+5f)Gpv}N-VA9A1O?yuV$DQyc}6RqouX%~#)7I+ zGVv&BiZ9GONcnS_uw)~PG#O$!KlFbuz|){C;lJ)aXepJbdQ-i$w5Dusq*JHDw>NUS zvbDtWq;F`T`Yk^T56VWB?FV<LO20HroTIWmE!?iZyNIo4);vy7omOh9>$viS!DBt^ zRN0L(T<ucLeX4scoy$gVzC)655uKMGn<bsI3bVzUcD2)B<4F(5FJU3JfM{|ehCfq= zXcU#m)o?@n^ggV)DcI1-Flo~ygb%uHD$`*|aB^q(lo;~M0=P<{2FxjbiPG-><_mvQ zABOf1qIm`LLM558E}Cbk#_#7@uF$l*sS9W`YPMvzeG0;U%%7d>JG}nz!sG|0j8{Mw z4yW}{u<evkwSzq5srZBDF$cvvMa;L`PVn&=md-ksk*Qn5IjfTk!f0StoQYjF{VxGT z4>U^~cqlWg&n3y5GQf<NE!5yjK>g1-FcRejuOXxMu_N=afRFu4&vnEBeFJ`2C%G1J zyxKbrtLr!mC5TR1AsTKRQO$}I->RE_=AmYmjUen|{|wa)Q+^Rhg9YFH3@!3LOV zAhPtnKm{U{dIH03ZyBn7EM=c=OLXQur;+T$v#jg59G~SKd6ItvmXV3<CHR2dO#K5$ zhpwKfDpDnX+5rxo3e(}u$Zs4G7NSA+SiB@vOq@?4)$1))k0zJQ1))Cg)#R8ZEMc>X z1IHL`4dk}>6T3sfGF)%e3Y)n*EJoMltU9(Z7wFPC+akFw4k@HssicYx2MyI{JLP^x zuIG`n5wmOfW;FaDV7dt=S&siX^fzV8Q2=EHD7$9_|DE7=YUuD&6j*VHmq(KDL$q}= zl;lxe#gVC1V&oLC85Wj&6-5ja${06^?SG_>qoV3_8A4dfWeA%r!+<INDhz5c-|RHA zWekeVJT{n1mOeMHlqAw+SirX1Ol8EhV!AOR999mg@4({DOE|VANRCA~U=GRNudkng zs3q7a!mPdEm(N&9nj9U#q6x)*(KJZDVw=uyW=NhX`&ew*FM1mK);)Ssu}?|}IFe@D zwG=Fjluybux1;=!MLHXp)8h|VKCY=W#UskZxn8&8!y+T;I^Sz_66CfxHp(^sL`pp4 zz|UNhPVaDwP3+jClkr*MCf>!WPKTgB6q~>rf&N9f&xEA&fgUkj=2@^K>=f4!SAeFD zIVaDay90z}L}Q00%S0(d7CAq@Sumv=y8cw^#gyMyhYZ3DMgy{3xwQ=Orw5GMSwx~C zn!5PP;ao`K+A+=wf2oBPCq$W2HCI1yGIc-m$YZ9|w&e85l-oziFdpO(is5<WU1EXj z^<Kr>#_qmw3Y*>sjyWW~`_tK40BVVTejRQdE)cgPztGNLuxF4&BLgS;lJBLXP5|V| zx_yoX8OvIrh8!FexKUgR^6yClcLbY{gQ^{&nlL+?zTRi;7{rf=)F=<C6m?sdUSUV3 zXV;KN`X&~$i&FGGH4x@t<_QaMi93z$XLu>jhs)KAx$gJ0P9VP*6WBzDgFSH;DVX<$ zyYc(8woMtk5?n&YrLZ_IDp&Rzrigl6*VLBv0?X{rdzS-0Sc|o^rc71dz!bnc$`E?7 zQN5Hl{*m%A!};IB2=?GHtf^y*eL~_8?$73w{O!+flJoGCVJ=0#5}f;Qje^}K_?n*= zXC)9CXue(wa~mf)Jxuh1J2}D}n{{sK%e|DIpa-R$cur&AGCe{#4v>GhnvWlTEsvVz z!q!av!nIp3=hlfeOY^k%x><{9wdLE1+0^jNF(aSZ3jekXR$eU<`!D%FN8!wnl@>(5 z7`joYo$LuKbtY^6FBCsg68lTFIylIpL_7Zejl6IOb1GYYX5TN9If`+kh5ED*v|Yp2 zvB#$+^6z;AYC<tu`+1%x^aU;}Vq1%BJjplN<gjoXR-eEcuvXvzw^Z)Lt>Lgr_zqB@ zaVXFnEYJ4ry|4`jDs<yhJ08=8cJyc4G(ARt)q`1}#<B<L8vJVA9vu@?T99cVL_g{T z)u$MW3?2_`rhI{N=>GcbKlOh0UQPSRzm8?sKy3I6l-iJsEDk_fIGp{nT8Ub^tI@uN zBS@&PD*J(goJsg|Qjfe|S%5iUr(tC|FxiaKP5Z|OS>3Bj(wbbDC_OX3!*{|-{}RBk z;PgAKB?1n66&7MGxIW7*aKlnL%s%OG>o+d@tO;no3w0%F-J8bga@o#462Oyg%cNgg zU*>0)TTAZez@^n3W4-#3#TX5eVIt-ZrlOpPpGGygkL#6&b`@x0DM^|rZuBv{q_-V^ z)cEJ)F{&Wmk_Ek|r0QP=R+7ZBzb#7BNRA#FN+c2_h6s1Q?I)vnt2^EKnn`R+`TLg4 zn`Td8^Sp+*q(7Hl#uuD)Z#xEs_Bo)FT?&{Rmq`>!r;Zz@FfLqT9|mb<q>G>E#zzvE zs+W?lz!Rh7G*y%VrTRQO-+-*x2jNZbfz>0uOK{fP@8&dh-T|?Yw&7_@@5^oF`j#L) zvho)UAM<eIr#d^LG`95u+PN7li%{Cf5XJd;di#^ZS;I*|P>B@eElMK3?!LM=$)y)U z20;|ZC%f@;=I>mvcOe7AZocHCF$xx|CPFt(6OVUrVO9~i;~L*GWVqqGnyXnQwuzhU zZgKx!#e5CI0J$KRn<Zxh!E*RTTCgr=_>2Bey44PNbUZF2l?WY_(wKT35=E`i@@!#r z(dA<k%ukpP|1dP1TvMSj34l4CtI=4$XR(B2n0y+kJ@~AgUoFJxkx!WmD5$}6E9yNh z{-*^159s|@_|u0#PsINrME|z$K}WF5F`{dxo54E_{}BZyI6c8A1*pB`PilHqj2OH8 z*d3?R8(#p52VMa%x+geVr}nGDLL4FB9U<`YwfH~AI+pC81i*1QOT&_#*$Lu=#oEgO zaZPZ4*>to}c7`&Ywx`3BCl(D9&d_>eCfFV^g`djl&J~_Ik@e(rBtd+ZhWjJHE|3r# zDa1z4I~=K2KrQ1gzqQ4G-5&hGpJ&%bx3@p|<GV@>UsRE_&Cfz!NY9dQH#t|Y>K`qV zzP}{9@2sqVJ&paD)oFUZU9``H^>Xb*wx92%$Rc}HesKuymRDP|YX{gJ&3thOTy?@4 zm$J=Yn|Ey$B#Pvg=jBu#65PCr4OKWAMDm<Xp{@};)QxKbWGLqt;k-Vv;qtjie-htH zqA$`+bo2!$bhc08iTa;@r2GIb8M?>BYD-LEOEuFfQ_kpI0`qj8hqdF<-jTENJ&EA5 z(26|v<Tp!>vcV;4S}euu`6t1t<6B;x#?hKyY(UPy_~<yJ`YXdORWY-oH>EB4t$zWB zXZBbNyEIQkIbww;iQCH(ag#^pEm3$Yz}evMuUR&O43=p~e7V`KOxGo(Gli949;foR z+T3Rfq<+$%9GXV+4BNMf2rzcm7mj<fhIJKL=M1WZ2a;N!tYqq$NMP*J4mMw;!2>9! z@{%YR!LQ$5IZdfMOK57O3{!H75PkG=An^cDUVmhs9ym8SO4$1OXQ<sNwIzT_u)H~M zSAE#?1#dRh{)Gr$50=M^#g*uKEoyKFj@-|$5(V$?Rdjj_0fjpcu)eNFD66?vfa|ad zk<9P&+A@IR`{VeMzSEH3_EW$Z@_Bui{<lt0BFAR^TX_`1V3laZh~}V|Ajyd+{hC4B z^&L|P5Q<xH2e!G`L9-=%kGwh}r!XX52L38hIGNgCWL@r<6}eD&MAzzpBv_Tq+5EJd zlPvYmufDka9R)Z-L!~`nPx*=s*b*eYrzp#^hx|;|jhP)MD(qs$qXbwZiJtifcvuWA z(vk}ub*gE9N=Wy8<E-6W1-knYbf$YLsndG=Ys1vWd}vc$EBNdCp<h;ozfW_HbVsSx z@qGnpfyEYOePrW-H_|`HT>lVqsw|{xrG9f|&HP)fIwV|On!;4+KBlYjG2UNuimYpx zp14ww70aEb+2Y^K$ls2@9QI=U#8N??u59bquSt47zY>uw78>M(yiEwn!IH&p*jznz zw6I9%YA7vR0mr{SI6mrPz^Hdnz&zG1;CL-Oe&Q)squRFVvAVJ$vH5uW<Il#awwSiS zIF^7+lq@BgX4bfE=q%wdDT^VuC;L8M629VdX6-nd%)D<i?tC|}o!9Uxa6-2v#~>dd zBW<J|amvzo6L>oC*J-vzDUFKLNBoD;L!yn8*XN0LbG3oC-u9S5)l?lNy!2_3Cse-h zs`CU_Q7Ms|#C%N~gOLWJY9<Aoymb-#lKq@%VDl-uJNi*{V3)Z{2_Ysawp8L+KAw&{ z$(H9F44oD0x~oNG+04N5vsA8+plX^(h6JFA$VcRWZyzE(j)*oB<umBFV@~?z+X~ch zjl<GFsv;mFy9M{Iw^3i@_l(n6;85xM^aXy}>Tbt4U&{U6wErAg{{<?J-3_YU_AMk> zj*VL})+G2rMgWlB;iOg1sr7K>SE31mSr1I47i8R4qb=}9#kQ`JBtD3zbdrf{rmApu zfVwIDVXH*dZVKuMlNlF913CTmJI644TyUgaO&hoNR2nc-{Og|7qf(6HiPRoJGTtLT zhzTt=%Uq<1mkU%w<!Z8;J%tlL{h6!sfY@8<qcx7VFcfD<y0K}&$+oVOCY+e?<YAAE zPFEm4p72`0HUW=@v!mx&mz&Zy#3k?T5ok{aOfkq2;A~Elf07DEY8GM*r19qGcC>(% z{Z1dPeeIrOcdkG^8R*WOeUc7Kj6=I}G@0rew0HEb?S7WbeWKNA&Y~QxsKi&@D31S9 zQ=)%lY4>bOAYk!QoLjFk5!AVTi8$@r18jji1edWUig{(XUPU}ZFIPo|r?}abm-SwY zMAxGk@>-5es>lA_StshnDi!uKieS=cZJS!OMq&;MWs-W2+fmcx{TVQ(P(Dp?Z+prb zB+6pVO^I-iR(G9y1o!jm9qU`mT0`@5BpG!m`T=VRpByQ<{n|^k_mROPv4vD0vtr_M zs=WsGtqXH<M`9x`_7ZV7>+<*Wmm{|VYu=zRoYW<sU}=1AGw*`1Bf00z4tO3~k+y@p zmavXBWgH|8(5oBYO8sIc%?h?M1edb(Z+`i~X=pG=jn0`~`|CGQB+BN5+g3CObU7{$ z36uajXl?>P&S-bnYR&aeD1&H1&KYqL&W7bG@Ij8gq3{6P0pnSy>XHKzN<H|p1C%!i zK%jQFjeDa~WWHZsbHUxWiC%6VJz)z0J_St}+lvE6owcj<)DT@UC!EaXD_>)*fIe2n zMb>2AT>g|Vq-uuYtF##ib8Ki(=jp6DmlIC0ck9c89Epv40MqlmRb7aS`aLV?!m~8; zIWGvx@>4kg(v^@NL)`v@O5(2okp%IL)_*2;9+o)O=bz%-TYrdrVX3fulorOF|EL*5 z@ALNIY2Xplo3$+8y~ts{{R955WO7JFM0*%zvvKPO8WNVXkq}qGa4mc@Cl<}bA-D?< zB=yNp%f%L|MOO$9hh`-AC=(Oox#yfo{C(#S0ib6*qL;YCA(or6$1xD4M8Q$;`-->p z_*?Fq$}aEhYN4UtN=sSIFRYp+<i#f0xQGmAK&~`v62I2X0h%<?g~GQ2pY>Um7|(*z z4pqf0;kc=$`7X+|sbYIrxisXds)b!?s$%jbWuw-o)QwNm8O3~X_``=J`pVbD9W}Ni z!;HR9a&eSkUC5vPGr`IZV`DKehSuU2|ApnK;BnYv$*>*9Ma6;BQT=hXU&=-L9?4*H zrzV*$_o{CS$VYG~?4c7ufAs`adg7x6f~<t?SS@+8+jB-PzQ(gt#4324T)RqeEJbCw zPG}ZPY|o959>J;HA$N;t<JWrVZq+qC7fXZon%KHPqFS(U!9HtXVHE2Vu8qrm!Ahb} z?vh=s88!W@K6v+e6DkXFL?2O6o3p~SQF!wKQVZ>VJ<8c5+H>M?GoTA6sdC1CU=o}1 z@2}l@>ee<upyNr9c(B^G4+iEs$}8<Kgg|xIhZKBPiLzG+TuD6mo(|c$0&pBY;22gF zyES{0wk+;r=2fbT^B)6Vnj}f)L6Qo+*%$=2{)wkoH%qTZ=T-_LmEZ=B!<vk&8-)_j zyFr}Kj=UUky2?L81wKoM38wRsX_l(%W}-~LW<IFq<9?JaJfx=B>YQlIeN4Wq)Zb7Q z@4Y<YwmxDbanB7AcMa~nS;N>EYA5H%FKl8|3^H#RD1QAwko#E6c$pQB{F$he*Pp;5 zt$ND8(aRABC=;V<Qq5j`Kn+thDyJO#X!53=J@J2Euvc6sn@{TfPt^l#-fo9KQ9PSd z7J2e(5Eb=#%UYbFf}$AQ-(e=8#Q8!*3`5Yi^J$CNLDs9_2k!CnL!T&i$39q~*3Gvc z-!HI<14e|lc^J$AxuficUmq<FgxA&I%2(s_SLJ8(VPcw_8EDr><4mhxm1fsU-FmSN zEW5_-*kO1w;p`T8k}SVyK(#|GDnWNzzB%4Y;CL1JAT8=v=zj4u-n7>EX?5SLU6-d> z+Y9`U2WW9)8tr+vNnCxK{dxMVAEm~3{D{+mtv1D1zctzPGACOf#Itx4N2-5vP+x#c zQcc+_6J<eqS$S?57Qz^23#OAewOcuiE9r&Q{^*<aOu}G3z@JKHyHxV>g2gN1<aa3a zB&u-FZt;MpEo};FA8N-4n3Gqcu>yaL5rk47ZHN~5oq7ui12{Sur}VkyR{&beL;h>0 z%=H01w+jt7e#|gbm+Dd0pXI*tuSd_&3;&&lr8p9J9<kpBBpeFc+WR_*fa?WV4#J?- zM4y2&&<wRb*pQWY$gbN;b--6Mm<{+@y7;|Xkinz0{z%XO&{W~shu!{&Jdy^Yxc02U zW%PLnH#WQjpdgl_v<?U|l2)R%tW<2))$2N3T47-DyNS3rB7w|Z!Pa1(iuF#f3B;B$ zt-`xBmZ;*85#%4@;o<5?S<e;qFFg;#t}M;J#Ooy5xjzm4`tZ@vXVewz)+Zy@uDiF0 zGO5(_@1?Pp23Nx1a3t}~jwo$g12WNR9j>JK>vsl%RD^|Q)+iG@YzS2}|8CAOoS*O6 zic=0oo_XdF#r9u*gUtsK68?%LE$RneVjoDT;e}wgGR}<`h-t_lhlc00y?0ANK3LuK zF;1}VIFB9U0!s&x1#C+~wMB}}eLMF0k%FH7V<Ff_>iiL7;yljL$|_!NXoO}Bpyp0; z&fLDOisR%ImOQe;(cS9sXB79;ZC&ZeaKkS(J<%UH7|zp;M+{$=C-SpfcE#yKv0G9y zG2|VrrDhRK#PaUbs!UPUdxb2?UNalCXXu%OJTuaLtf0CJmfZZo%2{5rH`VvUryKld z2v-0T!^$lP)C7Z~h4x9e8TQ_7O4+e2e>OW`=!G!M)hp$H1E$K|`4D3+@N?XT>hrKO zJuUuq$sCtA#a8on?%G?61>|6s);y!}dXw7VEeg=ni{4`~87IPdv{wCFU`HND2WWPU z#R(^bK_UMe%j#VRyeiMR+CZ#FEI(;ruNZB;CzY_u2Ji=ruH*;3{wzOc7kaosN4{dZ z(*3WBXD)t$7EdMLYM88E0M~qzrdxLjD=GT|^^A5p1PIS5*omDup2wx#jd)$h?7Zs^ zb!1_~JW!X)JgF{r-t#(tabR*jc40!2CR{?`aVgdmhO&0yixw0Lueq%SBI?KHpamf2 z(Wi_VciG6ROnH*@xwlzG@`vVbX}gJ_WMkg=Qz)$hmj(=zy8SCoR+cbDVygPr6*y9? z#AGxTp(%ZmSX|O&^}a+kQSL3La2t|~PBh;5*JFz*GDnv2;(>ys$gGpV7fGWy_+5ko zX)ws6`WQtvPR%7HUV&U$+{@}X1dOe&V3svXeBaJJN#K`q4EQFVi;G-bLA%oK6Kag3 z#5Xa&<8IcjGbuA2{R;Q$pPe_#O#!PEwV2N|qF<Isp-Q7MPazV*njcr<;96-#aEHdG z;`X!vk)rvdljGj2<_kO~r!4d#wseh2B%-WGyvs`rwj|CM>~6vV*X#jC&z41R<fQvB zGk@#C8~*l=!3y*EZ&uZ~rp}XFJGzVW^v71<u3&3Vay*lX(Y)h4qph@pPyFb2vpB4_ zCYR!St*;vuwgi@(fGU<S(2r5`&**NHx?AwQR-h7*WbRGgN;Of}@YBYxE?KiT$T+KD ztpj_=ZL#}?L_*j4|Izf_(QrP_*GhyCOFp8;BGFqUN|Z&2Nc6s|i@thibwWhch!!P! zU%jv1d+%-a7HxH+zt8u)=jT7?V0m`T+<WKFOkelPRlni0HpII%v+t4HPLZs9=7X;n zNe~+zYp(mJ(USC`G_k87oSNA4O{#G^bC#ez;R44_@E{JLVD@&`L|&62$|8efRn!6o z|GWf7lcGAoZd(A)r_-F4a2j$dodab{;D_x2^q<2Q2qoFdEK-sk^}%;1&K2wpGb(G5 z*;({KkZ_{P<}kOPsH}Z-d6Qd~DzDXvw+AU&5<Ms|q;qw%3KCI%y79}gtNb32vhc8w z1xg>pU!7-=Y4D0jl+d<xZ`q-rzq{sg$z}xBj!uWOzBnl(%cmsEdSOGAFz!h^JJ~xN zTi;^O8u<x$QKy)b)*RfAuH+YI$Mj1vbBSCkrymUYe~)EU1iTgDywyj3jB3~q+7x!B ziCJpEhFA*CMTHR}^e9tLxd;Y_tLVJ!c?14?K}8=RO0Z*Ew$%A4b~0FRLXTc!C!IEf zF(jPel)*IO8JLzs_Lum_qqL#Pr=rx<<`JYR?<m0WIe%qIGNif$Y~O5bn@%Q03KT#A z1NA>%zF+?#&F<nX-c%l{s~r+#s~-iXNn3F-&Wn?(>%AnR>Kn`Jm81iO|A}t@l$7Z= z;?xt<XIku#x{^3-roC=p?qi!(u@(3*T%<`iOD8|iWG;0V3^L|8Jyywl3ZE9BYIIM@ zPNM#5{g|(U`qhs25`I<7{+5!J4pNKvx}Szqu2Ma*|I~D}YlW!N`4Roj<gd)Zz!b3z z(VyWb=I{9+N#e^w7v`EOI*C4#TAH7FzWcD#iZN5MG)<TsIGUCcFT8t9<X&^d(E&D? zU}uTKiby03&<apq!(Ia+-|BFONgsBC&55I$JIt4#PaBd(pcpIf*;79>v|j=ftRkaX z4#C^(J0CT=fgfO6pz`l4gP7UnVGyM8CqZ;w$!tg0sg<Ss#B>6A`3LI2?fpBo?~q0c z8+=qP`<piNj3r$c(I=fd8vwO?yfiz?D~-^~+9=O8Hd+IT1DWrJ(dkw!{(n}M^b>Fb zVAb4mZT(b2t<^%0NxxGJ^#Q~Qq!X7~fN!xmi@LClyYv*vCq~hof;Ul?M>ZUt?V9~4 zX8jQ9vT&6Op|F^K1A2uNz95+-!c9{4xSa?w0QoK1OeZk4{Q4EX5yQ(7GuEl$J%CxD z*4{ME2q2IYo2XMzG~b>^E4;?MBDi!{-Hm^CyrE$(=$d=4{pR3`QHIr`_sqg7Red-% zISC)k_%zk}Q|?@0tAD7@34k;7ZbfqmqtrgjDSpbK=2i%Sy6p}5e12k=cOuN<Yd8Kw z?IBG%NZ4-fZ`d$bmg&Zfd6|D#TKKz|($t8q3jFBHbV(XUSz0Nin3)eAW9>$A<$ZVX zn-}?SaegE9*w<x`@dBQyk5D}|p62M1oFxi~6~dU!2ULWI%+S}3-E$#D9ra|cUTT%C zx7QPmn<Zc~x*NJAQEQk(Z8+5peCzZmoQn6IB_WER<Hjd9I>{u=CdW-I<H|J}nD+d= ze$*rmlVXckvT2<5*BO_wjtGA;+_|MzDMP5d>ork))b_5&zoxc`6)*6WwuJJi{fi;t zVSxj_ApbG=n@UGBpQ%}*P;A~c(BmgD+HLi`KYwoboGRf-0YRl;&S$v>f|!W6h<$!e z4@fW8wqT+AY<@C?ie6u+9Z3Krza}0Ps6_18r%LG6CnJNFWbL;8YJGpY0(xKR`1x_b z|I|q1s1JbW>93aOZ9WM8BD#uYp0D)D%<0ut!VqIl<aWa)XJCYHFwis6&TU1=pxd}8 zQvfeQ8^iY=;qtT*V*KUtR3HIT^E=|3{SI+eOBrz<^psSas>4)9nn##-yCl=IF^AgH z{w;QV>E-aRUG}{(qeLjK&|<s*Yh7Q(9L-JLoBE#2H=hKwp8{LZi3;>^uuu3bi~fp5 zv-U>LX5*UmM~*0BCE!I|7(NL|_%LETp&;#9;_dGsHI|Ubm`n&?vf&zDqYqT0s5*6) z^^*-up!uiKaQv8+J`rt9vBa18XI+L6L>!SkWcCr5DITL3r`~bNmNd)_bk&I*=WYLU z{#aqt+$5iW^pSNqjc2MYx?<hQ{F&CR0=3oQ9x!%%cXwwju4US1qoq9^dZ?@<P<^j0 zA?E=_ZkJ_HUL8m3ydaG_wQCTddWy+ZEgJ#7|J|J|ow>1J$ri1x>x3c}p=vu@O3(T* z+`O0WP4zY|jkmxXRssbsmljFo#qSk!t@rG6fj_*9Hu*w?)ZtZk&?xsD$0eXRog;Aj zJ9+8Z)Nr9DXL4GWD?v<R>U8sjZbH`7P1x(u{i*E(d!s}>(+d|~f|zP1gWyPUr$v=& zD?dNK;*eKn{jxX1b%v4<v#Gk=n1FU)fyeAm>4YVE>jgg#Xjcu3G{z2^^AM-%c7lcP z+3DK-u^jP7UZ(xDdDOfAc`ee$Tp#G_|1gUB!Eg3BG#?Fr3N-zuFL1IJGy=`GmfLjG zF7F?ndS^2Z44PA8j+{vmq!4C|A;Y(?WNRRiCBT3;NbYywi|PR3_3Zni0;%7dSIDlP zULK&;UPgUoBK+*oWcH=RYc<lP8*ndCVKHC~e}0HJexsGx&eG>8Yc}2qeyU{})oWt3 z-HGam)h!Xj<Y|~yGAg6XYinz}GhcSUCq$q(2TA|AXHv-;!!1vac{c|S`4)%24!&L% zXR9RO3VS#;WR)=H7h%LaVpH(B=1Y{WsA9_+1LWV)${CP)@tpsUVPGCVUb?s!e=uU? zDd|N1po{|@Dx(0@hS#a{<i$XCMA?H}fCELl8J`44R}@@!J7Ek$<0$gWn*>K8(1C;6 zQU9cM8~YP!H-g!fH^OI}WKQi9`~1);oS3jk}e$U#fJ0Uwm1h!CI$l<@~I_FO6bj z3(Uk>8@Tv*lQO9vv1JpheiFTL|L1Tbsbu9(LRtD{cSJprc?R4Nz<1p-d>k7#=o!9| z8Y7kR%b5l~jrGRlcgn7Z46l>ChdGTYy^M`qlB+0}LEaC7hDEYBWM^+zVzo8ish(HD z9l7_&s161|7aBvxk6tG~g%3T>auoF@-YsV8(|JzUo0yWrLE&|s9g{2|;zCMgsr)(E zdj5<Azj{!|5Q~-FYHlx}Kgj0eUiH+D3!zukSHVxl9)3SbX5>P_qvofyrs@6+QBEig zyMBu|J67J5emu*}Km?JB`%Tm5hVvgkx@_I<0*l)NJbpP&L%7sZM99pw#${hCELtq& zFBJfJsI*x>^(}o2fi!*|0F)?7x7-9H2E4b@po#;$7lJI9Bi}RU>~uA1jLg@lo7Ko{ zh`MBCP3X-JxLSV&kmHWpE)COu17&l@qJJOm@rk49moXqe{Q6n|wD;UoneL_zyZC<d zx5rKck+RWL@vySp2KN1*H%0F0XITmJh$n*Bj126G)>5+Kv{#+~n-7Etu)f=)(&AaS z%UHBS6w6n}smVaH5D9YP;Vv;-vJ&QmlDT4b8K^b&oy%88J<Tt<)jg{~xh0g>D58 z!Dd3D>Z_IY!+&*DbK992``pCw5n>(<eM5Q2M$fp3niBMnyecU|)!KpdanCgK<FEtg zD3&-UFm95BVoZ%Wl8~t>Mhkk4dgT+uWY2-0-)Z8kNlHiBZohI7f3CUC_>9whQUe zsXrSZdOzd?ZsOzE0J3bta(2qLH(`|n7xa=o9Px7$i4TMM$gHBuxgwQH<6nLkdoojR zmj#JZ)x|{`V!RG=DSWjL@#)s);!>);T$Z#(;wmy|882>SSpO)!B60I&Vb9Bc`YcK@ zZz2=>g_$XtQ2El2b5%XR>@&wNN8ZPt3<BZlzhW8O99i`liHfOX8RDi|dPK5qXk<ev zcDUv^ISa=2Tbwn(&&gkDzhAF2e)scK8U9O~W%}zg!wQC!!}tRn3(c5U{o-`q%HwrZ zZ0l5xkyNtE=wD)sKshQP=y5&+vW9!tidatwD$r?i{a6dw9<SAqyZTQw-GU(H8o<KS ze^rpee9_d!;)Dp5@mnCh)Fe}H0d|zVf&}K5x?i80tb-och_d*8647{CMT&3`2b=`B zM+~SyjmC<kTA-1v(Fs&Evop(ii`3sPZrXfGtltv(fnr(;AaqOJa6H>uF`n!gFSIP& zWF@ld?KEMom7d5!C+=kjxD#!YR0rehkcu6~nz)*aVG5(SbU@Aa%?&^Pq(?Q^__{hr z9X9d3FWNi2*K4&*D1vD5#Sdw7YU*rfNxbKNB@yXywoYUftE6IXuiw1D887KKE#~9> zJD@7hVf&V2kWI0FxjZV~dw6me&d-ue=-CW-Hx-@$_tbX}6*~ik8-Cx2u?;0%j!4Bm zJE&Nq-UvHs<*-ie*=AIX3^u@FcG3c-sYzt%J+s*y#CWF^Nt1rP2zZAaoI7HzO=E~K z>A8M;L1MJZ!#LAtuN>j|;>CCzRmLE{P^C+_DRZx3RHg!zzf0LZvs7zqN1!yuGTEK& zS8m6?zyae|K`^%Y813S~a5pu9%;??2v0G`MBVAubNd~8+|E{Bjs92`hP->SBHx5H> z$oSP}S)PF@w&7(BV`WXeO!{tv=_k*R?x?-K^1uwW`tv=<cU{!a3NLbcCS@BtP)G_6 zhn1s?i<DNUiq!^lJYl8W?+eypO*qrAg1AwbzC*f47hXY(2z21iEzKHJR{|%)75lo+ zRG7L+ou%idcvUnz9kM87t%p=gK2_%Bx}bw}Y}RcFLq(<pX3o0)8dM&mQph16;?`Z2 z`p;d}-aGj!X&V((&o~6f`8fs$4Xj4GS$AQLA5mmAZLLLKtM!E+(`u=vBXt*U<TEdt z)HH(al~7Xb*Ihbckra`otC6Zt!f^M$yKVJ8Qt0<^4Bo8~Z&?GyxgESa1i#LuL<lJ{ zV2<|PNid{oA&@@<MNSFQ6=WC(x@{Uv{+sVln#48LdO{&OlYEca6A$kiDG{;LI(VI8 zMBM*n>xDt8^tDA#eQwWZzWnY}_*y;Z#YtXcvDc`VsK+cHM|@72Ph=_llZ6Wx=LPM} z+0I1Je}PHpQ(a5fwhpPl*X%UrodMaPH~kMWY8fBK1ES6-1O2P8JVJEO<YA)On``wF zkoOt}+ZedS#LD(*&AF8u_sC*k*WSsc0GO{JMrx-zZLm&3A*prpXRBM;42CpYPE{ZR z>Dh-h{x74xLNi6)2zSQie4JCciEv+HWN~q^%RetL6oEkS5Iz#vbV(ts;0V%Bf2rRp zRw|sfa=$UI>(S)~+b<&AqK!WIlN_5mP8d#^b#-=aJF+lc<H<Fmjf`^v&t#>FyM2sJ zsvcFxKMG(cSv9aP)L8f&kc{)5tjP^R@!~O3B*FSs&H0AjC;UZ7l{iE8amItX$NtFs zhsHW!BTIsh2zFoBG1*W~rALaq<8;Ssg$NDJVnJ*QLw5?ovUe?p@PUp-V=xPAfZKA% zz1Q<T3OuD1MI#DayF<1A^8zf_P5DK9=5$=bfhqpprn74-=d2YPd;ROi?r^d_H13cC zxaP%$IV!3W@g@c)k<~oPP#xRL+EL^J$|xzXN7NuU^Zfuj`dR|-c5v!vLh?FFisa>X zaQ8YHMyt_>2QxZzNP~&Wr~pYgeh$(Jg(x{S2k1KnKdv3WM*0e01oE$tVU9%qQguB+ zaDg<i3d|eb*ux;xP_kP}gvQGfR2D}l%VCy32;qHwwi8s5h3Y^#w}YFV#W<90g1T9V zJfJGBwq7L*)jmc^+EQ5}Cbd>us|Vi&9BeCL^C<FEU**kPPcdB==+nXtv%**X_OREZ zl;c*D0^2%6SjDjgg|=l{x%TOkZ^rlDjXC}s@n^*=k{In6k=tt4RdmAtkz5qJK5rE= zqDPn(8|8^h@I!$Bk115i1tcr?JCmrGg&NgQDR?C^^d|N(!-H!-9qa+Zw(F(RtR-QK z7~?pxWUKogdanMT5Q_B^u~pX+Zq<Ru&J(o|r9Wp)g2I>Mq<H#Z3q9y)`nHkkIjYz) zu%%IlhyvvOJ83h?kvJJ0Pci+@cLy)0|L+$jK~F3Ty9JhK2g6j>`oN761;|{nso<}Z zC62o}yUgVU;~4XT0}Z5awsAsw`rZO&$CAhPXSf0Sb;YaacoX6`-JkFvFzh0Y>x*x3 z!^Kzj%gtiyFN(!s9H=Vx^(uaT$rcGz>#*r?-J_WgaJ`&xh+xHG1*z(J5zW)2L7^fZ z(&NDy{CvVt)|GoY^r}Hk`Wjk2#<#TR&@nfsqJe^gyV;-ve10yx3Tmt8h;kDSh3w1B z8b#6VRdd;Ce{{?>y=gWU?asGGWyyI$Wgx4OA<lXo;F6sghtFc|qEZ|qw=|d|E_O`* zkIy+<ijm5wb<=+9XL5~WuU2(Y9c#a~m1e3^ZM(pP3C|H)8X`lfDFE6k4M>y@;8>no zGYcs>&Ow<3b&3HC0Jkoe{oeNjXEM}%JxTmrdy4--<F%<r9ZPD{2if!)27U;1+Z5K% zwIo|yzVX<E{VH~PPB8aMU7+*A>8l@crT5%p%N?zyTI&1}MUDh4%_&lkY`I(Er}oLp z>2}iQQ?)1kP((pxol_eJ1@T6b4fP`p>tFVIc;WwhrkdIq4939!D_->%zq|9ftlo67 z(7x7FWH-(?F?main@j9C78}@4R_=!LS6vmpc-AqI!)6uhrvhK++KgXJ8=5A2e^u6o za<cEPKzcnhWfGt2P&?80+fowr#gQ{v`?Dla<Mo0H8HyIk?tY3KvRae{6s_iWJ#LFO z%-=I8sfm>^>0T;s#yTfR%-)S|gI#kOaIL<j+rM{p;#o#(3(ZtXHLKk<lI*<6LoiUK z{#3injBY>Qp7)~rth-7s&7`0-KSn*8Tx78g(m5CG;~&=YE@1t((sT8!K#k=%RBgXW z>!|Fev`6Q?t|T7zIIy1bdOz4$pmA^f(GZiqXR-JPfr94=`&VdS_tOt752YgAohy5V z6Ys@lS6f1v+IaN)gZxkk7e7I(h7wXaIC`kG*m5L9EnOL9;`m87n8sbVXou8~Sb2dt zy5yV!^F~-?s4t|T$omBxJ#nK13=pt~{?mHoNrVs;7dKGJzgEDz99{-OVQ*v`_E2Yy zlF}3I-v>Tjnj2jMHPGPhu*{6(SSNY5gDHY@&i#NiazztQ;6BZs_65D_gSxPJCnHc= ze!TYCv1d4B*sD}#{!xoU00n&~n5A1ygGYpKT}#B&1K^o&e_#T9Jw5A>DrSFI;btl5 zZJHm1?i*Go)sLha+-w<N9Lh<-FtGbH=XaoY1ytsr*m-pOC8xx#Qklw-96!DyxUCn~ z>~isfV*W$>Ujfg}^YrR;JIqVdV0wS~(b>htMNo3xA`aZ=(PjT}U0wEP@2iu|4~w>v zSI5W4)KoAN??d+|VZkwd!I$chD5%q>_yNHIH4mF?%Dgij&vJ(}BXT%a<9bFwzs{gQ z@I(rNMjMF;H?g$2UJ1BA9CeV4+;p0@oiEDWNt_2{pTcs?7MGXb)0<}XSy1dI)fg9s z!=?FaF6im#UUTpv;eEIiKZ<oQZF|@@U5hw@fvq$v)NJ@T*}eJAj1P0);AzKaXD%5w z**3LPB5A*+#tNS!#B}QfEsuRX+_kUbesT|)9XhRiA))^I&pgM?wt0d14eM@sUw!n* zFpC|xEis`|#9WRt^r@u!lqYxG<IUSv<KcS+lEhHae^+to^kOzx%OA8GX59MS-mwK) z<IOwQNUgX<XWPoM>V?OZm~ChCL94}QMU$liC?*v6p}5sC$f{yT>n^43Z3VR)F3l%{ z#_Q9egZ@78hRcbX(v+bPemM$66;al;Va$fxyxuYZhR82cKKEC?Q11kDzxn~;kFW{y zwmuX?Wu1OO^4E~PQ_UUrj`iL5X!3%ct!;Rn(qL3rnznbQ7oH&Y4ag(PNB!EtDW~Tt zOTZclrcjEIcMf0BM%WJj^w35KMWetJL>OL)rDO2%WM`F&%iFR_4k*=ggiw{eHyMJ; zD-5z99twF*6XSW;4(|@qXIHUzN>)>{25ZP8*dFw#)j4^+X0Ht<JA05{Tc_LBL?UL^ zx024RIk64$`lZcBSRbA=NP%VeviMgflO<l~49^p}bA&(nkMox;-lrbhyZ0PnS|m?! zbBKof<F>Mfh2wmoOV+x3M6VwA)=*eKhKJ2?<Vy}Sc^#blOiNhd+Ih6)h*gI&HJNm@ z4?El)_s~-&*YYRPq`~wp_Xa3hY>%y9pNzjE-g=B0{xw%{<gDO(ZhL~IX4+<jgqlL$ z5X$fCYcytwQ+3B&v)hi$w2r>c3(SRJX=tFG|8sG<$bZgNpfql!0gvf^iB}lMzrNU) zQ1&Sq`Tgql5`La1a=dl^aW{OB<o)f@Q`1K}oG^E`_=>$d;Dl6tk<5=u>^OKeTg7(m z9VW@9wjqVW#6&XmNq%s}CC@>x@h7~e(@hjB2!GhSj-|9EJ`SG5TMQ!SEn(<Qqe46S zg*a~EeX$l#O;Qxm8C0%necj`YDo)s2UM#NYDlK?B^GZC(l^DUMR*|L)AEkbgc50l$ z6+%PT@*TqU;Yt|F<V}Ros;0!PW?W)gZ$e2KdI4YjbfwX;Kq|tT6}_5d8|-wbAMPBj zF1`w~EM;~5OvL2-0K^D5ggg|&F#|-2TkCBRxt|hH#=cFKcaz*@UO;XzVw^<FYmpOr zIX5L0d*k-XjL#mpG5Mb5v1eo$s%fv6ScWPF%x#jHctp4+l&-?%Gz{~PiybqF3bA{; zUjH86kRyz+9b|dkf5d%M6QFxvd%1r3o9Ok=s@r|o7utIo^0v^izj8EW+Rw&WKfSht zP~+UfRvtw=(Z%%^J6FB1oY}`pC*Ri}L4K(b7m#o^__*ytVsh0As`GFdXgYZMgCD!p z&w8RmsX*&+aYR!`P283w%E{sUtgP6&a7My1dVXURSCQMxj72P}P{}2eaWc`J7S4GO zn}Bfry$wqDyo4i^CAis^o!tnu`C7%ZSf-%4I}Rn-^>OFw(a@k==z&P^`pqc4>0yVd z^eXPo`(fC=*ZGI&08icy8(K9v#O3@;O|tX=z2)NAXwWW9x=g=AE-@a?-PCGzHeEiR z1-nQ8W{DqPlM9349ekW|EcqCk(r<b56kc8PCHsR->1;8Z^c+=YUT<I6htOz-kM<OY zeN+Z*DL&n@|7qi~Y$K<KR2;JSUSQboIJ{@n8bq?vQ9-~zzphAXnnN%cwFV+81KwWk zFP?6WJ+dFARlm_ZSlXZ>*Du#V)Nc;@wf<UWvSYOH&%Z(B8YmF%O0rkgF)uM?y_*L4 zi_#Il&x6=cyCduH&QrEo(Jv#$eaf4POC!4yLK)Z`m@6~>TMxyq@)Dg-40=Tr!`(Yw zsOZol#2qO<MB5Ssd0yfH1YPU0Q2+GsLmJBD@~qVFZg1-|ZUJU4=VQ@-YzLpPOm0vI zW3c>BV<(l<yM_1lP|mAjC*4B~CRKReS{NxYE~!shb{5#v(-Zdcjypd%I5<ptzqRIt z=ZIy?<@w%BScg`GT>*(RqPeN5DZSX{yIER`RA*~uHgaans*~b-@P04}eQF`oLa(CI zqG*o0&7y+6-(uic^#;4Vz)8}KEj88bVF?(+H|L!8Uow76oLbC4k_uGUuhASE8j<>l zJg$Itg~nphAuCi926th?NFbxLt>x{Bcd{3?aTYgg?F7G6Qq(Md&&$gTOH8`vMcu!f zDDxK%(e|6csPBA*rPP#A+<v-=p(#JF`PiDE(zil9v%It<j%Wky3niOx<P{g`oRp+^ zo@~B`HX^Nl$K{Q2Q2ayi^!v=$%^|{@oq=~SJh#<EdQ@`YxM*+J2EWtYXlA;@d}^3E zcL9-Sr?#DZMmIO#*wW&MX_c?eKS^8?RLib$`{T8sb9;Mr8rI<$oOydhu25r8(;^pK z!B*zAtP?Z+SGx-Fg-k65e}`^!SN`-GAg*bbB~$V~ihqb)n_F87oo0tWLkPylDGoWx zj!#G4zc1v9Tz!N6{jO0?)vMXdj$4PotqXj2N`}doi`haNld&gr(#TnR5F=0&R<BW& z+W>^Ds|P3*i*!K8u$(x6bOvwtpDyq@!iMHTi+L<FbSIL&Xhymp`l7n|U~+Q;=$8rA zZ0o1<4>uq)iNA{P&<x~SX{p2L1K~kdi?=@iO|O9z-JqtEqpo|<(Cs%NXBYaX4#7cO zVn*3FKqV3f0)9VV?TfO$Wm80r;DHJSVm1Ub+j&udG9ipu1HrG{d|!LaHQWJzjD0Hb zacH!BygBfDds`2^%7saNxQInb5&a<a7e$zNzoqprJIQ<UTl7%u8?m9zvk4QEG}}#S z2Q(g=gezHLnNi#a5{hl#qI+S2!&e1M4<+YJL2U0)fw6cUpq4$)g_pCoRWZ)?n>5NN zep6?HRFD|HC`QW5ot+)wC~d_r#ul|^m+Xq|)=|H?zG&c<b1M~Mfr1VbT@6Q&;m_GD z8KLboZ+tvGJ(mo{UqIf&p5niTcUryhc;V&JOT4Bd%WnH=)Hxc@jjhQ=u>n6WS%1YX zRdUCe<S%nbiC<xaV(29tT0HOiSO4YRr(kPvM=`JPj}k7koEH&9Fm~4$OJ5mt92sN` zGbL@{439~R>8u~4KFVTc{x=e0l^*E6;}6Z}EdEF+-{gp7ut5JZm=iJ<l<0Ata&V&u zSx|ff4K`@*`wQb1xCcC^C~$yMEEwpwo4P9VZ8niHAN_9BEw0+*`SF5)*1ammXxq$s zI^g?aJ56p4=}HsysvP$UmsI}WMNy4lZC=gDrL#|}S4+w!e~HCYlvw>E$DlA|_|ED? zWRpI1gPZ`=Rk0xrfO92lAkJyn5v3qnGsgkr`zHh7UgUIKbiF7QiF8zlHrd<Is*Y~` z@;=OGw2@;Q-?&}!h%|cjsNtsV6otxq#nS~Q|IZ??-paYUZMG;7)q%4`=r1Q@eNgr& zlP_T{GDdS|`b+?AWK#ze%=u6VvXd1<^^OfgWq?tbyy({W+y&+(nzr?HcSp5?4T4Ru zyTHx0K6!F(DJB&^n#5jWv{oOOEOM%Vn*Fw|?)SXO4~X39Ys?#^FQbDTX_^8dNnLRx zxh6L3q>sBmO(YvS1xt#rN%s#Cr2nG;wBvEYHWK9l@Gu?qdb2vOf4Z>&u7%kg+E1eQ zc6F{qOC?E-bGjwroTlSOx75-Uk3cxD^^NgTmu6C1;+i;g3Puj~BE1a+XD}J$A2=5l zvT?+S@tVvF)t1r-?QqDj9X<A8wl;M-#3f1JFS*5(LL-7dS`v=iWf#q1zmasH8h1P9 zpj2}ZxlysZ5OHBG_9e-Ny8W?qYPyb8Hm?VbXfDks#t!q$3V^{y_X4msijT#ioc=~! zQRdLy?&yC`(?0ag4gK;&<2gYEG+7&kvi`wV1=O(BM@9k3)&|r*-Qzk%PV*tLuvbSX zUN<)SBXnnBW8}~Bc_VJrtfKnnFv^4>XHv{t4dO(G*;iM3oWj<s?b$QuI*#OUp+{~= zW;qDo_d>1OJ$-y5e}xY5As*{SxMW5p8+4gWg*^vZWu;i&1c%<~c)Q#ssCdET$T=~y zr^2g|2Vi!~9G9u&tmpv>T@C-|h`)2kbZAw%LOK&dWaD?p^jkL9$;=XtUn~QP9~4Tu zn3G<{H|wCs5^2BMh`D8-MF^YxY8B#kZAN8v#jZsTV_+0l-youu*~bs8Ktb~XP*DPh z&Jhj9;@4PWBLz_>m_k5jlnYa)!Y@7a@ECE%rOrMqB#Jg_2Z)+Vi|{x1LO$~zQ*$Eo z*4CAV&_7rQOhox^i1Srf{1SHE6mi{O@e5v7_OHDv$9212d<~Uqea(Lr29DNu(1CVX zWvJzf#CpvVO>1;jtbGyw6xblCV<i>WB+9j@b<+s7(;zJ;pU3UN;%CryZh=MO;n4K$ zy!W6J68aNO-n8x5mfocyP3iw5pdsydp{{`f$MD9G}%_06juBo5AH71nCYfO$bG& z7p-e0qTHgNyM6g9)FJ?f4-sCMOq8Jip&NM2l&lS)@1NZf@$<Z3E3`Q;8NzLR@=ZS~ z=^qVc|0&|=NW(Q+&4@QEVA1m5lF*icnuzmE{cDRj&qo%!TQd<0iSa%o7UFveA|DON zbR#67g1lqkl%Df~q8s03BmEqRa`X-oe+O(XU2QiWF$P|m7OHX_l{A1yYdooP*1`rA zWP#d|xpREhH#v9=+hVsMX2qNwt&fF2!rQS}orS^ec|vZ{r}n(to)uxGt>N$l|K%&e zuT9&?j?uV)bFbQ(n$I;`MRv7Bha#FAZN}OSwXEoJz7C&lbgV4$c`_MB$YZAoA3<Pc zMihIU_g`kerrJ+*TKC6G|DX`^=hlC20qp!e053NM??&4sr*f1VM2--`-9#G@QO-XT z5;PqfW70yuj2Bu39e_$!K~wcgC=+l#AS8Z(BbJT3bWtXU|Gq&)@&P<e@d0^#lPYj9 zXP~}7hEd7<B2tF*p<uqdWgY+sM8|+>?g6jlHR#TK2;5mE!XRLK&n!}n*~T0meo3&X z&)5^0UwsK@)(|=NOv;z}To%y$QN})&BRFo!DA%$}vzjuFec#-63;xi&Y~7$(VBMCq z;zYFZQCszSs|T4!y`spbjPL#JRc5^zkvjd$!gyC+O06fEE)ms8^Gu^2yFDq=H-tZ4 z;njSe5?ID&dYDQ_Du*0ay3pwd5_{r`u{=vz-`T!oIPf<i?t&c@AHLV2efHp%jyZ zDrQkl2G|w+gd~r#<sd3@L_|0Z%Ebmd1*X-`hmQV^qKkL?&84SLZXy9VM>%DVz18<f zIm$0OqU2;8bNTy=uSdzg8`f0E(6E0+6`jS@JiWeQtWv=vH)+w%Y&x##*NNx`XOwSw zjtfN6aNQHn;IRs2p^`rR4s&rpQg6Pu$>yS#<*#B6FQ_7N3>n1F858GUy?(f_!;YfR z-`H=^%yzOX=IYj}21^KHYpa=2_Ld|XsK92Gac3!H6iitJZCPz!AM46Pf?2=3jw%}Y z2HlL2kazrC;9n91`eFZGI8F1HKd@huawId<rArFH#l`=0pmiuI1`eo-?Cp$0Paow+ zOLr5fW6zqLqCqg^78E2{KMhFA{aFy}4ZV};uyjA`ySy~tdJmwUL><;-X_Ax!LJuSG zt@S^l?3@^tO@)ir`ujCd%gD!$j~0C<5c}bGbtF(TT6J0b^u+~2y_5!<nF{wjxI5&Y zMRAyv5>b^r^BT>*6k4o=TIc68m%Ib^3*rjEdhkUxD5I=3x3wTRH)@rw;=MlG@1m{V z+nGxuNWASQ=ZNtS_f%S>`VHUtFVxhzRF6l=@tvAI*;3fLh_?P~KE3DTK3fD?dlO5j z_`)i7m<gIL<#}Qy7{%6GFqx-~3QR+G%(6#akDE>b?K(+vc21aWvb~{B|GaE~qhVWm z_VLnE3h1xXS6k;K87kWS&?mky%ei`Ofyyd{7zfDnJiFckLYx0sRM1h@IcDbuH1>70 z`ykea+`aPje;*6o6qlaPTHR@u`n{E*Cy4n9x*}}cPq*z|_=*`{K6^Tf+tHD^$kQeL z=RJqmUnY6&P3gGt@Gw|_^=R$+;hpA`vOuX@-GJX^3TEVB>uFK{#Jh5p@&V8~h`!Ke zZ#;3oZYz8z#hN;zIFn}lMR;1tYRp*~`Tej(N%U?dC9PK(5vnFPg^!Pp>-aA^_psy; zeR+0t<nZWG>RTLnMS%$I`-lH2q+Go({q&K)4L)#?3&>swd%a8f9-V?H6DgU`>;K|a zYrhIAnCup5P#)K{dTtq<7sL#$?*tEb0|khyT{fs1=V5sTl=x&h5VF6a8DfX(5NP@a z5VBYV1>%R}zVA~6muxw3N0&EFxeJWr3|V5S!!ZpWU1S`WO(w7rtF<`r$k6%##Hao6 zK)(S8W|Xf8mE}CSmyT)p4l!*9UPT1Hd7HKE;27NXt9W}jRo5cfJ$8G=%i(hYoU$)G zusnxwHmKaT)T=_ff%ZV1d2m%u_$O>o|I90-Mk_~Ho11+oGqB7x5BfBn_S8x7yhWvS z>7{uCsjdVL9SO%(qj@fJ;_qTscvU5B@uR7KMXd$s>3(?;3H|xVL?3)6sPlrS3RWAu z^jYGRCdmRbKB(_EqPZlMHv^_8GCPZX(?3X<S)_xa-fJsM-&{4T9@w?;SP&4fA<q&u zYzvaD4L-NPB?{LSgh7j`v~6p<7UzBz$3gjvnLJP;mk!a7FSPe~c^(=o;Vd|GysV|+ z^`QfE=ZG9e)Mrj;;YlPzVenA+h4&Y6&Gl@2qwPhO$#S35qzxw$Did|`6PMgWfvcaD z%*YJ_oT7Yrqsm#sT7#e}3T2Ta8@+;+ujQ?mss*mw6uUbwkK(U0TEiTdH(Fl>?oCsd z437wLs+w%L?TYkdjiq|Q@w(KyIF>n}72_x4k$RN}YaU7nmW&jR!Vyn_Vs(?+!NmGC zP-#Knk{i1ypA`il=k6J&4)Vyuom2BVmWK)d!Ox>Ti4g=^!0xS|hh5-d0!uxwcJP6Y zoFhjNLh6i#n1XS@-H}C$aOw#nw%U*~50$lSk8ghH4Ub)WoO&)dM)}}=KYwrx7&-R* zX9YxoxYJy+Ubl%@kuO-D2VjYm4<P%bGj`9?6e#OADCA(Mf8I7QD|)8NzKvz)*E>mD ziA-`W;XBQ;Z7|y>a<~>E_y=yR8AraFdd|sVBCH7`#@M923tLtcW~dvPA)b{pB^PGd z7M56lskX8qS&y7pUth1>$E1dc$^^UE)=qgD;vZprzFq;mhdSXN;FyAG;y#{jU4m>W z{#n7vhP77DYh>`8JaGsJHD%FaC15TGSiJ+kfW8G}Ws1RAz<p{TDuCzWWKH=muenmv z4o>4nrOiGuAeoc+6^q1g6LojRtl~w&*N*n2{pYG!I9_#L<E6J&n7xXT9^Gl|z<Avh zc0|FB@+6F_J*_xvT+b!T)~tf<4zq`MhM@{96WE;v<SF0hmBpD$cJ!B<3#B3y^UuIh zxQ*LfvoDmFL!0}dx~FmqA|$M7nyi@Ne4o4P^AA?F#+(5o0OQ}@`yEhY{qJbCLwc=I z0D)xUbS<7&lC+Ow%E7<6g4JmzLeZ@rg(GS2-}fMxQ}N_)8pY__iaubu9!>{&OW1IH zBhOH^?U{v{vBe#Q>)%}VZTu!WG<d76Ha4M@41Vfk98THo8>SBHO1a`~w)OY+n$rF% zw*J4AQ}=??R%-qiR=+cxe2Mv^j?k>|=&aqIX;5-;jGIf&<2bA4_v*bLhMNGG%7ZCW zdmT}WgFozMcfcj?LxM?obZ=aT+R`W+TX9JVr3bD6*P$GV5nB6i9LW$|1r=BqfG|F0 zmcUioAHxD+MQ8YjE)tkzJ_S4Wh)?)5o|?OKu7TFKo1LG`uyuL$r07qUmO7ow*YuED zyp&C<CbUeQO5y?dxbxs}3AAt8c_3gG=s82tFTb;4qB8eHkJ!vA9cG0c+QGWY>c1wf z3`aiqum9K7Rd6t|>PJMDWY>a^5DG)QExa7@yFY!ny}vme5fr`mD3s1yH4eg}T{~z! zqSy%7-{KLaLX?AkC6;qjiHnIXq8AsN-YoLsUNB4u`w~smR8eQAQWMG0$k>(xy&UmV zCOlUd_eM8z-i_uu)!-T!55V^f&hJRUD=7B#a+o*&LK-~{uXef=TXG`H8c#=7Ox9$y z>CJ!j9tB5(ic)C*aDFU%)ZaN4sPaZbs;J*)q3^%Hx*pX|HHI~<nL0ltRXnpp=EM<k zbe2!l-V}#Y`9q0z9nSr`CBj(paD9kKtuH;b-05N4DKB+053x~3Q;z#!gZOBp+H~kR zXoW<}O{sUK2wT6dZDR0?@tSBq$h|>SK(Y8)34`R-D4q$kD}v+&-S5!9o)dN2Bk9b| z^)fRI$~qxkPq4GB9WU!q^UHH$Pe%_7D7-|yFZZG73Y3axd<uBxY&t^pFtmQZ{{Hx< zpI)z_y=}OX4&tn-v{`doe6#g1(MFMnPMg_Yb7<BMp~lPt4~KQ}+i`vJ_<LBVTbxqc zmwNi&qn71rb0dfM@RNpZv7|(Bl$e(^*9E4?NuIel8#C++*~?-(@TNq_(AP}3{<m9h zy}e&B@-Xwo&nLB|j3`^w)v?ETVEST<;Y$ZNZYu4Mb8xBR{c~RxRVVm(^e4xjkToV- z)uhHs`GCoxL6^}7FNfd{PawfHcF=Iwd-st}<n7vWYz5b?n|LisDrAjA$;zutNR@CS z6!%>W<^OpBCe_B9fzaXPz?69%3cMiFh#*5uimcLL{#~{_+y%faB^&ts-9lP??>xUk zvSE~n*&qZ<>7)Vs{<swId#SDcX*s!DDA!Sy6uEIU|K#txCdfg|T3s-83jLf-CG%N} zlz*=>=52j9UHw!9^!EmeFq~N9oSnLt5`{_9IVdi<d(1<rBDxQ0EqauZW;R_EUW9{B zN64W*S(y3w=lEkJi|Twg#W%?|YxF1moPpK$euKkpysx?mp){y}g_*Cg9L)QrPCD0% z_}$@na%pcf%DHs~J(us6mZz&E2C7$AjoVET?JN5$nZ@RTq1LKPo|{_A_v~OMQS22k zSAYf-%D?T>Z28u(FErR7qWn(~@2^^YeZnlLfS7zqA2vkZacvoN#@*a|^*fi5=l;2_ zQtC5ZFJ0X0@v3@u?y^2L$bXL!ic^mW^JZt5n&sY?R2J_buZwAP7+OOA)~7A3mjrcn z%gM->M+Zy_9QYJc!5FuY(4>#-HZK*CU^`+;ZluhON{MD_eHBe`VQqKp&v@QVgA4Cs z<$)6T^ZC$Uw<iNUf`B7*1PZmx5!mA!(<~myY`<Mo=!c0?nR%`()y1URvnUg~YK0Wz zkLjYM=nIeq(?9=mqsOc&Q6|<tL4!cEeY><1d@iv-J@#l2qYBrp8U7BrIOXK;cPX>B z%*&5u-l<-T^!x;LR4=(PvuR-v&t{RpcPw(p^A4S<)mG(h>;Tp(T3G<U#;EKrChS&L zi~`M*1T2IyB?9FK1Q1n6{KgN6HzncZ4~S`vjHB~V2*eWu1PIHY6hChg%#l9OzhBXa zYX30l%v(7;$Z^F1Tv?zUJ&!sw`@_bliv?K`5jE|}Q)?9$3T)9RsmUPDKiL?H!XqCT z1iMsqWE7<v_F!#<=`nwdxVl!Iq|8=}tB)^yZXUnbAq7;@3CU%Bd2;E=cZlP}1gco2 zeslT!nlW0TH0wjqa?EZ}Slx5t;29BG7ChBue`rWiKq74~54U2vxID}sd8D4h%c;gn z^Px%ZsTFJzPXd#84H6cuM-JsDa;$JaLy#mB#MxPDs+N>8w5`lpA;BZa{)EP=1+Vd@ zOB(P8n6&j8;bV1jotkdiEsak#xM_tBH$|QVI@n|zLTM|NwS>#Yfe%9X>n~BOGipl3 z9QKEGKR0z6mUL6VTG50$Ir4C5l90~S>6_RJqs@xNUY}*;`N__K`F<)LJv|Q_m77t~ zSpyy9X!q;x&9f?9z49MZm1RNv>n2mNk3=x!JE2*ve`19O^i)zck8xTM$3BjWK6#hl zeKo|E8~mP&6*Su8fA_g;80q>8>|3BQf#JQUrQpHjU+0q>j5s)c7IR0QRUsHF(<en| zs=8imI;D`ix~Y%Q7j7O@>4?odeByw^<$ad@}-?S&z_G9wrHRzlQg8%HApgT?=$x z37=&-pb9KEH8gmUBPQjfLiNgf0d=}sv%abI_8UYe9Ek)pWoucqV+05VKc_=y97Svo z`vpQ2BoMIqHVTA><B0%Tl_&x5Qs}#x!>WHt6$bpk9D;USs22T8b$*clG&3L84p+u( z7kH;XuG71gtMP~uJ~cTvU#{G9GB-ZS1M5qhUj6O`--LnWZp){c*ciy&`hPf#Ncg z_(F-hj&T+JB$*H#?yP8#yaMmA?bo59&3;9bAOEzlmFdt$!g-Oa@C!(B1~+?G&DHk{ zIebqQx%O__y;}SyOA5?kPs@M@H1i7wzc3zpRs1PlPLX3B$yXbk#qvXujhtw9siLqB zUX!+1d6V{Vl@?~zvs3_1>etmxgx<rj@|OLdi(QT9RO+-<8rK@Rv#Y|+@SHur2<cWN z@Y5`&9vXk+?`P4+<sKKn&vgy9ha;><uAap_xZz&h-|{sy$Mq~ZQ@PsB80W|vjuO_B z7bih?cN=dey0oPQ3qHUk6}dL8bXTVqdJ~C9p4DB96BSeF#$Exf4C((W9xR{EA~T2g zJXv-wop__I6%M%KQssu-6Mh^Z6!eNx?S{D9RHBTJjh#ikG$AiG)8)UGM{{z^OOl8E z8vZ=%czSDJ+hw<Vv1JkM`s|AW8>Vdcb;^+#%4E-ZMA5(g!JzSXCI^ue`lWl!yFC$g zyICus*sO3#_koH}DZVs&*UeHw;8qEif8s=5D>|2Z1})qHJ~lD)Z5gy<=$==uTMUpS z$Zwt@_R;grzna!>i}agaf8h0}AgCi+P*TgK6atsax^SRxe=iOR>;x|?4`-8vu}!Ck zCIyk0<(_xGO$DX>K482nXQaoxcMO)MCobWxNp<Kc_-l{wUCep7TYhMgF#uY!{=Dc6 zzv!TfyGv=_tmwEne$FuQZ+Ph<Cm5q4_9{9o*6O^ZNZ}3ZSBCN1M?bZ%n`abMr|?Nw zJz`)XRziUD4>1;PkTXb_N3_~Q@7H*>{`0+^oxOb;rIkP>_+ursq&|YWsCd$rG#K}i z7GD&}S=v8WYrkwqM@N?$SUS>8m@y^8xe4QZ%0T!!HrN0$uRr770LzW@n<V)}SNU9I zIdLoErn#CQk6^shP3E`wR@ni@tZ|Q{b~fJaegKq{o)OCsY^hruPttNOsIq5Rzu02y zOQI1oqMRl!78qE3e1{-UyGZ=sGrs~1lXz^uYYGSz7EWPX&<9l~Z~Uv&ORS9VE+@U0 zMfmZ}Ks|Q`{4H$<C9B!w964&muMR}ONcyQBuL8NLrHRy>xRGM|nPw~5yhPT*HP32` z*A~W0c57?jyp&|en;7x%l|qVg1ID8jOrf?;?hU)9!$mTZi`e>+7nb*#XGQuQYbR^2 z#PN_yUdO;Eo?5ZIeT(Asq~%iPti7)zkDb;i8&a7W)b{^W&ffr<j=NH)U@PWS-2*8n z12fTw1ekLUg~hOD1aovv{TX@WETK#vQQ`yn5mr}%&76Kf*cb%y{+yKR3jp;SMyLx) z>LM6rf_3q}4LrVg0Uzdx7%#Bsu`KbZOy;CRi1$*LauC2y?g40js@nz5A^-ox>b;+@ zlK7vVihqc9uyN5^q@0wOn`}yKU&U1yVbC9k;3poC!(mYlmGs~*aOKifP@*6q*6r=- z$jI4FjO{m6$H&|c^26i@HyXSAN{82OC5`w9t-tR9i<_>t5WpnM&%SZ|PkVIf;}2<; zG3U_Ny^<8jMwrlbn>(+U3@Gbkxv&i~>|<NqjC2h2XPo>Ih$;GGNt{ZU9c%KsbpBnc zcI6r4(5uUKffiA0i-nxsq2x}RKyoVU(W!Tp+*+L73*oRi9f1RE-Q(Z@BJ2=v4U%hQ z=|80+tLdBejO|ci4dLOHal`4|B(z12`sEVgTCsxmqN+oBV0c{Qb5qYBv&<8!I=exO zV9r;=`W{*wHY)RQc7ubm{CSpt+;=W}R`@<}E4c~I6v=aDvA7}yuU6qa^Dc|l(ZJ3* zT6PCK9}tJUvx<Pl;m6b2afwT%eW%`KN)7Hl(Y~BLqm8d>KZE)?yjJWL4=bOKy%Bb# zE1(mBIUcyDh!)ha=pN{Lza8T~A6VW)YcxH|Hr5a>su(ENm@(4L_$tO2Mo<Xj#2USd z2?%1oZr=8^aRrUaou-b|pW`Z0q`57nZrtf&@fjeKcIqZKT-QVlO2MQJhi-5U6<)g} ziP>VepEnqe%a-%Jb}h%?e&kIFhoBs*i&l#>=^E&5RM78o$)zxe_v0?`c<ufVDnKPF zSsljp@J*bQk2r;dK}3Hmp|aj<qQ|PaF<SfLKwAX31_>0jJ3xxw^{R3n*-oF=727~- z5~{n?Q5WWHCF|uIvrRA5Wqv(fO4k3+G5D~()BMs2kRog*1xxQEIP%!dp#uScYF#AF zrH?kM@FhmbU@sxu=wzlpH>^?iDL~^l1UaGby}7n#IrdA^lt0OF))11Z^NSBYq~_*M zPPUcoLwkqr343#6NJR)E%S#+bW`5gWFHCp8zV&C!(==RtI)>zPiifmh@+JqS5H(xp z=?EZVXt+cgwGE0USt+%vm#r-}&J*JhxNg1kxP20hhe`i+Pup#ZZz?yGXMdS89g`GU zHmV*c);f<audh$9#zc+eSLzE?xI|c=?d;1!6L(ctM=bdZwft8GjD`=cswZ-!wN<AW z3JugsiWg^?B=(5a)wy$I_SnmD7yK9e_WS?+#Q&tY)c=;k+p7t43~Mf_^BtJDV2Isi zRy2hwW0$?Hk1nB`O_|yC<?EXuvZxYYPu^;e;}eLSJZP4XBdw@jzkfa&XFgU(f*tSt z9`od|!O_hztCCh-a6GL?yD&+K<5l{r>Cn${zh|t{#TnEne1gRn)WhTLjLuy{j5vF{ z>6d@@r>5kI6mWTxV1&QUh$A%8Kt5j6DV+$w8a6yZ^8u||zcoAxm^<KRN|`i(o}6!8 zvQ37uXy?X6iNm8^+QGO-YAt{-em5T_l|dOc4AGTu;-i}b7kX|v^puQ%jKi$#S0jfR z$q{D?w#GV#R9zl_bouJ6j;H5hT*;<WMxEL}oLZ*#3UTI6U;!B@q;k8ZV%v;cwokC{ z{8m+?<4OQhWcK|>jv^air9CjzWhn5AMVZW0{?l&Z!PB_d=ZQ`PeL9FLYtpTJR~W@2 zrTY(zQ&L#jvAugUgPSX59pKAJUhJN4Yxl}{R9{d!OQFC9B<*TAh}U44zMB2Vqmb8j znMP=H^KevOx=5;eAky_Cg*%Od7?(i$K9)h8Qqd^Sn|~#RQK}NPhBa>XL(c^MJm0Wv ztPRbGi%;{rzuG$89vKO2NwF-yW?>kc99nf$eAwu+uOvb%e;|X2#a0Nsb&kx(A%zhi znDRf1x|kqL*=uzz->%#(M;kTJf*upq{QkiXx52SK$1p{`)ZYVid`~w|Sb5$VE2ja? zi5#{%@1m<Ej(rcXkfLzIb`c??Hro7eOHxDFh#i-%!YyLoj{9rEyOuQ?Odp+Gvvm^^ ztqH47fme>}Ow_0m*WTl$v2dL<;^EG4l(4Q(gTh}dUoNV3Z?Uf4sG~cF52nvjXO_~8 zNh27^Q_G!1bRwP)GD{AN&k9#Zv8rhB`W?#Wyn-@wd)6&0z}#x$bc}!NIA9vXM+&T4 zPG5DCSeoH%s3ma>7zlgj_@x9EW1EZhbb@h?07&w9%uVeAA@Bys_B$~F6MzD#_7|@f zX+XonrDuaNT82kk{wmk#r7#6Ne=o~u?0z?+I=;=I?BJQ1FM)zW77Z}7E&+-Tao^j2 z?PVS)sVmEo%HkGRna_MnUVh%*jaUDU*AYN;4JDb%`T^E7?_7a!*k~uU3Hji6h=P!J zH!E5-M!soO?h6ItZ*tA~toD(P>n$s)L+sy&ByF=8Px%C98og=r8qeHsYZO;@o^wr0 zlr=AGwRP}p<rfbxN71=wtB~542`U|4lc>9_#ypA6m0cXRgMzB+>K42w0ihGLZ5T&f zgX>av#hh2RS(uxrM*%fr4=~@2GvrZb`~yaj9uJ;KF-!Xj6V*J!{&PXXfMLq2tV-Hr zH~|09qfv=?tLTXMPhw+onGM6tOSq+KKy`mrDpDGk2ecylb6&E-a6@Gc>$}dS)sj7( zad4me@VW7L!^g#&q_;@~a(q!7TTxB7nw%eQKm|+(8?tx{UT80}R$Xn*e`U4?SChap z$|tG;-jjTBtz2s^_d`sbAC=zh8&vB1MUO6>&VDU=l<(-SmJ7R)Puoj^t=iovsWddL zO734H3(qAE{D&<PL5Z9yuN2!&yTvf*A@PY>7O@X~|3DWa@82NPq`_hc5%?RwH(><# zmBWEsxh04g6*AY$jI$U}t)^??ch7O)Fc@#mo@Qlr`a?1wHY;If7hy~shw_0RMXqOV z!(*k2(l`o1@#hEvV{VorteV3`5!%l!02wMrWvQ(UkGN0(!xaGmfs-YYj=@hNFS8Go zV#aI#A5CW+)%5$maU`XNA5u^dRJuhJm>`OPbZ&Ha_a-1MqO`zhkQ%YUq#2A9P(ix8 zq+_EI5d6LUp7Zk@|IwrWydR$DzVGXGUAJdc4HOt>H()VL3{ywbp4R{jKV?B3%Oe_` zrv4tdrB<qa$NKGofg#q#&;{E$;AvM4cD3+(Ri!6;>Rey3lF9RhnX2o#oWsGXSW2+e z2z}fQYbr10{(&5)t=xO~sp~2)F#uwO(PAv6VLIGpNX$&P>@tW|nWs>0HpaGC=>vqT znrfJ~IQWA2+}yb1Q-v*EnSC{{fSTPMcGA?WjeK*v7~$JEk*i&A?iPxz|9BiZtjTda za+yDS+RiRl^Gt-@nG6>W<ZOI+MsDbDRv8l#z0pJDK2aWUjkR+VzisV?_T7gkD7GAP zPN;ePG*r9_VkQt?onOKn67@g}0(Xcbr4IP-wZf1S)|Z3sHL{rH57G_+cBaP&9V|pV zCSkHk0qkU!ALHa(RWgFfXvN4MUPWZ93_Y97^XT?lQjKyxn_fUiYjHe*HQX&qTVFXb z=F{FQ@sX2!SDqLlpU0@w5tqxwa|1NyVmWbMmpLE;%YJByzUf$J68)u{c7r|63Ce8n z$<@!OeIuV=qlA&KBMHA1{oIw{BF9_zQ^9DwZ{Frbp0oV7l8XKut8Z5WuMn;GLpM2b zkDF!h2%e5esa90t*5tpi%O&^bb_=ABH+=1y5C1@k(jSGH3vcUt=_BRD-z6=YG$5@6 z(1LhA<dn;F%Rh-L&pZqMh8k|l@Y^3S)4Z$3cCPkI3r_Z_EDuPYe_jF+#(RSRY3iPX z&b7q~C^@hU;L2dCdveD5(nij{_t-)JtxQ2Wt0-)9K;R5p3$rQomGe?=Su#$k_^XT1 zo*h4w&UWl#zIYZ04VAdgvQ33mB<)hdX$n7pon@L_(o4HN3!Nicm6Nl$uYtZ^WVP-3 z<V)5)K@X$IWIG3_GC8K6A2F%l<Y(D0P=2R_3`J=M>7^;+6~4yda53^L@EQBmk@cla z)4$%Ui1@h;nujJg%p&a&fpi`c%PRkY)oL9a_eI<a>GSH-5d|WlzUlqjCBhS;7Okdy zjW?y#?OV>09TMH%kSI}9y3JDO83Y*w<9O20+IL<l@h4F|b$3CeK$#@?&Fmm&)9iA3 z&Q*|Rg*@Fap!UftGfx-ZjtuI_4NS?!e#L~)O=w;rXQ7<1$>1fJJ80hG^Yf5a&&|_& zU~$X~FcWlX_tZFS&hH1s1g_+8L)A>x%A3#Adz&L^#A7vzj_7qDf1RRn+L0iKHKqhK z?qP;+on0O&^@0RUPGjIvn4Vro&5BS>9j8FIL4QX28#+N;yHbXdsUu#Q<EVu16U)F5 z-$(LG&F$dzg+eo5|MBp*lb6=XJ09aueleg^^M{geFZdGuwoT-ZQ^{+PbbGm#Idg7b zq9%|SRd>vu+|`{Qu40o)R_NENY6WYV$Tku{EPWj)ADg)$ggzPpN!H^4jL{34z3G{I zhPumdVP0~y0&<#z=Ei`JmjRv!+7G-lX9hSgVwDY+>=?(9;-dP3hXYDCSMS}s_u0#s zX*e3JzUeH#mHFgg{xe}0Za*MVh*bc*81UT%phm6*iP;-K%6;1hDC@Tg=REi!Y|Ge7 zJB%<U{$fF-Yh{!Yp8jml3<MuDK}MG>Bx8RuCIikv*|UUu&s#runPuTAe2BcFtkta( zx{(!&vS$OjT9Qy|3Nq`7{Ke~*#>Pf{iJEHTEd}&IvfAv=6t>EaIkyjFZ#pukYgnhu z`-t_V1J=w5$h~jQtqm><g8@es-`w+Q_4!(aLOee&-@iWHo0TY;CTdwi|Lroa=eVuv zmg>CLVTFL^7Fnt!Ho{jz3yQ<*d7l0OpB>h<R?zRYKPeL?Ohj)_guV?jc~9;qSTj0B z;A-lPbg`oNGm|mzoB8xyj@FXrqaWRZYzP2+oJ)hWXL`KXS0A_I2#5Qo-425xf!(wo zeoA{VlX2MnXRm36+>o;eBWJJK|Ljo+Zh?9T!Aw$#^w=(+Gk5OR+K;`h9t73rl}W#v zk{5;YhQ%)d+lREgfJf7r5x>RfI0_8Y@xX7s8%>u}9rIjg^JtYE`h1chze2eD<N&g} zgsn%VMNiIe`@O)W5%P<J!dl#3w91{SR=_FpvmXd=P$afX+VMf{`faH2WUsu<X=UI^ zhq0R8BYAmYV3=Y;<2kRQ1N$qiNfltiCFulN_nWjl6v^o`5_1~qeT3u4c|Mnc`<z8u z(SxfkV(Wy~&lVtZGR|FJJDJ?A7Hjme@JP!P30TaT4x$F=cD`~OGQ$^lDYDgEK8fo% z$1^!7(gUWi-l-dvH9DMtT6!#jG@S1E4=$w)AZ2XR({2<1C+Dg+H_QrXxo3-1i@bAI zPp7BvM!u~tHcepW+0*_27RWG@`C|4xz<6)od1u(at@ot~5rEZ;Cli9x73ajAF_f!G zNPvCWkO;zdS||F#VxFHgRihuY`ko%Y1KURIUjH+$+Lz6k7@+!$DsOWz!8g_TnM}0q zkkMZQ9eWxv(c!+n@<HBo=SaGmzzefV#A;n+={bT^QIao+(={X~wv_p%LH=WHwrtZ^ zk`+5kTTcS*PV_^klombh%b2Oj(Y7?EDupPv$Vb^A5d(1*Pjh}bv^(y5S?p^DM{X2} zW&N|K5&4gi`tK{K%UHpNv&{8LOD(nY&eXvOUOFD>>VWwl8W47;yh3O0U?oLfl=Zq2 z>_b}wrrvAqEH}keAhLD!MW`M1+dH#x=yK#d&ZR+ff(n}c!Pw|*A(nPzF=a6&pwuIF z-5>eswxyugo=>%|;rV*<D0W+?*D7mBhL13F$T2T^c6KJZZc$Fu#G}Cs{wq<lR6!lb z6&Dth5X~~>#9ZF91I?W1t(h;DjX*s;58mx!YKCE3b2)T7?ryqv56Ol^59e5wUg!r! zliEW6V;Yt^ukj^!+enjmzjIe4f7ocw`bT>{rJ4iJr78M@eQe!JmumMLR=JFls&&cb zG%b`ZzE7QAu=h2L=1DYfy9wC2J^zW<mc$UVNq$Xff&+?yCmOmT<1I%3sIZH=^;Do@ zMnV0BbKr?0b~+pHz;h;@>@XuhYdGb|DVcG_NW40cOq#H_YRvghT*XTnGPfIl!69tR z1UDp_X$9()n9TugK(q+w%bg$a(Enj~som)_$WMJYCuDTsm++j`+a1?ZY-f$SR~Aqt zg(s1{2}-ON%^~<|%tDf(|D^rjb#>5tkC4rRnl)I$^vO%2b}lE}BPgxg7U2cq7PL{B z0S!G%`N*`Y8e}MGU|wo|Pe8ghdPU7^vk#T?%zcXqdRzARa%9!}r=%ZNC*m=;=ue8; z>XpH4ayqwVRw;CT+q)mCNi`3e`V1m}2rW|SwGhkD7|_vDOi~@I^Q0)6dG24jjb{oO zu9-)^82rG~f|#2a_YX7wlIQJPaai8FgYzr|pV`!Pb;^$lMQk`}i1JMbO(&Y!mF&>z z<azcxbcn=vG;wf~EKT-VR<xrSc`JTwc=z|?B<L@mWQdh*uIDey@^ce9j8$zZ%GhD` z3aI;W0)jz2cjV2|ikZHTbd%12mVx<5N<qU|ZYMqRYPu<S0JrO}vZW{6-x>0E%5Ii* z2%|-@C7Uu&=#9Y#3%yR^S*^Qmks|s;4%cd0NEKiHx?0L~?STVZ(Bz2Xvj^KdOE~YA z(hs~gc@obCe$@r8Np8!FSi*<e)>{Ui`C%vG(>^8+nwt<0IxZ^Th=)weOf{q%&gmG< zLQpZ_)Jode^MU$>*gJrT-rj}UVA{Sln!c2to#S{)=wR2dj$_LCSzUvzd2?+7$`qWb zd^Lwr82nCEe6z^qxGd~2sb~eXfy11?fK0Ws(s)Is6z80q`LO$!=0%Kj@hXh8E)JkS zg73}&%~V%%Va-P{w0*a)2k@t|vu-%V-GBiqu*_2*S~Zsd0sN+Rn_^_|E(;0kci>1~ z1Dbjk;HzLkB`c4rM||U0Vs75sAEt0U`MI+vZ!>G|4sv*26fibg&{2@&3yP?(Ua>MD z+`REwK+*o4eFymwvAcyP!bH`-tZ4w0BI`ou_SX!5BsJxxOdyaKl&ilcGcGnqePG(p zjGxYQYxjAf=5=5RSNN$Yd|R7RH9(Vgq+G-(zqG5S$Agxr0b0Sxrmo(M++b=qZt-LH zm^TTMWz~b;>R8fe802__af-;Zrh!e8dLy)+aABk~75;F1<A^<RtEzGKe3Fp@vix%p zgb@>yI}&(`S{wh>GZ6ljR^Tb^YZ;#vOIL?e<JkS6z5TjTu7tNe{kc(-OMx?NhZj3* zIwX2GV%Wvj-oich3<KJqD4{D0vvDqHa>rI1Ct<%B47^>kjgvcwB6^R;Z=z#Lm+X-Z zHZmj3dqXo@I+@D(aF_5~78Ph@g`q4~!4HJWc5)Zy&@s45iDGLMBaEmGcquNZe8v*T z;j^TATjOTGCR+8G25DGX5z7{_rfIr!`CRKs=3Y^%WkBa^v<~#(Id}%1vguP5#lahY zl80g^p>xBsItSq^pqLzH$!>P$u()pK8{G=s>;e5#(@!*o;*F=0!ppn7j3k(EGJgC- zK9R8yJ-mDV_z7?#w$*AJ3Zy=;r>=k)sJ)^Xtz))$UIHVK4GFTD-$unRfw^AMJnhC{ zgMlXdX093U+`)q6-qib#X^K;$eYgTXfm%R#kemEEw$cGi{zZ~AoXZKf9y{{8m3)pE zzxJY}ka_0WU%eXKYh$4{Ow>&B>TELXHsZ6f#_lcuGOnEuQrVIVc}!7mVl1)akpiVs z+7-sJ^URH1huS+0+Pr~+cT@@ZqjD;fx~U`9AOD8@F$zZ7zRq?cM87u%$lf@<t~scj ze1rLxkPJGNF6;2%-UoKbH=Z=_z(34C^coB~EOYVMrg6Jp(>Ci<Y0Rr!*SYeZwK@C$ zS%AYf^ycHGN_g$%R8!3b-}8m&rHS+QggM(Sr%QKk!3sybym#t%s-Fu^{$<cOv>X6v z*$#ybf+kdjt5HR^UljIvMlTm2<4+UOw(G<fot>TCVJ(+vt(38v{!dfOW%3_TF6a>z ziu0|K&$%{f+wXS7-1_%&rdSOfko4y`hc9ZJdH?MeK`2Tq<c%X;*A@Y$*EaOW$*$|r zY3N}Ohv`83&0NWBAz6jWh8Aoz&a8><o}8&K;pby9ygR{Fi*L6&h#xIqsb|3}h#y#% z619wKC+*P065bFtetl06y<1E15S9p5TfQXt3CMH(Y?s_LYF?a|@e<8q<P)oETWoCs zs_Fbz$sSvZz?_|_i`tiMnxAvVZ?w;+0kfHP2K;6V@PUC(n|p>wO<in2ysC4`mqCyb zU~<QdFLEWYXNgVMB~m$Tpa7<{^Wm*vYIw>84&S^DUjecIqL}%6vGc`YZW(?vlU*Gy zr<k|H0d;(tPzLn-zjf!hsM|^H9G3o7bmAeOubA;e#vQf+>_;o{+`-H?vwPD0IZ%Yp zqF{@QxYFFRX%l$|aQrvwB&30xGX2MCf@{SJNcpKyv0w1dm2<^MzrrEj+GTPz%|KuE zjLzLC->BW|bzsLtp5s~wor1qn|1Wj@zG{d(zeVsQXFu@1I5!jrnRrrX^Vm|eN!S?M zxwdzxHdXj-S$IEYCx(kPbygwnBc7UTo2q<=5I-%i2Ppi`s2EpxgaKmEmuR?ah|1Ez z()m5|S%HKE$iGn<rQ}fkIM0E;A@5<_&m}vi$+)tY2@!+d4dXuzeCD0C(5i>;*_&$+ zLS|LpEKq4<ve<2hU(JG%g7bENlV$8qjNFewUSXlm?oc~P8-~2;e(wR5#$9g=@<|V& zUPkZZR0|9D^QWuZG~@CrWtKtL^?Pn{Ca#q$g1@yPTKN?H>*~ZUgsYs+8Y-o!3KUT^ z@tqOc(`Qg&$;NV)$hViOyQ<=eRLHER_umH$__)l-p3+%5Xr7({tOd(~&yJ2o=Edgk z_#8r|nvv>JDaXkCaeH-O>j`hv!mFXLiA*jIs*f|6iNGH9x62Pc=LO}p*K`}A{t%KV zaCywP$h!piv@NjxXc|)?4g*Q2$wxyD^rDgdtknZ%sr7>R-xnu4M-DMy)s8yLqPNXe zvp({3`7*XwhCnS%|N5-Xx%ouG|ClY+eb30#DEltn6YB49_KpO0nr3Yd4$CZZp5R+k zo8z*qb!ptF$Cw()qUI}pV^`fGDHxh^0W?}MYmS76lP5{gKHF0niP2ydMvZrQZ>%Iq z9rSvBCkk>{%9aJBDrUe3rux(GGf+cKiogWxjMT?6npfhPN>h%_)o(dOgS$o$hN&a< zaB20HAY6-MfzX73=H>kiCol$7<^JyQ8Q5Z!(}W6I1Ah^b)w`V}+QH>;ua{ZAMfMxl z)BW^4@avMk>^$}DY@^*$tKL7;&b2wNm3u<bh>s(W%N<Q5?|yh%iD0$?8w#Y%9Ids? ztR#zY`nh&2lGx=WuxYyGr;2RU$$01vtgA50D<Bsbh~JH7p0drHo`gCl=^RNh_(rX( zem~r=$?<rZ@1TWax|k{bQzyAc)Ee4NRZ#ooV%<>u>A@$S&4o|j);czgrOODAi^<+y z;+Bu2>(Z+OY(ivC=v03(97r>mN!0{=Y!3Hhc#WtR_{vFEK)>b(hR3(BL`q0<e3cWN zOmL~@;KDx$nIJ*GcZRlTgsN(Yd1*sOrwm2O$|Cn>dRZ4Y$|cs8gCFV0srZ6zo-XN& zBcku?gC?w#4~pks-$0qU*;%A%Q^&>)M{`PTlsTu90om>9BH0>=E894;r|l97e)Y+s z$+cCm`$%cyQt5tLRTuFC!62o3alj2>_GnVcDF7xcqX+qT;4+R^{X$m@zPG&J;?V0E zRq%{C9<WdF2lF`B$?dnW7S6lC24cXPt*V&uWp*a9Zc}qThqrMKg(s~5`2$BWZ?j5< zKJ&xzlmqW5TeA2Z@!3H8z%4W29`n{pk!9!{E&l<;D)ezz==7PBE7-i%kQ27O;>9W` zLYbi5bTAMav>{QO0q}^ryV2m&OVP1D<6$_7boTn-1@dPlnb&}p5H)0AoMu)vGAg1c zj8oCQ3c=o15`RkFZvR!}C0d%tR<$_*t0k=zyaF(=WJ6~QcMXs2V(oPs{GR4@6oc^2 zJ7^iZ$RQ2eaJw_>vvqAJI(`Oazbp3pLVw{*%;Qlr`G@=e?T$ax>>wQ%p$SKX`d*`+ z>4W(Z)+yW8XalW#+!-hIrT!KgGrLk3&*@|%K1pz0#N573w!zU1BV)IOG{HJvG2LGq zoL7S&y`E3w(^fb?l$%zPV+KgFj}K*6WdiNfz9622#Z`63XCE%18VxHD_DBavj99=u zCYm3Gn67e)tjN0zoovqTap{g|nWC{hyrOd+J7bG+y@ML%kaC`c_P~|VO&u|L6-&BH z9V>Kc1O8o9VT~m$hIF?LAiHYlzMuZK&LRWRK?XDMzq&bCX$G2E6`(JeYvCT5>MB-y zyR+7|WXiFW8mW8c##T(W(prv_-!bp1CRaYlm#`~e85D^zxn}hNrkceKBLI*d@MeTN z>Nk-VU<=!;y)@^lF4^#voSvC*1~?z@?%ZsToc#8+b^gL5&|k2gz86OfzcqzdluL7T z65@lLUlcIA84w1D3>bVjB{%6;+>_ELf`$`!RLG;N0QtQ03edw=a2Td(AWCe*05DFh z)&a1(-{Faxu1ZyL2k;Oj?M&3GtOsk7e;5n2$@H2ghAL~$3GTeZZ=4dUnQC7<an1St z3AZnvkr&hm{A6MpU^w>BB}%71Kjn7qcFn{{dj!dWy+cK8W{<nnm}*<zi>6oo94@!& z9V$_C%<*@x$yhdQWo#_9Yr8js1WGo-5lOn=ZNV>et&2N6#A-*@v^THcew>ui(+w`a zbu-<d+r&WmdAPR=g)<y*C6qfMmL>#xat9}%L9yyXeZO}OXP5sDCy>TNt(hNB2;U-o zBPEp#ak6!ifNDWhYmD6|2i{el8Td~N1o8n(GCLP*W-Bx3kuf`wg)aNSgB!x0iOf}g z<*}8a6I?zW`D}k;WHoL!0M$)y?ic?X|EjNW;xQK=p3d}w+*T$loD|6`LC>lAIiD~0 z<HsVrac9}+?J?;%W+nmd3eNB&`H|t&bdP(?u}1n{W`qTbiM!qnSyl&yN2IzOXZ}?0 z`93;RXqjKNH>xT%_5GaXxGMZg4pLB4(0$(!t>O0}?WdWZc?<{WZ-byYQVMDHln#r% z26$50z*ED@E%o=R@;kX$W$-JZ9}9AUfVyPKg?&Gxl4Oj0I%qFn<ee6@>>#P6mLY)G z7MaQjA7%oW;@xNG9CO33j79mqzEe>E^+seY1AgeC_n<4g+^><-MCXqnOM>*xISqTE zApnz}x(4Rg(K>I*6A}^z={E|;fD1*p01(q%bb!?7mNyQce%#hW)nOI<{{oULP9OLW zk7_mQ-$&(W0RPao@v+Km0H0$2O2MV#mx2MMz}(|NlUHbC_m;0vnp<~fxb*}8ui@?L z%eTWBjY?WmF&Jtr^<t_wMYL%jNFF9uozw;S>2=hLfOQJon;EQOciBhuE+rnQKV-Ru z6yAJ=>$X8|Fz(XMK`m*mp=W5{@q7z(jP6a}vx-X;Nw4>vv>#F)*5C7cy*UJUdt(Q^ z=Ju{~&M<=YV?{w}X2cE}yBNOY%^-u^ae0r(c>$lOT}HA>$@z}&7qz$hXc<9@6CN++ zf)TG&sp+2?ugx8$c#rr!b?Rn&C-b1Px7s(6*!!$ZrMcZEOkdtB^DoL%sVrtMpmrPi zRR?zq*g)4#b^osCSw?Mm-Q^69erUGrZmC3-LD@G+E4U)3HLxEyVA4G7O;A`-C_j4k z#BBu!*KV!OQF;OVJPJIoAF48XMQ5uKay8v;GFfW>V@E*fQw^UsSquNlG(T9nO%3cz zaC%viX^TS;E1`es8j?!2e%6~DeP=9LMqGR0RPktg<2DXSiq9ESD;n&=0xs{QXaUc0 zk}_fm-his^+!fIIdGLhOywqQSe1G!|5$+oMXt}C$#|Uz_aOZ7uYc)fC)RUOz)p?N8 z+K?nSKz-i&U~FopJP;4Sfcc^AQ&JwwAl%E|>>W8#{N|e%4AsmFLYe78|D5hiApVLy z9w4g4<Pe|(KLDMU1M&gww>>~04N8m#o8nFm(PbL|;oKeZh&WaSI5(F*zD5q42!)0Z zg5-dEklNGa=<mg3n|p9MW4-_-$f@F@Ot%ZjGBAJRU0Pci_JpNI-qvUu)R+9Y$Sf8r z*<@H>MIaDF$MQ)h(8Q(h3wvY2jsT@wbY@U8+B>n5B({)9WfFCs#F(b4>mlCr;5f95 zO;=F7WN_v(<7T*}_DqU`jdv)LHMQPGu~i`n##X+K54!zqW~8F*SFrnz@+ivXTMU$s z`BfUxwp)#)$UdfMh1_5HMxskADyI4ujDS+I3v3NIfNBN>liQ3ZrQr25^|;96%n+~K z#Sq~IPLrFo-m9{V<zFY{VFV|_9Mz}wAO!jI{)N4q_*U$4$cqFF{?a`xPbJLk2Kv}M z<Vt*--s8k+a2{^lK^!(Qfw#XsVV5}Kk|sZDc4c<=hr!pDr7@AD8XuqK(<TGjCuIO( z<R|HL<d376l-6q+?XnsiEV7sx8Hfo-aICUXWcnJr<+7OvnFag~gi(^#4?_05>P!Cw z-I(N8QX`;slPO1Xhfkf(55pZ9yvuTR-^UI!W9R+`;z4&rb2FcrSTaiN9>osl?sT)O z$?Y+VV5BV|fM5Js6{FH35PERa5UgNr5U?@g8HGygW{+V<)d(*O;2mQ{DjRS+Gik&R z@ue9RwKW4gyTSU@zJp&Jjh7QKPUsD}OP+rhQH>lsu(RxkXJV40^2<OnaFksNK!pj} zmhLx7x~u>W<0%KjcJn#BP+H#NeIu_Z7_+c%FW@6xmYfsMwz?7E0uZNMcmt>UnjSl< zx+wsAp393APhQW;%2NBBAzbwLGUP9zAJA`(^4EbtZYjjm?Bpso{+2xBF%!;v&x4zX zQbPbU;u7^~s5s~5UvZJOp8b(-zO`4fM?vqI%*TWDH^e%O+98#eqDChvLGP2w*nT;g z8*GgG1(UBB#O)GgM3gbTEd7{&N8#L#ffNyz>1kN!`Qs<7dMuaw4RXbZzf`k{KG%Do z#C}3EXHocfc0n)E;_B^&4CdN;dv)E_I8_QA!lGYYyPci0ORwL3GIa&R#x3eMlH#L3 zyUr@Sib(u_nPrKgMaHI++23Kpy2;L`3Z0}}?7yyFA64qC_>b|D<bf7ogc&0rx9J5I zUq4}$ZgKu2BJH;?8(lQ)&S)Tds27zI26Cc;$je-|BZ&4_&63*Ypot##79VgXhuSAp zzAZx|cPt4I+MU3H+2`%lFhe88CJpuE8fzYL9CM_j$oGODSIn{@q9LC-!O>b;T2KG} z{{CEqUfSVi?1tLc-8cO7OEm`JwU65Ml&bGLZCIZ@;2eDwFy~Eo*3>cE0WJ%Nz~=7% zVnpdLq@YT8_3b)^`Bd7<X=)xLAZL>w{p_s|^yb7lccf)41rX)$Lzu$=k9yf1yl3mm zJ0NQbI1$H3)eO*kOjqIhVM(WU@cyFG-k6yGP~E~W0IqAGFyn(GrgXQByyE&nu^^fA z*#k2pbV5)u)~5Xw$b?cVkfnnfas-2yL1f;5Gr6a(JC+ChZEJb?A9NYAKnXXbVFN8( zI6HKOulF!cz3dz)=I#eH)3dEVsgx>SQDpJ)6u*UF!nn`O`)o1H&!04G_&=(%oTf67 zz<r_4%y3hhg@NVY-a^M_>qo1z^%Wqq%OPzV^;C`So8A`l$A?7?tmuc<WX^Oz#0!2M z2nAc=c9Yl(otVFPY+ClT`$=53Ig^z0&CPJ11A#(pq(R6%C#a-pd31u?kMJvD8g5dJ zccgQwA-&&gaYY%ak80)M3{+Pd#$KW<-gBySsbRDv31(rcq$ZNP*<s^l6=9(Ff+j{x zMK{ud21C<1hwHY>-&4f)i~>W6?j?7@Fm_b-WW4(>xCkb{<09c{Cs{H6pWqroecp#v zej!M35j7cceG}NJ?es#I+?nRh;cZ8Q;pI6<E9@3wK9})mM#pn+qUBA<x;)w}0pnE0 z4ZcbHLsb=CI%Y)oMME{~C5a?w*7yFNo)*<8-d}Z4XbwebQ_9CQriCvSZ3}-+XFXWh zNxux*s#`iw&gAcf#lk=u)iQd8P8Ly@!t&U(c{Ld6v0anW&d_BK%AuvMJU3uM<%>{v zV7unl_Nb-D9+iv>@BSexAprV1<&nWfipY-cd;MwC6#<0Ct-`tTLFKt+)@QN0$aa_N z%5L^RI52ww=)gb#FEmi`MH~xAp5xTg)gL!J0cvDWl#8bzauW02A$h|Z*J$DZ6wkUv zK+%-l^q6Vg@qST5>a_@<b{z^o@v{I5A&s{v>w0)S(BC@IZw$<Q1n;KT)vRU!k15vS zpVzsc&;&p|$B;Ro6ax6%3)8$~bIfvlKi+M^I3Y)z8m7bue_g>0HxzryW5BotSadE4 zZG$6y&}t}cCDYb^Zby#*+P9Q=0^%`CKk2K>74Aay`lmJ0|7H=ob;3DpTmUB$oaRgE zpy@2OMJ&sjP3gRoDzIpwiOpLt+FpO3^kw%?0!7MUF$u5Q{j=S2Ph&;?wC3%{YY`W* zDNv!o>1`;xkIVY`zigYq0KV?&I*6QSH|w$RjKopPY3T7Zl;>>qg;j$+MN=3`p@TyN z{b7b)G-_61HblT~6D%uTcj+T=@n-5WUck!@Qs)+I2hljxy6aDeXnNN0MvRk}TYdC9 zOiqjByWE}6`FSU+a-x=F&yl)Sc-drk2A|1`Bps(mkbLz0xIr}=iSzD5ELe2aFGIWZ z=H^?gep6(8j?@_Lbar;ufh|3!9H#y@K@!5`dOV}0xx^$jUFWDjx!scUEo{MzfEtCe z#`RB5)V{nMo%33yc88POb<s+Baz}5uim1E5D0vERaieCw8TPQKy(||gKTtX$nf=86 z#3;w!s+*l>h1bVAQl^WYiLyG&cur^9-eDBOFFLViej?2vhU4CQh%2TD26T6)9snzR z+|9o5xrUXjUl5c&1yIE`EgB;Foi&D2(sH<OHk4BFoOnKoRa-J0vhHu~4FGjKsPe-5 zv&85c5Z2ra{0@*yql(X7XV72+N7(<Dx1GbRmZNjfhI|+UzT4YyzI4V2Kb`}^IrIC~ zVzL2+#E$Q-hJ+SLAP?iuboQ~sP~R%wn-{B+c@JFH_Q*}|zHAU&Z8OObbDH96rZxMV z=6s!YxGW3NYPQ$lC`RAU^iw4}B+~x7Nc!5+NUyfH8uYGgZNWK@8WXX@&Ql+`b(FSZ zcT&h$5f(@GAo&$ZKFOde7k)n#H0Jy&P7_@2VySnHJ?xXb;dca?XzIkDQ0mTHK2+t( zGh^!RU6r>c3_292E7^TVWTmLChZaRuhs{n@xu}WNND31rEjY|Bl2kNZaLDy08gu}8 z)-dxKt6G7H8zHp!D^d`G7}d1ASC*CW%M<aGufxhYgj;{^DRPU=8(h5Hl}>YqOgn`6 zZ%8(O106i!e=;C)Al9J+H8%H4{t)zKWZduS39#-CWt<z>_nR;8%*S*QeOo}6Q+o%9 zKbTTeMt8ZzP=&KFNR00lX{5gr85qCU3ol@FE5qvk++EFht+JDnX=k@kQ>l1AEMjp( zsC%rdTvZJ`o4ISM!5w5ax=`ZPWTr=b19GmL_k!{_P@sgK0G1Y=MBtO6@_;ZMeW13< zt}_|2F2Z(ZkRykbx5N*C7bw{(Unw>B2EH5C2ZUkn{FDUdz~5wmvttc&SpY7DVu11L zBOkQ;JNp^XD?cm>WoNuIS#{I}ZVgwB7;x+zTs%M(bKzyN3cdA|-zec@y<b_SWt&YE zV7D4Hk3~|Xe+6R&`kNJTOWSHDiYrCHOn3-{H9>rOx;>|{c5A$pxmFe^z-h*e#LtM5 zU3RRQX+YVxf3uX+wpP?iY0tJ9aM>cV-G1wQd~8u|X2#-{{Hf(wr(*XHmer4r<quy2 zn0J|MRu5d2OC(~yQA+xLyOc0^ciSCNvQ*b9!%G!u6cX1_6o_?K^++CVTiUYX%fai* z^3A)SodLlBz8cJPu`llj{aRjLE|A^vGt}^XV?Le$!ci?SmqWbETpE`qNgM{@l-I-= zj}UEFr?Zg@e<yOsC)i4j4&dfR-$G*;ygg?9=W2cfsN_-WY-Z(;;pjr5*S%REYs9+- zP-ZbOM_0gk-Lzwj$P8!aS0AX^-2iyYH#&QDSq%yUot;4j0vZf287d$=O!uoQts}K9 ziU6lFi<ubzJKR10iJ0%qal6?93oF4DFVl}{=+rtwy@yP+bls2xDkRTz#^0KgoZ?wF z%E<F1E9ThTZ?ww_(00D7b-;WKoxkUBD*z;@CHzL;?#Hx1RFp}F1$V1r^|!^V43{^N zQ9uh!IDd@RovZp?Q?&kS>$Dt5IIU%{?enZK<OAk(Z~r2l`Ae-SFxXc>MX_7{ixU1= zoDneGDLDZrWP_ja<}G+E>*3-GXlw4mu;=aVmNDy>g9R(`%=evd&$vfC`W+y^1lKS9 zy6S}erH{q*&X@I6*2!4q@;uB9>1O{Inu5l5*8MwI27+JkcTK#MHN>>GV+YVN;Cc=v ztKi`bC+eRx*o@i=(eqqTxSzyr*Sp4o4k5=S2X`Ud!<0}<o1y(mGbQ6RgNRUtQ)sbE zfYVNuC3MmVr@*_INY?57`>FCVkjuLW_>5)Yu6<u+H&6B}1Mb@m;y;|}O4dUy8(yGR ztlAkFsZ41x;fPF0X<l(oE+)kxXy#n-r0rB3Axy7R;2e+9!MO@N+1pU3saR51RNJr8 z5Hy^7Keq@8xY+m{5`2A^pQ*xhS2}J)r#CJN!IVM<C7E?<AAdDVI%F%)l+C>Zezr@` z%6XD!yyU$ULhv74A5+wgRMK=aA$*HAi}95?>%}+9Po2kudIE!B-1>TtdK!W-+V2&a z9DH|&das@iQQs=chW5A(?ykOa>w`+WKif{u|Ah(M!Sxzk9J%H|=SxRsF7Hx1A_<MW zKerZZG8wQd_hB;vmvflRz~HlAaz@V<IL_u@x6sQ|A8NiYgo;*VHo><eAWvR7fYn}9 zFWE%pZEF+fFcTqRZ?r~sioW`-qjcK}>kU7;%?bLn<Dp*4f9E%LGtBd;aFHN2LH&J> zIj&pm`2B3{uYY8LjRG~YIwk)uo_61}nSln>M<B+~-x&Fv!HJr2C0;;sMg=jjE0n90 z4&bBL)BZN}E=krUDxqe1&FQY$LiogZi=!!E<U9N!+7@Wt#b8Fwrd+SOC6a?aZ(X|+ z<Rf~6;;X8K@~rBXC6!+bR0C41<xjDJkJci%wSS&@pHF>n#7f_eayG_PSMW)q$$i%1 zQj<KLc^gJXmuJXjOuq0c(#&2ElOeeqjC{@gYK+-k?I1)3jbJ*}7qt<a(6WZAxxRke zpenZ*HqIa=VoSOnU?=GB0m|RkyV`q=M#Fw$6Voi8jSx^$`uc4aPj*$zw;+D@+1md( zo`9czi8t=!-z8_c6i90B^q?Z#d|u><bb*J!w?Z-*{;M=vOG;hdnDi)!ig1|}0p!4Y z7O!1rPYItP)-?;1+wIiByS;wynoJBa)F*H;73SB!Ih-e^q^hX$EE|*XBhQO$WlDE4 zTi2~Is+wC&pbeQX#U#ITP54Qn{6J|gg3rJFzHHMGKW+nF^9zH?s-AdV;l5~jT|6vo z!SeTO7Rn7KFnkFKln-sb%)DDxyNDvt{BCNkFgHKi<BwD1X!0o-xuF#-uy#C4yYE0@ z$~fwYsSdW(P)C-(sTVHRe^Ew`yl$*f$sH$_kLpw=VNQpR7)LK)oZ5@^tG<E4CPKo& zZ_i*V#|8fa*;4*I1v1{^&Q{`K+}-T>Js@wr6;}+@tQz<jaCA?7T27<qUs|{j*I{$D z;T~HRy7G3JR3y6tf=f`x{gC%}16BZ8Gx1+83s6w})5Ea89+CoX7L5Pk#fT-Y7@#3A z{Uw0y*Km`W;iKq61Xw6H-IoPE7LLR!G;4cQQh&~1pF+6oawf{LK%b+b+~2G2Uer5O zr0e^HKo$p*UA^>4<*(ct8`(#y1wC~=Zqr(de(ObzPYBza9J?%D(31)LYq9^~@BMpw zdp=<Ec8~E<A~yqMkCGW?Uj5E7I^hTN(Bu~j(WGq19q?m==&;b*YpR`xd(#zEZ3^R^ z_)NpF?0_hBH@Z9f6^B~U!yRDh8H7Y?iF0_Jq+60lWU;f7F0qzUq(xhBkkxHII&+3v zxu|+SM7yMpbQy%U=u+ggZ!MG%s(qjd_gsv$JOYl)Q@{i`7;p}wo{z#<_50=UJNxzB z{zZr{^ax!DWbOYxphg>vyo2QkvJX$C{i3QeQ&T>T`t0z%W_<rb<94#?o#bg>x?J*k z<PUvmuf_Q=n=_k@K-H2R?Jes{#{UQ=8G2Vrt3TAlpYWtVe68jevRAV=wG}cvfbee7 z{m<nGEHLo0xfreuKC8JZG*oUpso<lso>43-C`w5RYF$u3#%GRY_g(yHWfnfWKFxp; zul-Gnu6<K5n2}Q5RNtW2>ht~gjO|bjP_u52|3h9lu3pCems<fO&~C;edb&uzq^<ow z3!u`oB|MkE6l#_OkW)og&w&7b7!mTtMCq`DKRvw^Q==&mz7(Z001Q#g8pyOKYbDGs z7lMjiE`UD}d^Ii!_Rcw~`OS&nEPvx*R`hj(dRth?OlEH(i}1DX`E%hI3gaNx`Hx@$ zkNK87eXKJq=xI!UAjJwfe|WN^C_eE&9i7OSujkMIo)7*#0@|Fm+sv*FFH{ZvD?xqI zMUcWT(bR_LrOGkcN4=wN3jad0*Bcgt1IZ<IX;8RDqhtUKct*m&l1dRf9uApou!Jx5 zTqZa0PkKOf<7UeBU54rd4eZ~DYT7(WM%1g*=E)60wwo8pqMX(Q2_{D+sxfSQ6)-e) zTZEF+KzK95{*(Rk%m%pjjrRdFyGCPnv!M4;Z5^)@Yh1uO%BBy%SQ)7~*1MCwjo)#> zYcB=iO*^_}s&T)8UL@;ZE#WJL);lpZT$&NvoXDk&sSOi2;A?RovA$pIlpYlo`~X^D zBEFMf8F=e;zz6iLhAVM?<tVdxi@=h=+#myDe9ua5sXMzXW2um)QPphb!bR%6Imtk_ zP~pirsyZ*d9!ucyYgPU3IEhSQqpMIIHJ0>v>5&HMmT8>!9!&dVaB5yf!BkO?$<{hr z((fHZ75xbwKT!8xi%AH#hY#Ql$lMtlH*4l*+|Cqathw9g3!yqeU!MQ{b5ui@N$8C} zSo!Pp0XwjV<2j3w(<e@d9>yk+IRfY&@z?NOAk{?w#u8AN3<CklZ-KCv_0bY7QQ#43 zz;*_`0TNQ27G*rIZLv1&D!@y6U-jgOW=;;ZQY3!?40Bf=)%ovd?6GNipB!O_yUyN$ zi%6hXr|-Z#C$2i>=2in!nd$-Vq9STFu4h;8z?#lcm}O>*oTER$E`mlN(Y^kI{q97R zgWTJHT{aK557q{S!298(d8X9l--F*b)<+d>2o8Jb3{Mx{10q|v`}<C-o;^2lAOk@? zO>N0r?Y==stBjq-drxce^Wh+h%D4U^b0|@oN|U|K{H0}pgIRfOXdE{G^NfRLp+1p1 z*R-_a*=s$1L$3~faWtsAm4uEOc`)~biO%t4w!Mfl!)+CWYWj%AwYtY76{5cVP6!)~ z@XGR#V1<d2vZ5YrAs>fO$tsy1&4vcnQ)dVAQt#@assp%x&*kfSmZT6QZ`_zgk<$ke zZ~K}?hy7XVRm5!wWKAtK<mnr&V8UQ8sM0Iw>Fz!m!m;E~jHG<=d4Q2sq|_YQ;<(V| zbD^2=e^z$y@CyDK_csk|D#3qpYh=}D(E3c2yT`K4f%o1b#@2yPCfnVvuTh8svIk`? zftS`&wWfz`KlTNwCkhe4-JtBHhl_ZAn~2CrT}fk=39*`i1KC1NYgS!ebtu^-rj9KQ zbGgzas64;Ol45?OT}{2tYMotso4?}6N~a9wa=QB-!GLDzNQ?u*<mI9k5_{uZz^$yd z<ibE!`ZTATT@aT0${wI)<VwO;fwu*+02H!ktv)Js>HG7lcj_WUlYwShMd$F9k)%Bf z+|aY!^ypeMhNLAp8k|D5D4VGckO~rUKyMwxAZb4*WAO|#b`D%nN3WYIv4!?Obrpnp zqQRsDKxm-mjP6zcNB|;AKefM{n3(%GVINBm-*pA{)fnn@Hh=XoJBVhpRoj6O^&YK9 zKCVgfay!XIy*p$j18)}yY8iI_2OzSGVe7&G>e6{OzsU=U3iz0kR9F6+jd$>pp?QMa z*gfb*I`K_*tcc`G%YSz>O(L?8{}$&}slvQ>-ux6YxctPFDtafcv!2#bO+diQW$6%1 z<tbSR*z0JF_@7fy2tFuPP1r&C&>h0i&?1lT0`=pQ9z_3TPw+QF=%XNr+1lubl?Gwo zo?9$Q3{kd&vF-?%+p(&lOuBHC(et7`f+|6v&c$H_({~-*lMZ>g@r|Ywd3VdE(q)=s z#%lP~KPpYw-B1|jp$}18yv=_TYKRocewF|u@`H7NN^4t~ACo5P`jz7+<*VrbH2uUu z_jcLz<`u4S6ln2R0jXxW7fVxQPCBLEoOMAhTGULxei&?NC9hRDIjq;WX)rRv6G5x+ zo*Ii?)_I-0ox7jK$Ga4`K0@A~1<gFTnFJ2xaV)Pwt=tkA_pg5f+ot4cKg~{25alZi z>Kve(rk;<PF9BTFu9FFhA%M6vm<semVcCGDtmQ)s-&8nd#&2fgX+DZ;@2*c5R4=#U zB5#H?C|ugyyluh5#tE6-@GLmQX9~Y!glF5=3-Uca@|j$oh*V0m{wPqy4Brh#a;06j zz=hF8k&ulqwdBBu7fWp*k)3m}b|>D=o(zcrqa5wiy0APF_5?r-7{-dw!n!f$E({Yu zaOr!ChY~L0GL<FjpDBKjGc^o>X#(N!Gt={{f8P2JGa3Ug#yD4FDrZEd+{Ue98n;<= z-N^4MNq$<WbzbeUDC|Uv6v4#n`2Z<c1k@O0f1UuPnVI=4SUz5T<&WGcir)>b#M!qu z+(%~Wv+Nqrc=u{W5K62LMlDepenB36m2Tn&WEGl(H2?wwTDB2^$o8|QI?+65maTt- zU?3kX!>9SAzH5N%hX6sP|E`n{kb7uD@ssZpJ|p_2W4(-}^~TGkseI?p2qJl+7Rl@L zqm2hly5^Nj=cMnLf)bB}k!~s<qqeUXHnzE1H(D2GGoiA|Mw6;fsHxBcx@7|c4}WmG zPrmfro-^(S7qR%=oaw~Qla>YWAWdeQ!~;W{4C;gBf-Zdjiy{|$!m`vVcCdeaQd7Dz z5lsz@`3J>+ZWx5>$k(%qppi^;V#^0|vI_dv|Kfm&@~N_JGHazwxa3fwPrp@-gldI| zApIQ{7e1RSF2KQ$5jMg(IL_&=WzvU`V?B+2&8|1Up?G1j+xJif_DP%{ygV|A;vNu& z8VCU+yH9~%|HcB;=ntQRFSh<o$P12inzb`iiE7x>{2sOd)Sh<q8yCCx<3K-TUaqAD z>0u_c0TshsPu&~TV^3Ot<PA_tYLmg7m82P}-28#AA&`wdF*ST05(dt!WW&L(cx!yS z<D8*;>UvjtGBJW^z=*oP!4BEa?PC9z&Q{MYmV4HB^mg~p7i{NefU44^0)~W>-Rw^& zogH0?gN#R+W%jb=o;@>N0y6|KpxgdlUp~svnb7blV{eC^7`PphuXPwrmv$|h|8TrL zTML$2>#ASzLb+-vm{A(8B~&Qwah$l{lKPyKLFU0txcG{EvnN01sG0aEl#c~E{oH?^ z;~_bj{{cFW_O0RcnWq^U^m7*EkAVLE@$vB=Ie4Nb!df9~#FO-IX5?PRu76G}`m~Qx zJ<+>5@E#wl{8oE@#5%QZRtzekFUd1G7YJW#o9eo3^}fofo8}Ue$?9y6*4oTA`^%JU z#O^Ej1^u?px0$SzyU%PC!elI8?fsPZ0&0S=EzhblJ&_v>1Id;?b95Cpxb_>o?u?>) z`cE4gv<NVX`#r-hc4IcoayDe=@6R+*mOrbi_Pt!@BPF+9X$+pW#)-x_onTp!{Y5`e z2p_Vw)P$t5<$klj*o#)5s1I4C!u4S4trz-=vJ?juR4_3teRa6ajRB`kvtPK8XnlPY z@4M=~IB63FT{hCUf$LD*2~ADXRJ4r)y}Bmk<|AfUu}aT$00S%C-ovegn!nIIWuKRW zW3rdr+}}vKCj^OXzWS>QKth~d;ps-s8Q8)DcLyz-ejtDLAXvN!+sRsb0j5mV0v4bn zm>vr|mhJP**Y&9M69?5}js&K2QjCP{4U2%mef9x8{I~jB17;g!K@)!OnC^c|tipM0 z?|Rk$IBPtsJE<IK5r1Xu5a|QR+F2yW8Uw&mEv+tQY?n3AnCB8o9f4vdtOKM4(UxR1 zdulkB@9+y4B-+UiVz>?JR7=}t1HF{(kliByswJwLoSG_(_tenp-v#!GpuVG&yl+Fi z`IwyUO!VusSbG@v2U8@?(;!GwlB_)s*0!#V&2!tk6biOY?LYa6Eq2~fHj9o;`UHiK z-B0s|7aSp)R>M<Qv>^{93?Q1t7_UdHHAyCg5;ua@I6d6m-T%c|klr%+3borC+U3wU zI~<bgzvbu&q~r7S5hp{Lca@GqjS=}HA0R`(=jhO~G(Y+wOYKC*qmFbkqMW+~@Y=RF z<RE4?A<_ek;AE(Np)9y@K04^Ot^SI%j`(h$5D)fy1q{>V=wMJeo^P{70xR3y-Ms>B zdQ|ELn6zk}3T@QnJ^Ca;3VW>n>=fkp!rfqZ)m2uk?tTnJXX{~%9b0rS0KRp`$3>>> z&9es!@br$?3p5pJcs6YCuc3StWuHAIDO5N=Jq6jKEB}?a{Q!KXScSZ%%`p+rucpUK z)LpL2`S84+DU$Cw@rcCfb4S^ofso;uzUb2j>;^>k5MPK3cmQ?%7$$5bxS7oHYd0m( z4Q2I+%6Z+%TUTZVP>dz=&{Lf<^SS>CI7y4@&E@+Ztc)$3UE{pFF{5Pxz^Yqy-Ldbt zJ*<&G-U+~S^lCVFG68~NF!&&vEOr@WbM2{Ir4i{3R7p83_4Fblvv9u!4X6G2ozc-z zYG;>?YH0eH)afhUEAu%WnMLd4T&)Z#pcngCx^j1gcH^*qQSd|6#{DaxV7{1MiRXFB zO#iqz#mO3uQKadXYr6Lb56ljW>Kx0)j!m$I-&+6Opg>>Ca@p8Zg6(v003BM}+dnlM zFA(^I6?2mvfBYS_;G~VBc6zE)(?`rBoy|V7ON<usrBMBOz8kiZ_l3I1y$(|D**W&z z3Q|72M@3GmMEw%!dlQqIXsGz<YaN08`J&Zfa@#w~ErB}3<w<UTt!%SwIZP|??_O%l z6ZuvbLf%$*)C<SY267H@Tx1`h%t)u#%40S!Egz<}Ae@r7*qg`;8CtexUi{)=nJW8j z!_+n|=wR?{bJzKGOgVoc5o%}ZZ2#Yw@tK@l>wfGoc95!oX|sYvPz>?}WgaZJBlmrz zv3v?wT%oy@>_xwMJG9DsE3<xPUe+S+I!uqCfvCOkklL8I?H1Mhdn2^63MZg3QdE9n z02zSS205L~hYv`ODkMv9vE{6lJy%5}rgV?fl~Q`$NMPr>k^4Bcf`p<6mn*EDVqLQX zALw4`+iFs+sJL6!gX8r37#Q<97Y8uMRGB-N!=rG6FMfls%e*L>b8gU!ZQVeId|>BP zqzj<U;dL4wxjzP2<%rQHjh6l?Kovs8t^aEI6&f%)MHO9TN5AE>5=`a8d&&YwqvVZj zQ_k=94byvff7x<pA-4S5E?uADzy^AARVOmVp$B>5inkUE!W;^)3N?6OE#p<T5~sTH zoX?#PllZ*Dk%8v{B6V*B$bpS}>~4c64|%H2%2nWit9WnZEudpEZvyfbTs+LB!@fHj z7!^EVgA6mm-(H^XJ<2cw_Ikg;qHorbVMfox*Pax4C$8O2o!toyI9Vcd+l$||Wb6N` z3O~=+JK2{hAKBCP)X6F@H|Bfo*RJ2m`}AX$%bgzBFZ+aN>5w+ogyFESJ**g%L2xi_ zW;yh?^iM3pAypT<QyuOKG0Xg<U>OtwN~@Pydtr&t_vH0NG~ItQRdbIen925qO~hx! z$|zB(N^kBosO4&bvbO1yWHDMg!|Z__|M<5ChNZX3Y`ai$GPaQ?n$bZ4gEu{q7PS|@ zmW%J_kfalT)ln!Cr(CDe6`<TZ13%#Qvl>*oDD5d%yam2>;=iRnY@MNy&CyJLy0?hg zQf~Q_b<()D0-0?4#!c>u3GF)1uC;N@05jA}xdU@7*R0&D3RXQkOR?D@yG0xqCP= zHrXza&Jcf{sP(-`N0={Z$FBdp=pWl1!xTEa+Muk@t=Oh6SpRwdN;%C}LqDgY@)ytR zg_(&E2SPtdp!iSFl>N@LkY|FBN00oEE(KrtWcDO2)Dn`owDWKNQn)hbx%cI61%9iw z5C}_u^l%(L*#yd~RbW~sEeEl%bWy$4(!B(BK+I$2fxBTow!!nebuj>NqJMM(ONtiH zWCQUdp*b6O#AE@t?jZ1m>*<)Q0K#G3XhV2nIFK6tW<3SP?KW_pw*q2fL>dA|4%P+y z{l~nc=OcV9e^t95RUMa4g{X1)VJdhs@q!GgnFZ0$cUPI<uP5t%neYI+L4HOi4~|%u zw(VRp!=)CyzOv7Th&tN;N}Z_kLs3B^zxkngLs`t7ULm(qoN6;StZX??-p>#N>F>>c z`=(pkL6k~9Q!nl-dq?d6UUVg-ry$ss2==-*DTH@Tprg#l8!1`AqbVkjqzF>0UzW9; zwZqouL%k|j)_IJ+8rRkS^J-D~)ZgDxHy<d12npVT)E(8xzCFVz`)k)Zg|x-h7-9bH z$?*$FBKV!Ejk83=j0g4)_QLCvR>6jTjR^iI%BKzMHM299Kwxb@FhTGdKJ~*Wvn5p! zn!vMV$Mb}mlo!Inhqglww;&l`=2I)ch*DMY*)a3SHWa6%v{`wjt}q|--0d%<kzjqz zbu`)J!tBb|qDDb(7t?Z?*ofs3Qw_!(y-IZ6oXb2O(L0t0&CEIb75kns5A+8Hvls6L zK`Bn3-a~qPpZF@;_Q(5(5c2mj+#O4RM0!P>U-Xp9@CG@D5QYK}Z%|#35K3_Oz|vzS zkJdb*(R>qrGu|T`+#Zj4p%Y&jK7(IY?P8z_A4rag@II+{H7hx9{svf>!u4DCNGS$N z+|*yQHCRm$#cTUI5`Zx6KY`RQM*#7<cP;H;S-oQ-4BP4Vuymri5o;svt4O(J^{ov! zcr^5hS=a<syBEfDR?8id^U{?oUtr<@&2YH@xMecw;X<uOW82NS5^uWMtM6c{{#{*E z2`M9E62(+bfs?@SwWSeA4Yc}Id4h@R2OLAx-Os%GR32L&{%uv}PFjosHz!aA<}~*n zBSvi8C$U$TKpzux-cxa86*pqRL|ztNai3)+zIVjpwZ#9?bk<Q#zW*Bs5fD&7DWw#H z7$FL%FhCHIPTA;^?%rq#B^41E4N^lGT_Z-9^ynNZNNz)ruHW<dp7Yz^oWnVLp56C5 zuIqIHWi^o{3tQ|)+CAA+P0Jrlo7sO~h-D!rW&&kgAg2PdIOd?ZS@e6tu`I3TYGGiE z%VR!l{$>%YXx4NIsHL3xHLYA9q^vOhfi2d$SDsFiC17v@mOR^VFuZS|zL!h`Mc|8G z$BZ`(Md^T>o7vq{r4-p!YfJFp8TgJXdb>PyL9Ho;8ltDHrrqaB*}PPFv?7q4rMY%* zj=*^b;^|&sVp2(Lq&9%m#<RE_m5CUzy7*?X+Cn3@T5~IM80F{IQUhi(re%c=e!ZO` z^104r-iy%8{#l9S$TS(S4WDi$(EHLIF+h;1mmER0G_|27_VT~S4vXb*==l;>mok0V zjitOQ6TdR;Patzpz?(It@KiM&4$g(DSkCe~O;ArH%HpVc2scCyN^x2)$u!{f)xJ=b z%nK+K&{@nqeX8`;WIzk1w|t9Iw*+b^h%Q)4eQsX1-4I%TfPDUrAky7jE|*`pRM@eS z`a&P&@+DHS@NI^aS6H^^=##urg@7b&aTUzLjKK|ITIKhAgyGj^lcYSoe}VbTiiMRO z3kygnCp?_!Y7^F_w0TlVj(!U45&UhSbAo|eHn4UMT1UWwxAX2SJqpY&<Pv@?hI6}v zuVc>rdLZa5I8t_MM>$c;IT>65mOT8@)s*1_<XeAK^kIglKQ8Up0g|&k(OuX5=SzpS znN@Tv&=0TqnQUhrI@)CioO~wc11%f}(y%$!I&rp|x|Hk{>s(>T@?ed9bJTaIv4CIK zP$gwU-ky3YHHFGX>K8eGz=lSCBPHoBW8#ulV(5Qa+;Vtsz!mrW@uH@WS#XnCZt28O zjAv%=pm}?tVhBw>`(zFG+K0(#xtPBokv>b`SUoSV8%A07+SvvX5PicA3R%8Kftkv$ zI91ss4q|7j_8*k@&7Sa+sr!_kiAV{s_duE~<i3n5vOZWH1)cEn8d<sO2(5iXW)_1! zz;nZ@Qa`FUk6*wB`+o&Zko9?$xa~ANR@MRUI!{b~QeVFP`St1+b*iXial1-@U~!+y zpoff}*~70x_wL)-aP~mM`2G009H(q3ivq8M%1Zdn5pG2Ez6a;KwQ-fSa<+s2Qk}AY zhrIeRKY4-LfhddceQ#*Ak(}9=QsJ}nO|pH*2T>H0wRw6dNukcpT6&WpvCn;2BBOlt zH(lqUe{YC<0du#}7?Y|i-BJ2qRbj63v%H-hpc0n<x$}0@S<9)l0CIZKT)hv?SL?|; zI88qi@JAbdgb2^pM1l>5i)Y6&5mh>)0TLqmxQccC{%e?sE{^|dQu%D4atShNi$FyK zgTH5`WXFWt<ahFzqU1X{I1V{43tOV7v&8;LQ;8`Z>^TY_Hid!vqRPufuh`rauoM9> z)Z2!$dreM%J=aIXaLcD2UkMmMWdVHxY&>EqxVh(~L78HFK>psVUNKySp5yJJZ8=iF z4&nK-OErwHsTqh&%H{YzO?;&=^JX#H@=tX{f>k2FEewBayGAR?jLgTl4qkzN&LOe4 z?syxV{#0?Kyr_?w)0g5M<@c%CQnqvEwveJKjx~4tK=f8N1j26=AC3DVX5I)KdD%$k z&mZDGr<&f<NeP;O08;?L7~kjBsn%jy;R?5qfP+A2)m_8iURE<BEUkCy+;v-(tf~h1 zAv*2v%oAc4cPoV^5N{w-18Vh0rtfEzzb9G<z0^HzEqr4sqrbxQp!SiE+HI?;ii_HV zo#BPU!P(AuB09&S()lOEY{@U~)b0rIMrK)6F2fD75wt5FEI~7BI0?jy+)*vNLS!`6 zP0AS9lEFrW1R-c+Aqk=Z^wD7oFYn%U&-|&q%PrX#0+Mpt1FsbrM~ghet4c&{`k1XP z_*{>tI%?n$UsuW_PDHpl%yw$mJ5R-Jx4s?tfL++0^xRYl>4J6bNC;*gW}({&>D@!9 zCT!Cqrqy>oI4>~W`cBfgq@5g|nk{-ZAnu_>r9{5$rdRiT#;rMvp>XB(qHqL4KfbJj z)&6b4w{JOj&O89TU$n9mkS#8>Na&=3^Wu%OsllnEPa#EHvDH-ui0YRWfWD#lSfW@n znAR;Evg<`6FxmVWyn|+f_q5OWjUodb+Rcd!gGRWKCfA(D4%$1M1@s|xa^K@BVdxh; zH_dF?)q(Kykh?<;Ut|HuRY(IIjH~lDd0jDd57T^P<NFF74`dExerE2Bl1txq^91xg zF}4A46lh!jJ#HC{o2hl4q=H9;r{Bj(H72K|V79JJf!xtnM<nDpGzAAtETX|JY2I$b z;-HNhBRIhU&FCs8cjW2mkiDnI@U+U5-)(OM?h0v8f3TV3_G~WD<Uw&lDI;5vt+I9L zDS`9@Kb$Ilf!dH)OyrILF|~vqzkpgmADF#?Se0$<rFk3ucJqtX&(`5kFE4$VVgHKu zI_l;JKa4w4McoUD&RJ!x>98i**{vK`pd6v3HLyz977CgrLN4-^Aw#B0_4GFiN0G|k zlp-eDq2?MxBb<AnZK}B11#)`#aQ?ZvCO7~Q{f<kyNtDss<>%;pTj3$OaP;l<<uUud zdKlVxY|T%1%hRFNKATF1?>=-F6q41ODdL|YKE7VGuULA2(QD091s<ET<XSL3g<n)w zDk9-auBLxz=0!3;Q-HGP)5$9Kr`s4Ksg@_jv>+V?OeAmuuPQbws&XAnpfZ>_0C<6= zZ2bE_s9emVSR^yOXdBpPXTW0s?!2B|#jsXDLz|(*JJ?qzG^je8P3(A+;9xqod9)NW z*av}{c=5086$RDnaTCfv2;o&A%FzaZX0Ka0QoOzySeJJTV<p?{Y}n5ifJ@AoKm}JE zWQ6mcKO_vlI{YtpM_MG~p26)tf-RQTO<@Yq=OiQozTI+$;fJ3;|5=GadHaT?CqJ0m zCdkF#FHDFs2a=M;3(%t5T|7(xi1fp52B3T=;N#=+0Nn*Mwhgevz*b^1TaXn|;JhD+ z+_oJSSUljid@;rBc&nNnN8F8(lcNw;L)@H}E*{M)mgMF4w|99-Z@8wtQ0@;^i-O(a z6o4{-SEo9=9UB0b$>d<&+fFreHnlZoQ&*o$w$gFjxQ)^85+?~3qYG+A?P0N6?l>p~ z^&dyCevw3Uez9HsKh9TEua<e%L`gq8=&lKrX{_-tR)kiOy@4`ju!+dbO5OhVLeIAc zETXCWg*Yvgij^VfegZ{4f$lZ#b@OaaYri)5d^^Gb!cO9rrAzYAwGbQgPnJ>=={{MY z9rXiSHae$GD)HEbd}J#b+e22Tg#BRD6rQ*8s$*@xSTg?)=IjU>E2WxF<Jz4?Rgv(L z{H3HP`B&{72~`J5WX9ZR2)|>cO_`xj_^=>jx{jyLth*YGKp7v5>ap=h4$m3`p@Q#2 zAKbS@T#{U#`O2+uUY<!pXdoH_vBH0+52|goz9%q$2i4DdblW)ZJ(WjRZ*}iNGx+oV zvJy4~WNBzKUyp92!+}f@Z%&L5n+P!P6Dg_dAOtxy)X4?YSyhSwN)Okk^{_cH=WB+! zN*H+NuWM%??zUin&Pn=jq7CK{;8t*zU~^JEQNVu7cx*_{m%@`Cu+G&ic(~Pdh^u4d zyRJ!F5T}kYIZyysJQ|SSarzvND(3ULU?uRD0{^=1DIol7E{jji_1m|c7)f~=pTi<r zrIqud+$*(XI;r%uDm*7HrjOa7?Oud>Ga33;Ngg%rS~)DJ{}#$X-AY5_s^INd)X$08 zJsl}Cd)%L3VzeYVms+kUt0&n^bEanKgliE9dYoZ+TX=%LqV!NqN^l7zs6g`b9Ck9u zDGiDeG&9V2fgdFKe=R^<^ZElLy1e;XrdZYwGjF7+s9u%tgo)a*6l;{IB@yCT_1c1z z0*pPtXTzXR*mAPCYv3v4LZ;G9ZDx)I_$!EOLkBt`!Iv3wp1bb_`=oQrD92GtPFRPv z7^^(;i53gp%}o%bi-i6-yWp`i1Pc%K>S=j+!(ZzLe@0nv-YDbRJuj4WgrND%Sa^Hn zm}6i4^OtCpvQ*2X762`1B3={<g(x&pH{@^Qxq`M+6V<KG7fi|@7N(kqe?d;*eTr2y zmC-tw5k0kHg%i8Dv6N1ShwN%V0R5evdX0?iP3g*qrXFLy{NiO#ys({WH?t~=&)%cr zWlUxk2e%N=jUztA)y7b>g^T=ODuthhiv6DwT!oGWaavI|SY7>tA?t?B0~&rp0Z)=l zo%g`UbSDqAtXWasKR`22PAErRnc$WIzO|wcp!W2=V1$n|6ut%)TnW!{>YsFqYh4vK zt(Y%>vu68G^k7tW6gZtn08u){1xPYXY&KcTfL-TrrA6e?Tuj;a@V?pE+Y0vefoQNn zmhVUkAN|Gym(U>DmOH(3cRAm2US5k*9yTD=lFgS}L-IM@?Ypje`swI{@N7T;ppZy0 z6>4>7NGZNCyvhVNeUJouO^p2=7NHTB!PdPXqJL)}&|_v3Jf3g5%hm})Ym6P<li#yC z>1#@7tgS{|8*IQRkBQ7wp&IRrW%XiCTmJ#|-RE>$@uj)WG=@qB3t@YHQ!`^A%8Un0 z0`cP?EaK<_ZSloEh|o*2-Eu&m^q)vUGKy{yNshzfc-#zk@jHlp5*kkKbj~{z^Gynr z?{4M$ayY4BXs?cce`7g4%D7eJt0s2NbE&m?=&Q1WeNikuJhE)mHqzTRf7ilM->rRB znQZD-6#ueN4Ir?kOwx$Ug0cd12aGX9t+(GnyPAhCnc)>DeWl;T%r8=(uZC>7Qupme zZNKQhshbw&3Ti-2iS&q-#3hi8Ft4GH=KjX!*m${aTi!wbx4>FpI1^tFRe#<;R~zki zN}=ys5dJA{Oa&&Gse>GPt4%Jj7%4zy)rB|U!(i@x$*?)Ftn{|{*>x9hqz8@}f&k@e z!mI;#1Tf4GCko=8eW@U7>$T=+HH{eo!N5R_`oAyWyd|LF5v|3EC2Xw+zW<|-GiNcn z{UhTjx@ccpD{lUJId>fDCF&Yje0e42!w^6;X@oHwTL5dUeHQpmJ(H2kqEi{22XLo& zzo<{_GXZAE43usP@hQMH^1Si}!0KP;Cd5|a_2lg8GWz)#y1WbS_7z+ZdWZb`zuawd zbnC3r+-j&QW$7JYPSyVD;86Izh0e$UM}7R|`Jk&)m5ThZ-au%%wJo{;O~u?QI%q`y z<KgG0<tYL4A8#c)Q%`6XJ13LYGR-l&OlaqUk^^Y+x7(IgV`Lkp?=%dg)w2l~+v=AT zylg9se%yqL)Hzv3pJ=2V>u42xNMK6c<IWJ#I;}yel?v8h02;HW63k?HCvvzt%9t_0 z^##U)zdA0ibhD`}ILj-Webh5UU+G`#Tyu><VUprzC`D#SBzk#%Y)Bxvvp&B_T6@#_ zN2JJ2(4d~UXWhY-1>Pj-w`5Gdv0Oj1yyMRP>%l4R7Z0EKTqt*nz4Rp+zGPf3e|t>? zn~#ww0`ZS^_=Y>K-zauv%9<-F3Rn63be76JMomnCKNsSaaA`SF*v{JL%fCF=;qdQf znbQ$QKlIe@7^_O|z{+<+<okD8$n2Yszd~KZD?Q_+%5E|Lu%=LVXz-xW-rRE2@-e3o zLM$Vmb0Y`zGvc$}tv{q5Ka#>|{4Sxk;UQZly|<`TR<Whpy~?_oY5k!%i<KdOBIC92 zySn_ZJlq-D4yy0+rj&n-SYq|E-UBW1v&~)iBjeo5dW35{g4I$v*YvN>lb;#lY45iN zT-?I301qu;=mp>L4S0gVA27=jCST<z&=u{h;%9uWa>GIS7QbW|^k}Y0Uv+<DAe6_h z___-+!gbWDcY=>x6`C$3w%-GaE>vW>pJVI7<5n@jcRB*V2>Ea76I7H3U|*0IfkX># z6yCMDv%K^DnE^W=!F5st+G^t#t_r+&G<BGkm!ku7)#$J1yL~r^6t!lzjI<vaHD<W& zQWV2b5zkATD8prPp2r!oPvjiQ2+5nvjNhYpS@@v3w5SB8q`Ohx0AY~ga->oDwz)J< zvC??IXc@}Lp;Oa7MF{RVhJ4Vf&ljQGV=2;lT4Of#<W~E=JSXLNu~7S|-1$UhE7pGv zOU53MF+PMml1n`MTF<2g&x+_{=ZE%Q+9#@XuctH-_PA*ZTu3oFNH#L^Tc6rRJyaY? zrf2MVAF5wm-AT)F>L@ngk>wwGS~}ksPZd=40I}@!83N&9m>nwBGv8T&WoB1h6FZiI z^nrCB(8qyBeMB%?qp~}#64*5n^qs<IMHM@F29wlTOE!Kp_6r3brMIvl;xa0K_vv58 z+_*`ZDQWrDA;XQgDR2J{_bX;ze_cW(a}T3SVPyJzrLq{f9RHw!LymMY3Qle$R#;4; zIB1I(LNq)QMjb^(CE@*bU*+sAekFsk!R`ZtT@VyG>{J#(&dy43Tm&9MCSMmv$jgd$ zYVscd`{<FX*_9z~Ipvs>pozYa!eu|)DK#%9#lDw1(&@E7(wMP*ritMI2oT~Qjy3=V z#CD~3wOCVChX;_87MZwibulj;3N~=%=g+IN&}+CRI?pf2>n+Xp5$Evp-XP#j`3{_J zBZ@a6K7kOyGj{ODO~>QNFx&R#yZ^$h^B=07go$BNo`)db8<xEW6!#g3d-yj@NkSC$ zS?C5o#WZqOUi1xXGs_h*vpmTy&W1K68wc6b%k_s9do#?bq3dgHDCOKzU*jqyN?%?$ z7nqYO0ZVzR`M@a<{G^T|YgAH#>`}`InM_02mM5AF+-V2Vn#d~=EFy(UF}~f%N+s$> z?w|vtBB0-=k7k`>S$FsL_WB^E03vCCIFpTv=qOwf3L5{Ygk(IJnfpuMDq1)zA{^nF z)huGeBcD|=!5I^x5F9gpjSke}@vI$nCGGL|jeH(yG`^+etUJm#RYz5(A-IZbbT)lC z)v@58m<<(@pBfn8K36J?dQWF=Aw&MQcy#I$*6WpT&NYF)d78`r;#_PY(QGA9iBClK z5!xn(l4<8k8Rgj=n=ov4H7_4md`|85RNKd*!02DvC&hPsALzy|0h)$~!D&ICbr>+9 zK20{Fn7n6<YRZ8ZYk&r91};tY#W)`Nb8hBY{cEqRMs6?^_6o;OrpI)5m_{*cMx22Z zwyr!U3uvGGx;T`HSAeG0tF#qR^8XcZumQAoMk=sZ06vksT>(%pa7-Ba1J)8nHL=Xb zaPSvdl?Kr?NB_dPCgQHte-3^rVb%>Lf14IlUq`oa<JQqC!Gby%2Wi1#Y@G!b(C<m! z7dTB|ouTcqar>nMq%MIdvNr*6`V+v(6i^^wAHWRnf$mD%m-?lii8!}}gFD?(+JLm{ zDv%DoGrMquL_pJXSS_aE+^A5MhJ+%G)<M_WiDlcI7hyM1XoWy>;z^*PCPH~MkU}sd zc%1#E_z0OfU4u{!bnYNoxb6E-Q;rKKcFLIT7K@3t#EJ)FOOwUMi?lDxBh`^X0UC%0 zP|z5mKVb~^&8Y@NQy-NURDqw~t3#^v*1mXO#`D?antO;^T^`*gbh|Nz%oQPAY(KD( zNHGq1t9t6#gi$~bsqCX#B7!>2Uky4Hxvw0(>g2iWs`iTRz023WWg$-9RZThYgo%2( zedvag)^I@i2_GFJCTXb1=PH^(*#cGM@_=LB<(WD$W(Z6*{FURHw4J<RG;0Z!V$)RV zdp>^d7VS?C>L}lI?&K+JbJaxH1~f*mLzGffWeNcnBrlQXEA?YIlA;;(V$zO%1I@nO zW?R<6?uxl_`minxMf;>_0ABv8yw80z!z*U-N+ACvBSQhCNPp}VYiQAzdPzml$*lqz zN~E~uj`p6_2bY0<q?D_ONcP$p#?EpgLRM0o-41|b;=ca6l6`@=<k-O@BnE(q>)_1O z=RK<8bNsz+p88K^B*ltl`I=1;tm%PVm8R_!{f4x0`)CAUl>7!Xz1EPC3i%+QVIG<u zGN1tirxf}w4=~F`jIOKf0FqGND<fRRD<E{kPXSbT`4muCXs28NcgLjh`bvz0j#2az z!(VAmLWF|y;g6x<&R5Zk{K?HJDQ;sYvDXWsu)Z1GHBF}C%=<;D$s7h^Tj{~d&k*t@ zl9jl9<tHw`LHs);I|Ph+A15n5Y9|);EoP=f^wG=w#rF#M;0?jORFFZFkW(?yCapb6 zCN!`qKs0PTtv%Sq<_^02Xy0U?M3M6RkE*dng>fix4DO6{mpg?_2$!e4!ec4Yr5^k1 zBGh1NhVwJnGK(eidWWhK$@2FGp|Wjf`b$;5289~|L)KmY0<?F`N$aC@5YVLldAVwP zJ|_?G+>6gi!Bu<F_y!=$>Tmm2;aP`RKn~6mOZQ;%XP(GgXn1<dEPFOp=On?U<pQSl zT}&(9+3Xro<YlSiSAGPvA=yk}X%C1Ql;sn3t3BNst^yX%n@`wjyS86y*U0mKKZuy| zD3_^Nta0GM4-)h^Dl@F~LRO`GTIaNQg9;j;<j=N#XFdKq+0nqDQh<DGzh$jZs1)?K zT^(_xy$J(LoDNJQ52PINPxGB)3ac0}Lxl<IuH8*fgvUIO9tSvmcO~y*xK(=YOXC-H z?#(e2q=>IJ)WtnZRCN25X*%D}@d6$6JJ6QP-r<xLaFY;kmN?#$%|dv&g{$x0Uyk9v zu4aOaDx1#HsT=KsWZ*D$fKP#tUVys~G&o5+^zlvKfOyq9V4mY*9V;2HUfoK~5D8ZA zbEGXKHYq!Zv^kG7t!M!+Q~tnz9rg(;p@2SKo-0L+nzZN5=&xZ9zdEmH2G(kB;eJhk zUBPx_X0T)=+Oj*_y~@kbu_O$fU|2?O=zYzsh?=9k_DMr{xeTV*n{BAi!Y8qxcKd}3 z#)P)Atypk|+x;w~#vVc<5+O9rW{cK40`GlWyGiYCuzV;Cqyq^01P>|wRSv9WdNyB- z+?pwz&R$q|M-gDl6VpRc2_)zV&Z181O=M^dqU^qU(HuwleAsMb(iI~vVH@O>yWQ*a z9h!eQQ1T@?2;YGBW|cIeJG*Hkd;O+g8MNM0^rMeYy=J4`(#CMzgft}Q<|Ison)dnz z#9aKzB7!&>R6KifdMPjizQsnkSD&vTxr!Q{mLDdwdj0gZ(bJ^&0*)W50-CPMYQxCT zKt8H!akooWRma~9g@Wv~7Slq<iAM<7K_J>%tr8BiH8GU$W+F{r<1aDC4%5zE8Y?IL zoh%K?GEB|wgP}B`QB!*3;%q)=hT+^(nLa;5X5tv*UHJ2(A0dMh-qij09`jJINJD2( z7+>xs6@BacW?R*>22O2QN<ZT?=J`yuOvBlt$d>rxP{=maF?(Y;6Kid$%%-!fjWchv z8tnpH^0dZo3Vi>D{@vSFzU@Z`S4<PRH*G)<PhTDCdd&P4(><%kM<|$0EWTyYeu!H! zuyKe6pZm{H5t>r{rjC$xzu&r5Ml8L0(-f>~3(Mf4iHp|)&@xXufkM`5%jyLayw23$ zB-6NCiY7^<p!7zZ8Z}0u(pI{iBRcIr_BIpkK0J!e;d|DH6}HqArs{beB!na1@bgc} zDVUXi<nP8)o6!nK4}y8$^3js8j4!W1JdUQiz21KI)f5s|ZCKSh5_Iz8>U`bnu5&n| z&1ClN$v-un>n3=Uoq)QNBEjaYhHbBWvyVSX^CoU!%!IN=l&^mvH^TQZHKxvESvq8D zTOaGu2SJcXLR0SZI!<saK6ulQGvI@R12%x#ra7E71@c7g*UJ2liBVLsqE~Tso!k#? zW}VRIkx79S%vF%;YiFmN$*Y8*;;Tr9EKX7>O(P81+UPsBr4k{(vLdq*R-u*v;trq{ z4UtC5HIWPltYmX<><&+>e){)ly<T!dA>+>75*q7eE9{$4O(1czW|@^&MtdNa`hzds zOk0U=P<ZBe5ue;luMQxAE;h(@=<y=%WID)FD<ij6xOhLSmSxe#u%+oVRzEjE{*d^j z`@LU%%(_7RQdC;kW>zO~mQ|0uK`Clq6DAG)R5Ybp=!q=l`?V-OG1NcZG;_*HlKA3} zfBN=>cqqtxVq{@;Gzz$FuJAUZIgZaNJ)bj>90k|qhSlK%6T=FyVL^dJO$~n1KMh|% z{|*{)QakJ}zZ{I0zq$SrLkthKoK}s}kf#%uV*(B(t~2n=`X%h)kJ5TRGQ)4=XmD?d zp*bQl?<f7|@W1H40ie;1%hro*>Kva8_Ne?|s$zmC8?nG&-7mam>!v^xMExsaa%THB z{HDh=7o^q3xUqzf&k_;}xtX7lGO`><0oOsF4-Tj@IT-x?{!!c@G-koQ1^!?b<=$h$ z6r=Ugah=!=xWX1(cOb}N+X2+*Ilrm_5EkZQ0(@kLU+f1?0S4FH2~o<}!#n+UI5FDc z9pUmEyp59Drskg)NgWUbx4;t@HZ7N^25hPT!N71rd*t0^`2-~k&W`?l7KZC()nPDV z<hG6_!>SjrFSbo~-02$RtI>{jH(JOc-x@MxzX2Gh2KV>($)6gYb`!dsds@2#Ct;Vs z)Fv&c#qai8s<8hc11NV3FF4a*JOf=W`75$)nfwXM*K<;WuA=4eyC$ubSv<URfsNKe z{CX~knJ838K1i-6?!8>E#59IwM>~-KC3)}w<w*#NFtbC*+w9*Q!arp51Mv_8%kSiG zX8e09b?30DsK-fT3S(2@efIwKt>9Xj2I=>s^oN9hkM(7HxUeuH^j?y3<yIYIvHPXk z7YBMfH+7jp?d8lg_YJ5AIiL1d{+fAnEB*syH6b%&xg6AT?=vf!`f+i{3kv6jysqnr z+JwWzmNGuG;4~_Ld1l>ZrC+cEQ-*?7fuN;qt=R2>9VM;)gI!L-U0xuqk`qnIYzknf zHH1p1#`>HOftmgM1E+FNcJQB3fHVql8fd3nUOQrIIsn$0)lR`pnBZip<lUA-0UZ)g zXC+{ZSiWHy0>xE`iS}h1KffsIj00{r)>3$W9w=pQzcLFZRr8S^uCr>sef$WQeFZEY zD}b<%N8Hb7!6+{LAy8iVz?{evZ|dIruhiPYJxeLnkB@#Au3MCe3}q}%>w<4+mzF*- zG7W{s%$<5XvR$>!(cUkVu$ntGwCXy{##_FuL@X*R7z~Q1d{gR5d7du$`!v$Cbr6;% z`1c~kp8YcL>+vCuk%!kxl{LCrW|M<Q*sQj@gSeX6BxfCD^J5uc#VrXpoom@iqE_#| zy}s-83*E512r02|b6|SUkCLXDD~C*iYI00?AZ=-KXg?W}wVj0CHCqP?+wd+7o&SrH z#2=!^6LqHavwrDZMs%->OwfdYn4(qwGCobvg(9NqN!S{KjbZChsQf)&LFpI|%Pw@Q zHvh;*8-&SMQ)e#MMT%BDJ4r-uu_MT-kU+4B1lfbv&AlN;=K+ZnS@;j*E$xKt3a!r# z&;{0)*AdJeIF^tsSd}UX<Kb?Q5ab;)19pX!AI}>{o%fpQ^jh#QL9H~Jp(<ex);8bU zrLv;(>^;>K?Y((2oE@XOZp$k%vc`r~zDcjL^mD=Aorcto<ujr~IHp_`K8u`Y;`@NX z#`CqIW8mS>(ZD`{42|s8hUjbk@~1Uy`tk-cB!8u2ill-rb(n>L-|*tVZNKIl-N0aW z{Z+c07&p);p~7_g)~$~PP|4{4Z!^Ahg%&Y>35+qP-d5G+iaZAIBircUI`*a%0L0vC z3qmT%7YECn{WQNns(uN0rwWVclCFpzhQXzua{<L>l1fneh+}pS{1WKf*VM1FyAq-; z-$}W&^aRf|`5SlLYUJ>C&(E!X7JOny+m6nA=eAJi?`n0Dr>00=(f3H$^+rGHNaoVg zXD(od2=2iJ*E=bSm(!Z)7Z!f9$S^=EGFoC3nZ%~6ro|X<Oa=QA$8Ba$s6w5?n;rDl ztC$)SVr&hY)R)%2C!IdqE#_JZ*`}pJ3eJB~)&?6nyzE!ACYce_3CNS!oUnSDm1H4w ze<87c^!plKWpPFX#WK+BCpdrW>0D}(dR|Xx>+svrA$yyoRi&xAqUwZEYRMbhx4Go8 zaz91PN_(4rbiG;(Rg$G6Ur$$!Gd_a_e=%3{mw1aisToO15HpSAJ@|E2nYsx!K^E^b zYYX5lC0s;F=7MdDP9YJDt#A{SXE!)H;A-2vv^S{61%#*D7`(qJ+h|(}z@*?pDttZx z#_E|`UK1~%K7ry9+nmJNm!%T-Ev-hye%~Bk`1a;ShM{W)h8Zt&9P^K>q7t*NeVZOr z8wF0@0TmgLwQ04$-od41NE~JJ>*TE8*{$KXP6dGa0R{#ZL(bU%ufgkPEH`8&=JXBK zG(@Ia#r$Eh&fy9+^Q6I3d8M}el#?KA2l#PO1#3QyH8lr-iL!LN;u?1;Py+1~Olu96 zY(KI-nhH5Di~w}rsM1C8!+zIapF|REi+}%g1l|n2r9&L*xov<iaN~$_9SYPI2u&Di zq%h6lD^a2-*AXhXKn3fzxnt>(YxpfnECYi#!w!(%BR9JjM$XVzgYflYZQOgXD2uYh z^{NGi$1*X8cOZp}yHKp(@Vaf`ThPI4POpg`eX{pW;c2GARm4+(OY4Ai4V{CMY^7;q z>8+r*a@6Xmvs5_;Dp}5(1I`XnLpoPU0SlSNMFFE6?BnsK#mn&spZfSTzGEPZqe})o zaR&iQz_XFmQZJCsriOV*-P1wR_?S(3<j9RdHz4=*+XaK14swEwFPlVI&{twFMXAv3 zwd;%2*${g9>v;-aq(8V<-U~Gzo2<UPww+h_#IyrTfyQ5r(Ytp&2g&L`iv)tHi7&5? zK3>7I?@pkb9ki7bvfMl#zIUF50|4s>d5`PQT(G$aU%UL&4W$aL567a6&N&Z|x$bk& zuEaXT?AF1AqBhDL^ACYZ9DOuzvE8Y@Kba`<Ma(9FuIypbdeFbQRKizn(b(E)C&}sk z1Ct{Tpe-qz!pw+Zt5GCSEtTCRX-!BK(`h%;S~`!J#T%j|YP~8$1k)7VhBP6Z8*3?n z%A(ZfioC2$zc?E$5*=Mq@^n5-s;3##7Y$_CjN0^HA1RGoZ#FZ+aamRCfWWsh=wh|) ze|jx0S2>f<Tx>Uh2zNK)oo$!92|KO3hn+G9Ln;`%(VwqF!C&fEXlHI`)b0mFg7Zxb zapt&Mel8%a&N};C3da?o0v%MSlM{Dd-)8h4d9=-#iyz1sR|dD>?zOX`8cLmR0>_o= z0At8)l_>0?O$P^obkk-bEtj0zcvNig7W+0YLAZhuUc7sXpR1iZs`9$p+jFl_Uwka$ z-qk--qm91>d0s`<Hg%l(^GBIye&{?m>4m=R$fY9(+nl4duc4WgqeOB3a<&IA8Mm0( zEH=i4zbB5{jIBlqDjQETzJ7SHJw+qNCSu3Wu=n&o9JVehydyHu)J~b_B_Zk#5IS$7 zIA@@RTK_g>a|RJAPpKp7D)(hp&2EXgjS_9n)iIi08>Q@}q)Jy|D1Wcxx|jhNEptKA z?xd(z=riOmM0Y~wIG3JP<5|6Xy@RNAJA{s89ZBu06YVeob7<x2ivNayNcx<h6a8HO z7X$j=lYQO}vv*o!^H<rA&(SYbm@idfag};iq&>kMZi(MhN^^^y>ho3`Qa066)+Jfj zJk0EBHS!rXaamXUBF+P;AN>h6hLB{%^_D7OR5Ii$M5^j+zr29*F=~TQ){Q@_-kk0b zTzVV)))Q6<HpQZ~tm5@<c6vkM-lm2&B3sqol}A>PgVkNUM@4j{mxNaGH_4|0cYRGm zh}Wu^I?^W+`mEBQNf$}$eilG*fqAs!=RoiYzJ-{ikK93wrge1N?<d|kx&2zG|NEPj z;Hu%x+&}<EY9oMZ{3}y96R=PWfb`_IYph^McYTeU!od`lFC)sXqBHG*>FvsFr^@eD zU=gr{t5U^jRk?y+M&C~rBi?fy>ZsYwthoV}Fm+P^{|8*W+qHgBRreck?v%YzHKsvo z6Fm|eeJ+0hrj;{bPIE2*PT!`6IC%h*%<YFMBM85zURMi~>h%Fo6ZO!k36_^;i4vN~ zC*VhCMi-O`Qq^lUt(BoTY~t+d152-Vjqp<xHAnuxa;Bi<T~S58`<t>wBa@|LstxL0 zPA^~RS6?*R)IQGZ!0tI1`v-7OoWslKLX~9Z-kM>pnI^e4IBcPUoqcn?^F9c>;CO7c zd-4=$h=SgZG(>133Uy~fEbsmsFiS~;A^8~74E!NvaCNfj=SPM5O=yY^?Y>XqB5Eu9 zLGDAQpUGTbohPoeIo2lOm#Svvht1(jsC@3Zz8wQDU7=C?q=m-^BzHWg(lxe}PL`05 zd&TZ2@6zu$eu4;GRL@$KOotK&ER|ae-c~}q3O(1(SvIP3q3>k_ViQHbG|UMVP54CL z?lvS<$f!ql@S@CgjiL~8^HFB$ho!w0jMZAAc_s<X+v57Unnzc(t~MS92XJXwGV8^{ z_1d70^~$K?ah*lH%<vsSERO|N;$27|C_RO~*n0~*SHcUkZR;$}a5()0hH<1aNQAqB z6!~0pAEs!p0l9=r0ECrebcoG1dHP-$q{U&$7{?W%n|dUL8xiL`8nLER%VZASK}UhN zx@sR9x&2a#Y4jNUxj!;wl0l%bz%l>77C^0!reH3^VCwws0eCqk^BY8RPAXlp6yTJd zawRs~>AqusLWotL3Q71uoP7?R`jflxd?lvT&cf58$FDB;jhGcbP-GqC%^Wmkr#O)r z*6fGg8V`{dkG<8imgw>qTvroi@-;`trXb`qM1rzW;~E*wTk9dAAo2!i_pNreJMTx! zX8$P9EA>}KSwOcASo7w4XdP<TT0#k{_qAUBgWO%Mr-mJVc~RYnP14v|ehMj|ouL&k zn|)Nbd#3AiP@ce?C*VAnugve8^>wV6C2pS*^T(;Kf%gZa5tKX$B<z~iS*pG?zY6iM zeDg8KK(E)6S<%(u?BfqBn^st$ahDnj^vJ*iY?GnxFzzG4kW32&)2ts5ZFEUNHNB7f z<a$FJP-f7{tv~_cn*Bzsp5*B8a8#D@w-AnaCno=`>}s#AtbnP1nTsp&BooSc4@?@$ z&59qqYxqSAwHQ47y--hC4^gF4w)u#o<MH^d<y!kvx7_UtvQmeT3g0@|t$2?#i0eu) z-j=w^V2~)xM!c)O0O>tzbBD=VX#I|r>Fh+yKZwUe!ZO76E|HH6Ni?<VR)j|z$am64 zW}3^VwMf&oEy=A)Oo%fCK*msRQGNHJ-zw0iH0~UR%u_PN3|)twE`~&&sf}#|=)1o> ze;+)V=mKIi0DL|erMxciZQ%(3dEWU4D4`$%fc%^O^@(&R2j&~FoPH2}ve@zwI0@{n z1(~&QfR`vhAGgd}%LXF2TKBIzvy6U7tCJ%iW*|(@?inEKfrEqE^5?^d&kfimT074n zihxgG)pp5n{2tJ<^Ey6a=)R``_)&0`j}8Td;!^%ghjX=qYYO%VZj{{tDUKZ5v(3nj zWINYv{WNYN>hV`nUjB!Rpotm@D?#5)vekQ1yq82dYzO@rYDM!F^N#K;#X_H>Ix6S% z8_sFsX|cDDts!4kNX-(cfUV1#DNI_I^wXU@WqqPJb@vqaVsPR8m@ETLM;5E8wexV0 z*<N%>SkKsjLD>nl*O;G6U;CtJ%^%~^jFLj`>1!f|k?vO|OZ~)ZWf#gUdqYk|WUW5c zp3GizI{4Y`iVwAZ3r%<rz&^LAGd<g71Q|RMHmeE1EeBGvi`6B#XMfrRLM0ZCl_zwj zf>&U=8DGoI9+vdCxwI9v&QR}AB)-gQAbp3ip^fzAt*LrcJ0mn#Bi5vM3J5m1J{M;H z;I2L6Ahos{E4kE%IM(Q1rFMN<Utf=oX`}slvMm7hNgMzxZdIBssK>jFzX>I$r>w$X z5*Do60iI$@)9r8H-%HyZ1MynXZ$diuQ@b<%yx=gKH@UdHIQx%(T4eK0B*D=148!V8 zy#?pwLtsAnc>eH;LtoZ#+S*JwM{>%bf<X!IqY|H;in5o~XBel(Kb(@8jhm&lB^pbp zE`Ct9(F9@*3|_%Uybq3#y`L?judCojs(i3SpkRs43e;kL5}*N$1Dh)DmUQ?*bRdcU z!JvJ1unQd=h9ALaJgA)5U@XurbKR)PwNceV!IS%aco;qwopx{xJ%(}D#T^3x*`LY| zQ|XPyN@{_%3RW0Erl(<2h3|s7{fYzZPtzAf31*j<uaVDl<u78O37jB`4O|WpTD7`D zdtvYYYgX*0N|G4Fyr5}pCFbHHE#+QSDSEHAzVCMlPncZiR*Yea_KX#abYZKpC71>z zSS?skjZA^l$?%g)U_h_y!pqQ?v;`oJnGi#H+i(n1yI>gfv)Ci;l3(@-eIh&^QdXk# zu@s{5>U>mU{d+R^BgB>V^o@)2k5S$*OLnxVt6_x>PUZ)Po$qLzXFhD$L^<#1y&MWc z|1VaPrn%d~SycRx(+CPX6d}9cOjlp)g%_OYm<04=_!suo*2pf}UX+=i2FAHlhNc zYV4wTvn0qPbP0B?cp!b%Un<LSUYAK8w0MX_z>LS{-)sL$eQU5ATU0!-)=7t>fxMkt zcT#)lHZm~v3f=U3DK~>b>PNA<iWp-t>(s1TiE53p<hlnV#V&`cpldZGe$BYU|Hbty zrX^u>G{aiz`&5IVoiiNK`TkDoAtyQ?LN*K6%V6&L@i+}Bq*CD?R4dnb%@8Yv_<Ow- zmcDiHfk$7gA;YbkwCG2-u@ozXGykf4YFga8)tjmpzhP1bNkukMk$Ezs_4oLzudR~y z<0<1i0LIxKU^3leAjH~>wA!ql*Z^9DBEU6yv&|B5)ya`6GFjzP*MSA_Xt3gZhmeiT zaT?$V664D#2~=32wetBo2!v$jbTSGG&yn7NJC?mPe|Fd_Y_J0&OmjNC+!d*_ShRRK zdsOu1Pv8}!jRTc=@PuXCkrP~lI!{D#Na~(PCx_HnH4h(QI%Vn0I2C*&yY`cZ{7pU! zzf0yObY|Z1z1Qf{h2epnusRt?a_l>8wPV_7IN`(Vme6i8XUggz&(|%e1(3Eq#!pYY z&hD4o%p7_gdB)4f-=&fosq`iC2WdWH=%P5T(7Nyz1??_Gt2i`*)d~>?iBg(S1x*x_ zdCbL5ye@mL#$;vW3VXcTY+x)H{(b@ZU_osm5sip#cu}^e>l;o)k=YLE0HI0LYpBN% zQPi`PacYG8_1YodyEl>7J!$)?GbuCu`beJ17@uk}8L$@!-G@6^hnaF0ILXoo`_l2W zFi$zG&8tO7#F~73OvF+<V=6Od_)BueziA7qy+~`U&;QDD%2#)#_TqZ2Un1<e!z)lm z|AFBM;}iHAzLusyvf8thHqga*%C<H{5Yi(tcs$+YC8*3`l<t0OE;1haVLdD7{()Xa z6yBF{npeJv`bSI4+2SQb9z?kj;`6%y?pU&*Q`NImOSJ75X{JGSvMX57frA^f{P5_f zdY$el^J=|E6BGMtS#WpOGF%fy7;VJ2p~v*@_x+jSI;y{=aLdKT)WN6fN*VBPhy~C= zS=^b}U1s=A;n@rjp*)vMBx_&3d$wc~yAm@h8t@|{7vJhP)sF?_49~haG9o9ls{XS- z2|$^C7A|d`Ne+Gzbxs?f`qmdx;D@dvDsN*nUPps*Ke!7!-ZLNTOfu*KgvN^e95Q@k z;3x1U(9zUhBjMz27&Ew4k@K@3L)l`c_tTCAVVok7Lrt-&>8qIRYTR!Le?9ti)g=>G zMA^NHH&AouR>(4c`PR&VM?r&%|Jq;=_+MSta^qWmILwqib+Yi}-#JIle(TmB=SoyD z(n*u=)sW>lZxyjR<PLIqJbg%JGt2yBASC;5(nP?bn6iiPjq&fs$YKuHiI26$h8-{X ztW17C4pCcx(L-+cMd>5R`rS-&yyAosJp^p@>^r5$<UUr>QoLeHRqyua7A)!ZY5FNn zce24*01HAbJifadB!)h@#3%MiT>|vir(Z_;mP@biM`~9c5Cn7!-$Kk#JgO5HM!&S( zimgvL1sn99p-0hT;`F*y^U@mei>xw2(9(XBNY4QGJk{h@s<`WnqlVP>ths=lc1kY* zmM3&N!+mDJ;@$iu=l2oj&sVx@Y07PW6iE*&^=xbFs~&HYOsm}uzyiUPlcTiw=hWOr zV;EYyioW2v-sdTfN5~&8j!dp%leKa{0!HR~rqpO6!~(cO7&+t63+vEcPpgcB(ajVC z6kr!v;TW2HRrKuhPw31=BM|h?GTj7tk9c+gB)MmE`{Ra$w?CA~X;VF&)b!aait?w_ z-98(ChD8}>*^v%-yQMB3HZj4+HRtO*m8BhpBEau{)cWbr04!s-@OFBjp?V1HwHLyb z<C&h8%WC1wYp33X?|hn1dcHyZkq>j(|Fp%3TZC2ZMeJ6&J-I2T<;(1+^?e}isXqaG zK))Rgs#sbKUZ%zABlt7|KblZkZ@%C9Yv{(Ld2$a;>DO9RLP!r0gi~TQsF}{1HXT&- z3w{oHpZn1Q@|wE;e01+COu3!jXd)}eteq4}K=&LDpcK0IxhNMB?j?>Hl9lW|fdr2R z4JacbL)i><|3z`u)uXewDW1x=U7rfbN{W3D5V|hr;na@5`5BSex3QJ|sHv?qq7Mdj z#NU;0$ge^N7xt+bej{iwP>^}aUakZO<pc`)4HebZ!QX{et+g=MHu{ogEH0l%{i_C% z7JhtMWB!plV1Ubp-{L}2ja_XCTwaoj4a(7}q5e3YTM#$q*8)Dqv5`fTa@o;e9u*k= z{_9|-H|1+rh1f;M=i5eC4k0oZ8VU@3?A*I!2AOJ3iL*QG-{cFsSV+@|wjYm<fLYKV zQvm#*w&hG?o}0`na_DShz<<k@Xhl>@jlwz|{rMsv?sKFHEMJ}$#Eu4Sub5CeGgNik zMSBg6G?aeL9n$xigevR0u~@7fmdq~zwJ3JJL`(`R`NQx=%^Q;+w}{zY;>c9s4;Sp; z>ESBiJDQCm-oVJeWOL!8TX?c{pr`g7Kx-vnC1&gQfKbr%xhwb^5KH%6`TNt67th!T z8|;=~GGK0_<0>YkC!=?}|EM(L6R}ax%cECNxB(pvRu$dJ!=L8w0dJsQxwu!klg`e5 zv;{tyFfi`jsGI~yCq7*EM9el_o-JNAN4!?~faGhwO;Qe8cP)w@GS5ekCCVxVS1Q{d znu6k~Z-!XTe}{b5>v|XX2joC8Vb#pWSzM_W{}3#{Hww0Rc&j~ev+#|rYeQ30Q-OD# z4?IGUM3-D%IoO}Lx$MGatCJ6|pSZ&WRy~(ke>6RlO%z#JrxmCV_P@l~gu1U~fuB}l z{aqI9DW?c-OL+;eh#fauD4UfGm=tclDspr-E~sesnug~qhVH-KJLMnrkK57_f{<w5 z&w++-t($pSv=x~=H-1VEN2ieA*Dk$jjUFs%Ewo?JtpDR5;ti(lX61W;>Z}3jQ+<&A zcWC|OwUp-31tOu?5aR%M8=ih&{{ehsh?V+K9bw0?b-JD`lWFT1;@#3Ory<=O{x7Zs z|M$u5-=~I!ua&q}Xl897eJ6R+GoO|%bEfkO!V>Yx0{MdP*zOl!*CouxgeK5jxTN<N z&DCy2i^07n<t5^Ki?&;R6tF<?yiVhioVjMG5w%rEE5V|3#egM?W)W*QDR#iQbG9Bk zhZsL;Wgzfcm3UME)FQasufUH`iZgb^sp^+)axr!QJ9UKA*;t9`-uThRv5-cU1jLYb zws#Iy0F&CSq7IJHLN$_34y&8M=E3Ik7r<gKr$XJb{R!OZZ{_6=Tt7O~RPnd7cO$P} zMNf$+Mf!qoLtdWUB)GzAh^pp4p9l`!tzQQMpX|<tI%{}=H)kiX6A0}A3g&}<ci_d3 zYKI1{*0Uycl5hS2(WUFajRw&1>d`Xl)j<ZjP|`0TAqsyRwL>$BFLh)!BzYb*CP|_d zw6ZA^5_v-Oa~`-Qh}Utge&Pt*v~~F(t_c}Ozr|aRu#;ad^FBLUnF3)({6%{(9wXb2 zXLF0r0FTHy@Zw-fH&oWf_)whYvTt+7x%LUJqpD+DXtkysQm-FW^SLG1D*is50rA%- zjhRJ|OwGJgd-e8nGhz^9M3L;`gT<h2#{|-k#J6jL{GGH<RZ38Az6aOeiAeo0A*bvX zgg0kcFH|bjv|`iOpAPZBaF!_QvZ6^!{-b_C%(c9B|1(Da=N~R=31L(yn<%v=&EHl% z+Dhe+c(k1Pg0}j(O*@WE_hW+ZSwe$dc-yfxvbgFUD=Do`DW(F;eiuzY+@@#I5ftR$ z)?#WUvX&+0Rk~R@g*T9Xq6vNvQmp#OqEmd@991rIlYnub5!AE=ZOlB*koQmr2YQ*p zFQ`)c)Q|DCz?T8^c)T{s_n0GQ5D22FOZ|}HY_QJpk_+%v{fDw7@0nCZOIv&(i_U`n zmz3=b*P8}51lRuy4RF|4+E=>fKlOU6;$w?tk62|BH$j+>0scy5=>m99_G5thq|Jv8 zUe~Smual#a62$+MLaSjh$8vL^kHb(kq1y}aOzs0-P8yt6x1w7(5EE$5)9)vim=FiV zTLiKdppOm5RHl^O!YeKw;g&IgxFTeIH~6!)n}XdZ<|#?jgQ}STy#&6mK3HV052gfA z=FkX~ehz3^;b9RGS!@o#_yGK-f}tMyYG0e0v89$T>LM?FylD-cN&h>W0>@y_9~HfM z^YvG1Nr}fJQ_Ta4H8SI+lJokMB5G|r`69Oin^*;tK^K<l$e<DjyJscGsad^)j7BLW zI}04;i6&;qyy$UwrC*xF=a~ys=e4h}!D4j7GmR}N*7cOElXHbRy>KfmoRKNu>1s#O z=_>bOKq0DnYdR$QoufAI7OSI!aqCjkjz>xCnNWf>K_I!rxkv&fusK)}FpILP*-T;= zQe<T_z{An)a9)Tf<#1*iQ)S7C7pP>o*1_t@$Clr|iJXt-%a^8WTCjjOzCm;4-n4yI z38f-a49F<kvwGn+N8Dt;IjP^`v)(}|j26>Ql(>RUHiAP)TQO;uAo4E2HOwplY7zU7 z{6{^LyU$p6HlB~q*cdDr0WmL6unbQt68>Z3;-c&_v!4)Vv6tuX{WYfcvTuUL7Ln+) z_h%YB?K@|Z7G=b6>A*}ThJ|pAx51<D`QDtkSsmKZoclydB?_I%&Utjsc$aW-@!x&$ z-xEomDL6kV>^Hzw_$AtNi`6pjYuTj5Hiv^}E8GD_xCG0&K8`C{;1&>yq8XH1m-~W* z2V@LBLtrli2)6731p2yK{y!q+5z8meUpNV|)Q6k|-fmuF?KZ9nKj7kew~nAbI6wFI z0N$>V$nmmwI4y(8Oo&@JnquyL7gcWmkCo^hYNC9)KEmjCB!?<yNNlC#NE1jEBigtr ztk0oMg>0=`fXbMksMVFG{WVXrdXVoIJZ&m;9CrC1m$9#@5y;)N@Gg`!;K1{XIMQ=y zmLu}>s@Yvw%F<6z=Zy3*`PB~P+FRxU?m5h>uXM+v+<lTK$XvFEj;!fLNJ}u4VF_X? z+OYc3x>IP6>^z0hlSMKuSN)n=Qtfa{jnKk5OIC7VgK%T(=!4aJHE;e1?IDml*H3@S zZj_)i8bHnBBwxR7frjOA=nTsYT{Tb5g!!0>j(i{e!~OJb0%m(4B!i-8%KhK3;DuS^ zH_Ik_!o!VPEk6R9tzEC>8t>2kLm-QJl%&jdC=}2B(!-j2mfh-?(!_a<6=*9xUYF#< z&2;%rnxY~8bDQ5MwO@Zz>Pbpmk}jP6B57@rcMf}^eeiD@OAILUd)D_w+3shbRhOP} z7n|Zdc3X8(O3#XSYJ0`6(E2BtM^-1-HvT8!2?IT*WC$<VCMx9F<4yD>F_u7nz8?S3 z&Pn;ROA~s<L?YX-pYRpp5>1!3?g7mPm^w3psR=Kje}YK5qsqy@b+rdCcije3mWBb< zulK@%E!Xne+S(uN>#N3A4j9DY!&Zx-G2FWCq4kskUkvaPbdr;8cVov+&H$Inhuq~q zO8yql;G^64E#=>Uy+CzKG!<`BwQpaUo!2t{C_WUBV1ZAgN4l$)i~6(yo$qXlvBI0a zgN2N)`xYh&cm7>FzX3o0`|Ez$K77<ea8%4qVmYSkj@vIn$KTH%HmRYT41i|cl@mH< z=oX&K-Nmu83`qGpDsVff&-EiZvKws<pBwjjv_&Nt`LCMPSN8OgXXEKraRCd_|JYw9 zXX!b)i5&vXFN4dIIAjmxO<8!lY#}jQ=qUBey&k-8Z<UvI+g7E$=TDzh3K*Fl<%ue{ zs<jxb=y5?Pwog)GdRlJw)1>n3An*YuU|l4QI-G`c$Vr{T!I_FtP_axeUFm4NaVahG z#REVH(7Wl|grSpdpv4WXD%OgU_!fvBAEl(>CTnwhyL)f^n+1D>S)Tu?nSqy3v^PJM zZ6adaCqwGBt-mrIfKbaB8P}V_Bz4MCep5-R8c28ypFE~(0|iVZkNLUHPyWnyZ|<HS zyj_#(&)SVXo!7s+X_kR6xVgS!@_#g)Wmwbi+s2Vp5HJV<LG&lJ5h@_Kks>0U8{J9` zkgm~43kKa?8ynr-f-t&AgGdd@5u(r6=Q#c^c)=?UIBxFU*L9xf=PU{GXiEB~I33?6 z$qDZfo38RD5-z#JPUJ@obICe!bvDx37US*MNj3D!MPqtAHN}ogKQviTbk4ojyUOFE zuT@Np)~g~sFXusNNrwXrw3mBf?SV`W-Njo@w&`SDUiZBDk<ruZ&)iV0D-dEcGO_II z&s?1YOtp?<AV2}P-kB5rVsroZO+vXiOnYN2m{MeV5)Y}n>vw0j<Q%hKS1+f(LXAp) zdo10_K1PwySC<D&;AEOCTfO$cT5k2PZhf8(P?EF%P3`^WLq8mndog6k|3(Hy4IoI} z9=$5uoV?*V6Ips#ylIg_2RmmF_VRDJO)~S{0STMaYd8(|nD>Q0qkRR<Hck$1am*ek z$-VZSt;&UyIEo96o(*q&ju9HAdeLWvw!lP8kEr<omC)WecCYcEdb&Z?!2B^5l}2;l z*Dw_7(jo4;D3PcZPie$ibMdgiHmDS&ydmS$j=h9QN8SyXQq}m=;>zrJ4^2LqU3b;6 z-G4`66NB0kQdI~vPqGLg9R2z$$v_^43e{O1i7F7-yf%iljVp(}y*biYN%QjNfZ-a} zmQ3}08^yvz5-;6qriV%mEZFnEn`^h2_2YKwYe&qR2U>DVm+l<h165?h6g0tWKCp@R zg_rN0WjO7ut3y^j^eNP_MecgLohc-cHW;i3mE*w9S2C;TAgaY_I+uMpOx$4+LB*R* z)Ib|Es4~9hC)fxjly^;teyb9Ht~fr9SL1tz-SP-lVZtA=UNYW-eeCkqu*^U3x^zeC z%Vykl(kAJ;baB#U#g)9#4&a48h(=RSAG3QU>J^kpTmjjVeOdhIDv%6OY>RSUjqUk_ z;)Aq}oCpz~+;D$wTb+}claZ$<zZjf7eF#t-s%Ag**Dnxi+YIqJr1O9(zz}xJlb^%m z!JGahYCvPAGrk+G^+X|E!{7vKm|B*{Xz>}SW~Q;;l;!saEaF*&rdcVCZGYsq4+G+R z_Y0DL0(DOJf%4@$-|i-Q;Iw*LE)+}be_RjQwu9yStqEH$vkh(ht6OwMH51x*0R#1^ z(u1Fz=ICGyCw#PnxzM7EL(SU!eiT-wgKqB6`CKFpl`N0y<TUlBu@=Iyu!7SJeYu%c zd+~vooAX%a-|#~%P$F5%q)i>^PiQ5ZPD_An-heYrDaHxHTyD*^-z3<~VFCAaC;%Pp z$`JYo?Gp0%h~nDIn=EF>$X{kz-6sI8je>VcwC>7pHF4hRc}e_{fUe1iz+|~gAI?0v z)IoLU%ae=53~s;tW?URGOxD<T|E`U@O<O_{sLtlhCbaEH@ua9>>fsYTxM^F$pSX~d zRoxf6OgG^lO8DMEY1cHwI!+pd9?o*`oqa8n8nJHvi4TlYgQdBQz*&oj6>o=-+EDq@ zIFhe`1o{gWj~IM;Ga9c-?cP#6Bfq08q1*iLxoUDPixD7?xMOs6@)$&jVTd`psBHhN zs@2)Z$_;Nj#`<T&s#1G1kaX}ply?ctnSB%CCUMc*8nA%9Th*Z-6;us(_EbydHPHJC zD)q+N$MlW^qto>4f>vrbJF8}vlS26Be2*qcyC>pcSrTvl%rSU_KfPXVLp?zm?L`E< z0RQ;d0CsG-#?A<*QXRaozV;vf;pZjDv4j8?>OKmr+KyQPM(}X`v-b=dCE=Pt^}BC0 zkg=}tD-O_g?&F=Ed&_I3BO8JXsAp~s`1=PCFt^-*bZw(R0-Wgs!z+q-mFqy#z9BU@ zRfRzrDp!4PJw<@<>)g;OuEYft40P8*nfpI>xCy;akfmK2s7PY=M<S8VvWv|$w*GgN zkW=QyFc4MxeXqFQ+`M9rn@HJ1vJFLQR!rb-qgqJP+N<vy&qIC#t{HhQE3>X7t6qEb zl$;V^+tm1;b(#%pEMG1h5Yd9!rE-hm<vIrqwFd<tXilpux*<=2J=dhiigj8smcxh; zcNe`)>dQ|7zt<j(5JqM`WAEhp{1Si9`4c2r;<$v9*!7$3zw^16bUa6G%We|3)IxJV z!vPiiWqRq<8H^;jo?Pvv{sy8wKY)LNPNNCO2(78L`R#6jH}h3V7TZDKWW*zj8ZYOL z%W-s`EA^P*{I#m>caw9H`Ehk!pT^SW7*o=G-TyG>kyBr)#R+mPAarUU!}=~7W6ScY zTQ(mqbZjdXK}1?N*Nx)YziZNgD>+qbj%1)DlI8h-?X-*nn9(P6oStfCRJJkFp2JF0 zsN$`v5qhfw53@!k3($@iJ2ubb!yc~<_f`$WTKmZS8fI9#UE6Zl&k7csu3Ze^IDY<< ztZHfzPLA%aGFqtgzPlPb(={!UzRUVKOJDZCzcs;|D|jI4>+@XY|Ha&TfuXr;n9zO! z*j+-^_lN5}zUtOOt6bYt$o7HG(@pO5BSue~ZtqTZ)i9}OC_i_jn2yvDk%+bHU-`Y> zSeGGxI9QtoCXDdbKO$>dikz;0%{_839PsCemY|W|D_AD~y~iQtl?nQ#POo&+JouwP z;-sz`B+2-F#c^as<^E!8wVCBLbXBe@9Tc&3IeWB(EDOW|&jmy}z*Orw5z9!Cw4n+^ z=~c3wW{=-e$JQ_lFt;psZo8sc=|-M^hJN!~eY<aNm#lX~AFU3rEy$aY7(>-}`NO{% zaeBZ91v6-iJ42qei2eZITimyOHo4tGWxXZF!DN^&DlAg`yhFPppW4ytSF6}is>noD zp82opah)C%q*phxYoJdi8?$>wyhEgrFVS#Oo97TMPgwo=*)1V6KAd5f4`yUJxJMgM z7|+FZ|LQM15}C|L10KTemk)%|C2w2*ckhHFAG4=n{Di3){&k+IO6DbX!7&}NKyeJL zAmsW#F90YPM*_3`)*g^MZE!G|U?~3_oRLr{xY7Bc4>i-DV-lrCH4i2$H5er{__JZ@ z6Kd1nm4M!ctFULgzh@mz)oYZNn4sXyq-foT`zA2f<a##>S{hj^8{B6Ne1BlE)7<l* zsg1G5>9grR|FFDe^{}pUAPT<SY{K>W?xT0BY&;b81*O#>)L43?A=gzwlD@=GmYlZF zoFlFQ`!2vcqF_PC+En?Wo2sYrIRTn9ah@^0-?#{@NTkY!mt&vN>}sfo>EksA0H0m5 zo<4(%Ds%)B8e;JfaD^U>BI~<AzkxO-n%;WOP~4;HNNsE0w0fX$DJSCuqWO)LUO+=^ zF=ZVz23$6J5!%M1Gj6GDqCYYQH&3+gdKQxyg$3^GHEd!4n$V5NiV-hs=05Tv(yY)1 z0JXRKnI<a**QO_Gv}#fA98pIYb+MX0oqu^h;x69j37x%TRU;?y1ve==Q2av+b6Xbi z$kfC{aPBBr;Q`)l5SGcyYnKgMZcmabx7-N`Ux=*2cNq<*3A8peqkLCM8V#0lcwVUf zf8re@s1~|pTdO%yOHLP8=rJJZ5~Bsv`-c@#@Xs^rQ&BG93sl&R=U1EmsLA7I&ji&? zmaA)?{AB=3(y4j|y6(Fo3__~e+qp@bHeYO{zWqsDDb*MfcE>DU{X_kWieu9_Bkb-t zo{Vj0D)s@7WrSES0xjz(&j-5m3+T&;w*G1EGPfCgcQWxf)JEPv&;wx6qZGp?i&_I- z{4yM;LAfL(i5R$x;dV&`J~dW0E@&SvrM<D2<XtOysZMhj>3F130kzlK8T?l4Vi>2T z^;(EG2`^|W889`<+`N}sK&JG-WU~J0+@mOV?WN1&;$T(dR@ky(c*i+8IFB30Wb``e zaMrNn-~EhW^xj9y{fsU<xutcrnXkir>sJ#@+HSR}{`pBGDy(Fxz|Iy{$Y1HE?taU7 zg>*7o<#Am&J8u%xV!i1wt#co$J@X6F|Hw@9V0^U$chrL3lMMJFi9Z0!DNMhupgn#_ z98Oh-g#%&Q?G=EqXdDUEnd2vvv#qn(6`h@*pXajK-tN81d70?1O)UUe9ZC;99rsuX zx0>l0{(<YttfNCKfV08gA9w5X4gKlr8zX@I^CM`;#adIfoVbXRvL$uu<m){I>X%7n z^E7Fgy4VW<h7qr}5aFK5*NYwd%!8_Jw`f%!^Nf{PF)87KjNM;ezP`Q`cOCgR-ce|3 zajr|C1xy@UQc`Ycw6NKqC-`S)1qscQ$>@)Rk|&~Hx+>0}*PeUqBQ~kA=-|~VG}10X zKtiI_k>5!v@9xa(#tYbQ_GMNLDZZ!u<5DkX4fKC~b_^XrI>o)G<#*C|F8lA0?kn9O zn+?b<+d7y%@O<cc>V448HEU5npoL=@BL^eq^Xo~DUmw+HrtdlQ0i4vPTXwJleI(LM z4HR6N|L2mV2=BhM<nMtoo;=8Baf_98ZEt8-KBx?S)MnDJ;0IQ#PNU|({sSXkg0tkR z?KP9y=dgnRNZ|D3KvncUitfCoCAi+5^>)cnHtw0;xK^7bRsN0YvCIWi>N{`fXD`da z??Sz(*6uu|dJCIEy{+O7*Q$oI*U;!U#<_)YvGK^MG?gKx300SumtrEy?>r2D&v^gK z3`3YLC2rg7a<Id(pJFqZtW{OMs!ZKCBV^ay__%2qV;{qX5lL&GW%<%475JavNDtmm z0+he`1u=KzbNRZ1at+`Hx$!O#nzepQ)d6UE*LbNHc=Mb4gLc+uuK~orNsopDmB{sp z-B~qx=WuGZ`AwvBuXzU$5@3iq_!~2fz4Y1KQ%L~v5XueSC*}550AN_&*-=sbB)UoO zH^bS$MmZGhtY8iHbDYoec%XKa9PI7fhb_1f$6&T5TM(--UEN@2j?UEcP+$Uw_aI0d z!e=(?+zT2_u0jAv#PHUWzW_uSu{q;0Bs^VXxYMdVs($nD>(quy_YDcuhsQBJf-wRk zW0D5%m>F0G*`vl_@MRmuc9!`4r8ZNys8SNcq1nwndHQl9i%!%yS*|}d$W~MwF*9>b ziR!+3M%b15FO4|9CU%PE4DFfKy2f?0QVGOeiEB}8`2dk90nT$ja0gN@N#Kul%Nrxz z{*7(?2T^8gw>zxr?#;HN(jdWT1f^AFfj2sHybKRa)(BN1%Hh|=^z`;AiBSTsj7TQE zg1MSp&_-8HK}0A5&B)34J6&i*y<=Muyn&`vaxPg-V-&I_Arm?rrf}gtg5~qcV~(}a z9h443Gw@fp-Qe>}qQXyUz$UbV6lyL%!LIztCSTX3p5@#xp5>4j+G4Tx3&;2>+rAiO z-Tk9KF$)=qA18c`BnFmBY@yUpbL*Qd$b5gjJz>X*J}bt<q@<)Y;0)>R7hl{enK=b+ z-DyD_!Ia0#5;iQgDG{&q-1#%ga@1kC%kPnU@5?abY^JdMM8gIt@0d53FSS1;^!aKR z_i?3M$=t{UNYW4EIyb*}Mp*!~&Z)QZ*(j(v)r-)Uu?Fxy+T`##-<0^2GTBdT?|N1@ zn)-^|vMqYOZJ!lG!2ukJThY+Dejr(AuS(NtjJBW{_B@D$T@ju7`k_UL?xUGk<G43| z+09r#z~4zBV_9O?bn(EQqqpY2A6w0umMN}{JtnJk#A(3oK;`i@TzZAB$2L9T@SIOj z(>yEc?LBS0^lEHNoLFIs)ySbG?5Bp~<n~9-_C)WPuiF;}liV*-k!Q%ysSVz=V+;2S z?Is5ve!Eh8(T{PQvzW|RalZ#HU>(j7-*<$(d!b&9!QCq<!FDRr4yg$XD;EzyrAu<o z>9!NmmW@<FT_Z{}iQ|Ix2i_j9UqQ55)Ji+!535P`bN1VG?eL(4>4%v9*|gNzN!986 zUpm*O-dzHCu7-b-D5g=_(xta3!H0gZwj26tI^`bP7e48*k@?u*B;uBc&R9kI)?uFL zNhOT`fo>52WOD;+G|oeTVs&F#SD#$IJ5<DRle>kKb2^J6`z~=NwluO|kwdTCeq$(q zu&c2@V!C2qQ1w;O0dDu~K4br9g6=Z3@oV^J<mj30U{xcJ89xlA7@^hRQR5dIES7-c z_c*hsDc^gdpCH<Bdv`ZgVjnbS_7OX_VXNwCO0b5@p0a>q&EL(<l$a^X+meTo@-Kx_ z8}V%J$5~8H9XC!fF&n#jNbhWDKfQr&U8Rfjvh2U%X@j4^Rd#|!(<hOIjyv#?r7reN zU`EQ}mE%+ONDYUQhXHzJl;XW%Vhe!rRi!8bQgRnxBBAlGnM$YCIz3?k`B`C28G7){ zs+(Oa6Rd2))vh%h1?4AU_KXPn=$?tBR&ZNF!huDeMA7LcwZiYi??PgLb6VFqe4#tD zfd@ZI-bT5u<pl^DtbZWkZJTTNO*S73Sy{oKvU#xze3vy9&Z*gkJbAnzlcxw)S-VsB zbxUquR@kRQDnR5qqa0JUdm4vO<6bvV^J~J-O4V#U2p1@bVkw_~s!2frx*=mMzWsd3 zMjB6?kyQr2ozx;a@$XM4mFP%;AFRoNG5DZKjxo@X{eitnUw+rX?(<oc3^E+CFo3QD zYeV85U8n2TUm<c<#1#+Bv@R{1%7eBj*|(D{9y{s8SPyq!+Gz>ApZL&D-es=Q!*z<M zr9=PPGr=_L-8Os@H&*Fast^(yE;--S)RYE%O^fQ@4#oWKp|#$Tc(cv;ti19C$BTBC z?u~8ca%`}O*;{wFwrN>~cb3dF{=d(h9}XEoa#|@2)q~MMACzuvt753|eXK2?I8Rh! z!rs75^mgUdyUJ#3E`hwlRCoiEvMRyj2@oOf=t3OIR1TQ_sg7rXm0aLngHOCav0C(u zbvsEn)l2wHoF)oG{;k#j$zD56OP;0LP{(>sc%!QA{lhD&T%b-q2lvW+X-V`6<MV}Y z1<iA^)nhNHN2Zp)fB)W-sq3!n^U>{2319T+9{=Rg_bSELG9@dxa9+jto1>($Vd1Qb zg8q8q6*61|8(BI0sCODLZeioqe&N<<-2?pnTZ?Ug@t)5ZN1N#s{zs-#Nk`ew%ggJk zv}XiBk6a2?bl|j|!-?5H1Gin7=-LAQ`X2#Ff^K%?6l3xeHKQ(e?y9lku-nnl*On04 z8nK*sE7RA(8Swy9c*VvV&Hju+&|^=jHi@-GZyQ<lpD)0qkcFB225=R^Q3fR>yi<n0 zY$ow0h7X=tzup5{E_v6VSPcQhEqNZ#s#H*ulBnO_;79P^e{uN=yGe~3V;;BeCo<OS z+!zePUY&z#x0}<r2*TXo5mwTKJt<3iWn&+)uL&XVN*h1zb0T(3)U1rt>Yh^C(`Y?E zt_k!VP{Uj(BPwCoxzFKeHvE^dz}g~uXWn(;rIFd>WoIbib2b&R<k7=${R^0}1<}># z)<jR!p1pSx#{iOfKAVPvwAo?G&y?}BbjrI0u4zCEhs?pz8A|WO(HrmObsW4K&N$Wq z3Q}2+m4H3EO6wkNW}a{VQPPj~3zvX_s>OXtK%e;2oPl$P>%5s=(TC)t1h{Ex2N=I= zJoD^0{^x+8pm4gx#|FWOFj-<%!QOT5y=oovL0nbj?$mF(ZAo>%DyF+c*QP}0PbXvs z5*nIgpfpB)KBs{O-G!oKnf>>}$|iN;<st<=CdAl&Eyj;_XFEZ>Cswa>FW%~X!7t6r ziZY=-SG5R@;62@?{!I+QKQ>EeL8Z9<nHpoQw?VJC9&M83b5VDCX0cuu3cGohI^xYO zuvG~KN#b$3S7GGA++_qB;)#?T=Uel>^_NloKsXg$-j%tKNwmmxX^MIl0Y&M#(|TTy zC90sS=Z-9plXTPmy8n#~8B!a0#zM=`#o=yPZmMVp|6%{vhNQ!gXei^g*`^F>#Vb;v zvxQ^6WK_LWYmzCHUr%6VCZ$GL!3?1F{dvE<^hgo7_j_OFJ=Ftk0gzAxX1y_^2PYJ* zi|@La<sGOJUh3?O`c!EMDC&G&MO8rk`(;PB-?YZsdq!1Y(f#V(Q<wU+f9~RcM=TsD z0TGNb*<qYHDVVKZXzsZ+`FM{c8tQ+(k))iOBC$Sjec*QOkZr--^SW!g6nBJ7aA(i| z2o9c(GM)c%T++67GEC$atxZ&qa?ldp#T6fJ<g9c~d%h!ayf(DF-NCI<R*@92@2RUh zKcIfTPdVfu7?f(|yNyEV=%yH-%pmk?x~ysD2KJ-^@JGgLVe)kcC%>G`Mss%A@34O; zeONfXnd7+A;7>=&(j-c!H85Vf(?}KdH4nB`uC%vwgA&|t*J&t^#<GM|?5i1HDk)|C zh&)vhqhCEjC@=2p?tU`bg~YMxLWErRgjEf;n<~5X8cP{BJV+MSw4_S$FVHIx{uq}4 zNAs2LI>D=gj4(!LiHOFc<M{GCAYSg3c*nM=Up&|88$nK%q+>hq3&lNartkC57nM?G zq_)lHL}4}HXgjzfTb|*sS&j#0hPwUR$XSZ9{NIC7250unP|EviE(eQwC|6LcqBE#Q zN3`l%DqR(nS)=S3)D6nR?Z!#b?--;4a6+Zx7;k|L?I)+-%Af`tEu*k*Pg*x)k#_sv z38_!J))&bw78sT;fkMJ$MzR?P?T?*Rts?z*3AfbKr>d(LxyXU#;>BQD$q;Pt2XL=c zjg`U0%gJ{4=WXYYW>{}~?n<%yX=rNF$9sIF@_N9*A?RBGd^!>fOptp$>^PbzXtPwb z)icj-<sNoX^Rlmn6fbA_GTpKA(9ipTaDF{=uTliSCt+Ds0l1&&;OV9aKkWC`2k5Em zdvX#8$$Ofz@ITLrSRb8}zyzONI$BhCOhyXvXUM<%8aH7RBea1}MC##MXmCUJ39^ly z1}p5_wU5j-g!xcfU-7D<1PV&Q*oA1A0@S?Vdv(uNu12|RY_3c{E;d2kI(6F(yPFx* z@cILiNan($5kR^PK!7V6oBgMY!!wV`ugNjml5fyVM3EGGZ8$YHuR%CzK0*gQwGuVs z0fHM<CPg3|3EFeGEz^U+6!~pN(L$=TRs)R_BoRUWlkdrQV0Yd8WsmSKhY7sy!)`w; zrg>+W<Ljq(1YqT3DM{l^?j*jGFV+$g+E_yx3A?HNmY%qk>Ou-`rU-lzV{rMHK@M4{ zxREl26pDgHU4lfl5{(;w8A!D99Q})ZxsW+7WeQ0}s<OUQRbo4exz=kuZBVevJUkV- zg9J=}$ci1Ecdr5zZtZ4Q=seoYH$vdXX3h^bOYOm<rakrAPYa9{H@Qoz(;l;it7uR& zC_JnSB(mV0pRt`l4PR9snc`O#h5Ktm&>-VYuP~^NEyR1On5nR6VyY8>LYnw^WJKjQ zR!j?_D%*knROsGe+J^?<F$99FsubEYS%=1-{(bMHU_C<lmGR}BOIFt?WoVK0$LgkY z4nna`6UC@fGgJ<+6lM-7XM%15v2$_FXP#le#NYU!QS2?f2#Y(N^5jd}$QJsi<wRc{ zVM7>h3RM|ONy$awXHI7)dXFWrH2K>kTJy^homEql_qnIm9UqxJSy)ZKDx5AW9t}@U z68CaS4>aIno2SHdBnkX-)GOgm%>`C*QyIdfj^ztPKzj(CFAKzQfDuB8)~J=QB0Tg_ z0wXXj&?7Tq7YZv_R}kWM%Tx`sT<F$MkvH@q1Eo6l+->h<^QKoLt+M)y6dLTwdss_< zhs;WG2rUk28mx%!$#Z`5SEOC<U_o*c|9#2%dB=yU<FVcl3Yn~sz?sdGHkt4V<6#iS zTU>}^x1oP20B}(J)F8M{V-t7KpSm)Y6DU3R4!x9<c2iGC;{8`uVt@3QWGR{el`nE0 z_rOg%IoZv{J6&(P>)ZA#T}m%v)Cjoli3)>u^O~U+^G8Kp=eWG6d%H3cinH|9)J*Es zFOYvlF$_*~CnZ^55;Vb?+@w1$=lhMV(B}6<Eo%7CnOe5TaUvZP6q$$8Z@RSrjT!Qg zQ4y3ZLfG%6?_g^v!+O{$k`o|_xoa<+I@!6?Q2Btu)Cyp%rY5xq-<p-WN^l1QlhLM6 z9F^?vRiN5bQ&^4W7A{UyGvWDPKnM>SNZvpucx?IhFLo5a=}qqCwVfUN#W1dUQd)0` zFu<<}|K%s}PWoTE46gtyAPWKbE7<{pX~5M9Bun?c_GL)iOsG89v|@A;Q}{=WVG(0j z#dYC#y+bO1cjF`94r=%Q&)?I4m8_^)K44fR4!TJX<S_pg)=K_Tu$;k%{vL<V8q%U! z-=GEHb)st%Dd((ZEg)v(8!0@ji+s)H4aFn)y#3IQ2;TfHx{{KbHsF}NzA$jb`h|V- z%6E8Lf=o^DHnHx`%CDX0y4DZy<ZzvxhZWLst_}H>oQq~JY!$$L+%BZD;5)6*xPfsz z?$0@}Lqr&Qv+V#-kw>@Q55Zc;P94FgJfT@*47!muX%&f$W^M7ZLFnx2_`Wgp%@1&E zig*5rq_@Yo=bpp+ReMtJ?)9_WfPN{sP=U`3r0*Mk3FJVL8rqtV_1}MMACyftSKz+@ zgg`Z1j+qWplnfKzFKnZiTM=_C_n?+1el`h)FE%9S>He}kfE;6V%AWSEPfIhG+J}vi z!o6qUm4*kH2}kG@ma3y&k!9ququDstGCWn;{8tP5m5o>_NShmsrIJ^{(@P5FhfHqD zmkIE>!Q?9~45Q+W3m1+a=R*HliOG;`s)TGt_NTgh0|34x$scD|Tqw<fdI2}*zCVUr z8-TrYVF-8)d#AX20PExo^%@%Z>^Y0?A7J12)6N?Ic!QN-qp&pmB&Ymv5!aG?3phhr zx}R#8VnlhaZW2B>f|B9O?}ohtTF*QE`u-yDnh$a=e)>{+0_oSqe;qq7^Sk`8ZR4Uq zbrg`aituC9n%$)H)QK|cg2z?;W%Qh3sc{0>0Kf3!?i2U<KF_*GjRGPT*>SB1k>>l@ z+(nYQqx@J*on5q0?pT6ym`ECWH#e;-yl`iiw7~&cuqJU2rhp<e|4`@VfizO9u^Wl~ zx5o|goXIhs|FZK$KT_jP)ui;hTeK6(_lfLU5=uz@liWRzf&!}ibyO{=noO6126~-x z6!QtzLjJzCOx^V%WiO25dskAL5o0o~)2Sznz9cyEzSdo6lQ62?-eEiKVVUtQU7zKt zW4aWjAQ~H`Yv^4pGIzK;Tcb*@tYE)9NMmH1<IaepEaFbVP3#{5$#|w}&wU;;RWj86 zWNfgo7~}PF!?CHRiN`^vTPQdsWBAW~?{+tv8sPvQvR9!pr$&W;xXR<U|8ua73_9!r zg>JFssRx-ghZS&FXEM??+I8z!4WLF?(7OXLh)#ks{d}BftZ^h9<0sZM<$iD1%ai*h z%6x4^CK=gv%^T_mkGU#}^3TvMhc2cRxZl+|jQ`Ix^-HKQdeP&ZO0uLf|5SZ=>iyKW zyTchJ<zURNZ}<#aqtX2d-u&eOU|d;H+HyP1p1St0>JLzu>TtL#K&2Xfx&{zDHA7!F zSphGED^<X;x!c@}O7oF|903UVKcy<Me<?i0bz!C)O|;X!l)Lu;*WZsl0T4`Uj(}{_ zF3UzOVqHN6rS)<!6>Hy&7?<jfb3Mr|9X_`Jahfy0<kh2*il%60m4)5~5uQAC%qeE? zh;vY+1zNIGB=cMB(SBM~@kSVOOK>nHU&jZX>+I>uWXbuNfv`qHs;HaEr14|u?OGEO z6Vyolw!K)>sH9$EN?A|ij)|7}_tF9Ggsa_=ED_O;kFcj`H&FYoHB%|1Th#w=aLDj^ zerL^gPKOSak+q}!C%C4(&j(knv1aQ0+AkE!sP+^cKKdPN<^2lfs+!!jMkDo5N{;|| z?v9tCcb}4Q+1T6gZv%i<LNyGtK?QWjd%y0u?`IRA2(O^6U98gj2&eU<RFXGzh$EYq ztn9M<VMI1TGr<0=E{gjX{8i_6egZ0}p4GXgEB{kmg7QWPhLf*o&)j+pZu$`H6#Vl_ zt>zdC<)O_VKqg$Am^lwKys490Gg5B3Z8RR$9G|whjk=L*+{E;WUqe5~a09tBde70w zHLJ-#->qa_dxJmj2*ZXRLvGF+5+X4z*PMto+j1U9AJuWF8xqtr9_n<vo+Kv13PJXk zE}Mp@A9vU-ds=#<kyP9dds(t<C3)1O9#aSc>li)7Ef~`;;7zE66eRq*Z`-MhU$Kt( z6a}@rJ;DO`>4xhv4SQFBLfj^VMms;o3858=V#2C%qgLtA`#5?Q!{`GKfi8Bi#pFGg zdN~Ndq%aKjuoY;GfQJ32W}(5DS{_)nUltLvP=HD5&Fhr~q^J7O3&j51YHG0J{tb;{ z2C)JS=qsr#-~v-h+#3*jj=DG#uJ5{xYyIhMetVgANTo3v1cKI|@XWk6M5t;%4M*oI zR&O9)BML0o1|LfCIl`Le$Yx&S$;uujaMp@MT&ZK7RHK+klD4K^jV%8Q_h~v;2J=aF z=Bu3Ba=Bsb1;zChwRT$n&{1ajz|S}^k7s|tI%lKS>6EGb6Yw6cyNmgIv#Sff3Syxw zeze!r$=sA#|2?&XYo*JK>Ly9i4X!^OU;$}WukGO8--{OfNBZ%C;d_e?9(S=A3VM37 z!9`c}V@lP{mg7gx0y8mR)Ul<jz+AZ_tL+@Qr*4ZV;MEhDm|fidQrWw4YCwxVoXy+| zt`2I+emRiAp>sH{D{HD!Ui@D{-kxXEo9L&wwY`S-s^E?V@*g@ex_|1ULIE7)+j?Dy z${xR3fx$+C5Qky2)}Kc1AZkvx86>iF@dnC2;|Igu@06clgTu|NfL7K{z7CYdBCx_9 z0v0W3nyW@Vri4=*!;A*ZDZDgt(gv6CYSCNVBczlH>IgH$yYI3<+U#ztOFyxGlW)!f z&4(+gisF>3Mrrb2Qj+e1m{ZnMII)d_L;0)11?oG_hd}C6bNLqM+?S)d`0m89YU}?9 z#b=T1ZqReUY90@TC7E*ccgqG+5;)jNDnCHVtSw2hbddo9vFMZ{ijO26pE(Z{vZj z4Ljto<IcdVb%5+iEMAUveURC&RdLK#b;j#hQa|LR3muQU4>u|a%K&bxEq8!B-AGgs zPH`tV^dxxHCVd0eKbvRW>~mZb``^`4XB2>@<!u1_iJf16g<oMYh$Kj+?G+8V>E_!a ze3G{wrIcvJq@;w1H;r1kC}q{!nKPTon9ogW#gyjnRqd!B0f(n!QYRRftyA++GQa<c zk~E?mPouqKtcIZC-5{o_yjiJ0l(%a}sj8xnapg*@*)Z<|jwp{%w}iSi;Xg#W6bfjI zLp<L^%dAqBaZ9bGYHa=u2sG!|HRG*lJ)+aBQ|kr}-jffyr$>HLV7A3&S)+ujYx~ck z&_Q?W79kp_0@D>dZ*?7ZO<1HuGzqcSqfvuc`Q?KBph9ac@@DlCW7y{kyV-}WO61_F zm7Jodh1hP&C$bn}W7c2@TY*xhVj@-Ivq}&CjHeZ#iJ+g5+sHSA-@CiJ^a`y5$I`i9 zd(7p#O{G^>%MpJ^zD6*2k~<9h_J@t(m6Mf_?&<~t3)w{A)a+ETM_^oH<FC;JhS*+3 zYk`<~oX4E}Sd#pc72g?|2vRD#eNWoN*cR8m*}R2)Y@cH}15=Df2AS}zo|XYBPX<xp zyECnpR~Sj%nXJP5dMqV%PcBr1A+eaWP)eXcz2>v7d?C)&!6B_X5_+E;pwed~{rjBy zw?+&-t^vK%Qi&mIJ2KjD8*}$y>Mi##fw$h!a>G-vr-Rrp!1pc`)J+`R*3p}t-3d$o z^8)m+`vkkSP92$)&$_Mx99V!g%LI^JJ@&x29ES)H2BQ*U?Byz80rLH_YW=&cSaUcP zsC*V5ezBCo@Es5&MCX1kj(_b1URC)^Roy2-3y2DwuwT99nYwH!hHd)ICTAUYOc(B} zvhH1BP_wzE<$iw);*O*5LJfzXmBg`!>sV^3gh`x;)H!Q1pIvn|rx}-`K`^}^r@5FL zP*I|3YcEq>sk1?DS{Z-S`wWg#=Xju+KIN`gQzm4by(5~u0#$$7ZtdRfI3V+$>ICyM zRm0#*F_o<RO^{kS^)zMB<is@18`LM*iv}Wl*wK{%3|>1c`n-L5$-Q1L#>=qTu+B%= zey!BiYWn-iBK7TRT13;I^&%&S!XD}d(0jw_rb0S>vG({fL&gVNEVzp|=(y9T?e#SR z;d*xJvVk|!USrweNpw@PPPVr^cnWH+x5nHx9`^XK%dwlO@ZO2m*2e3re{I$DJ@-at z@T?E<=kDG}(Qt#@45>Ew8@jOu3~bil39ltneFm9BGTFM6G*3u8eta89XKWpCoI81@ z_(aNK2u{%cl}`-DAG9d*g>Vm!C4mfun%c=4T?)qpPJNTQ8?tu#I8PL^7hgP_r1uj< zhJlcTfarN9S5*5{zI-5e&s1=Tv^8VP0%Q$+S$??2<nytuhkafQ7nJb>%x}iRqizRF z_zYkLG=P4C<cN9s+M`L~zW@x>*#!uwlva*O<27$=1D6!YF{K!4_>@u5@}qcO6&GC` z&_c;lF|7170w`-9Rbl!DWHU|H6e0dQ`qJ4x7JihT^-`z4A}Wi>vQ5~QsRh>Kw;G(P zS7j-whrZ{L-825g+HAY82>hInfeK_O9nSwYatJbSI1Y&My?tpZDX_(9$(bKB796^8 zyQD4*<;7Lg9#DAdI1+_Yd}aE91ozmEZ8%Hc>?h~fE-Qy&zNe)Yi773d9$G164<YFg zF;2gs70HCJA`xS9uR~)=?fJOil?KM2eJn{_<=iyJ1Ad=_(zbr`lhouEzAc=5Lc1}S z>y~lzIOVabzy7bsef3{QI0muP#!2_rF5<3h7<wNpYm^jPX%wv&x^ly9Fw}`VrcPj0 z+%+q7pHx%r)d}4_cJm;^A|KV#_4jocdmi_!mFC!M8o#s^_Qz$iLt>-ECfM?NP3FZ~ zzoV$JE;^p>;6o2;kK)OjD&Fs8BZbN7j<&_y^4CT3g#vt*`*71(*Wt0K)C?}@BiyOZ zyYE-^o4c6~IZ7IQTs@?TJAJr_X|A49S7pQRK5nJAa>T|+dNa3BUCK;$t#$=7j|Vz~ zj^bHAqE6S0Vyd(}z-oV#a1wj^G#Bf|Npm`%?%!?Z78_GywN$mw;L^B(kwIoPq=?0R zS_=4kl}l!%6nmrzx(-^`#8>PX<j8|!6CA85A;~Q@P02z|fK$o<TD(5_(3dL@Xy&r^ zp9HpPJc<b7kHD)Np2hVWr2s$AT+B$5!CI_rg%0Y?jS~1h8)Ms9spnn!^4F#SLj?4` zCZL3>&H)}{0bmQ8|7l?2iOKBfuhP01Gt&Qh=CF13c@*(<eVzgtQ!Uo7@5)1oIK=aZ zm1vlBzSdy6ZkgA2#fJAH&q`MR(agJWRX0&$c2>1|?0Sv}T?c2|2Xx)B+YjHwTRco^ z+!GUvzBrcp8CUT++viyWC>dtqN|o)#%XiK2^W~Dvuy~(iR4Ro&7crFoGghhTns@>i z!@ZHeMNz6A$@vIxuYS4XzfgPMXH(S>o`|s$BTn6oO7_NDX-qEtH+SBVm?sIzH77}D zH8Daly-^+hg<Y|Ztl&<{-j)XoiIU5hNBe(NBQPE}=5$6%9>~5Zz?tkp210eGyaHNZ zFc>E=-xTY%2}Xpz)`px{?#y|7L+-!sTfaJ&Nr35Fo7qbuRpAcs4s?n&7bmjbQF@*o z?G$lzYwY|&7<5u!1|c_MK8<5p$^=R{bvvNvI%nz|RvRN_oz_L&>+h$<J&)ZNxt}(l z*!jBuohmI`l-8=wN8U44xeree=}%x2@M8bWkiA1&Y2D!0^1)6q5PuG5-*aQDOCQzQ z+XLi+M`~}_2&`_Z=tBUQqHmBf&GyDeAx0FDx@mG^olx(-?3s<KHt8q<eZZ=MD-%GT zwH@BgkWzHDbx<CMiInxEU=KSOOYrOe3+T{s`$VU3ofgs_KmxT{s>?zLL`<Zw#%2&N z2oX?f8>rB##B#hW(5!t?4vJH52jDlZUrrPo!=MskJ4oxXx3U%WUF+Qz={>qlZM~zb zv2zk$#>lC$8$De(Qzp-|bbIQV1)Yk)-0;dV1jpc<%)80Bxipgi*!61h71xR#mrnLB zHQ+~=GhNHK0@k~KQvOIs%l|t+u1lEWt~A_7wxJa@Sd53p8ENS&h+OXM*XmE>PtcJQ zbd+FkLk$->D9^}1!Eua3F1uCme>I(w_B-u}r2H^V<ZK?+YdN9L_v^?msqlzyaKpvC zlxNGk(h&p2r^OdHj~V8W&u`7!&NS)rzVrzL8VepYjjEwIxXV%Ov$#5~yoV(yDN3zt zO`S~hB0ykAq3`Y8Tiz`gJ&>FpXio7|S6CWssl}@ndAO)(n}!N<sCrMQ09lx7!5Dzi z2~Qpf^sOMS?hi;Wy6aPH|7xQ&B;}!Z$vT>{V~^h(BwRrE|N9(gQk)y7SW=h+|E^-N zo9XtZ@>rhFmJF~}Ni@&r;9bR2V1$5#MI9;k{nn?AT4)ZRKP~NZgk;9{)B{y>v|M$< z9j09y*2}&J0Y=HnQ@`I=$c{InCMUBx9Jh<Xi*huiQM!87v+4OFh1jj3{`jvO_Bz)t zYs3r7zJyZg-xO7Qe$JL{Y>yWD%AV-cpX}RMv~60|nX_#NMS?n7kp`<)2WHddZ|7eQ z7Nfcz|D_>(uHYnmE}Wfd!Yay}QqL8b&0b^kswLTIUINsd(3?Ka;aZ~wR6?1<>U)nh zwD3>o;*J_lZdXM&c<$NfSG@q#?Z-I)&Ad351IXf{etzn;b6JzLxrf+n)S3<cVf;69 zcv05&!=B4MIp*jXL&++2WK}Rr=1xY!UMeBwt+N>d4iGv^zb*r=!@ZQ%*ne>&{KA59 zdI*k<g@%Dk1LUg*<nbzye!{~4F;988ZasxJOa20L8OfI`MP7_K?D)iCX23ZHu`T$s zxZyyu%i7-3N_fVe$bD`SF_t^z1}XC|wa#BNa%`!iKYEUgTZ^R{hHFbcCSQ*d64z*u zU2053#8wk80IS;4zaM<F_C{D~FC<?t;}Vl{_yB#q*8ORNB6tm+h5DBFGPz0*_xxnI zz<$P9^JIYTv%m#z`i<(YOgUNY-W?C|;TVU|W_DRF{{q1`LZFjwoGvu}&pDw5*UV8! z`N(<&^c_qw(yizd&6s-;R4ikC|Bj8K;oZj&3H}+(TV%#!T@q!XUEnrU0@m~~2WTp@ zW%#KZ7vSoOk(qkXw*!l47u{Q_A__@Xho?u0!XlpKRK$%xgoiI;IH`FVW}m1{nT<!) z4$pY$K{CyHgHv28xUcz#XENgmFva(m%AqeCRxT>t{Vk_0!gK%7Yn@Ac|Hy?>zyvq$ zEJ@C2&hNkZ>yk0SS!?_-ngdz)|FL->dM4SmtKxksEiL`;&(jh)?IFQ$QGc37@+Lga z?#FEFz7r1Z+ziagRS_%p>wsI-ce3n_>rm<wB;gMb$yFy9r+)Uxl)>lZ?pUCDvwDwN z1J$~-p8}P*tBnXC+^I&nwHk}Dh4tm9BtC-TH5*)pg@NdmEzQ3MkNq6^8<U$VH*2_y zbw6DyQX6i{*94W91E|Pe#73KP|J3(k3k!f6ibLqU*R5M+))HZdI%5p^<L10N*^5Xg zo~C?RE97W)<wd0NfwzMu2U;hSNq-wB--qA*=!a#f^0`(WjBWfx(?Di+sExjC*<nBX zS@=B7p=LBO`8f6B^K}WMn?*0e1$@Y+na<`4Fr9O$OQbah9xj*Id54D8)NG|ayGxyv z7D-e3$++3+M!!P^1cRQiSb;EfdU;77Hs2NiY%E2K37fr^?t5MuGl^JG{EajR&*@OI z1Ijn_lZ_SgIf%o;2^&67(*MG_ByTd;Gwv3X>PzN<UO#+SB#6ffmjwhV&83Hb|El(4 zY0L;oTks(PYe}Kt6XJR&qohR92JA9sdDY-kq_;I+HMf+~K0AbBDTz|{$W_Hooy<zj zn}COKLEEGjn;z>9)2<4PV96Mj0R!83;1OTM0mpJpSBKYSdp}}n6{dfC*B6afJ>Gi- z$<vZ*<18iX#qprjp1-RbMef!&N$<#WPfq8n^fVinv0n=q_9l~_*0U&@c-$LRf22_G z`JTeZJ|<I<NfZ9LIk2&QmgrhK(CpT{DG`YM*gDa_8XNT9Ib>oRAla|Y2LO`vt>63v zja~x-Q!WewV&H9KnFg`|hG}Rn#U&silE2^wRD_2uGo($KFM-;@1hv&ybB1TTekMF$ z!k^i)GH<u#>;Fs=GIa!cLrkrcJUmK&t*Cq?I%)!-zmfa~r7xB?zk%0HFn<Ei-<yQ; z>~||_=Gnk4bCKX6&~}hA`WV$Q2+!p<gM3ozs(8i|;jH-rU#+6v1G*OX`%OYMesDmK zz`gm<EL+6OFy=|U0JJWoiUce1lf%jVr$ZBqS30zqZ-Qw@rq*HipJ?&2%s2c8FeOs3 zcM@Jv`2(vuM8jnNMaFfP4BcOTpa*FCpAhxE-5V&(8@Ds{0LqwlfH3WI1b{96*=C|; z?ZJ<fM0M44gQ&LD=*V<keE0FOZ$j_fbm9Is_G!I8^(OUtX{tSdlB^pKL?ay-=U|YH z4w_xjCS%4yzha4l)9&dqQz7yvyHBWb^M~-8G8H#NCLv$P@$cnTWL&facW#x-I`3mU zd?LdppkQ~8FSV5L8bmqKZ_2*LxDiGFuLSK!-I702^-c5QpYfG>r6-@XY&E-bJc-Ax zWeK}Vp1KFGdqChZEi=_Sj4LD43LsnAqW-DX)<@JASvK)??p5xHcU}ugJy%!6spB7y z>e@VQ(jL>iq_7db(&q4C-`o2y`iU0kV}T(XBg%Qfk#^5}-kj(MvuiNsnXWYv#f9#s zGHFBB>L26Ova$QzRHC%CG$W4(1lIwY(P0ZnWbOrnr;QiCp4jcD{l|F6mu)q?QeO0) z;?`$XfceI6Gl1ct4N?Eb+jo9IoAKtq--p!mrnQ8GL^GCV=r-^I_V+jdMu@Qa`M(}? zfSI9bo4XaTv$r_&=i9%P={g1MRju5QGcim>&`h9@-B7)NhRIW<d=((To!2AeAlQt2 zU@E7V_XT88^<$3HOk#5YrRR*_UC#&}CWPnnIrEw--!FqR{&@b-*~TcP1QNV5o=o(` zY!Bo*kj;d-k%fWOxcP(Cm?ME(<aNw41DTV!>Ue8odFljgY|JrUz;3=6F7*6t$6n#2 z#({$1ldk+FZ0g!~;@Jd9Jma{7h%D&hPo_3w%1)QpAmVrRO`1W*9#i*!A9>T}2LQkC zOW*8-ASE)IYQ|T^BJQ@NwKK}v@o*je<yvDuN4iCLq*^;T@T5(>D-T9j(X!wCnd+m1 zi8Txofp*TGez^QAyB5kbgpDlO(TK#?)~O0EgqTzrc^fZ)6&mj4rr`S(jk9fTg1uad zfd`aFJcb&afTsS$jd8Cr&8|iKfMUq2s45p2jpO%9^;pn5r=qCrEO7E^BT};0rbK`2 zmQhj>_Or0a+IJ{om80^mVBpd<zFSU<!>F<z5TCTazx*w@gF6Niv46inSg&X&!D5W~ z=xp&saaeP^;l~HuTXFi0%##L>Vtp<?>k$5zfF5KL5g{U|$oQ-lB5ZN8KxZNudo1_# zg=XL@A7$t8e!IygR!d+o;=?f_fkKUZg-B>BIbg1m8g5xbEoV6ODZVN|X;UWx8O@)q zkc?2K_9!UBZ`)1>W}ptreDjo*@JmH=bU4}awvBvU6eWY_n^C;~Oy)1VJx`VK>bTd3 z`mRoZ!Y5LB(N%nir1h+hc$hGA#?|^2gw|Sn;y8V*P@i`%8)&>;AGPic-;p!^YO#Yk zeoSS*ad+Fzh;M)$s3F0Ksl+gEq)|UMxH>M^vzB@CXs=UVgY_lzhu=Ni>hM$i=P@17 zJAv$<GO1=VzXSpW>pWNjPEHK<YqV@V1d{a%tmTq<Sb8CDp8pY$3IShId5znLu`(Y* zZ0W+p9y)aHzW&KsIlMG0NG5OCj4Z1iTu4s%v^V%QXdG2M+}t(2SQHXLnL^inBMdap zYZf213@M*)c&s%Ln&7#VlE6ow%VD<>JpHs0J6Q0a?V+v90wJc#bYl{&R-ZlZZfo9d zT`$*g*iTx@N^Iewe$-Mz6%c)&BbmE+Ae-7g#=DmV?SvCy{cn!NNj=_CJIQnMV!LTg z*52I!Qb1BIaf~~6=dEQx!Poavn*=F-NLe@Cz>&urXa@+Dm=QMlbXcI6R)Y-Dumq0U zbwybcD9fLe{c<f7={ENYj`B=RO-hN$hDn$_uCZG=&GkV84-jw@p8Q~{ZyXd~1q7o> z^DoMO3)Rcr_{SL`F!EJ1B`MVyc~%@hoyJs^0A*lZK&ard4v?egkR_1ZelzEA9Sndy z^6bgSDi#60fuYQ3fb&4C|2j#?S@~h$#o*~hfG=QB9T`dU`!naRxbB8AKrawhin#{d zIh_}34kYz`lG4zy0|1$pTv4CrA8?5U@Z_oAzNS(bsb1ahhVU^1UWG){jOf0O$>YAz z`gZH4i@r|}#QvW3Nej~LNv^-^bZMwtHi}RR0P)x*^ueuytiv6^n4;iOrio{7n)JV$ zu)V^+IwUX9;w>m$&%F~F$6nL3+g@`c55*lUI3z)o@ccz>2XZ&Ee8X(33OR{>!OqL= z<0uiXhL)-cEF=BG*bWP#y#AUU^>7~4L25IJc>bVj$K+kVC}P<VIY&nL@#BZPxCb#W zuYu~DRUYNdQgP@ne<cy+7h9?D8Ce;0Hv(F~QBSCmOar~cbgr3?rm)GbS@c;%SAQxY zaghGT>|us~+rK>*mXrnbbpIr2O7yEcf}f<7E9+>yy;-5UgzK`vpAu{}s;I`rN22MY z3!+_>Zn2rF_%^*a0^?rY{0)}hzV=o=VBi1Q54dkuR+dn{TTDU0qfgYe*5I>=kCh^I zhkpws^))eXE8{B%nrLbna-Q74D0~WLBn(N)alu<^B_BZ9TEC}qz?J+e*8k1dx4-!3 zvg)4`2`Mgr8OMqls<V3>e=O!8mR^uobg$0H9M}jl(W~-rD{o2<xY3-Y$DIK-mbk7K zfMO)Ly|)|z<>%kM`LrMKk^h>e8=W#D_GGrzTN3pY*MJgs)%j~8h4yq4EV=Ie1zxPt zs6zOW$rYU^phvCVq=~-jJ6dNYJQ;;DDgYiSP=WHiz->=2xcyKh^f}wcVEwQYcY*3l zA_o(dsOA*UsCdmVO6Zf453Uw~r-^HCpD8APCoBUQ<7EAV536)+bPA$XrhuRB2f&sI zCRj!{VjiRAcNV?Gm2*ara*E;|S{ruk+tZ&qwu_?;dN^NnLE}{^$-9+slQtDy>RKMP z^~9Hk8FQ4<=QYJlZ{ImYJ*20nXHKvT2uQyQs&wA#3#gkjquhUJhIXXFN&h+c6y46% zR}tclWCl5T*P}kZO>A4PmNRFYqvfQ1yKk1kZ5@)I_GTKLyYPd4TT}C{BD!_5wXDIG zN|2qDNoB9GwruwfoZmcaoZJC#j8>E)gTk9)xl}f4=GE#>@W^VEPJ_Wl0PN-bzWtwe z&}1-{5|uHpHM?_qdU{emL!4CTk#)H?JGHRi2H0f(MG#eG@Wh`U0&Q*7;;9P`>NLG| zf0I7iG1)MW=oR6y{hL$AnN`En$mFGdtU};Y3f=T}W|K%0*Ah1k+=@b-qZ&>Aekjq! z%DOJ<ov<y&-j^1tdLh7jh7>)-WcLJ4Dqfe7E{+T6_L_@Idjm@y(^}h>0YV^A_bw9o z{UJ#Y{d%d(FTFPlcgny1nWqZ&CRPfkC?S)k&@W0ejAe6RmX^g7k?x*JZd-`Q?DC(d zg7!Ul41BA>jdrc5cz{w<GVTvd%-x-j>+3DO0M8qF*T9<6)?K;ed<M^(rqze<S1^wI z^GCSs*%)@h48F^$&mVAQ@yFEXbuy_+37pyo4ANOTf4>xAnb9wKphp{xuH>S;I9Ti3 z@jU>N3iNSa&f#`7Aaa9zlje%ME!fUX=V&)TabPzhBBw6;89b{E0YSaVzl1pL)VHYM z9FB_Ub#M;XgBh8PmH<m3U*~WN)nUJl)Fn47$UU3OVf)!Y`!t*Ou`UhlJJmXfwpm}% z!Zotgz*p`uJ}_|}&U<y^n$rmI7tvd;IrDRik_P9+%GK<7?7t|VfXx%0yU{7g6qX0~ zC+eSroQjkx+g+|<k2~!u!E!UQ_O@UtL)xEn)Qe4Dg__MaZ(;ZQPV<$#3dCNF*ip16 zVr8s)3n<M(Qd~K(m~o>Bkw;LmR-q<Wn8>r)Qk|oIPKN*<-lwxHdc-RfYC_a(1Sas^ z`pG-)malf7w;%^8G^ZSZU`i)V?;KQTHvDQrRLZF_M7gI2zMH-S!eFZ&jmgKeOATFP zyl&v<=k4t+X{IJpEcsx~N;dB6pwI6KNuP}G6jxkexDn%j<w*Ud5LS>uO%fe|Ai-8| zMoc^{p&*--vS!45WG7`KhRA%|6m<8Y%B#$x;A4_oKV$x8_*f&?tA9MQ(wedPNbmw) ztWoRNVCQq!aZ^4c<clYEtGK7{DkGSomn7N*b4t+9;8kN%6<IhQ+{2qqM=MqY4thQ; zXYh2(BtGs0st3i(bnI$e#(UWRH0&$mS55#-u;OwLU21*TJ$<{J$W@D|df=vUTK1FC zFI{QVrJEntzB51jIw(L=O^p+%GgONOx3vyTJjpaFrjnM5tX1MHwDgR&?-_yNe1 zUkg|NkEZL6ruzT?R#aAzSu{RIW_INgl0CB5wfElF#m$H$Nm<vv_U0P*y4RL1d%L*T zEZLWgD@py{eb4#*k8>_Buh;YWn8j23h!qZ^YtqmuFLCRYiJw}n25Y~DW&eXUV4T_2 zJ9npD;0qf2+#x<Xqdh?LJxaW%mN9BosR$uEf{PptiP4l{?PTkG@>?dqd9*{h^ifaj z_fy(J-TqvDu25#=((zB!6hxM}L2&k8fXKfbfP)3yjGmYwt}5!aP502pzAjEUmq%P< zpU<r3E(R*!UI)VzAl>_Gj)^Hzep6=$N{zOUxTeN2zm|4TWPJ(zR)x2&cf~NAc?W_t zj)Lj!i(0l-X3m8k*B`8Osd5FL?VXM6UQQ3?;Q}RaOpe!W+2lxs{W=SlT7%>nUZu#k zAHTYqN_9rE-^`NL(WKSvaKEiF4iiyDq>kOI#W`A9RE$@jEh|qvcxTk#r!RB>wi%l+ za#&dd5~Y_OpGDeY5lY7CsfXBv1J0YNBHyuJt5K853dZ5W#0>U*+lK5Gm~jE}7(BI7 z{8;Ey<!W@{-I5-!2;Cpr3nnT?REDPkKibOg#YFgMdo%44k|@7(s%iQ8+3a~*7Tym7 zvffJk|Jr<FIjgL%Jutda$&@sh##F<30-&&-NF%MKSB%h^y4t3q2g;Ne>q%Mhtk6J4 z*PpGY2LVCzU{E~Jz470*UU^X4CIq+uxNh7f&b!=#rk1v!ncd}W<=ua8ZZsvk%1Ja+ zvvmQeam2IPYlwQ#H65w6Ak{%pp!Bq$(kkY;JAU=4ss1~@Yu7b%d<W*f0-9lu9RQMJ z&}TLP>46(_7mNcfwI|v1$E%T$3ON7tx<MGCER+!{{1*4$j=E&kWRf}2`ghcuz$}V< z<B^l}dWy#A@q4E72UgWelR<f2p3!)+c!Mz$Gxu<;t)S`UH`!gK5DB~Ek_C==ig~`o zi-TiyRN+kd>y=7)eEyw2&L#Nqft?%NQ;OWl0g`9D*;@J7Lu**0<{KLBLm71<1}_x+ z&-D<3ekfjk?kZrzP%LYNrK(td(y_^4xrj)Tu&wiL2dhA_4!f}Nu`~$$L#Pcc;GcD0 zcRii-Ht&;GHP?$+3AR0|u<c?3N9P27<Q5DSGheDVFiYuVa22ibbbhgD2G^Cb;juM2 znta{O8N<<2oPy9kNQD|xp!+>3(<x&5gwC4kjePEHdKKdny1(8RyhlnTpet8_doV_% zPbxKnrO9G&Np>DWR5X?`Dqsh(jg3kF+2^XvaE{XB{DfvTNXd!Wz4Y0~WAq;2DQAbA zT{>lNyz*DB-OiWT+LxWV>w3bfbT+2q5-Imt?HW@<nzwXhcx5M4wWso;Mnl;}TuDG( zdKaEMjkW}mH%m1O0Lx|RjvGMx-MzDEw!gD?9-3=*IP-Av+hSDAu?(R0Ob23K?bZPY zr2&u`O!1ujmEVAL1r!(9r$DtC#3ZGGjlT~87|V$>O>!ELMK&dnwx*8UfA=P?p~1;T z>Yu{@F<=LP!N%Y0aT4o1I^+SI&UjFWcqj~U{?U+I5(unZ$-_Vaw^4t?()bo`47G<A zR?JR}bJ8vS44{4J^K}M=-GuRxsA8J3whk|MHta1vd}&F!v5HGP^z*J5{LV`yWagnv zA>8V`H>!5BZAiu2v`C@~E)}$eG~V$;8ynWcTkh4V_ygd6z4(>PixH<86BTHaNoI8_ zb%i<u9b@nUIUZ(aU%x=(7T|vvmJUBSxsiS(v(s0B6e2seGIKM2kNthd%-jFICOMLC z#-!qkE5)4bvMI$hrTc6GXU!l2LIxf8R$6fpoefAWSo*~B#Xv(A$A{_maHZ+fEx(60 z*rY9FnKQG+g34EWNHem@6vJ`?;vN651wbBa)`j~1BAkU3`E6yjIjY!x&l#BOcV-vV zT_fn|uz*7(^)ag`3=XqxhYohaw||_A@?JUq@IXg`YcG&*gx%q$y4##4Y%#$q793)? zRCzjH_p|O&+5+L{<)P_!bKAetFl1iiY2u<GXH`$1iA&=^4la?kq@Yq<&t0{Tyi(g- z{|=)+GlhdKXcM`UH4;MPylY}4!D>DssV}VJ`#C~~^^9kD#XTTpb!tF_P6Ljjb^cxc zp&=){l_{v>7RA<YZ-5gRv8Oh_k*h`A%nGw;PJcelp(V6l15~lgPG|Sl-ZLPq<p%!g zmIefUEw;RWPTw9~o{ZEQWH$A13^5bgpEMqmI0*VaT=7hN6YC6q6@9<{X&Zu%tpN@p ztG;Ht&O;Mu|H>PTtw%Xe1DN0@zR~2?)x<w#>BIJg?6!b<*iIV{k`K9=*5UEkY>&Sk zyK4mR=0v9>F`K_tvlhsQ1shXqt-Y&RK6!g~wdAdJExkw6cCHC-gk3}tCOqtFWI?$_ zk>$}-*C|t>`>V$7vU0bm?D;Pt6)IN69nsWYum7^z!|i0_@B5fOYw5)5u7jk0xBWAe zeFwG)`|@Sw-Zzc!gOP{la$Z`Z(`nBq&R+x0)_Bn*0NKBrV;L<p?Ox|vHaS!vIwSbg zh@dp|iQHy`T`7~sjlR!B0RN2B>P5=9JTrMx^aAz45qh}M<VwkI&raPn8_Ji=lg2j1 zP-B9k3V($Ha%;{CrcnqRl3#0igmB5@pAAs3G2i5Bni4m?A`0=zYjt#ObALVbo(rD` zp03*AcvSrp?r(5Cy1u>#ebio(T0yZeZ}a)Tu9Db}xN!O)5SgI#kZy0wA@U@bIz)$a z|Hh1XM>Oix-xamV2~}KK@$!_fc*s%P$guYd3~990|CN_-DZ3#%6Z9Rr|LD;pHkY&q zSA)Jbik>~QMCa~O>{xvzp;RO{c}&%PRfh#Xe_*`wTz6U3SOf$Rk$N--yPpg()xeH? ztpqmQRMJ+@v{_{d;vwGI1sX4gd;vcD97v#lh_pJW>VG~io+%8tFD+Cuo(Q_?YkuZB z2%FpTVRgj*DILP`7&L~^J{gm2B;zIeRx9O;7O8kJj>2yTye!T5#ReJEB8%we+HU|V z#x_Zs5kfU7=Ep!o7}*y;CLJK*<SiP1bEoYXfD$!~aYf_v87F+1+rGKk{p2=iDEKAC zuJd_EwFsfotKor=8TLVQ<r_;I@EPn!lx9lK6_iuD;j;?2WEKm!MlqW?*HN8};-e=% zDTD1Y*{0rOL=%?UpwIqV;I4WD9LEiOq`cAotuN^&&L~wA{GKu1@9V)~wOXXRijIuC zds*f*10^{)c2Q1hc$A<7uC$JIL)Nh0(%j6xZsqhJ{hWyp!N%Yd5FNBq&WW>AzP!~h zj#)IkJoDd2;C)^77dshvXVa@?JKEYTss3AvLcTS|^v<K^Fmfl;cSha9LLRX^^KD-k zJiI(x1-N68kiR3V-n@-0fXI#eXU(|2O`3W_Zb@$yO)iVqL4;D6Wr#zA#`v7Z*R;S~ z<P|r+AkEZqV{_G^@2&<g)A$8GS(e%xfwV?vFoS#UasnmOYp<M?bz1iBT=kT)yyG-( zK7zdMW=bI#|2Qf?Yvc5(nOJ=#czbO~Jl+3Qve*)29vR5}+>g<%Vyr*_ZCPn{*<_ir zOJ=rL4=&cgy3}yR@Ln~kJ>x>%)in-?&xO^Fna`}&3&xGrsNXkC*an`F)+y27>`b8S zOT@nl+(uS!qhYBI(QqTLIbAP@O?!)&lwuaZdRsgMV&q%W?sPB1*8l<Z^W;GhA)<Td z0R8-{z&sI1;Ulf=Mq(s`k4lm=Cq5SUm3$0rs6u<NK+O`vfgp%zP%*7(r;`Gjs@K~* zMSc^}%VobU?wqy<h>Q_y|G3Ez(B6AX^-O$AaLUM4nODBqlK(<5T~jU$Hj=K7^m|p? zeYEw<uX%5L+q23Z_vAy7RYg&4{U?c6QSrPi8@^hx;#(EpH}2bAQPH&lLjnYs<OdH- zi<XsS7$-T==iOe?#8nBUMRK_tGHQ6Q!00}W{4RRqQwhkhv8o5OYt%#p7F#=8^qAe7 zi{pgms&RbPTC%1D-&OD@lfJWKWRM0#PxJ!t0v9IizKWkIF)5uZMgC2O`=wAjNyztV zzdw`zV;=KBDkbOFDskMLO(}&sfMSNBS=I&vSuk&s&r8Wm`k~xWBS{YXV^Bi6qeIP= z16{5<e!kBN-Vk3i2)9zWRb?fZo$$*g#+<pGoDSqNc8dtzH%egLd|fV%-?{}vRSxW~ zm9~Y(ZWzx@KDI?I`v27e*U|2fdrmbp{fEH)#7gs%Nra?|@<H@8wT<sK#v&Sh$?y+i z&uVg7{pTsV2JbW;iLkT;+-t2FrBVl<a;bksX9+`Ge~e~k3lhx_f3zjah>FdJrf8Zf zI|${2TTL<=t&Kovv8K&Rsn)an!9vMvtTYjTtN5Q>GRYR0Hb~#L+%<OvLE+t8Q3if$ zCCRa%6QznFJHOZ%3703rOz=O}1bvmBAaD0Aw@n-IPe8ymd`ei9_N~ZOpb0F8ElciS zl|tNepi4r!FD%DcTwg9^MFWxYc99C^H?h!$h>d@w$rtek^fq>GyCTlBKIzu*D9tFg zh~hz6cT=Ao(%|H^;i9GB#WkqWRTaV-%wPj36|zHpGcR|$P;2`7L=sJpy<VW`@@NN$ zraDy-Nt~4qXM+Hmyqk_}zgay`yl?D<7`9FT=}-U7H?Es84|6ie-tac@Wb3=%{%dke z$o@uRjcp9_7CrCBvk=;#F*<XBh6je@tStQ}U=Fx9c^N@-Be(H~uI>`{{EmBVQu)~I zuap@j+z#SebT=IzijtL2Nirosy_WNodVo3+84saG{?bTi`kC><2Pyg*yU{YLFt{Fi zMg7=Jj4%#Xacfj*d8=6NHHY2Ye^*{^>|oL-o)w7r&1kW0Ah7dE;ZLxaLL=Dz)L_w$ zap(%p>eG;!Kj{q3@CdXuA6@r781Whv<!Wz!_YVBX-Ck%l?YS*YMJ_XNhyy`^?FUPn zkL)Bu=ASj(7IG>@Wmbloi)XXHVIdkXB%p)(H#JrXR(T<ttEocBcUrC0|Fd@k3*>D| z3&tNQgbx35KAW(9tFy7F#Yr=Q)Y@ILa=AL12A00CkAH3kk&LL(Pk2Tv#xbcF17(~% zO9Mn#E2ewQE9htVI5sZhcaT$;JYywAbGsz4_RP)!xg<~Wj0ltCcZqc=kBEmO)|Nkk zcz>VV+}!2B{o6%WyR7p2VwvyWfr3nc1E5{J`^WmaBd!c^$F86;olOlrL!Pu5@t{=g zgUo})KR}k!@HI8+y*BF}F2Ofh+CDzgNoY|0&r87fec!}!$~~Frf?G8u*wI*)7}AQs zHYKYYf`N)e*MW*A2m5R53|Aif2KmL_dS3rxHry&6&>J_KWSN`Oq24XRNmf7ud_{OO zoA(AT+Oj2H8E`=Ohj+#|*t@B?yjHi>M|$dvf1^sH{;q5?groPF^F9>JGpKWr?m&GG zx?kyYaApDMkKf*6du@2-I#%pEezMDlvS{24XA8IXJVVGnShitF-U|-N7+SC?)C(^* zNT0fWMQ{I}(MZ8HWL%Iu&})zxyrsUswx|7OmTe;n8aBpl?0)KKEs&t;D==|8LvYD< z7szGEZ%}-3XkzLpgr$Dod<u!PE@>Qu=Zb}W5Ar0@!J2LbBDt2=4y?=it;f~^6+cU| zvv3^V^SiwMuEa}y!42M4S_%r@nVwjKDJ2L#4?;?<PA3suic?V5tWzlM4r+tyWZXln zJvArdT1}9m?0B#Ng~YRSZi^3sm=Rr|levyhWz?fuE#3GJ%Q0)j%gXSm853xUpa=lO zzTBt?S3p?RJ&{?(p1RtNJ(cNFcCoo2y8F8~PQ58wN`4QR_O6cUUbH`BA1gq-zgy#0 zHDFMrwwBBZlq&pMUErOG?U5t`c7X?uv+^uRv5uy{l?2xuCgxjEGexmdj1~_|-BJ!9 z%aR1cFGRl(TCzf_>(Nt0gTGh4gQr<8Dh6y?0mEH?S^Elb2dyCaHbDxO)600^CDRcS z!8G+y4e6eYf%EpC{go%^Kl(D(0i2`vX8@VC91FnE7k|+~wS#`#8mPDTEBa^^5eupZ z5s%UD-6U_43DnPSrl-rFKA@$N{tt~!Q_tUNbyN)n;t1ZIeyHci`~BEi<kdD?i2|{@ z$n)1Gb1=$lZQvb;8D^<PZ|_Y!g$a1Rcq|~%d4A}mRJGDDSW92$erHK4O5}7_La*_c zd4m^=C9NP;0^gnR4hfF-A7=q+zd$$Y!+%<TT3zaTcd>^uX$|*cpFN%vYS%$?zZ(0h zx4Vyl<!AV^&g9VDciiMRZ>Ze7Cx#(1EG|;vqY8dy47d2`KwD0i<9S!a!(0AyQ&}FD zF&h@WDw{_2G_!Gacqb`gdtZ5~sv{r5^hxGjE**WtTupEP^>H4mXJ{F7sF@>Ij@-S5 z{X4XtB`?6vw@X1B?bc_q)w5mdLB}Tn)}O;DFrz1zLgp=>KYy;<BMm+@v|>z94nk7R zIQfseGI&u$YutVHSrf&lqR-hB_O+`Z`h#N<oIYiMp)RHRaKhx*tnx&&h;GqinP116 zGE{k9vW=l&@Qm>V6*KoD1XiW5y5M^uW->@HFCmx<ygeSuA@f;>aOU8aIlB@iN@Ymd zzO>#*I*7@ei#;F#hwWM@oN_4fgG>MX>#X&UPpki>27hR{mM(Xyz1I}eUu+R>swzS( z=j?hS!aAwlnY)fmSZDAGi3eH4h}k_Py0Yx4`Kn#$!5uYKYb%|*ogylzDXL7qoWNve zEsH5@&ps|kfuza+i~I7k=A&jc{$?(6fZ@(!+e7@L$t$~OxqW`5zsP-pjuu9CzXP@K z;cq({crgZzs(7z4FcSqC--8JJ#G6&Xd6O;$xQk05L?xcqbWj_~ai-UAUEXdKVHM=_ zdQdTZ3LA8DxLgRyl#ltg?W;*?ii~JHq!L09te+bH?XW)Ii56K{v=r{qtLhr!!Ya{y zlrdc-!{)8np`j=p<G7^iNiwC&?_NXb7YF3KF2Db!c*B4cZ@IJPk6W-BT&Pkt-BjpZ zLGwgoGcwl=C*w%wBC*Yku?_aC3#tv!J~9Ve8^wUj75DE|OSQ&rChG2LdvA`oo}Ah= z_S%pI*oW-?bSSjG_GYy4SO2HtI?cJ_66UI~yH*}1PNa}us|S+qk1BMk$0GPwtF)_i zDm9gKg5iucwaQ`8rBZESDtm^z=p!@)_w$Lbk3v>713gK?I)x%HxAmC5dPLT2$~~hR z?SUd)Fwn#6Q>2k2DC3)4OV~erm-^xURZ-^Y^%jq-sP*Fa<!Iv`pLN;0(?7>PlGoe4 z<y7M54S818w=8Q#`~~4W3ec9_OA<RL1vGw-xY%zT&c%{j=Nl~$a}k~uE*|>@rhcgL zVNB(+m2C$EvuQ;rAT6J*NMEuNCNW0<)6~3cf#ug?>&qI`=KSZK8%Gy6DG%!Lnh_D} z9}R76mYm~3JO_Y}mdETZ$o=BLJpW3>EN_4HIs*>78~)FmJ0i3Z68=Yopbr)2nhK|a zzB2{BLk_`Z!lvOj@a0{59s^}<3Lx)!19<lCSJ*vAyG&<V`T$jUITi`fM_L&NAs=1= z!ef|Wf{p3m2OEP;9vTzx0QU<%m~BNzys}qLW@T2G{McDtTGG%}*9)+7^PD#%MB-@@ za#t?XYFJ`lGx=4936-N0(qx~5&hcSHihTKqqRF(sSBbNzZiLUc1|Ks1WhbsvEPv82 z$cr!?v`D!~?Jo`Yn!;~Z-M;&E?{~psfvBC;scM?hHSps)y1xv;CH7ITVr#d{foyr2 z7GcETyXw49gOs}%97%RNO$vcjez+?WoRx|GYn`V``Jq$S1m)2(CP_O(+I`3d33?BE zxuC~*`}4GW`d*{AQwI$_yROrL@k2~x`ZWphMkWW|flVRGg{M!)wvMb9m1lmUm9=kc zE8wC0wi9*vmp6zpDS^tZ+M_oYYmEgC=AXOV4RICnnH-uE^g^a5VBkVPey&(^kd*^h z!^4ViITEm&Amu`NZHc&NHs)dDYAIs4*uTUB*YdACfhqJ~7b-_{U&60KbQXIas>?i; z@tZ6SCv*K!b?JcUssHBa(#+y{27@UB`;Wvh7XcsQ-`}*(z?=l!8h-ExaUenRgGgJQ z=kF_i516&QsR0zOzA!G#J)h?-j)V(%TP5a?N7L70qo=?Q|AKkzGZ1keoUjY|0~jYs z94|Gc9(Gx=T)qK)!1Qo+00ih(zM=7hteGuYY`}7WX0;Vz^7S{(9Uf`p_`vTUCF(vl zPK-7*^*nJo+Fm&4BtFDGB<jfslZWO=8d_y>Ob_mN_kc~=y$pAKYQ9^N+RfWolG?Rx z6mRoydez=Gh}H1^5t8A7cz7dl$JZr&=6+@P_b5}!%obJhQJFWd&v*{%MyfCLIQSRR z0R_+U(#nbrt3DDX&FSlh5ntRMh<cZGU)at6IMkP=c+tTg8=f`RN*^Y8`sl`>ASALV zPOZx&R`_}y)QcN6J6vVTa&I=g;hOU8^e`EZN>*1e`SwBRXX^n5GQ<mEd}Rb%Lxm2> z0+cZtZTtEXnAzROhpbzmI=0eWeoF#B3{*F>o{bi=!<sg69az3#z7#~lJ-i!1uav)H z^~045eoLPO5sKkK9-qNh%}6Qz+YTPD42E2K+;ByaYUh?T`<Qbx59jQ6@EhYKGdG*q zgX^kXhYOl-$p)!Hj0GGTTySQyhK%`R4wtP@hqkd8C_%bNAjUYSziAMH`)1wj5C`A? z&nuHRBQ>pwn+F>B7`^C$Zr+S$y+F0@T<FMJJoQb0E(Yt|ai1nY`F}1-dyB+@c%*qU z9ACA6B4K3%F-=A70r+9f7TJK>CT0GKkF7V%!Wp6SRp!hEW8ZE<Jzsjw!~kp){#hn( z>iS2LsxIp(V7W`;W`mmfc`|(uamEw^a&iXz-7;AI*?sEmEbAlVYeh{xkOv$98jN`A z%Ji_yN!$0sTex@1^7=<6N+#C*oBO}jQgYT9>OI6`T#T(wvzoRu%=o_yQG(v*Hx+$E z+t*Y%_S-4CCt2D4YQyce(NCacoZR=~Zpsl?_|rM3Q8e~sQp&ppvgzEzy%zltRSl&= zY+9I-toavjsr;NfWjoEa?MJMMM@{aTp#16p5Z#>fC@lQbr%$GaaUNL{#je@C9%me> z_buFlZg-Zpg=7v#Jx+OS2I?K8v{1fog?F@=Im8XkDol5q>Qo1PWDqf=@rHQhO)3?7 z%ewH<O$gK`!ezJD8t;0(g-rYC;Rinfp8U>0)SAq-%oMFWxMD-fCl}^6%qq-;d;J4l zE!z0*g;Q#UNM;@bPTEJW(al;6mK89&X1UmJ`rricNm_qbZ4jU33obG4Z_(_N)4r0| z!LOrcF)6le^oOT2X_D)wze2DpR>|zP1;-As911bB>#+Y4O=JIJFEiNK1%6wr3tQ}& zdtED;Qn~wV@ZKGxo!mtWLxc9{8S`r<&xf5G$(szcBO=fZR6fXHQP#m1dDPpd=UX4K z5SK@)DL76Rb!~=JT3Hfw*NffO>qyw#jQN(I8Z!xK7%Vv>klJegv-`RVlpAl58a*1~ zGMc^u{|bT}zE-zsosdG8{%_xUe3we^MOSvtI;v`~Ka5_`fi2JPh0#LQAKZd&P4E(* zEU;gAQ}u$rz6WW)(C+kJ`^Z;3^hC(7vSI+pAi5n+OMKF&q`{pa3Jf4|H3C3KW-2)= zbnnkfI}8vco&-8gikuq~3do13hbpNImgP0FlGjpHe#d>O8BFNKG${-3hAWI^E--3` z-Z!*@UT1!t#<NRd$EXOSw{Ui^FeK@{ohJiz%6~7q1YO8wQwSX=iX3vYmRA)lt>7nc z9pqdhGlehv?|W=Jn{!z6nZlM0?|BF`#4QusnVq~AtsU~SVH_BEBgGA^IcgosSV?0l z1U2hv2gI(zs6KRhR5mf;L~JRbp)o&y*3Ote7DQf@fQLPXvxn{@Q?Id7ebDr!rbAK$ z`}~vr5T8Z-c{Quvnr~S8Ww3+jw4_ok8mz~z2>*~FwKvh2HND!=j)bG57u?~y1qN7c zu69YvhQ+|T>RGxH21;{oN2_5F9aR@`VLVUaZdIZM<pCPLG-z->Li+trfkVH~?H`q7 z2pJ4E$D4L_FiA06d`<9JblZ2D;G%Z<AbP{X5XPuv9)f7Se%)iB4dW2g#b@(ci8l&9 z;#Tj;9R3%aIQjZZ8F@fsR`0NS?RC?T?QgI#dU1^a8N-$I%iAXC9Fqgg{uxbZ^$r$S zitZsj1K&i2%v*Q1Q{vvXhepsqgWs}28zS@-rRmm=fyP^eY=8#s`4|F)Yob5Tt+HMb zA*|T~T?e~J%8Gqy4AhM8Rg=S!p5K7)bDAHEmOgnu<^p*`E-o(5uC}iO@|PTK8mi9; zv!qdVZY{#%ZCAo6ffd?>1M9OB%l9A|L*(s%Eny9#0GzEiFPVA(k!Sq1te8E|`bu+x zG@;&1E`>_G^hd=`D!55`U1MZD7fpj-8+}AacGB=z&v<2b&0^_LgETqSp!1%gDwzY7 z`ki8)z9orNM@>QFNJTePurpLZ`K5D?;;lyVQB3>KvG638Ek}E{T6&16_T~9Nkg)pR zm7(hyiow2lzw#FEt|}od^JjC@B$0H@GSz8;>hRb0H0k4`7eXmmvd=mW>n7O#-L!M| zx>H$^>2#~@#Y$$)l51%Qozj=l-xepDcjtd|Iwfhw&CxZT$st;dxnF<u7;{e}w~1Sh ziuO<&t=gS>`$Luu>7$YD#_>uia>TU64>422io4jC<Jg?qYsSxaoS~p4ca&Fc(E%d9 zc(podk*_XSw8+*1Y$)74(H0Zm3@a+etl>Z0h4qFVaj#r_5jBR_@;zoK2bI4R<hK}c ztOVXV&I<I#D?JRTm>D21+RyV{Z}JFT?G6)tXU(Ge_3GE;ANYzbFeM}})u>7!#-oHp ziZT~jOJFQ3h}C*8`$;EOIVE`-LqrR)1syuyhU@U??tC2j!dY}Swi8us|4pQ+XiCrl z;ulL5Lqz~WVaW<zvgGCYJY^0&vixYFP5h|{k6=B*+Ajg3Z$cQrF8fVhF~nQB@FH$K z1o8vgFDs(Tv?rHkac`T7;PJrUeDfCq5Drf?t~0FI)prkC{Qi3#+K^>K@bh=CiZ1)k zs(C6KYI_i|neOeq&VcL(23$eu(Ry1kLP2(^%L!0AhOTCVbHr}U3wsZuKE%{;-*(-4 z4%sQoH?8QEc}r6h0d;SiBAR*C(mr3%+sxdvTliXMYd>or3(e*ozM;M1?Y#4V5S^|s z^$<256`|!Xq66AepCC{hZwMkxMDVMD_~}F4i0`|&+H_kG-|WGpb=}@h<Ov0V(6V@= z1>%s1iRdnM-&e(dbFPh^6+=oun5xhOnU=i2fH{Z&%sF>CQWwXwPPRWd`4WANwf=~l zW3`t#?q^YXD(q$}u$o2ME`XW3B@X63P_|fp+W#arv3D=ib0A+ZMFEwM2Ge=hNM~n@ zVA9<r*}>#NRte3PhiUXcKCy^}&^Q<R3F}}c158&l)52V@dm}aUubZ$mw+ZU8jL#3N z8`E~q@mhRjGSXVs^A1JAx-zw;jIu1J=NBFDTMaZyY~6!0XJgv0-0kb2tD%o;YOi}4 zPyJy$`%~lM5i06wk|Wd_REdqOzF3y8rp$|e%0*FrGCVXf=Z-o1Gd7pSlp=q35TqtD zlT_!JCmQ0g&UGCbqO=fT)mYtYwtwd;*phqr(X|Kpzk&Ryg)Sg{N`619!%0Y#xaF(s z7aKIi;2(5Yd+#UUwQT`Xulq>Ii4T2G_~u>Eleg>Ih`kT?!Br#kNDfpNnL=#F%MU z{)lhtc{a{agiPx3jWss7nBnPOe8fXM+)HUn?VYq$VNvuOApHOgQSo*ejlOCyn9$3{ z#})*A=1Te2<Qqd)Y(4<NFow}yd1lq-4rycP+t+7-s?Xh78tLD=Du!W#bXQEVB26)O zF_sU%N(8Nai(jGs3oigA!CIhRLHKu$bza9L?v}aCR-3Z6Y%A}38{DM8ciB_!*zI9i zo&V1Ca<m6jyDkYGTIP}TZWPh7Cr0RP+ZWl*A_pNlvzrG{c+*2I!UevywoQd2pDy9R zB3|P$f>fZXPs&wz_0t#f2od*nQGd?p+Uxvr?yI~;6d{bc79w*NGdtO;w^0S$BeY*6 zT!%`i9B7|Rf7qRpeCtN{&hs1afj1%%N}T}6x&&xcAMw2Lf6dDyTat07(bV?9ndVF9 z3CRSJuNy#L>18t1G!9=|$!n~K;VkW+pTE8MVy-hr_oTV|RwC%mnBXyk$L#`0IcH?H za>k1hqD$CwizPu!Dt!QTtcK#|BR6md#H@(UA^Jn;2E>G|`iUm@Op?ooJSG+|{l<@^ zS2V7O?;V)tH<QaL3V(in{TF+>Lomzh;Rz$2F-&?yHH4L3i~r7Vfe-`{vuf~j_Sm^{ zryj8M!DiE2HriDGnWy^K@`|&8Fi}EE`(T3)J%g{Dyu6i05%z4)hnY(B`<|6sIso%p z`uMj&8qsR`qQr8nO=cn!tB}iBBolNCB}nf2z)3|tB^6=U&zsVKym*=S%!;fgEd4VO z_}b^{<nrG8jaQAy1JCiiZ%cE3R{FT$ZAAGwzMoPl!%9d@*CV2ty$s?0p0ww{|7!sz z=SoQodY@xJp{$u1?9BUYu)lvUXNCD#u0S5_-TT(K$}ni-H?SV>ud^};2H1?ZC<Ujq z<Tw-i)LnXL8|;ku;MCj61CTFY0#eX_zmh0W8o%7LXV$*4EY0?guwIfkfaeMQCqdz~ zqC4$O&qtX(^pZ6Pa|fZ&B!iZqb3d8c7fh+lQH$><f0X&&ySLu`--p=<O%*YV!b@YN zJmTh(>qC1PUK$Lc?9`oqYd#tI2Kudm?V&6;U}gr&BAo=i!VfGFD0-Q2eBe%`krT(x z{Y&r1A5sRuqG?>!48fi;`RD*Yxwbonf=}e1Ru5wL^NF4}m3{z6iX|KGHpCrheX#ws z@vK)f$smpMR{2wajcYrKUD?!<+7fhq(9+{SZq28Q#q&UL&Cz<TE3(+xK9yMIF6D(s zN(r$stE1uXQMG*Ge~4sYn321NfMLm;6?U-cX>!k{(Lz#MBc(8(<5<tcNmp>8Ga;NS zrCBqKFwLY;7F`}KwqJ(w=e=o=tvk-Zzp(3QCf&K*SNTDrkYN@g6BSoooRc;Q%G*=( zP<D@PpSv95;3E0_s%8ZO3diRCkl8<fdZ*pmPUbVaUA`Fhw0hCHZ}D;^IRrKq_-<WY z&OD;3ssCvI6EK{&0`2ia+J64B7eME2lsx=hlY=UAAD2lmkZt4k8>nP92h!3oT28># zbEzS%$w{1twa0+=UW&y{>HuZSSd;gl>cj+L0ir8K8OZ)jcQf&4GXUeTEbb=d{|L2W z?Bn9Q$?rk{(gFVLcYvKBI9dPV<0)CTvP+fqj|@20Jg<F)XU{q^K1)a0Z4S|~YL{ZF zS)*C`F`Oc9zyE9M*&zYAG#^`XIK#>kELj^^@(>5j9qP`OKZodFb*80YltdC|G|F@Z zTm7Ono$R><9RzmYV?DMf)S?gF^vcW|VrTx{jQ)OH_1f45Ph`9<SN2Z9QuGh1d~Hs_ z5;w_w6cRNf<L%Ss{iA%~RLraYv*XyaYaAAr7b2NK^clq_Uw5Ij{>U4U`OHC2^6A0r zKOASlXKXmtus^h=12?K}?(01nUebKd`T{OiPGd}Ct%glz<jQJnm&SrKHDjqb^+2|| zm$eDCnoA9QjZqII1tdM4CSZ7LlCAKKv!`Gkg!IL?h^5+=|1$63Yu7C~87Zo+^T`n} zTjYPqdCt_nn!!}l`@`PIkpbP#2`wWHg~lE(ypluOs??*1>a;$tWt@8mEHCsSmaQ+G z>g(su#rMBDl#L^eYjuN6DYmKHO2Q~VYWB$9-j}+$1ex2ZrDg*KLcMpsZ*{7UkN52w zzl4ii)KvF-*<20W;dYYvFA?|RJC6ePrn!8C!^!gN7ug?mhDv$mv<rK=!fp1~0Xo~A zS?Jy=-OdHjZ<*QN&RWB9aeMFDD<PsDH-P_7E*QZXu+ITfQ>XAR1F=rl$rwY)jClH_ z5d3_Lm6*6Srxf^k^C@6~9E#KV$ou&{$jBc6b;o4C{QNev!CgCD%yi1oAwmvr{`<^> z#h_{kA#@D1A3kdhbN?+uys`PO#Q7E=OxBI|(osLNPPjtq`dmJ;wdXLM%%-R15FLU^ zqzD-fa<3ZYlz%01xA{pLmkG1$9DaOZy;0LIBI0kM_?SVhfAJ9b)dcsBv|M64RG%Sm zp=tKDCPM{i+y4r+OiJ^;pnY1NA@;zBe&mD8TRD#C^$I%hwh6z(imYvF_0MNkj90KS z!?L*Nk$~gypgavzZOFe7q*Jw$ewq_lD1Q~PMd;NvS;UwvILE3~DlcOe4oY8WPLvuZ z#u_3SF`}Z`MIIA#6~DZ@{4Rt&<wS+{6u~9;WQdRQ6XIkvCcO>r?S@t(JT|XpJTxnj z3)vE4l)T^g+|R$IqK2S6Z1DTfiu?FnyJV23rs)IQm)d8}h#E`Es_KMEl2|o%5i|3% zbieG_Fq9#+bN=r$;E9#qYZ|R%V3%@+PLz7TzqqWR()})jSKF1W)b4YvN%)CzT3Np7 z7)bXzOv$U%c+Q!nyEk~MLeu$WG~x<BVkIz(&F+EleaGr)rbR~;Ei;V|cC<8>Lu0=f zbY8`SEb+j7(cumwuzPy~cSDdB;`65L!REYryEHmn3HF4v_u)zzdG3Dgjo(0Yk#RrZ zVPR1cE?CpJcr7^j>n1@z{)c@7Fb7BY4QNP&FaBKw{q^x1U=s9;{dxQbbcY89%-2M~ zJQGx^2{?7z_F+xR73CMIQO_lM<QvR76l{c9pnJck27j;;_1X;yYuvc}7eFOzh#i@2 z-T+xL%R2@$^j_nrSXkRg^TrTK;in{Zm52qe+L%fO>tulj_ZI1qFxpZ;tBhJnD>g`g zK4}y^vf%HPJro*QUhfT2cAk1Mr0jSwtORa75NC2ISbV%H&%Sy^#Q6wS!yk!0^~;jM zS1<O9jo$aPAc+|+Itqkm>)&(2h67BwUEoa8MSFOj@m<Dr@qp<~a8TMpvH;tQQ}aQ< zhfpUxA6Z3KX^?a!@^#j0ONClA*J9&0az}I1$eEC<)cOe5Kyc+{-I?Y2`)d`8kh3oK zm*l_yEQHU5RR&mC2%!D&O%4iaEk9-XgEFi})u`0>>-`d*vb2l7l-YbVIq}w%%(G~F zT}S?$jg63wmuy)y*Y_hnUuYpcy;kZOxB~gW(kAWT@M0K<-Evy;dS)_6omUXC9R7r{ zpL}OX&hbFLb9M)}QU9I!88o7Q2WyCFcVYe`|JS&Cm=hYF{APxIlBB&;=-6$EW+1m1 z<+TL!Y1gD%t^AwDB(-^1gBW}=0-OSSxJV~}Qsv+eKtvaUF~`+<LpuS;1f&dV{a=?H zNUCC9tQ(P(B62$&;0;L=K^-~+7HwCc4-+mxO+Bxd0Z}Nrw2$*53DiV#OlW_~4}_{2 zO0P^R7J7EfPTuX};<MMSJ2O8Bhz0FQ;yIr*`vRa~;P(mO;po5L=o{<6sHy3ZvYgB3 zH^39t!_}k47dfPsFb&s!nO5_y@#6QJPulCX$(dJfyng%PV|CkyB&FGy*|=W(p>qyG zOteTC?bwY{z`<6!K81#+KeePxC+jMeq)gH#Ff<rSmrk3cV?3Om-azSi=f&e51uS34 z+)lgvVgAosJyc^#3JOyS&BKi^^;J3~9Z`1Gl4@ipgr~9Q!x#r9De6EEB>C8j=_?(h zSeG3IlFxj$KC*=OOq>pq9^kc|=8xiHN&S+`Aa^d@K)J*@)75J`<x)5Yd7Y19O|fM5 zmi|8GUGZkjwn$$!)*J5WJDQupO;Z@6cZ*Ko^oF)qM3suk-<pxZOUtr06pnk{il!># zDi5KE=;8ACsY_*#KE@7dX@adfuw0$8j+VVCIGps(uN_!Ij^HTL;^cJ$UWEouABRfV zxHQsHMV@r^E{sK1YC4+0o%WF_@y2AaZCw8DK=kx`&6M~18`Bd*44y=>wtX5WR9SDn zONuV+3IpbzDBcGWL583AhBtkPfZyOst_Z^hJV?tA_TkiXtsqDX6qF)b?~S<E^NawL z&VmOQPB&-(&jvDdDq>4__vnBYe$9{vkQEjIqC!f+$7X<0jB0C=UmueM^Y^baIK@M< zkiX9W<OBwk=CoCscz$Ym>w|QIU*U7HItI>DYRGqwbMKhLIgZ^`=M5*YLhD_tpgt}V z=-2XxFd+D21>01F^9Amh#}M(h7*I#p1&IQ>XPq-@ws7(ZAe}z3Pgd&1`m;hkS6r<+ zc0(s6|NBy*a4G6|yTGJe=D2xlw4rhuJJ={|uZ84#-b_;yZ3u{=Tp~sz5#3capGVCh z!+K-la|CJ`NCpZOwT<$CcL(2dlWaZOka@429sgx0aW6{#snu#0P5Ei62+-aZ5ayq~ zc)ToGY3yAK8E-2YmdM{vm&kAx-+^B1nElpbVuGy9&ZP%}IyJe4<G_Pr?B@ippj#t5 z_JRJ7B%TNjG)o&9Z7VLlU({|UGZfjYi0ye(uRJ`IcG1odvGm&Ev;bS{ehO!M@&R|i zq>i1!_gj}xA+P6TNSdo<g3kiEN>WpUC!~U|zlQ@?@J_6g0^TE^#kWkkitB9E{Zsm^ z{}~$AEm#d3eS;y}=v5@$@K*LL0mloGUhn;KH;{N+f86Nqy`J@qT=g~DCF#Zd#o58Z zKNxYNa(?CU!mYMB@yXt4dA-2|QFT~aRZY-4{}fOjj<h<Lm_MD1iW1wX!{3$Y%8e-- zs!sk-jooYsJzmk&vpGSY+%Hn4bwO7W#`SAwlcTklOI8PfQTX`x9pvd*mOwx$G7G>D zg5=DB_kzbo$W)Xl_8KhVXn*`)Q<2X1n$x8eYE4elcOWCWg@egwa+~5T(5*4k*>NB# zxKaKwa98k{xjf8lfG}iSgI{#N&QOQ~X?6>2w8VgTOupYL{kG_?z7a<11!SCXeXp~+ z70ggM$sql=+|5MO!I7xXk=4J3DTor4+-4LghR2*Y{L)^_einD6gmx%q{t(aS&az0| zX}PEPP^f&)Z<f63?jk(vDxzjdrA)s&4k7>o^SuaiiPu2{N3U~cUvcN=mc0)ND0dM3 z@4I{`vg+{F&%?Dsn_G@s-Rp`oGMu{cg2$*S6fs!z(CP2XmoH66KHvl#EEF9gA2GKa zhzhN7`imx&gd*R8=wGd1U`xwp7`uKtnY%lc1|imvR=8tElRU6wlApHolea74|J=CU zkiCa}UWND-nU>b+RlT&*yzJOWwe*Yz_MGZBzKj@B6+luBk+(RQ^T!1@c%U?!d+lRC z)1<AO1NJT<7XhLB4v!Ja^`~u3_Y_UMeJgY49qb;d3kh)Pm6!eHENxUx714O$7SlT4 zY}OE7$q<k3_KL0;ACO*y;hg8(+Yc5MBo|Dq9rpH4jd1(TUtt*c6M(%@$%TmhaQx3i zPLpRF<>F+=a?1(dA0V{F_m<R#MA<rYgmIZr?so;e%e`mv!2Lfi9v-Yr$E$OHr$<$C za~aNseiVjf;Z*?Q1{<heUevPl(e_hY`Rgb?bcc&g@4s|ehR`v<!o&pl$`qTKSNEm= z^;LLl7Go%iZWrx-ouLV#g|dS|CW@IyK$ni78<U08;J0RbPQO_A)vnL-Vx*Yuu_wS( z68r-w*Ot8Mr*>@&3~)@}mfwTq#?Rz5JD<!i$V>bNpusja7sUkiDT#K$N}O*j+z9Z1 z=e(6SS%Z8uhF~y1yUFs2bk5qX<kAsbiW^<)bTqf$2_@{jS+OeC_%K@Qz6(U21Va?P z{en<FyrQxJA%{Tn7kME5;VdI@)weS}cYdd_>c3R;o39d1{ohxIT2f|5j@Ut+8cvx_ zTak!zj`oqkz$z1ancMmI$`<W5I~#IDdcfyN`OY2%x_oJ~jSOs#+6;Kd(zK;(y%K*H zi-J(iu}WNiq&7$I>y}>5)*<0ahkq|W|2-=VfstF{@sDge{^5K!L+$Q+9#LybGr4?- zR4MmFCsUci{VHuVQ>wgAl`=R02+e7`0BYQ>d|Lz?GZn&Wlerd5q>s68L{TbzB%wI- zzI2`)`tVLs7T_MeV^b%dX*0=&wH`_E-Xx*-Gv__(Uo?Km_>n)$s6pQak4@EXynMv1 z3TC|Gg5L0|eb2KHh=T~?+i}iD@W{O)x|-ydj6?rOCzpFjXXM9_KYJWoho*R<MgkAn z?yFK^$MFhM2ZLS?W$KuHzeQJ1EA*g7@U6n%-^c$foPVNtrj;sK9<4Ye&`_@@z*}7q z;#x;^JfYunMjj8jdO(+~DPh#_L4lFU4=Y~%KsG7&Ab5XPng&Lp*otMkVT_!O>I@Ip zfM>)JV+^P3tZljH_Vv8@IICxJY22Q}t8-TtNRB<=jBq|Z@RZt62Dam;$r&*2e{A2T zHx2W}N{=0~!E4kf?5RWFAML#Cv{OL0@X_H0)bsP7tHi@gjJwz0l+AXy`L*cvk1OF9 z`;}3$DO`R7V;G>eiq@{&2=LMIc!aV-k$@X27omar5$dt2B7vs2@SUQ1p=vg|jryru zv&09Y9}wQE8gEMgIz9>PqzI!;Tt#^ra*x^KhQT85L$s88^0$d{iYs2$r}LyvqvPhz zCgq4#&%uPCNc!Gzl1!|VqSFKJJNwKMb?l0sFLr%JF-Ib7v>k!2mHh2BDv)c*8}&oD zj=Z#|FR@D|6`og3tn**k)0M#N6>!`S&1Xq@Zm4|cr6Hr!uVZ94-w845eYRvv)TK!8 z0@8cS<mKp-8!Z!nd};~m%WqJ1&oIIGqhD79hn52+j}H})jeKPir4mHE3&Oq~($Z5J z@Jb5Gj`xldy(n91zc>1%!no$5{bS_Nk>h?U{wcbQwXW4VE|(ah!6Fns3m0lX4!CrI z1?+k#1o)#GY_vF%gdrs&T!hW=sileeZ&@<f`N$S|qrtj8baj<ZQ<NmLFU=*~%WK8W zCB}7NxpY|~T{H1<^swY))AY_~Tw!(!Zqb_a!Yqe>qb)Uwqkm(ms$bqj+$s-1{%4Al z9}E2<#a}&y9`JDkFO1_p&@mVSPy{pOMe;pB?NU-PNn?hDB|8!UWH6Itj()K?8$!XG zIc{b@wf$I~LI4qlrJgKuT6Vihm&!|Y*l>C1T;Gd_?@b^kpiLJ6H;}qMH9lX{df)Z> zTnO;aL{LH5tAOi=blJmYUB;x4@`9F0^ViEJ<>%m@gt4Cs9ez(L^D4yScl)@j*#exa z>oT6)3O2@J?;+!(!dRT$c1+Lm@63I>Cykl(W>xqr^=5Lk<w`;6yrN+&JgvskQ6hQv z-R)Z<LLlR|2!1_Ob&J7Tly%uT@k}sgdUEjTEzKA@0;)0U3gb7KHlk$eR`A5on?Ygl z+HKf;SDp@qQ%_axoRwztNaO|)KlOLcH2W1O)*(;f!kh6>_c$o!d@pM+$okWzEh^wo zW?pO95%9RMg$e9m)(;wieVLJC@~&UoIU#2l#T9Ob(+<>6P;n#UV?!lH7pG3xT#E&@ zMcJLISPzMC<b%lt`Jwyx3C|Bx3H2I8_BLMcSv7DBrgufDdx%_ipkFyWQoqiKIm$xJ zbaQV)JteYVG^Mvi=_#8UAghUcNXu0R`ME;M^#8;;ag`#W9exW^8N|gF7F2V<@ZR%t zxv)L#E??gd!hAuyncId<=Ss*mnMy4^4DR{a2!rt)cBb-tdAc|Ru2pGPx7|i9Nc#IQ zMe=o(RkcEGujPjVI*$lGN$dE4+X)^F`UL&9sWZa%j^>Rj;=`L;+IKlF*FKWI1hISI z+BLF@fkQEl@qQ(-%%$osZNbs(-wQohwqoKCnTrR>G6HCb)T2dfKo4`U_6C&WF->Jd zGyJhh@2C;oh<bEU4}8rcusNRt^YxlsL*Er#l*ABVTQZm>T@?R(DE>g4H*N0@3Ruh0 ze|%$cRsq6JUxv;JxPG9N3uvM<LXf;;=~o(@W$szjc!_zjf<Ikwtx{~|h5y<vy!7I$ zLYC`fgYQ{fNKY@>)zDz)KJ3s~t)7<pM4z5?P=rt}vgWVc_o!~`jd6lhCY++OXqhAo z5EkAhNV-DFfS@KX!x2scunNZ)u2=i;?Z{zcuao?{x3Mnh$R&gA!HO?0zB&$jz4b{h zJgLH#4>hMAniVWy1|us|((Ho%ORq2&TM2s@yV!aMT}-{8SR`HV<Wv^Y_+}|r%H_Xc zy}-LTosst{xIiz_m(FCGg^sQmZ1veI7Ye$c*Hd>Hq)QDb927@-?8aSxlo%eg)8v)? z3Xwhm8DWebi_c7Su3GbdS#-!!ggkMv>LtB`>I}V;^-<z$lDvt1Ij2@1R)_g2b*k|! zwNb`g0PW>}`H%a$B;kEb6A1Ak@sixdCQg@6&7D$sz8b|=V~^%vr-K{&<zBzr^Nn5I zHsk*}P4E80L81lBCq9OCgD-h3bLNFFT`vi{F7t_2l=pD&@!?3VO53#~doYb9mQ6cO zlNqw$C{&!Qv>$hTe*11bsCsWN_dN*P-^;~6(7Mh*zSZcnLL?p>JleD*&-5@b`6bfi z06Ss@WKGR6pujmMMK-89yQfYZhyd*B$z~8;BfhO_MgDpGI2Q8H5NX(8P~I~?*TA|G zp7yQx4>;T2tNCTXU#UXbwT~K&y<EHv5kSnyvgS!bL+V2ldyhirE61$F@>d1~{VA7m zu)Whx6ri{g8y{0Ps3|q7Ybs*-!UoT*S46Z4-SCs-xYd4@msO@H!ET=N;d~txj@ofU zGmK1D>>+OF_1anurFw~zb@oE@?U_|aCjGKZlrqC(skr0AJx9X@v0-<Fk>@l7^7o?V zb)I*Q?8%p))-Q1Xh1Qd`o>;9SoZQJied1~2xgpB&Xje9+0y9$eV!)uhD{z*dnVnH< z!$6{c`h+3p*}s{0<`g7+FAQki)?A)wrspy;L+&nrqK86gs`u?<*%t5o{QditUHopE zF;2+5HDv=;BM-?$)%#wo#4Rv!>}=2e&3?20r?u3oszYIa3Qo_V2<C<|a`af7GrxG^ zs~cA(DzS)Mj4q^1p~)h@1UOXF==TXaL;ekAsg4q=w{P!POp;!CEK(JA2CYacenT63 z<HB!z{UW@r!@lRzka;3?rgH7eKVA!fu8kw&s9p+T;Ku6en6inUAit$crx?f85pMpH zDAab8-Nk#tMSlr`QD@8jx}lpv?79H*7|L5M6KUZxMw*ol*{9=o0wIO}Noj|UTKS&; zH-&Y+QUXY1Nu7f2#?GZ9z-DDP0Z8_<o@H_gd<FzC)S;-YXHTmIw@>K=h<XhF2H>-- z-|ky=e~IDsg?|7r)~QGtKA4>B#P#^)aZ+_ZVDvWXLuJ11;mX>32O@c!AQmtgzq1kn zsJ7wEGkEI_C<vHhn8N>)np+Vj&gU*f0N;T1_>h(w_;;a5O553KIM^~J6DW|=u3ul- zaXO1ab$yNpeUw0pzuJGfH6g2|jPXG}Zkfu}g<%SG|86b*GLAoZ;}xAJTtPFN!NBOw zR!F9nXb$d@$U``KTv6IpX4D@(kkP8rNL8s&`KDNO4-?%<S3OIxII8|$KUm&18X_mN zW5QZT-$sU207JCs1DviqNmY65AF7+vrl=#i;7K309~Yg~?Yu4uvO12w;=~)agB*C~ zCF{da2G-v@3+l=JJ+o`HPF}rdh;7>NxB4n~(%^e~&vFB~2VOdLEdIde_3pHD&Show zz_yW7%QL~#%9wv|*{5#hFVz<18G`|Hv1qQjKw#(pc+9$#4Fk<@kxv<$Qr;4FKA~z` zBE0Uhrb_?BI~2aD2pZ>$C#i3T&%RynZ&;K`zjYiYctDV?)AVq1`WTn&MAACt2zH*y ztd6@Jt3!m5j6Lr*=U&3Dv84!}xtGZ5bjX9?uQB#p3eU<?axj;C#3ZC!?AMBMQ&n^3 z+q~9`OE}eKY2=QBpL^P8Qi72IkdcZ|@~4H~dJ_lAK_3AmP$<iQk;NujCJ4`_Pv$9i zBarhmk2A8G1sWJM2XKjA>UZx?Xm*Pb3cjI}7m%a&^eM;Srk;SUz#0OORfeZr00y6< zCQdb}df*yL-Nm?62dfh7k_)7a*4=mi(MUmnj5ovRu`2LX5xb8y2;z5YK?lH3PJRW9 z$aA^kkG_w1_UyE+c5hS2!DaDV#lo60MhJqL?*>g;&`bJ$iR@>^@Fl*>A9~BQOmAj4 z+pi_8PA2CkV7Nc<<INb)m!SNaAWFMzyt7*w1Ma;0=&w{YMbWQW*rycJt!Ee=((m8D zpO<;{oIEqkjHj(ubUjm;*tDC9TT9~v#VnnceeD+z5Ibyy_I4m;M$V5@exC-w!PmR_ zX^zNlKABBYYn0|qlaPmbQ;x~l?j(NA-M?qKa6kJ5|7}Iu>MU``^2%;Y(w9GU<%pp_ zM3B-KMQ@sf^D{)S=W&zh3z%A#{LGThxrvK^Mz8Cq{X9^eVTCRK-0;!=@pRtdRR90~ zx8-dWMTjVy2pvK~DkFOwTh=j-J&r@iR;i3+uVZh{!7<LU$tYX4W0Pc@Bgr`;`n~#I z*XQSt{&1a3UA>-O&&RmmZ};l6Am-d~>=D~g5yN#a(u|ld{YF*XO4~UMZRYiqApLXA zD?gcIn+iJT0-+af65a%dE#0J2%2K236r6G|YI*sz`jQiT*nUyrp8Wh?)ypqmEzGr7 z-M6k{s^T*A*;ZA23}A^C5-!3lUXsm9wUu!R%_Ps}B5B2fUz(B4`8$Cj`39=iOGb-! zQMf@nUX8RRV2<0t0qB>+Yw6^|w*?=jTwH~psGyn2eiE;EMHl2sj78WxOd=BY)_`Gr zGN7mZt`;~~IWy>(3;aUsa>Ob3sS7jXk0nBs*Ar8go6<&EELJ-2QhFP_9e)mF83_BK z5Y^2~y!xSx@O?hPP{0|W+r6jX-sh{G%+ek(x_H#`sub8j;pIrcrpfNO7!<%InX{Q* zd1v0@!dq<VXHqhiYqF>|{#FZMp5VT_C15)2K)8wJa%L83xN<{TYb2wKT7BSINRDNx zx@%1xeW|z1>50PLz60jT!wKl@;?pi650V&R0SIk;4r)V5KV67r{+(VKaq)Y*4G^$B zr;U%2qs~r`RUWBEwF7^J&Q*@D$G=wt78-nfVrJ;`KM^Z?Nj4|mfeU1L*_=yaG08?% z7h(J(<EKB?dzUviH%sRn$3rQ73dYn9rwmkWb6?*utT-Ft_NNyF!ZXmMmj^*nAJ-zX z%WqXkP*}VNb2+gtMXf8*RPJ0`^Hzmtx1^1s+)KfX{=mQ|<HVkS_R!l;V{l%rEbnAd z6&yfw)NpvCWg~K&_NXI8=5h7)OUYhumhf`T&{RwbUZ=JrP<9`aO&xLWGyLav`O>yt zWOF#@^XY0V`Lh5{grYvg0<%lSeHK02TbIcwu^RC|Er4s6IbxJ!IM=g7#SC7he=PO6 z;qS<Qz3#*)?FLut>Q01kTX|R~_fOWF4{a_GdysPu-leL?p9FvXGu?f$@r<5wIqYZv zCI&X6FOrwsyR7DR@)AfxY@ztlT{WSeM%S$ecebKskCkG9Xxn9iuA=sEO${f!20kMf z?zaUL826wuFAmJP&VftOtN}<?(t1POPoX(!!}Y45LB69<{f6iJ2}d0)&JsS$Wb|__ zraBrY|KhM%oJP#+WhbDD{bEVTj{2t+VRR}wF2BcBhXG_;_a)Cw!wkLmGT)y^NTl$7 zCT3N5HmUT&s8`zdJ@fig*Ax3658}+)K=D}&F|vc!0Oow+n=7FWlyev%lKlN(Es>?} z=2P4&<#6D9WTbJGPe2V^n^o)~rM*9Q_zL#Dw*Q+iHY`W+{)fqNsX-cT2n0f%(X=Ry zRNc>>IP<D$3>w42E}0_9YXbGG>uy=QZQo_~O14fB6%I`LMThH|JN4WLO&DGs8FA1w z%g8g03PU6WF&y$KTs8k@T;xTcF55h849=NOX~AkR{>5mzI-|TZggLi$cs|xhJ611Z z@ejlp;@XihRg<cM82$_PPraCy85Dkzb-DUEv=Ez4m$%PaPuX#9it$6%8oO7R^;4q8 zsNFVCwNHz`I*t3vX%GDYblwzV*O!io6jOwq%}?(+DeC_=E80;!FV7!HA~|JV{?6jG z@wK~etgD`LxTAJoLm?~r_FP;+|KuOX%E<Pbe6s{hy6l&7Ma%FmDIK1x;*sfM;2><+ znkN^8c7S=+(ze)?0~aCQ!uHZ4Vd1Z}``(0YZOh+|?Jm~_L0|sA)0~2fw%X0t)HfF* zkAO$GrFg%*#@hw<DLMF`>rvYItyTCoR|^??05^EZ==7X0qo+jY4_gI<F;E<+kh%E` zG5AJp`NUH0Ex>oMP>Qma2wZ_X{Zr8~%s7%hUru?}^QY5#$>ACXu&bG}mjkN2@hNto zQURj6ChWo|2gm&V&=Za`kw3Mbxh8APB2T4(H<SKPk-z7HUiW(ZY_-0A*Afl?{y;20 zCs~0$kJ$EaSVz0|%%+tOFtX_AaKPQ>9cA0L5&nC&kDP6mxl<lkF8#=FMS&Ku8%~q9 zOZCSQX(Npc#s^`b0qFOU0ZF*~Z!ngn6wH^4R6GCi<HyHiXV$SiR?1hSP{xv7A6k~y z4`T2A5C3cZl??yV;wwo#o1nR{K#|eY%EGPk10*t0STadZ0PRtM%^7%nhuaC^$e-4# z0a<a}pvEPi@zLxEJ*JUa6}PnMids*hfnH2nQ|qZ{hUbA1gpbd-6`Q4o-7R=ITCgn$ z@3C0;ucs9pFF(}$%W8O>H;JgCUUm%|?GuyTQ|o_&^?mDU$o-7WAH2iA=92yF{nagt z9w)C)+f<)Jx4Z6Ri!?mLwl6~Guzm)Yi*k|%-}9q2wr%7Hj6aT?SCu`g#=t_6t(^D> zP`AUiinM#`c{7%*c~Obb$tFYjZ^~`GP0&Z6*$KYNjuf=J(AzvsLR+<mk%aQt8I)?L z)2*qS&Ur4CX_E+-nfuz-p@rE8Cy*0UfzcR=0DV*a@)6f2^jPBW7oqx~3B>z0;(6C3 z?_4fM*eTEzsCDPhLI5lSHT219XA^cUQ7AAWj?@OsX583{C?7!-5=-uL-Mmx=uo@SD z?s#?G+E-Ig<-uQM7KX2YB;d`8@Xn+GFnHV88Ck#B#EQQ>OY2tL72ZtE2JQ@5+hz&! z`!^+sbsv4LdI2-RS)LfMbsE0@H%+y5)yy{&_s&Nm?UyB>4YrF@CXEA(5!ET~4qPvJ ztwC`;ae2y2_I85@+r~h{JuI!oCz_P#Av4LgEZly7A`qQeBP2%IPtk|z(H`0LT7A1Q zidOk^quYJTuaw@UbY@9>rXjUrZ1U@uaDfKjnD|(9g8@fHUVeUUbaQ$gcyyZgg;ulr z@XG^0mGyHB_`bB6075%;_p{@Iw8NlzS?j^0!94P<;?>7`sEfhZGi7!NQD}m7kU^w9 zs31L0hrT)E8@K7Vxp#>w%-(By9O+GP(LDQ(w;K7Id0R`ysgv%@P*7pbOx{jOG<CO^ z?(+H2Sg`#iI@)KbHI`g1oTlMO;#`$6eLX{W;3VG8=9=5v(bEq!fl8DFyt(=j0?YA@ z4Gg~(%OtMwW6eET;>38e#KsQ+WfR#}oB8ok$H2CahAB?{Y^6U<MYHLUXi{2Bs|6Mm zPMCPurF}a1Xh9=D*0EG!fR@!(U3-*Xi9$bs9kc`P*!A36Y49)Ya~p@A83^?_=CI+j z9j~8>uUkAi+^g-f<Bo*+OnRB#s+6pJnI_{%-fxi@mgEN;SN7ra=bmCa;)MmQi-Fdu zDNE&epUAEE5I7lQZ2Sae_DJuWEO0kw&w~*L_;jD!f0w+rc}K)QlsEwZ@SOd$m8|)F z%j_HZR|UAM=W}a+0fXZo&s$PlpGa8r^8#t?8QZuO=DEJvk<Lw^Vec>&SrTZTJf6Pa z;%d&Rio9gNfIax}Qn~6S8~ly+Zu0i$*BdMdN5DR%bB!~OWTU*_3N+d(2{M67CQnaq z<21?@25+X!K9l`FAmJ+*l0Gjv0W#AHS)jl@Y3py&@W@w<lzY~Jzdcvou3#$B3j`<) zgMM?RU$m;vbQ5W_#XOYVTD<H(=}mmIqb|j-L~)kd!2q#4^W*e1`dg@Af-9hH@p-H~ z#-fwkn?dmv@K^X(3|C##vId*ZwelA?PxEgx@lr?Ulvs9=R-u2>=!n@h;T6j$kI}sM zY)M0BB+nPCcq=RM*+R{UDLPZgyYRe7SC1zP#??IXlggQs=T;&-3&&~4sP4hWVQ5fr zuIva9+g&~0m<=gF!^-zwG-nX!Xf>if<+bR&=JjrQh%>oW{-+=2vDH1aP1VNliQ!W} zV9ALZR1!tK*EFnHdL%p~{$|a&Gz@_vap@b_-MF42ayQ7n1hY{OxB39^<GXxgOm*hp z?amhJ_3RSKc_^zz&fsk9x}<=Ur`JpR;D0KbQo#w-=N5N@+4n%N1V-<c=Pwci{m+t@ z!E*5m9(BiIdnF~m-0P2PyDnPKe(g-nyfD|t279c=X`u9mXr54Ov_+gTl00Yr8su~} zIo71M9B>;YH(GL$uKl<1PWh?#RrvK-5%LY9MKU(Pajp&SRy6g_I3*T%^8~yw<IrQ; zXMh^-x4}_9b)Gyu)|HrBgf>hqz*h^v0<wv{V#A`H8oondtu)zlMY^9CeVFoJuWL<< z-m)9eLfLJwAhkV8y^dFhCOS1V_+w20PZY%bzfRa<h%fIgubYMU)d%-FeGrXhMniuE zRRi5&bYF?6b1bRWl;~57#Pv210A3RN)lC3B5I;SUe%7Cx#o}7ykvUonmJR)Z;jw<x zRDU&h{ta5#qWm6G=!OMk=SvPKE@&!qa99^lUDEp=?S!dWl$2j#c>uZ}WL4AiXs;9B z8g%j{-23lAlu(5XBl#jNWgh`H#<qA;KKZ7rfZ<ikF-16DhRhkr=Z0UbBtTa1i9xrp zo`mRu@YMucPK?q}+SYW_nD%m74A+FMhmIJtO>1SQXvp`)OHwhL(;JjbtkO||UJu9@ zoG;<F)O<~?L7l_NVwUYzL$fy=$WvtqR{H#|UT0cLWYBX8QvjFpez6uT@aYlr_w0#% zH7>@|S1sT<*;A}bD${45gwG#YOu2X<C-)R4WG%(AncPt_1_4=0?Z3e6IPYNDQWzu8 z_g{6t*7knER};JyyqHwAzXt`KbcT_@_)l*6&YDd>_U}G9D{JHgF)Rff@#(ztwAEe_ zHCuSNqB0XSyO;i<NwqITV?e7^5<EqM3*T2}rP-FRhU?(cXIB0uLqvwEBg}W@W8M?8 zKql5^RU<nb#JcRSz9WDb*X$;@<cVZ_aob<?w!FmI#UDQ8Q?f2W<ud&G-o1P72f)s8 z_cdOg6MpHs&wAq24W7T@sy>sh`?KfciVyLEamw)-#0ElKYXR|3?!pHKeTn&gUY0Ii zqOZNX>!l$1#lfb11R%$J|1v>#GFu8D2YmUZ8=@!V$TZJqA_Yja0#}^;KFuQM5i(<3 zDg$5gR?%-$LIXO$0OFcGgdwAtGBVM6INhVaf@NBFkj;ah3Y;kX3~X&=%Q+3;<MM61 zXfm7p+2aF0XXO;IIAVJ4WXN|9g#tN$bn17qnS+%4Go$vRH_B>Vel{Ax;;g3JBp5Nz z?{s<JhB+R%b9a=QrwDYMR12B&nVvWFl$}#|I`t$b3rpOxp6Z<HgwwxaD6pN9U#bK( z37{yvbLNB}BTus@=7(o~qQ|jTyD9<O6a?kKSof}Eb<Fr|Z>z~{+MfI9cf=0OAxqai zKabj{B6bo7(+PXdSNZK5KML7<*1oO@bA?)(U17@qmfI-S+3;N4sH)M3!p`7=#qRib z(8?<_2HxgV<hcz*k+ATggHLX+4fNZGws(Bj@ZP3zeqq8#9W|P4-pQrDu~qjNSQ=$@ zdT>x?pB3su8ZlRzryiniofVKwcJ!lXlF~NkcJ8upo&IIZlVdXu?zfpEATS~|nC&rP zMU*>23$N+CWg%iL@nE@}3JZ`^-6>9hf<hp?yv6@E;(`UB00Xd(nKlD3;STXfKFbHx zE7Z9mNZP1uE6aMRerRM22b>S)?PqV^Dcdks{U@%BkRX0<nIHJWPQ1%NjK?PDHYotb zu;I0mqnx)E%yRmGO=0)N6}a21!+51DYNlh#H;6rn6uqbP2fXB905ELMixYa%x=u$> z9PgBYO+k4B=!ilsw*L4oa@dS8KYP7Z748pv-kQe6Ll4ROKjR$0#W|jkB$L&xZ=rsT zKG~%H^0k|-Y9{tYX`2I*wUDn(=}`{LS<#KFxPr}f+uJeqe@KVl=Y=lUtG9(I&^ht6 zH(M^L0hOzy8_E8s^0y$V$2tjk1&8PF8?2fKvS;Rc0KvjTje()OyR3K_oz{SwmzC0g z$_?_R$X~zi5*QRbQs(4K^|MQ-Y=x-96W1a<KE_o3yid@8Ky)RYUqTq^6PXJLi_nQ3 z&-~Ur%fY}*wB8Dpa@5zAj%0I!BW>?PIOM5at(?vDpSgbb14j&v$P<sOg>{%nY{&bX zs&-~R<Z~~gynE$WXkQ}H0pE>vEZv;!G-0TaQkE~42sy4hEbw_?f@y$<b7$`SRaR{6 z;PTofJh<AEr;Q@JP))$Ssluw+W`vLXu`O#0zq<B(_L0a&Ghxv0G3R>M#=WN47VX!P zHD;t%5W`QUj&SWHUBB&`>)5nGH%;5E9_>dEn8VDAQMw!T{1q_t_!vz}!m$f5&^a{S z_{Kq;KYpWZrN{;kypPhM7up1ECH?a6K6t;zGQMsi8zND55}qa?-?INX`er|Giq!>R z>tFZ?BpmPPCcjoz%A9g7jvu1L;BUlDai_dfmVblW%?9s;#_}{jNb4s1#*RPPcp9x~ z@{Z+21fZ{o{N0Wh!Q+0bEES&ZJLbJs*kCyz0EG|vMcT-Tqcuy$!jdpjvvV}u$`Q<6 zLhvK3NS-gAG>=>QHzt%wyn34ucG=}%cX=_cShaH`hB<EdM+g0~wUzDNg4u<NsgzN> zx!Z+OCfjjQ_iaV~Fg;s<h1XGr<dk<@YFbAVEuXH&n2EeoLhr8{97!oT%;`xVO_X#O z>L6~C-2TmdhB~d@O2GZ^*F@G65o3}SN4ePs!!2p*LEJxuudyc0b$3Hou0Mqlb-4C< z7aFqpx|m#$o6XWbLZwva%bx~sJkl<pyZO8`v}N)?<@W;`g~=V^SnX#q0TO+BfoadD zwe{EL3teqDg`cviu$(qTV>5BE9nW{de8|*Jgo4ZoAeBfvTHA=b7KQ&Fv|?N;DuV4A zYvekDWt$fa4oNBku1R!qu`na)c>iIL%9zsS3gTsCixz$DLW)>q%}nFo(7S31J56bI zV&?&n|A=XxZ8P=oj6(a_wUqQ(mc}(i*J_v(-a|evGCIZI?WumyB4d=$nY^l^a3(Ii zDHGzOn!7i!@@lm6!&fn4g~#f^718zSsungyKh3Q@-lV1V+#G6o?euG05@DnwW_Y0d zNS=|O<|t1eFR8?BITT30c@G$I+r?ex5sfzkF^m7yn&?8HyE-Pc1KRD90iCqIGP#Zi zT}qkr!9GpJbdn_TW;S5?bo<e2SHxcpoQ7H_$m_;L3wA&fsDrP3_uV2KqDr+Zu@^cP z9KgL};$RGlj44jT!S8Rcr2KSV)_ryt5ElDE4lbTRT;jVU-!OT}O?y$$3!{x@bHLvw z2e-V}^usc);9Z(4O=oTSJ6@SG+Idl^;OM!V#de#8=IiMlYs#ZqA#xCAS%Pej4$irw zF@qE-sq74vybIf{d$CVd`J%yE>EKbLz$A5ve1BUIBxKCc-F->zc>-?oZ3j;lns0Ut zW@yzAURV!;NmxM!1e=vYklW5Lm#Jk@cZP?gMzVU3!;@VvwJZPl62h!g4$iW&zqUkt z2sy5@O*i`)+1gaLxLtTdS9`k?Yu1n*9@yC@SWbn*`<+VZ@u`G9;0GxgN!VGwTWull ztxVTz%O&a;%4;3m^}n1G)ygn)U6ry><H9-9Rzvs}Ax9=^F*~TPM*D|*QJY85xbNVi zdxDk?&PTBH&!++6KR$aEzV^oKyDWrzy=M1UC3ya@{b^nehSA>H3?*)%D6LpH4IPKb z5>c)_BPi%2cJ{evo1Zrxxq4)&?Z;z>oL4LIQO*-#guI1-DkO9i)|`*j>Dn#SuCuTY zQv&A04Bx<%fGfH(`vlOTtN^~r-tMM6Fn-IjEuah7H_d~jWx_oVo&{S~`miI&`Sng7 zddV-e%bbUR9YWvC{mtC#JU^E;vA(hXMo1pz@xfpqgHWaLDxe2nQUDk0<214W`j9B< z8XV`6{>%J|V5QI2X{wr*U|<DV*ZTph8Ry9#AUW<GRZ96au~w3b9QgvSKWZ@q{rLts zkI1Kb8@gb--pRIfAbfqxlECA2Bjd24zUJW%=#xET=Ozce?!`W&{ECCB)G3IurOqlm zNKPWQ0+svL;JkH|`}m`I)onRqocY|Ux)<SDl2G!UnYq9B?pWP*7nb^r32FD2fgRDx zD6L7}wV<poZ0s;gZ(nqix{i9RP8#a9*h$)NldRiwmK>OcxGvU+`PI~Vrg^MFb7wA5 zH=NrvBzZ!HotIueI<WM@sG~2AsXeIPj1^Yob!xOvU$tgiLHLB&wnXX{zU)EmSsX#U zqM8ovFkqG6=w9dLcUdJ`PVql2Q>s`Zyc$pp>1Sh)o7f&n+z;>E?=r4R{{k^rv6t9x z;GVr+b9J~dVBiyX>gTID4-O7QP}cq3L!&E|9RjiiyqEXR&%6noH7!q$5A;*bABy=o zKC1RC>VOYjC3ER`=myd~<P_-wMv#8ERG7Tj%=E{H4Ft<-H6jf8v*w1Fik&|yrZnv% zB_r9xc1f`J1qaxBt`LV7tJXzfSbjj+jI`HQuwem8IUz1U7%{yz{;n-J1YF-5!%d$S z)mod|j=o}WQ0~78uF$2})1RUF%0av<p9hHeYEmWI%4joMcg5O*&{l|W(wWXH+9{z3 zafg2*O@%(*fD}M|rIQKVYbvrE)1-5*2B7kJJL}mO^|hb(cKvJR)Gzs`wZJk0a4re= zJh<}85#R>Y`MYdY0fx+(>%xT_+sduQ=W;}a)l$E$m&*I)$C7^z{$3okReNJ-Z?JwJ z8%?@%_r(1`{4O{9<bT8RpD~ut_kqd2nPZ8|L?n^Y(N}@uyFP~E>+3+5ST&pG#mL%g zK3uFQV(w}6aV^VJ2{N;9+kGr9JBv8Z6pmNnw%`peN5rvz^s+*o&B*S{z+?k}={`LF zVOZ;_3M?6hx$N8u_{4xH0@?b4b%%D3!@7V8uq$hDMUZdd`1p|8@E69wf1j>;edhz- zH48^nCS5?<cjvL7ju`d)AR)wRXINW%jt~Qk`iR%9R*_0wt#y0d^Cc>R=OMBOlMgps z5*JeffNg%PR_<(nX0Ls|zUI&rTzt`d>c`rwEdo{v4iE3#J*;|CG4{;5tEm%+daZwr zmw+oBkxtRQ;WW1Uf`Nir`uqr@G;gbQ<zxEE{~Y0~ahfd6iyeBMII`$sOYlZ~0{BJK zZmnh1i+vd~rdH>U*UIuy{Xud19JG%U(MSynw`9g7S9*+J{GBQ{FqfGh@I`V%unAkj z@xl>p99~8$DQSA*PcDFoZ>`0bQEEA$n{xoIJKrl*>U~$Ow}8OnYoU+rX*CoklEFF& zV5Hmo2?ls$Q4y8K(z>T)&J^|`5XM#8eL&RSS#<228YbJe3W{$5s+lYoa$vO+&?T$K zJ!>LK6DtCWaJ^+GT+@<4jNSdbO}z(9g6uliKpTlF!@yco@d@HnL!T62ZIZGK`^YP7 z+0Sd{Wa=$WoX<|ivB4X6w>miCfk46ifKfH<H1OIH>XOHx&(AYJQ!w*MkXZL=z!hDX zkv81VlV&Y^cY~#Lzn3>r2)Jv{f32ALX)Zqs`;;*h&(y**Ur_i!i${mLkf%y74l%DE zn$F;nQn@z3hDSR@KL4E%i@z6&r$YEFj==s{)rA1WPn=-|(&wmxTK>+S7%;mRrLH@@ z9f!Bek`K1THxHuqpJ66+q@d4Ll05hgbGrE6lWbFAN@<sn+NMc`bm8N5y%XZ^@2+8^ z+5$94l0m^xB&u;jPb%1$u3TVXWh%N0+%2n!1o89SqOKAur{;q%?^e@4kT_Iqd3R0M z^Jb8!mjnwYgP`DhGf1tl+b{n>X#!Mk%%PrSU%nLr8!d;{(AO7yrp#jD@i?B@t>9iW zsePO92Jvlocy4<6YxyK&IsY8KdE6bLVLdw*U72V*3I}p_?7j;KwJonFu<6a@!;PEF z&V}BP)<%U_V6A6Ht@m6EwG+Q;3GsVLt>~7>e_D(+qrWR59_?NIk<D%>zOhfC+5PWx zcY|>zuMQ!n)F2(<p{2Ii)am(1k4FwBa7%(&0`JF#s<-4j>}|M$-v*juK#rG$SE*(7 zPHPpgu&DPq)YndDUs}xh8ZLj4^I-laf4%r`dH0gETXO)(L#Q9vN4)w2JiOuAu?X#M zN~8Lzyah7AJL5>Rh1vx|iR2|I;>3l8<t8A$>K-L+;OwAD&Y=&032)a|3v$^B8rLh> zfz!yfSQ20WWMIZWoS)v(J_fd%>L`FW&G_k!a-cEt@had=5WG^F<9@b^WrfX~v@}G3 z^`wYy4+Vb1h2&DyZ5Fh7R5*W0P4;`=-a!onisXx<EL!YbONT5aQ{Z^79`)l>y3njz z^1<r!)0ZS)$$*1(ge^FI;1|lWp^UQC73SFf6QxhIRYTLw9aO;TDO|>TpFnOevt;db zdW0<MB%Y4jwym6`zfvZ&ftx!Ka<HtRu+h289&FXqh8ee5H^3pYb=Je0>~yS}`CG{j zmcrC}+roqiULcwnnsuy1KQlW;UDEJ0mHm$W3ZNPu{9Gd_iky%#V%#L0|J$r8*3UaH zM7fEG2<AUoei15-Tz4AJUi-K^xuGS2Z0j-;r}4%&Nv(-ne=x0_*7>a?l6BBV=29+! zRM9G0Z|=oSeev{zo?+NPz!(+F{WII-x?H?8I0f{y{?Y1C`cV*RL4=2d&zuE)DjOpT z<wu>K1J2iK${?`2P<-<Wy?t6kbI)?{Oiu<C!Q|#MUJ5;X-4)bR-1vVd<N$f*9DYR{ z>}3@6WyfY-2RO7wtvQ3xSVrzhrX(ea?(s;}Bvkjxd0DBN+0t(FYSlROey-MOBuLbo z4_vpSE;8fH@XefOpaCYfyn^`M;Mh~Nquf&c_74u=52+{xCS%8HT=CnFK%>M@`fBf1 zG~K7YRDXT`>mucQ(%L)a*1UdR?zHL19RNe|k_^N`dBa3xQF4n`*KP{fEfpezy$UsF zv0|$h=1cXioiv(qksFEZD*)o`pd6<$*ZHseJQlaC7YDck-n9q+qH4A-ixKM_EwmSb zEklYKS&*kM(8Op+aQItyArxd_(oK8dEv%|xSfXDqB``FCZzz`c$*)hY7ScElJ;g8< zK{PzxmIql?_C2(gH>AI{P^MDs_0vlh!szXSwAqaefX>4U=ju@@d4zz9w#-DQrbU!q z!(^h0Y8Lg@1K6c%)^=v+^mYO-{@}kLh;*nFU7M9Bmf_1#)-?<Zwpz2bM$_v<$AJ8v zr8qX@sr$Ox5z9`>7Iu7L;INenuS;mNd61O0{DNfYA?NRvi2Suwxi!Sj&H86`1<8;) zn1$ANs#8)Z#t0xh^u6uD^3dD+-NVB6h;gUD#m%n>?ikx==0dl|-rkkDEB~L1-b;@h zPu4fdGES{brG9G3PX{av9Yg(mZ4oJrA6A;A^$l3PpY*DThis{c=Sa3Ki_HvNn`=Bh zfD*8paH&M2{Uqn6UznPK?<}$M%|5el^aeWv)YHZh_0aRkXadzWo{uOyN%Zs;4|^y@ z8^=zoEB8&0!Y+gu@p5FAr!sB3jMc<H_>{D9=&dUiLmMxZmBuw%+B_TICIIW^Q^0|A zjTwN{XkD_?4m1|vgnxbs&}yQ(&Prt66O@$#+qENU7FT<CVLcexg^(v80pLDkmaw@^ zLb&z#M0*{3&aHke*N)IuXJ&)uc(LvP^|gCiT7fV&4+v^uyV}pIJSFr*=f9R_&pBV! zRuR-o08EVD7SGC}Hnz1*bpgdy>yJe}Rrplj^FJ*B<WlbI8oR?qtPdQBX3B`MmprQ6 z0o>u)(*Ix%AEF6K=RdcGmw~j&v=JwD<0Le7@1P@2ufxkXaH`dC$iH%7HQMkKlxx8O zh_nv0!x(vvFNs@~w;fP4et~y2kV}Whx#v_~LX?z!C)ZzqCG=lk#?;ew4ZhcXM5<x> z#z-{-h4b&Ne7TO+A8q=Bu$p4_b`pfB?oLnrJlWSg)+f8_g_fzK%(k8Fl)Fi~N=%+) zpPN?8F;xmPlPv|ircsJAL@J{kRk)r`W4nTS!%u#m40`+BTVIdoghSby{|9h@CWxQQ zCG928UC;=XB0~!A=`lh|d1ro-e}A^iVyfr>%T5WFr59#D2pluZX$4)WgZDiR-wJ|~ z6^;g+M`)nqKaRG?&9&3dU^35CE-D4W2Ge5{)5_9oltz6H4T)>thFVCH|0-xRf?rpj zcpF#*^<ogCG>R95x|VUDoRc?}9qU|#bUvpRDJtl>;z*^U<Eg*ze5ogUzn@F~AbdR3 zLSw2lykNSlD3xZi`jHo(4^$mesTgg7KOiNMLVQEvHh=&AJ^AvV54G|n^!)VLSiP~f z45#tC>g^j94$>kQr|v^2s`g#KYl&H1SQ~evR`ThRhx{QBEtqR3S=ICAt=in)9pDvp z0SDS^gXRbicaIZI-&mRQ*Y}^@@Lou(rUK+Rgaw&A9?tkhkx8e6_KxC2nk=QY;S6c> zfX^gXWp+-iO-dDlLjv`g%Ub`yMAvx9!LL~3yO38OFA#$vEg>hnq5Ovalr#82X4-@K zUzIn8^=3z`8NcYKgY#?T()MGSh!*^|ppoxTvHSM+?h(?T*SuT2r1kE~cDtxX=BP{i zbMaArxv&fR7_)5b*YF#NE3ICj_r5!P49QgHS{{H>rtYK02YL}XHoxD7??jtF8>1_h z?LdlquotRLep5u6(R9itlN<(f8`sAu?Pi7n+vkS3g!rZ?fMLGdQ8$v^>Y<*?oWq+~ z*09WG!6R~qku!JrryF~#MmXZJgxe^nQM#$ezh_|EjAH_Hr!H^G2EiKtEcr4Y4O$U4 z4Z0>qar|3ZchY&RN$|(_&>LA$a<rLHic2*e>do)vwuh_bVc|12<`>wGJpr$o%1K>h zVq;{}sqHX4<!?5%q}cOZu5RQ1Ab%6yS~aa$c@9@dHDCWkBQd01bu_DD%&>kD78|jp z0-ce-+V-ODKR;y8+SH#-Z%K6k={McPq)})x1<y90mRS|l*Rl!CksNo%R!!1sUvrQ~ zXO)&g%Xvbpz{(je;3jd!X{-154FdMpLiLIv$AcvS6Q9+MJ4*st9#reC0Nz2!|6t&2 zP}qYFmMsAAEaQj^+92%#E?upwm+X}fh86XJW*sA&ujiUPUu&}@;3xX_R-rd-1G%Db z8u%$a`%0?oi9>%3dc{`XDRV2-B*OSI4}ipOYR>ALBu|}*e^A*A&SD{W>c}kGW>X9R zc}i`)9FRlgkXO*jTp&-`8#;8J1*AIAu%t(sU^yuUU!N_>z_!R*ShDqxQWT{@+c!*= zR&?oG;MR}u2X~dph4k@k3Jbp5bl0ajfv99msm|lnZOQq@-QwX4Zzr#dy<gvCw8zqa z@IkOcZY>MU+)di|2ItqS<x+lL?Wt7PyW4n{V)k>TQB>u;MV}Y1_QGHn$2=)7A@6JL z?c;8%Sa>i4!r2!|*`PcjrXC+9Ogy_AN6;N^JWZ(mMumcuTs<nrZ@bP;Ara$hzI#?x ze;P-c{dw6LA#RK8iy|UNOtq-AMzEBA*dvgaA+c1jFs9S$)JHYF<BkshqAos<PD0Pl zI>$qzFc6tb7mSw_zdy@zHhoY!qFo6ViUz&UENf4G{I<&My}|jtCY%ar9nb#VuF7nW z#VEgJyq{qS1gWIOoICPPiv`$>hUO%RI8B*uOy`#iXsFjmC?xSG;aAv3_UxKGcKD%A z<+27d%t|P2zF;)>CsJM`6s%(zz~HAzKD73W6&$wq`?N%QryNw~%`1le)!u+b(*ReA zLwkUJQkWLe)-Q={XT1;Tqb33Oo72Jhul>b?ilw2dai9T<CcH2!Y9=3nmyDd4at;m7 z9|0!?vCToeJiG$L-X@+4fxGW<eZNFoZKNExUkpT*YE8yV`qSm_L2w#Hzweo&&(lER z-?JYMR_aYFf47pIgv0JpRNO=y_aV1@lfUKuA|G!w|9YNY%x<{2h8=ItYS8-x)2YiY z`PMdPdJxb6Bb0OyX~UllvaIhG%?x0zEVzWCc4UuDHVMRX;~4!sKAxTRy2le2qU^1h zkKUhKJ8%rlM5Oe@P@*uMd>)wGMKMu;qO&beXSrF^u9-9!Wz=c?ti7$w>yHv^i1cwM z_REV^AAc{iLaAV?T<|>_RysX$-_ZDqkGfM%BQ~8zQeH|aznd~vSas~B@5A>$>v`|D zPRz$YPwwdy&a!kBRg5253xBaK%tBc9Px{{7>xr~=rP?CKMkS!#kqx@gROqyPBZGQ% zbol%625K7~joi>MkH~V2^_(Ljl!iT<P1K>Pzi#kbcZ}L6a!I2fI(#t}8P}9=9yDFm z5ca}a6WRgW3XHU&r^C;;gMblJR;kQrNl6Jl`F^#7d;t7)Ha-YIBaJ_#`K!NEscn^# zC``qB$<xs}&BTRtwHQ$R@8{zWhVq^XpZoa6eq9(_90N(Tz=78H6EL7H^z=0QD76B# zzvlo8=H<ea%cI)1ti8DljZ!1vN$YkvFIoe^CaXaDdIjJexIox(1}bL^gS=)M{)@yL z<vgws+|8B`A!HLL)=j7Ztgj3MFs)qv$jj34=gQK0_)d!e@w-JF5VVu>soC4}PS!o} zSlgb3XS*!L$+qg>kpA!cw0iFq6MlJj#~p3qp9@HAK1kTP9cJnA75y}jsJ7Th%Lk^# zZ#Trsl{d0qnqTi4wWWjf>;re>yPb-sZLzMPT)sT$hO$OanL4Y9ZHDgE84G3Yh5hDI zi-<0Y^^E7?Er=H{Ui3(jCX$ZfUxKveli72?kk6iX8#nANU(B_``6I6+#S1OeL|O)? zD<Y+)x8)}I+rIx_yt?d-@!m<-Gr-8|&@(#@Va>kStA01bJ$(!SPS5{25d7<OCoP^1 z3HHQ{(zOlRO(TcjU9x~&9FLoCI5nZdZVc7!Gnfq59%XhZ*wz{sk_wT!_iR+rF@!E! z_02a2vsEiBV&`Wd5x;S7FV^eQ>&G|Gf^tLZ+0KYg%||*pxv<FvGix7G*LVMNqo_&o z97UL?DZS5=Zps0jn{bqD0GJD+fpYVrSYPRQYa?-m^wE>o`(R8qSf)pjmoE_{W2A)r zYNB0-M|j06&ke03lMP!#6`f6^^&{I3RLn-P7eM9!y2_7KJoKwM-{bI!Hu4&M&VkqT zO2{$b%iuhC{-YV!Y|*)gt$ozyU#+t7mJ;Ik>5j=wzfZ*BvyAxbQbtzLnf;f_rch5+ zQC1M2*zM)`d@2J5fFYhm1g?y-JvJDyU1s}3ti%=j0ojz|uP_GyVF=WPE6#^(JRHmh z3Yt1Ub)K{S`JrrR7@!=kf#W)~&d|pgfMMi%hd6N>!2t9@<U#C4B9L1dzz(mOgIogu zu}v~S++=w*Zu6gF<CmPGUFp}Dj?a!9>>2AUXR$U4Y{J0#E%{Kt^91tL<=g+4bx^13 zEj}~06QUNcK<63TOH{)!41oSKUs`SQsS2wm{r)8@=MAMAT~t#5l<AV!<vVdMmCFJN zyQ_%I>hq%)L-PB1`q`Vj7x}6YoykvN{-MuOtlZKUe*6x~8_SDxp(N1HyVQ%gjQ{?( zy^&Yi`?!WJvtAw_h|ZZm(PwtX{Ai^{db08EH^S?-x1+qco-ahwe^HC9N$=6rt4MFf zKdKsU#uvuDk7>o*&-FCxn;Zy;<X8-5dkf3oZly~LvJz-ou=elk?Yx%Go%j#PbsV-I zAbG^21y?&!N%Q@T!<tthOz-@iZJ4PX3|G1|j;I@ID1@}qqv3rBpRS_5c#cvuV`(GG z?Y>08Xo0*NmSJA740FvEMY3#@XMQ5sF!To$6xgYqz!m!R**&W(UQK3-d13sd%cSl( z=l(GF;}YT{)Ct4ur*697sloZNYlk;(bXWb+R(Q6Ync5lr-6N+8QnmL*++|spb{+k` zU)yQ<GZn8K=q#yjv1|DCqT9tm#NV@jNU<ly#~XjUlLP@i9<JhA&329df>8e15g^?> zH4k^oFT`mqv?QyZ3B)OjXDBjT9M`Ob%h>_$eLeg5jObAvi#X*_SGmRzAY(`7^5g*F zpJ%~}Aq9s%@!P9T`vDx66>C{sleH|c(_YQ%O$Pe+ymR18bgToNkNM*_*EW$@fTZ>T zsx!f7&!FWO>sN*AZ4xDlE*!)casQX~wd=Jqw<_S$8hT^)4;70o9vK<=+@sYRKlor4 zjBYMfaaL+8n2gbrmPgb$_w-A$yZP4N5Y15%Hs{bin`n&=_ObfnezvP}EJVl}Qk(A% zgl@=wmJCVK`_Z<`WOQ(neoy7<jg_rG3A=r$@avw4&lNpab1Ucx_GUs#RE)@)Dl^zg zc08(EjRHO0--OYLO}?~jsicnUc#!Up1`4_<+F=oi^3Zk_2Ss`j{tMm@gR*MbHrk}z zQIROzUt;RXium?odA<DQ$hZ-yF{}mdMkQ9UPjjj?xkFK=t6hiLs|r|g&n!;I%BqsW z-Kr7Kz`}9R@$T&6wsh3}-z}}Prg_^xmQ^%2qdiNyzjW9rBh>ZCjUFyc&^xKF@slNb z%Q$-P1V*~f8XC7bOR7F{1Z7Z`m?wCb)BF(z$=-8+0>Wg;)LqBa1T5=g@c3l+t^Y zN?gN#+!P~P7u5Xr++29D^`@d~)z2EGOCaqG(`t__YWu}nh@;$^<KIlH7k-)|8H@ue z)K&s}zW4#PaUQ=|kEXMd?DIJQ_5cLR&OBoG<%-x^Z)yl*1Yi;77nYZU8Q~UTV#K>f zMBnegr(Uxn;V>(DozhTxQdQ;yEhciVC*z}WVNI3mIfSWy$?EV5v&O%SfK7rZzlMbm z^^N5{e7goDFB81;p|Ql1*eS_=;P#Se0zfwGvWJCx1H0dVu}c870Xe21BD_$us_qx= ze&!-sn$sV&8I&S^xLW|?8tbf(H*x>qD%4v>mJbfHH%5m3N3{NleJMJ>ATTE^T5dg@ zM^L<@_Ma3)#<~00LLqqYYUTJ+PXS#!p3L%}X|1#<US-~3eT41V*^t)|=@Lt5xIA%q zEq7>IWR##*$W)0DMBRh5(5CQSb}90yTR5Ki)&fpI&U^SDgwHpC>K9;p*L)s%`6kU6 zMLTp2UFc`U284xX$ba&<xp#(X^ged+%q(z-b=%g-Y<GKg#{~FqaCZOO_3o97L6V$e z28E$-33$0v*wv9a)gaGa&Z`=Z2NV!Z8R~G2zik0!so|M*Gp2=leQbiVv($Ib7IeDw z>!02=G@)d6X}>Ad!X2|8hL!EgmlNBea7_tAN`ndwF$<Q@&dA}|_>%3&*-~0+YJU)$ zp-cPrCI}xlX$iF&9sZad={YK~?BRnnmOzxe@b+2T1O~J-3*Q==tvvtM48=@wbHIbk z6wRv=z5}exGZ*o<*WmZ3P;Uz-Ex26jwNj?>1J-Z%mlD~D6FY<Bhe(fa4o@^Rr4i5c zDrO`6pq-tslyk+LF?*K3ZsRuZX<53Lj90n3`^7SRbNmIIs3?Zdj*b4``n8w$fXfG6 zDDwuVAv>Ix4zPT60~z7Lvu~BH?30!zZAVt+_}c8kq=mDP5!fcBN3ikb&RXsrt<X*& z^~-DbdfIX?qsKSBi}ZeZt<3W(&iw};rqr75to$2Kurb;4PyHC~GxgYO^m%@AuhpvG z+i#9*C}!0z4$=etO}0#dg;bbMnJ1JndUdckxspdny4$u9$u*afltguGo7BR{o@zPr z=fE2jnx4RD#L->yF}X9!=U@j=a^8AAzkd6&i2)i!Tq%`RRrnn~3#uo3Qdw^^FSOu4 zXB#q2XRZYXf7AZ&yRt>ri$vXjfQJX4Xs^KLl;>%d=(0NwTDCru2n{P;5fKdB-kvEL zgSWDmyj6yiGn2j(vFDwA3yKVk6{r#`TMLTxD^No`%<9;t-STdAyfY%0X$~+wE&~tk zTJas8Jw&EHe6FiYZuXxr<IgF~&2MyHsc|9KdYV+gJdrXaj;#r>C?7&hgdA{x*bno5 zF8$3t(D8WT{+%~&tVPE7j@vzf<>8D~v~?so-Hi!FJ!=t=#UY-&L>R97sXT}(D4KB~ zPn@bZIi`QOYI-TzCXOX=Z$H+m%o>Hqs~r1E@p<wp?bw2P#^Qy<<z)@1c67@+Ol;R^ z#21g^zF>yq*saaamitBN)qR*xL-m|J$L2l&!m9w2!2tGEcHF(5Ca76-zss@AY(KA# zK5&1;i4D<ZoCHZdJ$p*(%!N5U>VN~?@>@&5e`)t;KNlHBc6LI-O7(&z{FRz_beb~F zE0+XY;v%fOfFB?ltDLF~-cV?-GHZ1$(mO!A(|19M02BC6eLzkSi}>wdr>4>0M|N#^ z8L({CY;r(#{`xu*2-Cs+YPugV=zI=@=9*5Z0HpK#8KWJZ&+$O9t@zwe6G;#3NDqAy zKzuerasX8QvUl@y%lI)3gc^1p2{_G{Re&l%Mq0{{Go146e%@$ly7Tf^%$8l8nvP4g z#@!5?@3$aFzoHu{^%oY1nswO6qs)~wkIirQ#0eQIylrkpHhiJ{fKdj7&gKx8m@KX? zqG4-9=4b|No+|YV_<iN;=hj-3W!~KBr!&RX$LT$3kh|Kpw{{&izoES6V|-NDh5hB1 z9{&3`G$PSx4{KP#N{+{%itA?k95klOtQ_1%BZO9GMbdJKcv!E1y-N#Y81$C|a|a#% z#<NIa9?~v0sY?}m!XAgbq`;v?nhs4Dz4|@)yDyTLW53aZrIg-`?s-Jp-}Vw2x2`<Q ztKpljAJnLmy&5qFGgnOX_5zc28-qGXB9<i8e!lARm97Idk1s=E(78K%7hA&_)heFH zzOnURA8+H_3O4dggtsrxM6n9NR^rZ`*m#i%0m=8Dm6-)RyzGo=dbdg%7;Crc$I9+- zZLcYAlD-+3;)|bz@k}OEBcn`B5`@D&(xopqi`z4yHyvCDe>ZrHpq(plPUm*wDp0w9 zzBpGvSTPHx6$mk0DvZ}!lA(aUav>A*c(P=53u^$x;$3vGEuNVDL#v1(Q-}s7zpz(F zGnw@mK?WP|?prMt4%weP39;3CWK*5D3GlD_C*FC*j*HWC!sFjqK#l>rUdSJ<Myqqy z6HfS>umqXbL*SLvi0rj|z~-)#wj4wJ0>C`;PPmEpuPC?ivFrT(E1tDb^poPKAH;9< zp>EJbER#NcA(!7qY%<)yy~o?0Cs?nE@mFVGTKgY;)<>-A_&l^@<NnH59m`Q|#(gp( zm{EK$RlvIAopG$wX`6^wRl?R8)A{MBo8IL>#ly9gqtz(XpC0Bf{4N1*ISzXQt6eu^ z>JwHk;-j9}y3!b?(70CtM!58uH6yRuo+bW3i7W2@Tgr=PqK3aFKK#bFHMkpe+w$KR zc3G<(?9z@j%ddAWH^vMeQ6*^y5Of!L9Pj3gS?PJPKT<c#@@3~>rP_?qn+8Bxly|C+ zfw+Ut%t>$lnum*DI|k9?JvkPO5nLtCm@6S9z|iEE3z8zc;n3*1zE8aCNF>fbwL) z;{1?JR1LlJF3%;j&Q_gaR16Xp<#|lyo{S#_Q&T;pn&V|W-}eqCuQt@2i>X+gpQCoH zu4J?WJlV7B_B;$<_$UxIHP>hJ;HnBmPsm#N<ue#z%BEv5?cKYQ6kl4cvw##pfMC6g zww%$RH{kdh+=*wOet265m-jpx<oaUzC(MN}>|5J=fO)jl06gH2vtL)kI{-dRwS~88 zH?W5MZR|hw&KeP~5)nic-Dwlzs-cA;fmG!&mn(?ihreyD+j@D4gMg3Ucb?>tZIk&@ zG|ehmj_s>p4+lIIXY>xxcx^1`i~|*I?9&(N+~de<!FrV?;}96V@ZO0imxw^E(a^@+ z%0ZO_w<w^)pn=RhS_Qlc!$SG`IHx_ryj+9-Vxy<Bg}I~DbroiUKc(oWiJ=*dM+;N# zK?z$AqGH*j!_<e;ofGlXyBp}mSCD%BhtH!+&-yq_j&r5DX@lsavwqYh+ut&rlS#>j za?{4>tdkzxXubc#H+#1#?0a;&c76v)_NOeDyfirs_d88gEUe)}J@ubd)9ZaqBRZPG zM@F9>ibd}0o~5NyR#3w>nnuH@>`QOj{T;&1#O2R6t|8QL7surwuR2q1ejW^50qh?+ zTQXVonoYk4HRg+N$Hx_Ft9L!mnpBH^N{=qbKeY-oWedJV12sbnZIfDr{1DW8_0sB- zd=xRYYw&9yb%X@zQdO<Q8XpOW1p@Q<YbJlrheFfHO|gc;`qhRKEQ<=ry(W;e>PzmR zQgLEzf18Pu$98$3eDco$p$I&M^?I$1#vFev60B6^V$0?^`IKvql4f kbi{8Dx< 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 IM6N<$f~8PYD*ylh literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/i18n.py b/src/wok/plugins/kimchi/i18n.py new file mode 100644 index 0000000..253f00d --- /dev/null +++ b/src/wok/plugins/kimchi/i18n.py @@ -0,0 +1,335 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import gettext + +_ = gettext.gettext + + +messages = { + "KCHAPI0001E": _("Unknown parameter %(value)s"), + + "KCHASYNC0003E": _("Timeout of %(seconds)s seconds expired while running task '%(task)s."), + + "KCHAUTH0004E": _("User %(user_id)s not found with given LDAP settings."), + + "KCHDEVS0001E": _('Unknown "_cap" specified'), + "KCHDEVS0002E": _('"_passthrough" should be "true" or "false"'), + "KCHDEVS0003E": _('"_passthrough_affected_by" should be a device name string'), + + "KCHDISKS0001E": _("Error while getting block devices. Details: %(err)s"), + "KCHDISKS0002E": _("Error while getting block device information for %(device)s."), + + "KCHDL0001E": _("Unable to find distro file: %(filename)s"), + "KCHDL0002E": _("Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."), + + "KCHISCSI0001E": _("Unable to login to iSCSI host target %(portal)s. Details: %(err)s"), + "KCHISCSI0002E": _("Unable to login to iSCSI host %(host)s target %(target)s"), + + "KCHISO0001E": _("Unable to find ISO file %(filename)s"), + "KCHISO0002E": _("The ISO file %(filename)s is not bootable"), + "KCHISO0003E": _("The ISO file %(filename)s does not have a valid El Torito boot record"), + "KCHISO0004E": _("Invalid El Torito validation entry in ISO %(filename)s"), + "KCHISO0005E": _("Invalid El Torito boot indicator in ISO %(filename)s"), + "KCHISO0006E": _("Unexpected volume type for primary volume in ISO %(filename)s"), + "KCHISO0007E": _("Bad format while reading volume descriptor in ISO %(filename)s"), + "KCHISO0008E": _("The hypervisor doesn't have permission to use this ISO %(filename)s. " + "Consider moving it under /var/lib/libvirt, or set the search permission " + "to file access control lists for '%(user)s' user if possible, or add the " + "'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x 'path_to_iso'." + "Details: %(err)s" ), + + "KCHIMG0001E": _("An error occurred when probing image OS information."), + "KCHIMG0002E": _("No OS information found in given image."), + "KCHIMG0003E": _("Unable to read image file %(filename)s"), + "KCHIMG0004E": _("Image file must be an existing file on system. %(filename)s is not a valid input."), + + "KCHVM0001E": _("Virtual machine %(name)s already exists"), + "KCHVM0002E": _("Virtual machine %(name)s does not exist"), + "KCHVM0003E": _("Unable to rename virtual machine %(name)s. The name %(new_name)s is already in use or the virtual machine is not powered off."), + "KCHVM0004E": _("Unable to retrieve screenshot for stopped virtual machine %(name)s"), + "KCHVM0005E": _("Remote ISO image is not supported by this server."), + "KCHVM0006E": _("Screenshot is not supported on virtual machine %(name)s"), + "KCHVM0007E": _("Unable to create virtual machine %(name)s. Details: %(err)s"), + "KCHVM0008E": _("Unable to update virtual machine %(name)s. Details: %(err)s"), + "KCHVM0009E": _("Unable to retrieve virtual machine %(name)s. Details: %(err)s"), + "KCHVM0010E": _("Unable to connect to powered off virtual machine %(name)s."), + "KCHVM0011E": _("Virtual machine name must be a string without slashes (/)"), + "KCHVM0012E": _("Invalid template URI %(value)s specified for virtual machine"), + "KCHVM0013E": _("Invalid storage pool URI %(value)s specified for virtual machine"), + "KCHVM0014E": _("Supported virtual machine graphics are Spice or VNC"), + "KCHVM0015E": _("Graphics address to listen on must be IPv4 or IPv6"), + "KCHVM0016E": _("Specify a template to create a virtual machine from"), + "KCHVM0019E": _("Unable to start virtual machine %(name)s. Details: %(err)s"), + "KCHVM0020E": _("Unable to power off virtual machine %(name)s. Details: %(err)s"), + "KCHVM0021E": _("Unable to delete virtual machine %(name)s. Details: %(err)s"), + "KCHVM0022E": _("Unable to reset virtual machine %(name)s. Details: %(err)s"), + "KCHVM0023E": _("User name list must be an array"), + "KCHVM0024E": _("User name must be a string"), + "KCHVM0025E": _("Group name list must be an array"), + "KCHVM0026E": _("Group name must be a string"), + "KCHVM0027E": _("User(s) '%(users)s' do not exist"), + "KCHVM0028E": _("Group(s) '%(groups)s' do not exist"), + "KCHVM0029E": _("Unable to shutdown virtual machine %(name)s. Details: %(err)s"), + "KCHVM0030E": _("Unable to get access metadata of virtual machine %(name)s. Details: %(err)s"), + "KCHVM0031E": _("The guest console password must be a string."), + "KCHVM0032E": _("The life time for the guest console password must be a number."), + "KCHVM0033E": _("Virtual machine '%(name)s' must be stopped before cloning it."), + "KCHVM0034E": _("Insufficient disk space to clone virtual machine '%(name)s'"), + "KCHVM0035E": _("Unable to clone VM '%(name)s'. Details: %(err)s"), + "KCHVM0036E": _("Invalid operation for non-persistent virtual machine %(name)s"), + "KCHVM0037E": _("Cannot suspend VM '%(name)s' because it is not running."), + "KCHVM0038E": _("Unable to suspend VM '%(name)s'. Details: %(err)s"), + "KCHVM0039E": _("Cannot resume VM '%(name)s' because it is not paused."), + "KCHVM0040E": _("Unable to resume VM '%(name)s'. Details: %(err)s"), + "KCHVM0041E": _("Memory assigned is higher then the maximum allowed in the host."), + "KCHVM0042E": _("VM '%(name)s' does not support live memory update. Update the memory with the machine offline to enable this feature."), + "KCHVM0043E": _("Only increase memory is allowed in active VMs"), + "KCHVM0044E": _("For live memory update, new memory value must be equal old memory value plus multiples of 1024 Mib"), + "KCHVM0045E": _("There are not enough free slots of 1024 Mib in the guest."), + "KCHVM0046E": _("Host's libvirt version does not support memory devices. Libvirt must be >= 1.2.14"), + "KCHVM0047E": _("Error attaching memory device. Details: %(error)s"), + + "KCHVMHDEV0001E": _("VM %(vmid)s does not contain directly assigned host device %(dev_name)s."), + "KCHVMHDEV0002E": _("The host device %(dev_name)s is not allowed to directly assign to VM."), + "KCHVMHDEV0003E": _("No IOMMU groups found. Host PCI pass through needs IOMMU group to function correctly. " + "Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify the Kernel is compiled with IOMMU support. " + "For Intel CPU, add intel_iommu=on to your Kernel parameter in /boot/grub2/grub.conf. " + "For AMD CPU, add iommu=pt iommu=1."), + "KCHVMHDEV0004E": _('"name" should be a device name string'), + "KCHVMHDEV0005E": _('The device %(name)s is probably in use by the host. Unable to attach it to the guest.'), + + "KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"), + "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"), + "KCHVMIF0004E": _("Supported virtual machine interfaces type is only network"), + "KCHVMIF0005E": _("Network name for virtual machine interface must be a string"), + "KCHVMIF0006E": _("Invalid network model card specified for virtual machine interface"), + "KCHVMIF0007E": _("Specify type and network to add a new virtual machine interface"), + "KCHVMIF0008E": _("MAC Address must respect this format FF:FF:FF:FF:FF:FF"), + "KCHVMIF0009E": _("MAC Address %(mac)s already exists in virtual machine %(name)s"), + "KCHVMIF0010E": _("Invalid MAC Address"), + "KCHVMIF0011E": _("Cannot change MAC address of a running virtual machine"), + + "KCHTMPL0001E": _("Template %(name)s already exists"), + "KCHTMPL0003E": _("Network '%(network)s' specified for template %(template)s does not exist"), + "KCHTMPL0004E": _("Storage pool %(pool)s specified for template %(template)s does not exist"), + "KCHTMPL0005E": _("Storage pool %(pool)s specified for template %(template)s is not active"), + "KCHTMPL0006E": _("Invalid parameter '%(param)s' specified for CDROM."), + "KCHTMPL0007E": _("Network %(network)s specified for template %(template)s is not active"), + "KCHTMPL0008E": _("Template name must be a string"), + "KCHTMPL0009E": _("Template icon must be a path to the image"), + "KCHTMPL0010E": _("Template distribution must be a string"), + "KCHTMPL0011E": _("Template distribution version must be a string"), + "KCHTMPL0012E": _("The number of CPUs must be an integer greater than 0"), + "KCHTMPL0013E": _("Amount of memory (MB) must be an integer greater than 512"), + "KCHTMPL0014E": _("Template CDROM must be a local or remote ISO file"), + "KCHTMPL0015E": _("Invalid storage pool URI %(value)s specified for template"), + "KCHTMPL0016E": _("Specify an ISO image as CDROM or a base image to create a template"), + "KCHTMPL0017E": _("All networks for the template must be specified in a list."), + "KCHTMPL0018E": _("Specify a volume to a template when storage pool is iSCSI or SCSI"), + "KCHTMPL0019E": _("The volume %(volume)s is not in storage pool %(pool)s"), + "KCHTMPL0020E": _("Unable to create template due error: %(err)s"), + "KCHTMPL0021E": _("Unable to delete template due error: %(err)s"), + "KCHTMPL0022E": _("Disk size must be an integer greater than 1GB."), + "KCHTMPL0023E": _("Template base image must be a valid local image file"), + "KCHTMPL0024E": _("Cannot identify base image %(path)s format"), + "KCHTMPL0025E": _("When specifying CPU topology, VCPUs must be a product of sockets, cores, and threads."), + "KCHTMPL0026E": _("When specifying CPU topology, each element must be an integer greater than zero."), + "KCHTMPL0027E": _("Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc."), + + "KCHPOOL0001E": _("Storage pool %(name)s already exists"), + "KCHPOOL0002E": _("Storage pool %(name)s does not exist"), + "KCHPOOL0004E": _("Specify %(item)s in order to create the storage pool %(name)s"), + "KCHPOOL0005E": _("Unable to delete active storage pool %(name)s"), + "KCHPOOL0006E": _("Unable to list storage pools. Details: %(err)s"), + "KCHPOOL0007E": _("Unable to create storage pool %(name)s. Details: %(err)s"), + "KCHPOOL0008E": _("Unable to get number of storage volumes in storage pool %(name)s. Details: %(err)s"), + "KCHPOOL0009E": _("Unable to activate storage pool %(name)s. Details: %(err)s"), + "KCHPOOL0010E": _("Unable to deactivate storage pool %(name)s. Details: %(err)s"), + "KCHPOOL0011E": _("Unable to delete storage pool %(name)s. Details: %(err)s"), + "KCHPOOL0012E": _("Unable to create NFS Pool as export path %(path)s may block during mount"), + "KCHPOOL0013E": _("Unable to create NFS Pool as export path %(path)s mount failed"), + "KCHPOOL0014E": _("Unsupported storage pool type: %(type)s"), + "KCHPOOL0015E": _("Error while retrieving storage pool XML to %(pool)s"), + "KCHPOOL0016E": _("Storage pool name must be a string without slashes (/)"), + "KCHPOOL0017E": _("Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-iso"), + "KCHPOOL0018E": _("Storage pool path must be a string"), + "KCHPOOL0019E": _("Storage pool host must be a IP or hostname"), + "KCHPOOL0020E": _("Storage pool device must be the absolute path to the block device"), + "KCHPOOL0021E": _("Storage pool devices parameter must be a list"), + "KCHPOOL0022E": _("Target IQN of an iSCSI pool must be a string"), + "KCHPOOL0023E": _("Port of a remote storage server must be an integer between 1 and 65535"), + "KCHPOOL0024E": _("iSCSI target username must be a string"), + "KCHPOOL0025E": _("iSCSI target password must be a string"), + "KCHPOOL0026E": _("Specify name and type to create a storage pool"), + "KCHPOOL0027E": _("%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)s."), + "KCHPOOL0028E": _("Unable to extend logical pool %(pool)s. Details: %(err)s"), + "KCHPOOL0029E": _("The parameter disks only can be updated for logical storage pool."), + "KCHPOOL0030E": _("The SCSI host adapter name must be a string."), + "KCHPOOL0031E": _("The storage pool kimchi_isos is reserved for internal use"), + "KCHPOOL0032E": _("Unable to activate NFS storage pool %(name)s. NFS server %(server)s is unreachable."), + "KCHPOOL0033E": _("Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is unreachable."), + "KCHPOOL0034E": _("Unable to deactivate pool %(name)s as it is associated with some templates"), + "KCHPOOL0035E": _("Unable to delete pool %(name)s as it is associated with some templates"), + "KCHPOOL0036E": _("A volume group named '%(name)s' already exists. Please, choose another name to create the logical pool."), + "KCHPOOL0037E": _("Unable to update database with deep scan information due error: %(err)s"), + + "KCHVOL0001E": _("Storage volume %(name)s already exists"), + "KCHVOL0002E": _("Storage volume %(name)s does not exist in storage pool %(pool)s"), + "KCHVOL0003E": _("Unable to create storage volume %(volume)s because storage pool %(pool)s is not active"), + "KCHVOL0004E": _("Specify %(item)s in order to create storage volume %(volume)s"), + "KCHVOL0006E": _("Unable to list storage volumes because storage pool %(pool)s is not active"), + "KCHVOL0007E": _("Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %(err)s"), + "KCHVOL0008E": _("Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s"), + "KCHVOL0009E": _("Unable to wipe storage volumes %(name)s. Details: %(err)s"), + "KCHVOL0010E": _("Unable to delete storage volume %(name)s. Details: %(err)s"), + "KCHVOL0011E": _("Unable to resize storage volume %(name)s. Details: %(err)s"), + "KCHVOL0012E": _("Storage type %(type)s does not support volume create and delete"), + "KCHVOL0013E": _("Storage volume name must be a string"), + "KCHVOL0014E": _("Storage volume allocation must be an integer number"), + "KCHVOL0015E": _("Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc."), + "KCHVOL0016E": _("Storage volume requires a volume name"), + "KCHVOL0017E": _("Unable to update database with storage volume information due error: %(err)s"), + "KCHVOL0018E": _("Only one of parameter %(param)s can be specified"), + "KCHVOL0019E": _("Create volume from %(param)s is not supported"), + "KCHVOL0020E": _("Storage volume capacity must be an integer number."), + "KCHVOL0021E": _("Storage volume URL must be http://, https://, ftp:// or ftps://."), + "KCHVOL0022E": _("Unable to access file %(url)s. Please, check it."), + "KCHVOL0023E": _("Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)s"), + "KCHVOL0024E": _("Specify chunk data and its size to upload a file."), + "KCHVOL0025E": _("In order to upload a storage volume, specify the 'upload' parameter."), + "KCHVOL0026E": _("Unable to upload chunk data as it does not match with requested chunk size."), + "KCHVOL0027E": _("The storage volume %(vol)s is not under an upload process."), + "KCHVOL0028E": _("The upload chunk data will exceed the storage volume size."), + "KCHVOL0029E": _("Unable to upload chunk data to storage volume. Details: %(err)s."), + + "KCHIFACE0001E": _("Interface %(name)s does not exist"), + + "KCHNET0001E": _("Network %(name)s already exists"), + "KCHNET0002E": _("Network %(name)s does not exist"), + "KCHNET0003E": _("Subnet %(subnet)s specified for network %(network)s is not valid."), + "KCHNET0004E": _("Specify a network interface to create bridged network %(name)s"), + "KCHNET0005E": _("Unable to delete active network %(name)s"), + "KCHNET0006E": _("Interface %(iface)s specified for network %(network)s is already in use"), + "KCHNET0007E": _("Interface should be bare NIC, bonding or bridge device."), + "KCHNET0008E": _("Unable to create network %(name)s. Details: %(err)s"), + "KCHNET0009E": _("Unable to find a free IP address for network '%(name)s'"), + "KCHNET0010E": _("The interface %(iface)s already exists."), + "KCHNET0011E": _("Network name must be a string without slashes (/) or quotes (\")"), + "KCHNET0012E": _("Supported network types are isolated, NAT and bridge"), + "KCHNET0013E": _("Network subnet must be a string with IP address and prefix or netmask"), + "KCHNET0014E": _("Network interface must be a string"), + "KCHNET0015E": _("Network VLAN ID must be an integer between 1 and 4094"), + "KCHNET0016E": _("Specify name and type to create a Network"), + "KCHNET0017E": _("Unable to delete network %(name)s. There are some virtual machines %(vms)s and/or templates linked to this network."), + "KCHNET0018E": _("Unable to deactivate network %(name)s. There are some virtual machines %(vms)s and/or templates linked to this network."), + "KCHNET0019E": _("Bridge device %(name)s can not be the trunk device of a VLAN."), + "KCHNET0020E": _("Failed to activate interface %(iface)s: %(err)s."), + "KCHNET0021E": _("Failed to activate interface %(iface)s. Please check the physical link status."), + "KCHNET0022E": _("Failed to start network %(name)s. Details: %(err)s"), + + "KCHDR0001E": _("Debug report %(name)s does not exist"), + "KCHDR0002E": _("Debug report tool not found in system"), + "KCHDR0003E": _("Unable to create debug report %(name)s. Details: %(err)s."), + "KCHDR0004E": _("Can not find any debug report with the given name %(name)s"), + "KCHDR0005E": _("Unable to generate debug report %(name)s. Details: %(err)s"), + "KCHDR0006E": _("You should give a name for the debug report file."), + "KCHDR0007E": _("Debug report name must be a string. Only letters, digits, underscore ('_') and hyphen ('-') are allowed."), + "KCHDR0008E": _("The debug report with specified name \"%(name)s\" already exists. Please use another one."), + + "KCHSR0001E": _("Storage server %(server)s was not used by Kimchi"), + + "KCHDISTRO0001E": _("Distro '%(name)s' does not exist"), + + "KCHPART0001E": _("Partition %(name)s does not exist in the host"), + + "KCHHOST0001E": _("Unable to shutdown host machine as there are running virtual machines"), + "KCHHOST0002E": _("Unable to reboot host machine as there are running virtual machines"), + "KCHHOST0003E": _("Node device '%(name)s' not found"), + "KCHHOST0004E": _("Conflicting flag filters specified."), + + "KCHPKGUPD0001E": _("No packages marked for update"), + "KCHPKGUPD0002E": _("Package %(name)s is not marked to be updated."), + "KCHPKGUPD0003E": _("Error while getting packages marked to be updated. Details: %(err)s"), + "KCHPKGUPD0004E": _("There is no compatible package manager for this system."), + + "KCHUTILS0003E": _("Unable to choose a virtual machine name"), + + "KCHVMSTOR0002E": _("Invalid storage type. Types supported: 'cdrom', 'disk'"), + "KCHVMSTOR0003E": _("The path '%(value)s' is not a valid local/remote path for the device"), + "KCHVMSTOR0006E": _("Only CDROM path can be update."), + "KCHVMSTOR0007E": _("The storage device %(dev_name)s does not exist in the virtual machine %(vm_name)s"), + "KCHVMSTOR0008E": _("Error while creating new storage device: %(error)s"), + "KCHVMSTOR0009E": _("Error while updating storage device: %(error)s"), + "KCHVMSTOR0010E": _("Error while removing storage device: %(error)s"), + "KCHVMSTOR0011E": _("Do not support IDE device hot plug"), + "KCHVMSTOR0012E": _("Specify type and path or type and pool/volume to add a new virtual machine disk"), + "KCHVMSTOR0013E": _("Specify path to update virtual machine disk"), + "KCHVMSTOR0014E": _("Controller type %(type)s limitation of %(limit)s devices reached"), + "KCHVMSTOR0015E": _("Cannot retrieve disk path information for given pool/volume: %(error)s"), + "KCHVMSTOR0016E": _("Volume already in use by other virtual machine."), + "KCHVMSTOR0017E": _("Only one of path or pool/volume can be specified to add a new virtual machine disk"), + "KCHVMSTOR0018E": _("Volume chosen with format %(format)s does not fit in the storage type %(type)s"), + + "KCHREPOS0001E": _("YUM Repository ID must be one word only string."), + "KCHREPOS0002E": _("Repository URL must be an http://, ftp:// or file:// URL."), + "KCHREPOS0003E": _("Repository configuration is a dictionary with specific values according to repository type."), + "KCHREPOS0004E": _("Distribution to DEB repository must be a string"), + "KCHREPOS0005E": _("Components to DEB repository must be listed in a array"), + "KCHREPOS0006E": _("Components to DEB repository must be a string"), + "KCHREPOS0007E": _("Mirror list to repository must be a string"), + "KCHREPOS0008E": _("YUM Repository name must be string."), + "KCHREPOS0009E": _("GPG check must be a boolean value."), + "KCHREPOS0010E": _("GPG key must be a URL pointing to the ASCII-armored file."), + "KCHREPOS0011E": _("Could not update repository %(repo_id)s."), + "KCHREPOS0012E": _("Repository %(repo_id)s does not exist."), + "KCHREPOS0013E": _("Specify repository base URL, mirror list or metalink in order to create or update a YUM repository."), + "KCHREPOS0014E": _("Repository management tool was not recognized for your system."), + "KCHREPOS0015E": _("Repository %(repo_id)s is already enabled."), + "KCHREPOS0016E": _("Repository %(repo_id)s is already disabled."), + "KCHREPOS0017E": _("Could not remove repository %(repo_id)s."), + "KCHREPOS0018E": _("Could not write repository configuration file %(repo_file)s"), + "KCHREPOS0019E": _("Specify repository distribution in order to create a DEB repository."), + "KCHREPOS0020E": _("Could not enable repository %(repo_id)s."), + "KCHREPOS0021E": _("Could not disable repository %(repo_id)s."), + "KCHREPOS0022E": _("YUM Repository ID already exists"), + "KCHREPOS0023E": _("YUM Repository name must be a string"), + "KCHREPOS0024E": _("Unable to list repositories. Details: '%(err)s'"), + "KCHREPOS0025E": _("Unable to retrieve repository information. Details: '%(err)s'"), + "KCHREPOS0026E": _("Unable to add repository. Details: '%(err)s'"), + "KCHREPOS0027E": _("Unable to remove repository. Details: '%(err)s'"), + "KCHREPOS0028E": _("Configuration items: '%(items)s' are not supported by repository manager"), + "KCHREPOS0029E": _("Repository metalink must be an http://, ftp:// or file:// URL."), + "KCHREPOS0030E": _("Cannot specify mirrorlist and metalink at the same time."), + + "KCHSNAP0001E": _("Virtual machine '%(vm)s' must be stopped before creating a snapshot of it."), + "KCHSNAP0002E": _("Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"), + "KCHSNAP0003E": _("Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."), + "KCHSNAP0004E": _("Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"), + "KCHSNAP0005E": _("Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"), + "KCHSNAP0006E": _("Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"), + "KCHSNAP0008E": _("Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %(err)s"), + "KCHSNAP0009E": _("Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %(err)s"), + "KCHSNAP0010E": _("Unable to create snapshot of virtual machine '%(vm)s' because it contains a disk with format '%(format)s'; only 'qcow2' is supported."), + + "KCHCPUINF0001E": _("The number of vCPUs is too large for this system."), + "KCHCPUINF0002E": _("Invalid vCPU/topology combination."), + "KCHCPUINF0003E": _("This host (or current configuration) does not allow CPU topology."), + +} diff --git a/src/wok/plugins/kimchi/imageinfo.py b/src/wok/plugins/kimchi/imageinfo.py new file mode 100644 index 0000000..8a22495 --- /dev/null +++ b/src/wok/plugins/kimchi/imageinfo.py @@ -0,0 +1,72 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import guestfs +import json +import os +import sys + +from wok.exception import ImageFormatError, InvalidParameter, TimeoutExpired +from wok.utils import run_command, wok_log + + +def probe_img_info(path): + cmd = ["qemu-img", "info", "--output=json", path] + info = dict() + try: + out = run_command(cmd, 10)[0] + except TimeoutExpired: + wok_log.warning("Cannot decide format of base img %s", path) + return None + + info = json.loads(out) + info['virtual-size'] = info['virtual-size'] >> 30 + info['actual-size'] = info['actual-size'] >> 30 + return info + + +def probe_image(image_path): + if not os.path.isfile(image_path): + raise InvalidParameter("KCHIMG0004E", {'filename': image_path}) + + if not os.access(image_path, os.R_OK): + raise ImageFormatError("KCHIMG0003E", {'filename': image_path}) + + g = guestfs.GuestFS(python_return_dict=True) + g.add_drive_opts(image_path, readonly=1) + g.launch() + + try: + roots = g.inspect_os() + except: + raise ImageFormatError("KCHIMG0001E") + + if len(roots) == 0: + raise ImageFormatError("KCHIMG0002E") + + for root in roots: + version = "%d.%d" % (g.inspect_get_major_version(root), + g.inspect_get_minor_version(root)) + distro = "%s" % (g.inspect_get_distro(root)) + + return (distro, version) + + +if __name__ == '__main__': + print probe_image(sys.argv[1]) diff --git a/src/wok/plugins/kimchi/iscsi.py b/src/wok/plugins/kimchi/iscsi.py new file mode 100644 index 0000000..02886ac --- /dev/null +++ b/src/wok/plugins/kimchi/iscsi.py @@ -0,0 +1,88 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301USA + +import subprocess + + +from wok.exception import OperationFailed + + +class TargetClient(object): + def __init__(self, target, host, port=None, auth=None): + self.portal = host + ("" if port is None else ":%s" % port) + self.target = target + self.auth = auth + self.targetCmd = ['iscsiadm', '--mode', 'node', '--targetname', + self.target, '--portal', self.portal] + + def _update_db(self, Name, Value): + self._run_cmd(['--op=update', '--name', Name, '--value', Value]) + + def _update_auth(self): + if self.auth is None: + items = (('node.session.auth.authmethod', 'None'), + ('node.session.auth.username', ''), + ('node.session.auth.password', '')) + else: + items = (('node.session.auth.authmethod', 'CHAP'), + ('node.session.auth.username', self.auth['username']), + ('node.session.auth.password', self.auth['password'])) + for name, value in items: + self._update_db(name, value) + + def _run_cmd(self, cmd): + iscsiadm = subprocess.Popen( + self.targetCmd + cmd, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = iscsiadm.communicate() + if iscsiadm.returncode != 0: + msg_args = {'portal': self.portal, 'err': err} + raise OperationFailed("KCHISCSI0001E", msg_args) + return out + + def _discover(self): + iscsiadm = subprocess.Popen( + ['iscsiadm', '--mode', 'discovery', '--type', 'sendtargets', + '--portal', self.portal], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = iscsiadm.communicate() + if iscsiadm.returncode != 0: + msg_args = {'portal': self.portal, 'err': err} + raise OperationFailed("KCHISCSI0001E", msg_args) + return out + + def _run_op(self, op): + self._run_cmd(['--' + op]) + + def login(self): + self._discover() + self._update_auth() + self._run_op('login') + + def logout(self): + self._run_op('logout') + + def validate(self): + try: + self.login() + except OperationFailed: + return False + + self.logout() + return True diff --git a/src/wok/plugins/kimchi/isoinfo.py b/src/wok/plugins/kimchi/isoinfo.py new file mode 100644 index 0000000..8de6885 --- /dev/null +++ b/src/wok/plugins/kimchi/isoinfo.py @@ -0,0 +1,506 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import contextlib +import glob +import os +import platform +import re +import stat +import struct +import sys +import urllib2 + + +from wok.exception import IsoFormatError +from wok.utils import check_url_path, wok_log + + +iso_dir = [ + ## + # Portions of this data from libosinfo: http://libosinfo.org/ + # + # Each tuple has the following three members: + # Distro ID: Nickname for the distro or OS family + # Distro Version: A function or string that provides a specific version + # given a regular expression match on the volume id string + # Regular Expression: A regex to match against the ISO Volume ID + ## + ('openbsd', lambda m: m.group(2), + ('OpenBSD/(i386|amd64) (\d+\.\d+) Install CD')), + ('centos', lambda m: m.group(1), + ('CentOS_(\d+\.\d+)_Final')), + ('windows', '2000', + ('W2AFPP|SP1AFPP|SP2AFPP|YRMAFPP|ZRMAFPP|W2AOEM|SP1AOEM|SP2AOEM' + + '|YRMAOEM|ZRMAOEM|W2ASEL|SP2ASEL|W2SFPP|SP1SFPP|SP2SFPP|YRMSFPP' + + '|ZRMSFPP|W2SOEM|W2SOEM|SP1SOEM|SP2SOEM|YRMSOEM|ZRMSOEM|W2SSEL' + + '|SP2SSEL|W2PFPP|SP1PFPP|SP2PFPP|YRMPFPP|ZRMPFPP|W2POEM|SP1POEM' + + '|SP2POEM|YRMPOEM|ZRMPOEM|W2PSEL|SP2PSEL|W2PCCP|WIN2000|W2K_SP4')), + ('windows', 'xp', + ('WXPFPP|WXHFPP|WXPCCP|WXHCCP|WXPOEM|WXHOEM|WXPVOL|WXPEVL|XRMPFPP' + + '|XRMHFPP|XRMPCCP|XRMHCCP|XRMPOEM|XRMHOEM|XRMPVOL|XRMSD2|X1APFPP' + + '|X1AHFPP|X1APCCP|X1APCCP|X1AHCCP|X1APOEM|X1AHOEM|X1APVOL|VRMPFPP' + + '|VRMHFPP|VRMPCCP|VRMHCCP|VRMPOEM|VRMHOEM|VRMPVOL|VRMSD2|VX2PFPP' + + '|VX2HFPP|VX2PCCP|VX2HCCP|VX2POEM|VX2HOEM|VX2PRMFPP|VX2PVOL|GRTMUPD' + + '|GRTMPFPP|GRTMPRMFPP|GRTMHFPP|GRTMHKFPP|GRTMHKNFPP|GRTMHRMFPP' + + '|GRTMPOEM|GRTMHOEM|GRTMPVOL|GRTMPKNVOL|GRTMPKVOL|GRTMPRMVOL' + + '|MX2PFPP|MRMSD2|ARMPXFPP|ARMPXCCP|ARMPXOEM|ARMPXVOL|AX2PXCFPP' + + '|AX2PXFPP|NRMPIFPP')), + ('windows', '2003', + ('ARMECHK|ARMEVOL|ARMSVOL|ARMWVOL|ARMEEVL|ARMSEVL|ARMWEVL|ARMEOEM' + + '|ARMDOEM|ARMSOEM|ARMWOEM|ARMEFPP|ARMDFPP|ARMSFPP|ARMWFPP|NRMECHK' + + '|NRMEVOL|NRMSVOL|NRMWVOL|NRMEEVL|NRMSEVL|NRMWEVL|NRMEOEM|NRMDOEM' + + '|NRMSOEM|NRMWOEM|NRMEFPP|NRMDFPP|NRMSFPP|NRMSFPP|CRMSVOL|CRMSXVOL' + + '|BRMEVOL|BX2DVOL|ARMEEVL|BRMEEVL|CR0SP2|ARMEICHK|ARMEIFPP|ARMEIEVL' + + '|ARMEIOEM|ARMDIOEM|ARMEXFPP|ARMDFPP|ARMSXFPP|CR0SPX2|NRMEICHK' + + '|NRMEIFPP|NRMDIFPP|NRMEIOEM|NRMDIOEM|NRMEIVOL|NRMEIEVL|BRMEXVOL' + + '|BX2DXVOL|ARMEIFPP|CR0SPI2')), + ('windows', '2003r2', + ('CRMEFPP|CRMSFPP|CR0SCD2|CR0ECD2|BX2SFPP|BX2EFPP|BRMECD2FRE' + + '|BRMSCD2FRE|CRMEXFPP|CRMSXFPP|CR0SCD2X|CR0ECD2X|BX2SXFPP|BX2EXFPP' + + '|BRMECD2XFRE|BRMSCD2XFRE|CRMDVOL|CRMDXVOL')), + ('windows', '2008', + ('KRTMSVOL|KRTMSCHK|KRMWVOL|KRMSVOL|KRTMSXVOL|KRTMSXCHK|KRMWXVOL' + + '|KRMSXVOL')), + ('windows', '2008r2', + ('GRMSXVOL|GRMSXFRER|GRMSHXVOL|GRMSIAIVOL|SRVHPCR2')), + ('windows', 'vista', + ('FB1EVOL|LRMCFRE|FRTMBVOL|FRMBVOL|FRMEVOL|FB1EXVOL|LRMCXFRE' + + '|FRTMBXVOL|FRMBXVOL|FRMEXVOL|LRMEVOL|LRMEXVOL')), + ('windows', '7', + ('GRMCULFRER|GSP1RMCNPRFRER|GSP1RMCNULFRER|GSP1RMCULFRER' + + '|GSP1RMCPRFRER|GRMCENVOL|GRMCNENVOL|GRMCPRFRER|GSP1RMCPRVOL' + + '|GRMCULXFRER|GSP1RMCPRXFRER|GSP1RMCNHPXFRER|GRMCHPXFRER|GRMCXCHK' + + '|GSP1RMCENXVOL|GRMCENXVOL|GRMCNENXVOL|GRMCPRXFRER|GSP1RMCPRXVOL')), + ('windows', '8', + ('HB1_CCPA_X86FRE|HRM_CCSA_X86FRE|HRM_CCSA_X86CHK|HRM_CCSNA_X86CHK' + + '|HRM_CCSNA_X86FRE|HRM_CENA_X86FREV|HRM_CENA_X86CHKV' + + '|HRM_CENNA_X86FREV|HRM_CENNA_X86CHKV|HRM_CPRA_X86FREV' + + '|HRM_CPRNA_X86FREV|HB1_CCPA_X64FRE|HRM_CCSA_X64FRE' + + '|HRM_CCSA_X64CHK|HRM_CCSNA_X64FRE|HRM_CCSNA_X64CHK' + + '|HRM_CENNA_X64FREV|HRM_CENNA_X64CHKV|HRM_CENA_X64FREV' + + '|HRM_CENA_X64CHKV|HRM_CPRA_X64FREV|HRM_CPRNA_X64FREV')), + ('sles', '10', 'SLES10|SUSE-Linux-Enterprise-Server.001'), + ('sles', '11', 'SUSE_SLES-11-0-0'), + ('sles', '12', 'SLE-12'), + ('sles', lambda m: "11sp%s" % m.group(1), 'SLES-11-SP(\d+)'), + ('opensuse', lambda m: m.group(1), 'openSUSE[ -](\d+\.\d+)'), + ('opensuse', '11.1', 'SU1110.001'), + ('opensuse', '11.3', + 'openSUSE-DVD-i586-Build0702..001|openSUSE-DVD-x86_64.0702..001'), + ('opensuse', '11.4', + 'openSUSE-DVD-i586-Build0024|openSUSE-DVD-x86_640024'), + ('opensuse', '12.1', + 'openSUSE-DVD-i586-Build0039|openSUSE-DVD-x86_640039'), + ('opensuse', '12.2', + 'openSUSE-DVD-i586-Build0167|openSUSE-DVD-x86_640167'), + ('rhel', '4.8', 'RHEL/4-U8'), + ('rhel', lambda m: m.group(2), 'RHEL(-LE)?[_/-](\d+\.\d+)'), + ('debian', lambda m: m.group(1), 'Debian (\d+\.\d+)'), + ('ubuntu', lambda m: m.group(2), '[Uu]buntu(-Server)? (\d+\.\d+)'), + ('fedora', lambda m: m.group(1), 'Fedora[ -](\d+)'), + ('fedora', lambda m: m.group(1), 'Fedora.*-(\d+)-'), + ('gentoo', lambda m: m.group(1), 'Gentoo Linux \w+ (\d+)'), + ('powerkvm', 'live_cd', 'POWERKVM_LIVECD'), + ('arch', lambda m: m.group(1), 'ARCH_(\d+)'), +] + + +class IsoImage(object): + """ + Scan an iso9660 image to extract the Volume ID and check for boot-ability + + ISO-9660 specification: + http://www.ecma-international.org/publications/standards/Ecma-119.htm + + El-Torito specification: + http://download.intel.com/support/motherboards/desktop/sb/specscdrom.pdf + """ + SECTOR_SIZE = 2048 + VOL_DESC = struct.Struct("=B5sBB32s32s") + EL_TORITO_BOOT_RECORD = struct.Struct("=B5sB32s32sI") + EL_TORITO_VALIDATION_ENTRY = struct.Struct("=BBH24sHBB") + EL_TORITO_BOOT_ENTRY = struct.Struct("=BBHBBHL20x") + # Path table info starting in ISO9660 offset 132. We force little + # endian byte order (the '<' sign) because Power systems can run on + # both. + # First int is path table size, next 4 bytes are discarded (it is + # the same info but in big endian) and next int is the location. + PATH_TABLE_SIZE_LOC = struct.Struct("<I 4s I") + + def __init__(self, path): + self.path = path + self.remote = self._is_iso_remote() + self.volume_id = None + self.bootable = False + self._scan() + + def _is_iso_remote(self): + if os.path.exists(self.path): + st_mode = os.stat(self.path).st_mode + if stat.S_ISREG(st_mode) or stat.S_ISBLK(st_mode): + return False + + if check_url_path(self.path): + return True + + raise IsoFormatError("KCHISO0001E", {'filename': self.path}) + + def probe(self): + if not self.bootable: + raise IsoFormatError("KCHISO0002E", {'filename': self.path}) + + matcher = Matcher(self.volume_id) + + for d, v, regex in iso_dir: + if matcher.search(regex): + distro = d + if hasattr(v, '__call__'): + version = v(matcher) + else: + version = v + return (distro, version) + + msg = "probe_iso: Unable to identify ISO %s with Volume ID: %s" + wok_log.debug(msg, self.path, self.volume_id) + + return ('unknown', 'unknown') + + def _unpack(self, s, data): + return s.unpack(data[:s.size]) + + def _scan_el_torito(self, data): + """ + Search the Volume Descriptor Table for an El Torito boot record. If + found, the boot record will provide a link to a boot catalogue. The + first entry in the boot catalogue is a validation entry. The next + entry contains the default boot entry. The default boot entry will + indicate whether the image is considered bootable. + """ + vd_type = -1 + for i in xrange(1, 4): + fmt = IsoImage.EL_TORITO_BOOT_RECORD + ptr = i * IsoImage.SECTOR_SIZE + tmp_data = data[ptr:ptr + fmt.size] + if len(tmp_data) < fmt.size: + return + + (vd_type, vd_ident, vd_ver, + et_ident, pad0, boot_cat) = self._unpack(fmt, tmp_data) + if vd_type == 255: # Volume record terminator + return + if vd_type == 0: # Found El-Torito Boot Record + break + if not et_ident.startswith('EL TORITO SPECIFICATION'): + raise IsoFormatError("KCHISO0003E", + {'filename': self.path}) + + offset = IsoImage.SECTOR_SIZE * boot_cat + size = IsoImage.EL_TORITO_VALIDATION_ENTRY.size + \ + IsoImage.EL_TORITO_BOOT_ENTRY.size + data = self._get_iso_data(offset, size) + + fmt = IsoImage.EL_TORITO_VALIDATION_ENTRY + tmp_data = data[0:fmt.size] + ptr = fmt.size + (hdr_id, platform_id, pad0, + ident, csum, key55, keyAA) = self._unpack(fmt, tmp_data) + if key55 != 0x55 or keyAA != 0xaa: + raise IsoFormatError("KCHISO0004E", + {'filename': self.path}) + + fmt = IsoImage.EL_TORITO_BOOT_ENTRY + tmp_data = data[ptr:ptr + fmt.size] + (boot, media_type, load_seg, sys_type, + pad0, sectors, load_rba) = self._unpack(fmt, tmp_data) + if boot == 0x88: + self.bootable = True + elif boot == 0: + self.bootable = False + else: + raise IsoFormatError("KCHISO0005E", + {'filename': self.path}) + + def _scan_ppc(self): + """ + PowerPC firmware does not use the conventional El Torito boot + specification. Instead, it looks for a file '/ppc/bootinfo.txt' + which contains boot information. A PPC image is bootable if + this file exists in the filesystem [1]. + + To detect if a PPC ISO is bootable, we could simply mount the + ISO and search for the boot file as we would with any other + file in the filesystem. We can also look for the boot file + searching byte by byte the ISO image. This is possible because + the PPC ISO image follows the ISO9660 standard [2]. Mounting + the ISO requires extra resources and it takes longer than + searching the image data, thus we chose the latter approach + in this code. + + To locate a file we must access the Path Table, which contains + the records of all the directories in the ISO. After locating + the directory/subdirectory that contains the file, we access + the Directory Record to find it. + + + .. [1] https://www.ibm.com/developerworks/community/wikis/home?\ +lang=en#!/wiki/W51a7ffcf4dfd_4b40_9d82_446ebc23c550/page/PowerLinux\ +%20Boot%20howto + .. [2] http://wiki.osdev.org/ISO_9660 + """ + + # To locate any file we must access the Path Table, which + # contains the records of all the directories in the ISO. + # ISO9660 dictates that the Path Table location information + # is at offset 132, inside the Primary Volume Descriptor, + # after the SystemArea (16*SECTOR_SIZE). + # + # In the Path table info we're forcing little endian byte + # order (the '<' sign) because Power systems can run on + # both. + # + # First int is path table size, next 4 bytes are discarded (it is + # the same info but in big endian) and next int is the location. + PATH_TABLE_LOC_OFFSET = 16 * IsoImage.SECTOR_SIZE + 132 + PATH_TABLE_SIZE_LOC = struct.Struct("<I 4s I") + + path_table_loc_data = self._get_iso_data(PATH_TABLE_LOC_OFFSET, + PATH_TABLE_SIZE_LOC.size) + path_size, unused, path_loc = self._unpack(PATH_TABLE_SIZE_LOC, + path_table_loc_data) + # Fetch the Path Table using location and size found above + path_table_offset = path_loc * IsoImage.SECTOR_SIZE + path_table_data = self._get_iso_data(path_table_offset, path_size) + + # Loop inside the path table to find the directory 'ppc'. + # The contents of the registers are: + # - length of the directory identifier (1 byte) + # - extended attribute record length (1 byte) + # - location of directory register (4 bytes) + # - directory number of parent dir (2 bytes) + # - directory name (size varies according to length) + # - padding field - 1 byte if the length is odd, not present if even + DIR_NAMELEN_LOCATION_PARENT = struct.Struct("<B B I H") + dir_struct_size = DIR_NAMELEN_LOCATION_PARENT.size + i = 0 + while i < path_size: + dir_data = path_table_data[i: i+dir_struct_size] + i += dir_struct_size + # We won't use the Extended Attribute Record + dir_namelen, unused, dir_loc, dir_parent = \ + self._unpack(DIR_NAMELEN_LOCATION_PARENT, dir_data) + if dir_parent == 1: + # read the dir name using the namelen + dir_name = path_table_data[i: i+dir_namelen].rstrip() + if dir_name.lower() == 'ppc': + # stop searching, dir was found + break + # Need to consider the optional padding field as well + i += dir_namelen + dir_namelen % 2 + + if i > path_size: + # Didn't find the '/ppc' directory. ISO is not bootable. + self.bootable = False + return + + # Get the 'ppc' directory record using 'dir_loc'. + ppc_dir_offset = dir_loc * IsoImage.SECTOR_SIZE + + # We need to find the sector size of this dir entry. The + # size of the File Section is located 10 bytes after + # the dir location. + DIR_SIZE_FMT = struct.Struct("<10sI") + data = self._get_iso_data(ppc_dir_offset, DIR_SIZE_FMT.size) + unused, dir_size = self._unpack(DIR_SIZE_FMT, data) + # If the dir is in the middle of a sector, the sector is + # padded zero and won't be utilized. We need to round up + # the result + dir_sectorsize = dir_size / IsoImage.SECTOR_SIZE + if dir_size % IsoImage.SECTOR_SIZE: + dir_sectorsize += 1 + + # Fixed-size directory record fields: + # - length of directory record (1 byte) + # - extended attr. record length (1 byte) + # - location of extend in both-endian format (8 bytes) + # - data length (size of extend) in both-endian (8 bytes) + # - recording date and time (7 bytes) + # - file flags (1 byte) + # - file unit size interleaved (1 byte) + # - interleave gap size (1 byte) + # - volume sequence number (4 bytes) + # - length of file identifier (1 byte) + # + # Of all these fields, we will use only 3 of them, 'ignoring' + # 30 bytes total. + STATIC_DIR_RECORD_FMT = struct.Struct("<B 24s B 6s B") + static_rec_size = STATIC_DIR_RECORD_FMT.size + + # Maximum offset possible of all the records of this directory + DIR_REC_MAX = ppc_dir_offset + dir_sectorsize*IsoImage.SECTOR_SIZE + # Max size of a given directory record + MAX_DIR_SIZE = 255 + # Name of the boot file + BOOT_FILE_NAME = "bootinfo.txt" + + # Loop until one of the following happens: + # - boot file is found + # - end of directory record listing for the 'ppc' dir + while ppc_dir_offset < DIR_REC_MAX: + record_data = self._get_iso_data(ppc_dir_offset, MAX_DIR_SIZE) + dir_rec_len, unused, file_flags, unused2, file_name_len = \ + self._unpack(STATIC_DIR_RECORD_FMT, record_data) + + # if dir_rec_len = 0, increment offset (skip the + # dir_rec_len byte) and continue the loop + if dir_rec_len == 0: + ppc_dir_offset += 1 + continue + + # Get filename of the file/dir we're at. + filename = record_data[static_rec_size: + static_rec_size + file_name_len].rstrip() + # The second bit of the file_flags indicate if this record + # is a directory. + if BOOT_FILE_NAME in filename.lower() and (file_flags & 2) != 1: + self.bootable = True + return + + # Update offset and keep looking. There is a padding here + # if the length of the file identifier is EVEN. + padding = 0 + if not file_name_len % 2: + padding = 1 + ppc_dir_offset += dir_rec_len + padding + # If reached this point the file wasn't found = not bootable + self.bootable = False + + def _scan_primary_vol(self, data): + """ + Scan one sector for a Primary Volume Descriptor and extract the + Volume ID from the table + """ + primary_vol_data = data[0: -1] + info = self._unpack(IsoImage.VOL_DESC, primary_vol_data) + (vd_type, vd_ident, vd_ver, pad0, sys_id, vol_id) = info + if vd_type != 1: + raise IsoFormatError("KCHISO0006E", {'filename': self.path}) + if vd_ident != 'CD001' or vd_ver != 1: + raise IsoFormatError("KCHISO0007E", {'filename': self.path}) + if vol_id.strip() == 'RED_HAT': + # Some RHEL ISO images store the infomation of volume id in the + # location of volume set id mistakenly. + self.volume_id = self._get_volume_set_id(data) + else: + self.volume_id = vol_id + + def _get_volume_set_id(self, data): + # The index is picked from ISO-9660 specification. + return data[190: 318] + + def _get_iso_data(self, offset, size): + if self.remote: + request = urllib2.Request(self.path) + range_header = "bytes=%d-%d" % (offset, offset + size - 1) + request.add_header("range", range_header) + with contextlib.closing(urllib2.urlopen(request)) as response: + data = response.read() + else: + with open(self.path) as fd: + fd.seek(offset) + data = fd.read(size) + + return data + + def _scan(self): + offset = 16 * IsoImage.SECTOR_SIZE + size = 4 * IsoImage.SECTOR_SIZE + data = self._get_iso_data(offset, size) + if len(data) < 2 * IsoImage.SECTOR_SIZE: + return + + self._scan_primary_vol(data) + if platform.machine().startswith('ppc'): + self._scan_ppc() + else: + self._scan_el_torito(data) + + +class Matcher(object): + """ + Simple utility class to assist with matching a given string against a + series of regular expressions. + """ + def __init__(self, matchstring): + self.matchstring = matchstring + + def search(self, regex): + self.lastmatch = re.search(regex, self.matchstring) + return bool(self.lastmatch) + + def group(self, num): + return self.lastmatch.group(num) + + +def probe_iso(status_helper, params): + loc = params['path'].encode("utf-8") + updater = params['updater'] + ignore = False + ignore_list = params.get('ignore_list', []) + + def update_result(iso, ret): + path = os.path.abspath(iso) if os.path.isfile(iso) else iso + updater({'path': path, 'distro': ret[0], 'version': ret[1]}) + + if os.path.isdir(loc): + for root, dirs, files in os.walk(loc): + for dir_name in ignore_list: + if root in glob.glob(dir_name): + ignore = True + break + if ignore: + ignore = False + continue + for name in files: + if not name.lower().endswith('.iso'): + continue + iso = os.path.join(root, name) + try: + iso_img = IsoImage(iso) + ret = iso_img.probe() + update_result(iso, ret) + except: + continue + else: + iso_img = IsoImage(loc) + ret = iso_img.probe() + update_result(loc, ret) + + if status_helper is not None: + status_helper('', True) + + +if __name__ == '__main__': + iso_list = [] + + def updater(iso_info): + iso_list.append(iso_info) + + probe_iso(None, dict(path=sys.argv[1], updater=updater)) + print iso_list diff --git a/src/wok/plugins/kimchi/kimchi.conf b/src/wok/plugins/kimchi/kimchi.conf new file mode 100644 index 0000000..1bf78e4 --- /dev/null +++ b/src/wok/plugins/kimchi/kimchi.conf @@ -0,0 +1,37 @@ +[wok] +enable = True +plugin_class = "KimchiRoot" +uri = "/plugins/kimchi" +extra_auth_api_class = "control.sub_nodes" + +[/] +tools.trailing_slash.on = False +request.methods_with_bodies = ('POST', 'PUT') +tools.nocache.on = True +tools.proxy.on = True +tools.sessions.on = True +tools.sessions.name = 'wok' +tools.sessions.secure = True +tools.sessions.httponly = True +tools.sessions.locking = 'explicit' +tools.sessions.storage_type = 'ram' +tools.sessions.timeout = 10 +tools.wokauth.on = True + +[/data/screenshots] +tools.staticdir.on = True +tools.staticdir.dir = wok.config.PluginPaths('kimchi').state_dir + '/screenshots' +tools.nocache.on = False + +[/data/debugreports] +tools.staticdir.on = True +tools.staticdir.dir = wok.config.PluginPaths('kimchi').state_dir + '/debugreports' +tools.nocache.on = False +tools.wokauth.on = True +tools.staticdir.content_types = {'xz': 'application/x-xz'} + +[/help] +tools.staticdir.on = True +tools.staticdir.dir = wok.config.PluginPaths('kimchi').ui_dir + '/pages/help' +tools.nocache.on = True + diff --git a/src/wok/plugins/kimchi/kvmusertests.py b/src/wok/plugins/kimchi/kvmusertests.py new file mode 100644 index 0000000..35350d8 --- /dev/null +++ b/src/wok/plugins/kimchi/kvmusertests.py @@ -0,0 +1,79 @@ +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import libvirt +import platform +import psutil +import threading + + +from wok.rollbackcontext import RollbackContext + +KVMUSERTEST_VM_NAME = "KVMUSERTEST_VM" + + +class UserTests(object): + SIMPLE_VM_XML = """ + <domain type='kvm'> + <name>%(name)s</name> + <memory unit='KiB'>262144</memory> + <os> + <type arch='%(arch)s'>hvm</type> + <boot dev='hd'/> + </os> + </domain>""" + lock = threading.Lock() + user = None + + @classmethod + def probe_user(cls): + with cls.lock: + if cls.user: + return cls.user + + arch = 'ppc64' if platform.machine() == 'ppc64le' \ + else platform.machine() + + xml = cls.SIMPLE_VM_XML % {'name': KVMUSERTEST_VM_NAME, 'arch': arch} + + with RollbackContext() as rollback: + with cls.lock: + conn = libvirt.open(None) + rollback.prependDefer(conn.close) + f = libvirt.VIR_DOMAIN_START_AUTODESTROY + dom = conn.createXML(xml, flags=f) + rollback.prependDefer(dom.destroy) + filename = '/var/run/libvirt/qemu/%s.pid' % KVMUSERTEST_VM_NAME + with open(filename) as f: + pidStr = f.read() + p = psutil.Process(int(pidStr)) + + # bug fix #357 + # in psutil 2.0 and above versions, username will be a method, + # not a string + if callable(p.username): + cls.user = p.username() + else: + cls.user = p.username + + return cls.user + + +if __name__ == '__main__': + ut = UserTests() + print ut.probe_user() diff --git a/src/wok/plugins/kimchi/m4/ac_python_module.m4 b/src/wok/plugins/kimchi/m4/ac_python_module.m4 new file mode 100644 index 0000000..32b9d72 --- /dev/null +++ b/src/wok/plugins/kimchi/m4/ac_python_module.m4 @@ -0,0 +1,30 @@ +dnl @synopsis AC_PYTHON_MODULE(modname[, fatal]) +dnl +dnl Checks for Python module. +dnl +dnl If fatal is non-empty then absence of a module will trigger an +dnl error. +dnl +dnl @category InstalledPackages +dnl @author Andrew Collier <colliera@nu.ac.za>. +dnl @version 2004-07-14 +dnl @license AllPermissive + +AC_DEFUN([AC_PYTHON_MODULE],[ + AC_MSG_CHECKING(python module: $1) + python -c "import $1" 2>/dev/null + if test $? -eq 0; + then + AC_MSG_RESULT(yes) + eval AS_TR_CPP(HAVE_PYMOD_$1)=yes + else + AC_MSG_RESULT(no) + eval AS_TR_CPP(HAVE_PYMOD_$1)=no + # + if test -n "$2" + then + AC_MSG_ERROR(failed to find required module $1) + exit 1 + fi + fi +]) diff --git a/src/wok/plugins/kimchi/m4/gettext.m4 b/src/wok/plugins/kimchi/m4/gettext.m4 new file mode 100644 index 0000000..f84e6a5 --- /dev/null +++ b/src/wok/plugins/kimchi/m4/gettext.m4 @@ -0,0 +1,383 @@ +# gettext.m4 serial 63 (gettext-0.18) +dnl Copyright (C) 1995-2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. +dnl Bruno Haible <haible@clisp.cons.org>, 2000-2006, 2008-2010. + +dnl Macro to add for using GNU gettext. + +dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). +dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The +dnl default (if it is not specified or empty) is 'no-libtool'. +dnl INTLSYMBOL should be 'external' for packages with no intl directory, +dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. +dnl If INTLSYMBOL is 'use-libtool', then a libtool library +dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, +dnl depending on --{enable,disable}-{shared,static} and on the presence of +dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library +dnl $(top_builddir)/intl/libintl.a will be created. +dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext +dnl implementations (in libc or libintl) without the ngettext() function +dnl will be ignored. If NEEDSYMBOL is specified and is +dnl 'need-formatstring-macros', then GNU gettext implementations that don't +dnl support the ISO C 99 <inttypes.h> formatstring macros will be ignored. +dnl INTLDIR is used to find the intl libraries. If empty, +dnl the value `$(top_builddir)/intl/' is used. +dnl +dnl The result of the configuration is one of three cases: +dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled +dnl and used. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 2) GNU gettext has been found in the system's C library. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 3) No internationalization, always use English msgid. +dnl Catalog format: none +dnl Catalog extension: none +dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. +dnl The use of .gmo is historical (it was needed to avoid overwriting the +dnl GNU format catalogs when building on a platform with an X/Open gettext), +dnl but we keep it in order not to force irrelevant filename changes on the +dnl maintainers. +dnl +AC_DEFUN([AM_GNU_GETTEXT], +[ + dnl Argument checking. + ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , + [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT +])])])])]) + ifelse(ifelse([$1], [], [old])[]ifelse([$1], [no-libtool], [old]), [old], + [AC_DIAGNOSE([obsolete], [Use of AM_GNU_GETTEXT without [external] argument is deprecated.])]) + ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , + [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT +])])])]) + define([gt_included_intl], + ifelse([$1], [external], + ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), + [yes])) + define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) + gt_NEEDS_INIT + AM_GNU_GETTEXT_NEED([$2]) + + AC_REQUIRE([AM_PO_SUBDIRS])dnl + ifelse(gt_included_intl, yes, [ + AC_REQUIRE([AM_INTL_SUBDIR])dnl + ]) + + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Sometimes libintl requires libiconv, so first search for libiconv. + dnl Ideally we would do this search only after the + dnl if test "$USE_NLS" = "yes"; then + dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT + dnl the configure script would need to contain the same shell code + dnl again, outside any 'if'. There are two solutions: + dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. + dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. + dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not + dnl documented, we avoid it. + ifelse(gt_included_intl, yes, , [ + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + ]) + + dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation. + gt_INTL_MACOSX + + dnl Set USE_NLS. + AC_REQUIRE([AM_NLS]) + + ifelse(gt_included_intl, yes, [ + BUILD_INCLUDED_LIBINTL=no + USE_INCLUDED_LIBINTL=no + ]) + LIBINTL= + LTLIBINTL= + POSUB= + + dnl Add a version number to the cache macros. + case " $gt_needs " in + *" need-formatstring-macros "*) gt_api_version=3 ;; + *" need-ngettext "*) gt_api_version=2 ;; + *) gt_api_version=1 ;; + esac + gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" + gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" + + dnl If we use NLS figure out what method + if test "$USE_NLS" = "yes"; then + gt_use_preinstalled_gnugettext=no + ifelse(gt_included_intl, yes, [ + AC_MSG_CHECKING([whether included gettext is requested]) + AC_ARG_WITH([included-gettext], + [ --with-included-gettext use the GNU gettext library included here], + nls_cv_force_use_gnu_gettext=$withval, + nls_cv_force_use_gnu_gettext=no) + AC_MSG_RESULT([$nls_cv_force_use_gnu_gettext]) + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + ]) + dnl User does not insist on using GNU NLS library. Figure out what + dnl to use. If GNU gettext is available we use this. Else we have + dnl to fall back to GNU NLS library. + + if test $gt_api_version -ge 3; then + gt_revision_test_code=' +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +changequote(,)dnl +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +changequote([,])dnl +' + else + gt_revision_test_code= + fi + if test $gt_api_version -ge 2; then + gt_expression_test_code=' + * ngettext ("", "", 0)' + else + gt_expression_test_code= + fi + + AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], + [AC_TRY_LINK([#include <libintl.h> +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern int *_nl_domain_bindings;], + [bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings], + [eval "$gt_func_gnugettext_libc=yes"], + [eval "$gt_func_gnugettext_libc=no"])]) + + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + dnl Sometimes libintl requires libiconv, so first search for libiconv. + ifelse(gt_included_intl, yes, , [ + AM_ICONV_LINK + ]) + dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL + dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) + dnl because that would add "-liconv" to LIBINTL and LTLIBINTL + dnl even if libiconv doesn't exist. + AC_LIB_LINKFLAGS_BODY([intl]) + AC_CACHE_CHECK([for GNU gettext in libintl], + [$gt_func_gnugettext_libintl], + [gt_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCINTL" + gt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBINTL" + dnl Now see whether libintl exists and does not depend on libiconv. + AC_TRY_LINK([#include <libintl.h> +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *);], + [bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], + [eval "$gt_func_gnugettext_libintl=yes"], + [eval "$gt_func_gnugettext_libintl=no"]) + dnl Now see whether libintl exists and depends on libiconv. + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include <libintl.h> +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *);], + [bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], + [LIBINTL="$LIBINTL $LIBICONV" + LTLIBINTL="$LTLIBINTL $LTLIBICONV" + eval "$gt_func_gnugettext_libintl=yes" + ]) + fi + CPPFLAGS="$gt_save_CPPFLAGS" + LIBS="$gt_save_LIBS"]) + fi + + dnl If an already present or preinstalled GNU gettext() is found, + dnl use it. But if this macro is used in GNU gettext, and GNU + dnl gettext is already preinstalled in libintl, we update this + dnl libintl. (Cf. the install rule in intl/Makefile.in.) + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ + || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ + && test "$PACKAGE" != gettext-runtime \ + && test "$PACKAGE" != gettext-tools; }; then + gt_use_preinstalled_gnugettext=yes + else + dnl Reset the values set by searching for libintl. + LIBINTL= + LTLIBINTL= + INCINTL= + fi + + ifelse(gt_included_intl, yes, [ + if test "$gt_use_preinstalled_gnugettext" != "yes"; then + dnl GNU gettext is not found in the C library. + dnl Fall back on included GNU gettext library. + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions used to generate GNU NLS library. + BUILD_INCLUDED_LIBINTL=yes + USE_INCLUDED_LIBINTL=yes + LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" + LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" + LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` + fi + + CATOBJEXT= + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions to use GNU gettext tools. + CATOBJEXT=.gmo + fi + ]) + + if test -n "$INTL_MACOSX_LIBS"; then + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Some extra flags are needed during linking. + LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" + LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" + fi + fi + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + AC_DEFINE([ENABLE_NLS], [1], + [Define to 1 if translation of program messages to the user's native language + is requested.]) + else + USE_NLS=no + fi + fi + + AC_MSG_CHECKING([whether to use NLS]) + AC_MSG_RESULT([$USE_NLS]) + if test "$USE_NLS" = "yes"; then + AC_MSG_CHECKING([where the gettext function comes from]) + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + gt_source="external libintl" + else + gt_source="libc" + fi + else + gt_source="included intl directory" + fi + AC_MSG_RESULT([$gt_source]) + fi + + if test "$USE_NLS" = "yes"; then + + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + AC_MSG_CHECKING([how to link with libintl]) + AC_MSG_RESULT([$LIBINTL]) + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) + fi + + dnl For backward compatibility. Some packages may be using this. + AC_DEFINE([HAVE_GETTEXT], [1], + [Define if the GNU gettext() function is already present or preinstalled.]) + AC_DEFINE([HAVE_DCGETTEXT], [1], + [Define if the GNU dcgettext() function is already present or preinstalled.]) + fi + + dnl We need to process the po/ directory. + POSUB=po + fi + + ifelse(gt_included_intl, yes, [ + dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL + dnl to 'yes' because some of the testsuite requires it. + if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then + BUILD_INCLUDED_LIBINTL=yes + fi + + dnl Make all variables we use known to autoconf. + AC_SUBST([BUILD_INCLUDED_LIBINTL]) + AC_SUBST([USE_INCLUDED_LIBINTL]) + AC_SUBST([CATOBJEXT]) + + dnl For backward compatibility. Some configure.ins may be using this. + nls_cv_header_intl= + nls_cv_header_libgt= + + dnl For backward compatibility. Some Makefiles may be using this. + DATADIRNAME=share + AC_SUBST([DATADIRNAME]) + + dnl For backward compatibility. Some Makefiles may be using this. + INSTOBJEXT=.mo + AC_SUBST([INSTOBJEXT]) + + dnl For backward compatibility. Some Makefiles may be using this. + GENCAT=gencat + AC_SUBST([GENCAT]) + + dnl For backward compatibility. Some Makefiles may be using this. + INTLOBJS= + if test "$USE_INCLUDED_LIBINTL" = yes; then + INTLOBJS="\$(GETTOBJS)" + fi + AC_SUBST([INTLOBJS]) + + dnl Enable libtool support if the surrounding package wishes it. + INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix + AC_SUBST([INTL_LIBTOOL_SUFFIX_PREFIX]) + ]) + + dnl For backward compatibility. Some Makefiles may be using this. + INTLLIBS="$LIBINTL" + AC_SUBST([INTLLIBS]) + + dnl Make all documented variables known to autoconf. + AC_SUBST([LIBINTL]) + AC_SUBST([LTLIBINTL]) + AC_SUBST([POSUB]) +]) + + +dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. +m4_define([gt_NEEDS_INIT], +[ + m4_divert_text([DEFAULTS], [gt_needs=]) + m4_define([gt_NEEDS_INIT], []) +]) + + +dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) +AC_DEFUN([AM_GNU_GETTEXT_NEED], +[ + m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) +]) + + +dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) +AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) diff --git a/src/wok/plugins/kimchi/m4/iconv.m4 b/src/wok/plugins/kimchi/m4/iconv.m4 new file mode 100644 index 0000000..e2041b9 --- /dev/null +++ b/src/wok/plugins/kimchi/m4/iconv.m4 @@ -0,0 +1,214 @@ +# iconv.m4 serial 11 (gettext-0.18.1) +dnl Copyright (C) 2000-2002, 2007-2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], +[ + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([iconv]) +]) + +AC_DEFUN([AM_ICONV_LINK], +[ + dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and + dnl those with the standalone portable GNU libiconv installed). + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + + dnl Add $INCICONV to CPPFLAGS before performing the following checks, + dnl because if the user has installed libiconv and not disabled its use + dnl via --without-libiconv-prefix, he wants to use it. The first + dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. + am_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) + + AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + AC_TRY_LINK([#include <stdlib.h> +#include <iconv.h>], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + [am_cv_func_iconv=yes]) + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include <stdlib.h> +#include <iconv.h>], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + [am_cv_lib_iconv=yes] + [am_cv_func_iconv=yes]) + LIBS="$am_save_LIBS" + fi + ]) + if test "$am_cv_func_iconv" = yes; then + AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ + dnl This tests against bugs in AIX 5.1, HP-UX 11.11, Solaris 10. + am_save_LIBS="$LIBS" + if test $am_cv_lib_iconv = yes; then + LIBS="$LIBS $LIBICONV" + fi + AC_TRY_RUN([ +#include <iconv.h> +#include <string.h> +int main () +{ + /* Test against AIX 5.1 bug: Failures are not distinguishable from successful + returns. */ + { + iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); + if (cd_utf8_to_88591 != (iconv_t)(-1)) + { + static const char input[] = "\342\202\254"; /* EURO SIGN */ + char buf[10]; + const char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_utf8_to_88591, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + return 1; + } + } + /* Test against Solaris 10 bug: Failures are not distinguishable from + successful returns. */ + { + iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); + if (cd_ascii_to_88591 != (iconv_t)(-1)) + { + static const char input[] = "\263"; + char buf[10]; + const char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_ascii_to_88591, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + return 1; + } + } +#if 0 /* This bug could be worked around by the caller. */ + /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + char buf[50]; + const char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_88591_to_utf8, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if ((int)res > 0) + return 1; + } + } +#endif + /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is + provided. */ + if (/* Try standardized names. */ + iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) + /* Try IRIX, OSF/1 names. */ + && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) + /* Try AIX names. */ + && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) + /* Try HP-UX names. */ + && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) + return 1; + return 0; +}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no], + [case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac]) + LIBS="$am_save_LIBS" + ]) + case "$am_cv_func_iconv_works" in + *no) am_func_iconv=no am_cv_lib_iconv=no ;; + *) am_func_iconv=yes ;; + esac + else + am_func_iconv=no am_cv_lib_iconv=no + fi + if test "$am_func_iconv" = yes; then + AC_DEFINE([HAVE_ICONV], [1], + [Define if you have the iconv() function and it works.]) + fi + if test "$am_cv_lib_iconv" = yes; then + AC_MSG_CHECKING([how to link with libiconv]) + AC_MSG_RESULT([$LIBICONV]) + else + dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV + dnl either. + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + AC_SUBST([LIBICONV]) + AC_SUBST([LTLIBICONV]) +]) + +dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to +dnl avoid warnings like +dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". +dnl This is tricky because of the way 'aclocal' is implemented: +dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. +dnl Otherwise aclocal's initial scan pass would miss the macro definition. +dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. +dnl Otherwise aclocal would emit many "Use of uninitialized value $1" +dnl warnings. +m4_define([gl_iconv_AC_DEFUN], + m4_version_prereq([2.64], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [[AC_DEFUN( + [$1], [$2])]])) +gl_iconv_AC_DEFUN([AM_ICONV], +[ + AM_ICONV_LINK + if test "$am_cv_func_iconv" = yes; then + AC_MSG_CHECKING([for iconv declaration]) + AC_CACHE_VAL([am_cv_proto_iconv], [ + AC_TRY_COMPILE([ +#include <stdlib.h> +#include <iconv.h> +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif +], [], [am_cv_proto_iconv_arg1=""], [am_cv_proto_iconv_arg1="const"]) + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) + am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + AC_MSG_RESULT([ + $am_cv_proto_iconv]) + AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], + [Define as const if the declaration of iconv() needs const.]) + fi +]) diff --git a/src/wok/plugins/kimchi/m4/intlmacosx.m4 b/src/wok/plugins/kimchi/m4/intlmacosx.m4 new file mode 100644 index 0000000..dd91025 --- /dev/null +++ b/src/wok/plugins/kimchi/m4/intlmacosx.m4 @@ -0,0 +1,51 @@ +# intlmacosx.m4 serial 3 (gettext-0.18) +dnl Copyright (C) 2004-2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Checks for special options needed on MacOS X. +dnl Defines INTL_MACOSX_LIBS. +AC_DEFUN([gt_INTL_MACOSX], +[ + dnl Check for API introduced in MacOS X 10.2. + AC_CACHE_CHECK([for CFPreferencesCopyAppValue], + [gt_cv_func_CFPreferencesCopyAppValue], + [gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + AC_TRY_LINK([#include <CoreFoundation/CFPreferences.h>], + [CFPreferencesCopyAppValue(NULL, NULL)], + [gt_cv_func_CFPreferencesCopyAppValue=yes], + [gt_cv_func_CFPreferencesCopyAppValue=no]) + LIBS="$gt_save_LIBS"]) + if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then + AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], [1], + [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) + fi + dnl Check for API introduced in MacOS X 10.3. + AC_CACHE_CHECK([for CFLocaleCopyCurrent], [gt_cv_func_CFLocaleCopyCurrent], + [gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + AC_TRY_LINK([#include <CoreFoundation/CFLocale.h>], [CFLocaleCopyCurrent();], + [gt_cv_func_CFLocaleCopyCurrent=yes], + [gt_cv_func_CFLocaleCopyCurrent=no]) + LIBS="$gt_save_LIBS"]) + if test $gt_cv_func_CFLocaleCopyCurrent = yes; then + AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], [1], + [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) + fi + INTL_MACOSX_LIBS= + if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then + INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" + fi + AC_SUBST([INTL_MACOSX_LIBS]) +]) diff --git a/src/wok/plugins/kimchi/m4/lib-ld.m4 b/src/wok/plugins/kimchi/m4/lib-ld.m4 new file mode 100644 index 0000000..ebb3052 --- /dev/null +++ b/src/wok/plugins/kimchi/m4/lib-ld.m4 @@ -0,0 +1,110 @@ +# lib-ld.m4 serial 4 (gettext-0.18) +dnl Copyright (C) 1996-2003, 2009-2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Subroutines of libtool.m4, +dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision +dnl with libtool.m4. + +dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. +AC_DEFUN([AC_LIB_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld], +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + acl_cv_prog_gnu_ld=yes ;; +*) + acl_cv_prog_gnu_ld=no ;; +esac]) +with_gnu_ld=$acl_cv_prog_gnu_ld +]) + +dnl From libtool-1.4. Sets the variable LD. +AC_DEFUN([AC_LIB_PROG_LD], +[AC_ARG_WITH([gnu-ld], +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + [re_direlt='/[^/][^/]*/\.\./'] + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL([acl_cv_path_LD], +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break ;; + *) + test "$with_gnu_ld" != yes && break ;; + esac + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$acl_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT([$LD]) +else + AC_MSG_RESULT([no]) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_LIB_PROG_LD_GNU +]) diff --git a/src/wok/plugins/kimchi/m4/lib-link.m4 b/src/wok/plugins/kimchi/m4/lib-link.m4 new file mode 100644 index 0000000..c73bd8e --- /dev/null +++ b/src/wok/plugins/kimchi/m4/lib-link.m4 @@ -0,0 +1,774 @@ +# lib-link.m4 serial 21 (gettext-0.18) +dnl Copyright (C) 2001-2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_PREREQ([2.54]) + +dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and +dnl augments the CPPFLAGS variable. +dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname +dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + pushdef([Name],[translit([$1],[./-], [___])]) + pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + ac_cv_lib[]Name[]_libs="$LIB[]NAME" + ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" + ac_cv_lib[]Name[]_cppflags="$INC[]NAME" + ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX" + ]) + LIB[]NAME="$ac_cv_lib[]Name[]_libs" + LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" + INC[]NAME="$ac_cv_lib[]Name[]_cppflags" + LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + AC_SUBST([LIB]NAME[_PREFIX]) + dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the + dnl results of this search when this library appears as a dependency. + HAVE_LIB[]NAME=yes + popdef([NAME]) + popdef([Name]) +]) + +dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode, [missing-message]) +dnl searches for libname and the libraries corresponding to explicit and +dnl implicit dependencies, together with the specified include files and +dnl the ability to compile and link the specified testcode. The missing-message +dnl defaults to 'no' and may contain additional hints for the user. +dnl If found, it sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} +dnl and LTLIB${NAME} variables and augments the CPPFLAGS variable, and +dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs +dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. +dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname +dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + pushdef([Name],[translit([$1],[./-], [___])]) + pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + + dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + + dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, + dnl because if the user has installed lib[]Name and not disabled its use + dnl via --without-lib[]Name-prefix, he wants to use it. + ac_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + + AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ + ac_save_LIBS="$LIBS" + dnl If $LIB[]NAME contains some -l options, add it to the end of LIBS, + dnl because these -l options might require -L options that are present in + dnl LIBS. -l options benefit only from the -L options listed before it. + dnl Otherwise, add it to the front of LIBS, because it may be a static + dnl library that depends on another static library that is present in LIBS. + dnl Static libraries benefit only from the static libraries listed after + dnl it. + case " $LIB[]NAME" in + *" -l"*) LIBS="$LIBS $LIB[]NAME" ;; + *) LIBS="$LIB[]NAME $LIBS" ;; + esac + AC_TRY_LINK([$3], [$4], + [ac_cv_lib[]Name=yes], + [ac_cv_lib[]Name='m4_if([$5], [], [no], [[$5]])']) + LIBS="$ac_save_LIBS" + ]) + if test "$ac_cv_lib[]Name" = yes; then + HAVE_LIB[]NAME=yes + AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the lib][$1 library.]) + AC_MSG_CHECKING([how to link with lib[]$1]) + AC_MSG_RESULT([$LIB[]NAME]) + else + HAVE_LIB[]NAME=no + dnl If $LIB[]NAME didn't lead to a usable library, we don't need + dnl $INC[]NAME either. + CPPFLAGS="$ac_save_CPPFLAGS" + LIB[]NAME= + LTLIB[]NAME= + LIB[]NAME[]_PREFIX= + fi + AC_SUBST([HAVE_LIB]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + AC_SUBST([LIB]NAME[_PREFIX]) + popdef([NAME]) + popdef([Name]) +]) + +dnl Determine the platform dependent parameters needed to use rpath: +dnl acl_libext, +dnl acl_shlibext, +dnl acl_hardcode_libdir_flag_spec, +dnl acl_hardcode_libdir_separator, +dnl acl_hardcode_direct, +dnl acl_hardcode_minus_L. +AC_DEFUN([AC_LIB_RPATH], +[ + dnl Tell automake >= 1.10 to complain if config.rpath is missing. + m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) + AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS + AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir + AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [ + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + ]) + wl="$acl_cv_wl" + acl_libext="$acl_cv_libext" + acl_shlibext="$acl_cv_shlibext" + acl_libname_spec="$acl_cv_libname_spec" + acl_library_names_spec="$acl_cv_library_names_spec" + acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + acl_hardcode_direct="$acl_cv_hardcode_direct" + acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" + dnl Determine whether the user wants rpath handling at all. + AC_ARG_ENABLE([rpath], + [ --disable-rpath do not hardcode runtime library paths], + :, enable_rpath=yes) +]) + +dnl AC_LIB_FROMPACKAGE(name, package) +dnl declares that libname comes from the given package. The configure file +dnl will then not have a --with-libname-prefix option but a +dnl --with-package-prefix option. Several libraries can come from the same +dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar +dnl macro call that searches for libname. +AC_DEFUN([AC_LIB_FROMPACKAGE], +[ + pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + define([acl_frompackage_]NAME, [$2]) + popdef([NAME]) + pushdef([PACK],[$2]) + pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + define([acl_libsinpackage_]PACKUP, + m4_ifdef([acl_libsinpackage_]PACKUP, [acl_libsinpackage_]PACKUP[[, ]],)[lib$1]) + popdef([PACKUP]) + popdef([PACK]) +]) + +dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. +dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found +dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_LINKFLAGS_BODY], +[ + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])]) + pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])]) + dnl Autoconf >= 2.61 supports dots in --with options. + pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit(PACK,[.],[_])],PACK)]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_ARG_WITH(P_A_C_K[-prefix], +[[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib + --without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + if test "$acl_libdirstem2" != "$acl_libdirstem" \ + && ! test -d "$withval/$acl_libdirstem"; then + additional_libdir="$withval/$acl_libdirstem2" + fi + fi + fi +]) + dnl Search the library and its dependencies in $additional_libdir and + dnl $LDFLAGS. Using breadth-first-seach. + LIB[]NAME= + LTLIB[]NAME= + INC[]NAME= + LIB[]NAME[]_PREFIX= + dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been + dnl computed. So it has to be reset here. + HAVE_LIB[]NAME= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='$1 $2' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + dnl See if it was already located by an earlier AC_LIB_LINKFLAGS + dnl or AC_LIB_HAVE_LINKFLAGS call. + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" + else + dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined + dnl that this library doesn't exist. So just drop it. + : + fi + else + dnl Search the library lib$name in $additional_libdir and $LDFLAGS + dnl and the already constructed $LIBNAME/$LTLIBNAME. + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + dnl The same code as in the loop below: + dnl First look for a shared library. + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + dnl Then look for a static library. + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + dnl First look for a shared library. + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + dnl Then look for a static library. + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + dnl Found the library. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + dnl Linking with a shared library. We attempt to hardcode its + dnl directory into the executable's runpath, unless it's the + dnl standard /usr/lib. + if test "$enable_rpath" = no \ + || test "X$found_dir" = "X/usr/$acl_libdirstem" \ + || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then + dnl No hardcoding is needed. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + dnl The hardcoding into $LIBNAME is system dependent. + if test "$acl_hardcode_direct" = yes; then + dnl Using DIR/libNAME.so during linking hardcodes DIR into the + dnl resulting binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + dnl Rely on "-L$found_dir". + dnl But don't add it if it's already contained in the LDFLAGS + dnl or the already constructed $LIBNAME + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH + dnl here, because this doesn't fit in flags passed to the + dnl compiler. So give up. No hardcoding. This affects only + dnl very old systems. + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + dnl Linking with a static library. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" + else + dnl We shouldn't come here, but anyway it's good to have a + dnl fallback. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" + fi + fi + dnl Assume the include files are nearby. + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + if test "$name" = '$1'; then + LIB[]NAME[]_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + */$acl_libdirstem2 | */$acl_libdirstem2/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` + if test "$name" = '$1'; then + LIB[]NAME[]_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + dnl Potentially add $additional_includedir to $INCNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's /usr/local/include and we are using GCC on Linux, + dnl 3. if it's already present in $CPPFLAGS or the already + dnl constructed $INCNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INC[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $INCNAME. + INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + dnl Look for dependencies. + if test -n "$found_la"; then + dnl Read the .la file. It defines the variables + dnl dlname, library_names, old_library, dependency_libs, current, + dnl age, revision, installed, dlopen, dlpreopen, libdir. + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + dnl We use only dependency_libs. + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's /usr/local/lib and we are using GCC on Linux, + dnl 3. if it's already present in $LDFLAGS or the already + dnl constructed $LIBNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ + && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ + || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LIBNAME. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LTLIBNAME. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + dnl Handle this in the next round. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + dnl Handle this in the next round. Throw away the .la's + dnl directory; it is already contained in a preceding -L + dnl option. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + dnl Most likely an immediate library name. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" + ;; + esac + done + fi + else + dnl Didn't find the library; assume it is in the system directories + dnl known to the linker and runtime loader. (All the system + dnl directories known to the linker should also be known to the + dnl runtime loader, otherwise the system is severely misconfigured.) + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user must + dnl pass all path elements in one option. We can arrange that for a + dnl single library, but not when more than one $LIBNAMEs are used. + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + else + dnl The -rpath options are cumulative. + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + dnl When using libtool, the option that works for both libraries and + dnl executables is -R. The -R options are cumulative. + for found_dir in $ltrpathdirs; do + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" + done + fi + popdef([P_A_C_K]) + popdef([PACKLIBS]) + popdef([PACKUP]) + popdef([PACK]) + popdef([NAME]) +]) + +dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, +dnl unless already present in VAR. +dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes +dnl contains two or three consecutive elements that belong together. +AC_DEFUN([AC_LIB_APPENDTOVAR], +[ + for element in [$2]; do + haveit= + for x in $[$1]; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + [$1]="${[$1]}${[$1]:+ }$element" + fi + done +]) + +dnl For those cases where a variable contains several -L and -l options +dnl referring to unknown libraries and directories, this macro determines the +dnl necessary additional linker options for the runtime path. +dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) +dnl sets LDADDVAR to linker options needed together with LIBSVALUE. +dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, +dnl otherwise linking without libtool is assumed. +AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], +[ + AC_REQUIRE([AC_LIB_RPATH]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + $1= + if test "$enable_rpath" != no; then + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode directories into the resulting + dnl binary. + rpathdirs= + next= + for opt in $2; do + if test -n "$next"; then + dir="$next" + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem" \ + && test "X$dir" != "X/usr/$acl_libdirstem2"; then + rpathdirs="$rpathdirs $dir" + fi + next= + else + case $opt in + -L) next=yes ;; + -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem" \ + && test "X$dir" != "X/usr/$acl_libdirstem2"; then + rpathdirs="$rpathdirs $dir" + fi + next= ;; + *) next= ;; + esac + fi + done + if test "X$rpathdirs" != "X"; then + if test -n ""$3""; then + dnl libtool is used for linking. Use -R options. + for dir in $rpathdirs; do + $1="${$1}${$1:+ }-R$dir" + done + else + dnl The linker is used for linking directly. + if test -n "$acl_hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user + dnl must pass all path elements in one option. + alldirs= + for dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="$flag" + else + dnl The -rpath options are cumulative. + for dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="${$1}${$1:+ }$flag" + done + fi + fi + fi + fi + fi + AC_SUBST([$1]) +]) diff --git a/src/wok/plugins/kimchi/m4/lib-prefix.m4 b/src/wok/plugins/kimchi/m4/lib-prefix.m4 new file mode 100644 index 0000000..1601cea --- /dev/null +++ b/src/wok/plugins/kimchi/m4/lib-prefix.m4 @@ -0,0 +1,224 @@ +# lib-prefix.m4 serial 7 (gettext-0.18) +dnl Copyright (C) 2001-2005, 2008-2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and +dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't +dnl require excessive bracketing. +ifdef([AC_HELP_STRING], +[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], +[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) + +dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed +dnl to access previously installed libraries. The basic assumption is that +dnl a user will want packages to use other packages he previously installed +dnl with the same --prefix option. +dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate +dnl libraries, but is otherwise very convenient. +AC_DEFUN([AC_LIB_PREFIX], +[ + AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib-prefix], +[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib + --without-lib-prefix don't search for libraries in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi +]) + if test $use_additional = yes; then + dnl Potentially add $additional_includedir to $CPPFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's already present in $CPPFLAGS, + dnl 3. if it's /usr/local/include and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + for x in $CPPFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $CPPFLAGS. + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" + fi + fi + fi + fi + dnl Potentially add $additional_libdir to $LDFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's already present in $LDFLAGS, + dnl 3. if it's /usr/local/lib and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + for x in $LDFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LDFLAGS. + LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" + fi + fi + fi + fi + fi +]) + +dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, +dnl acl_final_exec_prefix, containing the values to which $prefix and +dnl $exec_prefix will expand at the end of the configure script. +AC_DEFUN([AC_LIB_PREPARE_PREFIX], +[ + dnl Unfortunately, prefix and exec_prefix get only finally determined + dnl at the end of configure. + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the +dnl variables prefix and exec_prefix bound to the values they will have +dnl at the end of the configure script. +AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], +[ + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + $1 + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_PREPARE_MULTILIB creates +dnl - a variable acl_libdirstem, containing the basename of the libdir, either +dnl "lib" or "lib64" or "lib/64", +dnl - a variable acl_libdirstem2, as a secondary possible value for +dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or +dnl "lib/amd64". +AC_DEFUN([AC_LIB_PREPARE_MULTILIB], +[ + dnl There is no formal standard regarding lib and lib64. + dnl On glibc systems, the current practice is that on a system supporting + dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under + dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine + dnl the compiler's default mode by looking at the compiler's library search + dnl path. If at least one of its elements ends in /lib64 or points to a + dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI. + dnl Otherwise we use the default, namely "lib". + dnl On Solaris systems, the current practice is that on a system supporting + dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under + dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or + dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib. + AC_REQUIRE([AC_CANONICAL_HOST]) + acl_libdirstem=lib + acl_libdirstem2= + case "$host_os" in + solaris*) + dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment + dnl <http://docs.sun.com/app/docs/doc/816-5138/dev-env?l=en&a=view>. + dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link." + dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the + dnl symlink is missing, so we set acl_libdirstem2 too. + AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit], + [AC_EGREP_CPP([sixtyfour bits], [ +#ifdef _LP64 +sixtyfour bits +#endif + ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no]) + ]) + if test $gl_cv_solaris_64bit = yes; then + acl_libdirstem=lib/64 + case "$host_cpu" in + sparc*) acl_libdirstem2=lib/sparcv9 ;; + i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; + esac + fi + ;; + *) + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + */../ | */.. ) + # Better ignore directories of this form. They are misleading. + ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi + ;; + esac + test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" +]) diff --git a/src/wok/plugins/kimchi/m4/nls.m4 b/src/wok/plugins/kimchi/m4/nls.m4 new file mode 100644 index 0000000..003704c --- /dev/null +++ b/src/wok/plugins/kimchi/m4/nls.m4 @@ -0,0 +1,32 @@ +# nls.m4 serial 5 (gettext-0.18) +dnl Copyright (C) 1995-2003, 2005-2006, 2008-2010 Free Software Foundation, +dnl Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. +dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003. + +AC_PREREQ([2.50]) + +AC_DEFUN([AM_NLS], +[ + AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE([nls], + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT([$USE_NLS]) + AC_SUBST([USE_NLS]) +]) diff --git a/src/wok/plugins/kimchi/m4/po.m4 b/src/wok/plugins/kimchi/m4/po.m4 new file mode 100644 index 0000000..8bc921d --- /dev/null +++ b/src/wok/plugins/kimchi/m4/po.m4 @@ -0,0 +1,449 @@ +# po.m4 serial 17 (gettext-0.18) +dnl Copyright (C) 1995-2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. +dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003. + +AC_PREREQ([2.50]) + +dnl Checks for all prerequisites of the po subdirectory. +AC_DEFUN([AM_PO_SUBDIRS], +[ + AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AC_PROG_MKDIR_P])dnl defined by autoconf + AC_REQUIRE([AM_NLS])dnl + + dnl Release version of the gettext macros. This is used to ensure that + dnl the gettext macros and po/Makefile.in.in are in sync. + AC_SUBST([GETTEXT_MACRO_VERSION], [0.18]) + + dnl Perform the following tests also if --disable-nls has been given, + dnl because they are needed for "make dist" to work. + + dnl Search for GNU msgfmt in the PATH. + dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. + dnl The second test excludes FreeBSD msgfmt. + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && + (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + AC_PATH_PROG([GMSGFMT], [gmsgfmt], [$MSGFMT]) + + dnl Test whether it is GNU msgfmt >= 0.15. +changequote(,)dnl + case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; + *) MSGFMT_015=$MSGFMT ;; + esac +changequote([,])dnl + AC_SUBST([MSGFMT_015]) +changequote(,)dnl + case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; + *) GMSGFMT_015=$GMSGFMT ;; + esac +changequote([,])dnl + AC_SUBST([GMSGFMT_015]) + + dnl Search for GNU xgettext 0.12 or newer in the PATH. + dnl The first test excludes Solaris xgettext and early GNU xgettext versions. + dnl The second test excludes FreeBSD xgettext. + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && + (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + dnl Remove leftover from FreeBSD xgettext call. + rm -f messages.po + + dnl Test whether it is GNU xgettext >= 0.15. +changequote(,)dnl + case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; + *) XGETTEXT_015=$XGETTEXT ;; + esac +changequote([,])dnl + AC_SUBST([XGETTEXT_015]) + + dnl Search for GNU msgmerge 0.11 or newer in the PATH. + AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, + [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) + + dnl Installation directories. + dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we + dnl have to define it here, so that it can be used in po/Makefile. + test -n "$localedir" || localedir='${datadir}/locale' + AC_SUBST([localedir]) + + dnl Support for AM_XGETTEXT_OPTION. + test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS= + AC_SUBST([XGETTEXT_EXTRA_OPTIONS]) + + AC_CONFIG_COMMANDS([po-directories], [[ + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + # Treat a directory as a PO directory if and only if it has a + # POTFILES.in file. This allows packages to have multiple PO + # directories under different names or in different locations. + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + POMAKEFILEDEPS="POTFILES.in" + # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assigment from automake < 1.5. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # The set of available languages was given in configure.in. + # Hide the ALL_LINGUAS assigment from automake < 1.5. + eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' + fi + # Compute POFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) + # Compute UPDATEPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) + # Compute DUMMYPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) + # Compute GMOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + UPDATEPOFILES= + DUMMYPOFILES= + GMOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done]], + [# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it + # from automake < 1.5. + eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + ]) +]) + +dnl Postprocesses a Makefile in a directory containing PO files. +AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], +[ + # When this code is run, in config.status, two variables have already been + # set: + # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, + # - LINGUAS is the value of the environment variable LINGUAS at configure + # time. + +changequote(,)dnl + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + # Find a way to echo strings without interpreting backslash. + if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then + gt_echo='echo' + else + if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then + gt_echo='printf %s\n' + else + echo_func () { + cat <<EOT +$* +EOT + } + gt_echo='echo_func' + fi + fi + + # A sed script that extracts the value of VARIABLE from a Makefile. + sed_x_variable=' +# Test if the hold space is empty. +x +s/P/P/ +x +ta +# Yes it was empty. Look if we have the expected variable definition. +/^[ ]*VARIABLE[ ]*=/{ + # Seen the first line of the variable definition. + s/^[ ]*VARIABLE[ ]*=// + ba +} +bd +:a +# Here we are processing a line from the variable definition. +# Remove comment, more precisely replace it with a space. +s/#.*$/ / +# See if the line ends in a backslash. +tb +:b +s/\\$// +# Print the line, without the trailing backslash. +p +tc +# There was no trailing backslash. The end of the variable definition is +# reached. Clear the hold space. +s/^.*$// +x +bd +:c +# A trailing backslash means that the variable definition continues in the +# next line. Put a nonempty string into the hold space to indicate this. +s/^.*$/P/ +x +:d +' +changequote([,])dnl + + # Set POTFILES to the value of the Makefile variable POTFILES. + sed_x_POTFILES=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/POTFILES/g'` + POTFILES=`sed -n -e "$sed_x_POTFILES" < "$ac_file"` + # Compute POTFILES_DEPS as + # $(foreach file, $(POTFILES), $(top_srcdir)/$(file)) + POTFILES_DEPS= + for file in $POTFILES; do + POTFILES_DEPS="$POTFILES_DEPS "'$(top_srcdir)/'"$file" + done + POMAKEFILEDEPS="" + + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # Set ALL_LINGUAS to the value of the Makefile variable LINGUAS. + sed_x_LINGUAS=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/LINGUAS/g'` + ALL_LINGUAS_=`sed -n -e "$sed_x_LINGUAS" < "$ac_file"` + fi + # Hide the ALL_LINGUAS assigment from automake < 1.5. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + # Compute POFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) + # Compute UPDATEPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) + # Compute DUMMYPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) + # Compute GMOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) + # Compute PROPERTIESFILES + # as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).properties) + # Compute CLASSFILES + # as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).class) + # Compute QMFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).qm) + # Compute MSGFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang)).msg) + # Compute RESOURCESDLLFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang))/$(DOMAIN).resources.dll) + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + UPDATEPOFILES= + DUMMYPOFILES= + GMOFILES= + PROPERTIESFILES= + CLASSFILES= + QMFILES= + MSGFILES= + RESOURCESDLLFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + PROPERTIESFILES="$PROPERTIESFILES \$(top_srcdir)/\$(DOMAIN)_$lang.properties" + CLASSFILES="$CLASSFILES \$(top_srcdir)/\$(DOMAIN)_$lang.class" + QMFILES="$QMFILES $srcdirpre$lang.qm" + frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` + MSGFILES="$MSGFILES $srcdirpre$frobbedlang.msg" + frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` + RESOURCESDLLFILES="$RESOURCESDLLFILES $srcdirpre$frobbedlang/\$(DOMAIN).resources.dll" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + JAVACATALOGS= + QTCATALOGS= + TCLCATALOGS= + CSHARPCATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + JAVACATALOGS="$JAVACATALOGS \$(DOMAIN)_$lang.properties" + QTCATALOGS="$QTCATALOGS $lang.qm" + frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` + TCLCATALOGS="$TCLCATALOGS $frobbedlang.msg" + frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` + CSHARPCATALOGS="$CSHARPCATALOGS $frobbedlang/\$(DOMAIN).resources.dll" + done + fi + + sed -e "s|@POTFILES_DEPS@|$POTFILES_DEPS|g" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@PROPERTIESFILES@|$PROPERTIESFILES|g" -e "s|@CLASSFILES@|$CLASSFILES|g" -e "s|@QMFILES@|$QMFILES|g" -e "s|@MSGFILES@|$MSGFILES|g" -e "s|@RESOURCESDLLFILES@|$RESOURCESDLLFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@JAVACATALOGS@|$JAVACATALOGS|g" -e "s|@QTCATALOGS@|$QTCATALOGS|g" -e "s|@TCLCATALOGS@|$TCLCATALOGS|g" -e "s|@CSHARPCATALOGS@|$CSHARPCATALOGS|g" -e 's,^#distdir:,distdir:,' < "$ac_file" > "$ac_file.tmp" + if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then + # Add dependencies that cannot be formulated as a simple suffix rule. + for lang in $ALL_LINGUAS; do + frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` + cat >> "$ac_file.tmp" <<EOF +$frobbedlang.msg: $lang.po + @echo "\$(MSGFMT) -c --tcl -d \$(srcdir) -l $lang $srcdirpre$lang.po"; \ + \$(MSGFMT) -c --tcl -d "\$(srcdir)" -l $lang $srcdirpre$lang.po || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; } +EOF + done + fi + if grep -l '@CSHARPCATALOGS@' "$ac_file" > /dev/null; then + # Add dependencies that cannot be formulated as a simple suffix rule. + for lang in $ALL_LINGUAS; do + frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` + cat >> "$ac_file.tmp" <<EOF +$frobbedlang/\$(DOMAIN).resources.dll: $lang.po + @echo "\$(MSGFMT) -c --csharp -d \$(srcdir) -l $lang $srcdirpre$lang.po -r \$(DOMAIN)"; \ + \$(MSGFMT) -c --csharp -d "\$(srcdir)" -l $lang $srcdirpre$lang.po -r "\$(DOMAIN)" || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; } +EOF + done + fi + if test -n "$POMAKEFILEDEPS"; then + cat >> "$ac_file.tmp" <<EOF +Makefile: $POMAKEFILEDEPS +EOF + fi + mv "$ac_file.tmp" "$ac_file" +]) + +dnl Initializes the accumulator used by AM_XGETTEXT_OPTION. +AC_DEFUN([AM_XGETTEXT_OPTION_INIT], +[ + XGETTEXT_EXTRA_OPTIONS= +]) + +dnl Registers an option to be passed to xgettext in the po subdirectory. +AC_DEFUN([AM_XGETTEXT_OPTION], +[ + AC_REQUIRE([AM_XGETTEXT_OPTION_INIT]) + XGETTEXT_EXTRA_OPTIONS="$XGETTEXT_EXTRA_OPTIONS $1" +]) diff --git a/src/wok/plugins/kimchi/m4/progtest.m4 b/src/wok/plugins/kimchi/m4/progtest.m4 new file mode 100644 index 0000000..2d804ac --- /dev/null +++ b/src/wok/plugins/kimchi/m4/progtest.m4 @@ -0,0 +1,92 @@ +# progtest.m4 serial 6 (gettext-0.18) +dnl Copyright (C) 1996-2003, 2005, 2008-2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper <drepper@cygnus.com>, 1996. + +AC_PREREQ([2.50]) + +# Search path for a program which passes the given test. + +dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST], +[ +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL([ac_cv_path_$1], +[case "[$]$1" in + [[\\/]]* | ?:[[\\/]]*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in ifelse([$5], , $PATH, [$5]); do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then + AC_MSG_RESULT([$][$1]) +else + AC_MSG_RESULT([no]) +fi +AC_SUBST([$1])dnl +]) diff --git a/src/wok/plugins/kimchi/mockmodel.py b/src/wok/plugins/kimchi/mockmodel.py new file mode 100644 index 0000000..b269c26 --- /dev/null +++ b/src/wok/plugins/kimchi/mockmodel.py @@ -0,0 +1,627 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import libvirt +import lxml.etree as ET +import os +import random +import time +from lxml import objectify +from lxml.builder import E + +from wok.exception import NotFoundError, OperationFailed +from wok.objectstore import ObjectStore +from wok.utils import add_task, get_next_clone_name, wok_log +from wok.xmlutils.utils import xml_item_update + +import config +import imageinfo +import osinfo +from model import cpuinfo +from model.debugreports import DebugReportsModel +from model.host import DeviceModel +from model.libvirtstoragepool import IscsiPoolDef, NetfsPoolDef +from model.libvirtstoragepool import StoragePoolDef +from model.model import Model +from model.storagepools import StoragePoolModel +from model.storagevolumes import StorageVolumeModel, StorageVolumesModel +from model.templates import LibvirtVMTemplate +from model.users import PAMUsersModel +from model.groups import PAMGroupsModel +from vmtemplate import VMTemplate + + +fake_user = {'root': 'letmein!'} +mockmodel_defaults = { + 'storagepool': '/plugins/kimchi/storagepools/default-pool', + 'domain': 'test', 'arch': 'i686' +} + + +class MockModel(Model): + _mock_vms = {} + _mock_snapshots = {} + _XMLDesc = libvirt.virDomain.XMLDesc + _defineXML = libvirt.virConnect.defineXML + _undefineDomain = libvirt.virDomain.undefine + _libvirt_get_vol_path = LibvirtVMTemplate._get_volume_path + + def __init__(self, objstore_loc=None): + # Override osinfo.defaults to ajust the values according to + # test:///default driver + defaults = dict(osinfo.defaults) + defaults.update(mockmodel_defaults) + osinfo.defaults = dict(defaults) + + self._mock_devices = MockDevices() + self._mock_partitions = MockPartitions() + self._mock_storagevolumes = MockStorageVolumes() + self._mock_swupdate = MockSoftwareUpdate() + self._mock_repositories = MockRepositories() + + cpuinfo.get_topo_capabilities = \ + MockModel.get_topo_capabilities + libvirt.virConnect.defineXML = MockModel.domainDefineXML + libvirt.virDomain.XMLDesc = MockModel.domainXMLDesc + libvirt.virDomain.undefine = MockModel.undefineDomain + libvirt.virDomain.attachDeviceFlags = MockModel.attachDeviceFlags + libvirt.virDomain.detachDeviceFlags = MockModel.detachDeviceFlags + libvirt.virDomain.updateDeviceFlags = MockModel.updateDeviceFlags + libvirt.virStorageVol.resize = MockModel.volResize + libvirt.virStorageVol.wipePattern = MockModel.volWipePattern + + IscsiPoolDef.prepare = NetfsPoolDef.prepare = StoragePoolDef.prepare + + PAMUsersModel.auth_type = 'fake' + PAMGroupsModel.auth_type = 'fake' + + super(MockModel, self).__init__('test:///default', objstore_loc) + self.objstore_loc = objstore_loc + self.objstore = ObjectStore(objstore_loc) + + # The MockModel methods are instantiated on runtime according to Model + # and BaseModel + # Because that a normal method override will not work here + # Instead of that we also need to do the override on runtime + for method in dir(self): + if method.startswith('_mock_'): + mock_method = getattr(self, method) + if not callable(mock_method): + continue + + m = method[6:] + model_method = getattr(self, m) + setattr(self, '_model_' + m, model_method) + setattr(self, m, mock_method) + + DeviceModel.lookup = self._mock_device_lookup + StoragePoolModel._update_lvm_disks = self._update_lvm_disks + StorageVolumesModel.get_list = self._mock_storagevolumes_get_list + StorageVolumeModel.doUpload = self._mock_storagevolume_doUpload + DebugReportsModel._gen_debugreport_file = self._gen_debugreport_file + LibvirtVMTemplate._get_volume_path = self._get_volume_path + VMTemplate.get_iso_info = self._probe_image + imageinfo.probe_image = self._probe_image + + def reset(self): + MockModel._mock_vms = {} + MockModel._mock_snapshots = {} + self._mock_swupdate = MockSoftwareUpdate() + self._mock_repositories = MockRepositories() + + if hasattr(self, 'objstore'): + self.objstore = ObjectStore(self.objstore_loc) + + params = {'vms': [u'test'], 'templates': [], + 'networks': [u'default'], 'storagepools': [u'default-pool']} + + for res, items in params.iteritems(): + resources = getattr(self, '%s_get_list' % res)() + for i in resources: + if i in items: + continue + + try: + getattr(self, '%s_deactivate' % res[:-1])(i) + except: + pass + + getattr(self, '%s_delete' % res[:-1])(i) + + volumes = self.storagevolumes_get_list('default-pool') + for v in volumes: + self.storagevolume_delete('default-pool', v) + + @staticmethod + def get_topo_capabilities(conn): + # The libvirt test driver doesn't return topology. + xml = "<topology sockets='1' cores='2' threads='2'/>" + return ET.fromstring(xml) + + @staticmethod + def domainDefineXML(conn, xml): + name = objectify.fromstring(xml).name.text + try: + dom = conn.lookupByName(name) + if not dom.isActive(): + MockModel._mock_vms[name] = xml + except: + pass + + return MockModel._defineXML(conn, xml) + + @staticmethod + def domainXMLDesc(dom, flags=0): + return MockModel._mock_vms.get(dom.name(), + MockModel._XMLDesc(dom, flags)) + + @staticmethod + def undefineDomain(dom): + name = dom.name() + if name in MockModel._mock_vms.keys(): + del MockModel._mock_vms[dom.name()] + return MockModel._undefineDomain(dom) + + @staticmethod + def attachDeviceFlags(dom, xml, flags=0): + old_xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) + root = objectify.fromstring(old_xml) + dev = objectify.fromstring(xml) + root.devices.append(dev) + + MockModel._mock_vms[dom.name()] = ET.tostring(root, encoding="utf-8") + + @staticmethod + def _get_device_node(dom, xml): + xpath_map = {'disk': 'target', + 'interface': 'mac', + 'graphics': 'listen'} + + dev = objectify.fromstring(xml) + dev_id = dev.find(xpath_map[dev.tag]).items() + + dev_filter = '' + for key, value in dev_id: + dev_filter += "[@%s='%s']" % (key, value) + + old_xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) + root = objectify.fromstring(old_xml) + devices = root.devices + + dev = devices.find("./%s/%s%s/.." % (dev.tag, xpath_map[dev.tag], + dev_filter)) + + return (root, dev) + + @staticmethod + def detachDeviceFlags(dom, xml, flags=0): + root, dev = MockModel._get_device_node(dom, xml) + root.devices.remove(dev) + + MockModel._mock_vms[dom.name()] = ET.tostring(root, encoding="utf-8") + + @staticmethod + def updateDeviceFlags(dom, xml, flags=0): + root, old_dev = MockModel._get_device_node(dom, xml) + root.devices.replace(old_dev, objectify.fromstring(xml)) + MockModel._mock_vms[dom.name()] = ET.tostring(root, encoding="utf-8") + + @staticmethod + def volResize(vol, size, flags=0): + new_xml = xml_item_update(vol.XMLDesc(0), './capacity', str(size)) + vol.delete(0) + pool = vol.storagePoolLookupByVolume() + pool.createXML(new_xml) + + @staticmethod + def volWipePattern(vol, algorithm, flags=0): + new_xml = xml_item_update(vol.XMLDesc(0), './allocation', '0') + vol.delete(0) + pool = vol.storagePoolLookupByVolume() + pool.createXML(new_xml) + + def _probe_image(self, path): + return ('unknown', 'unknown') + + def _get_volume_path(self, pool, vol): + pool_info = self.storagepool_lookup(pool) + if pool_info['type'] == 'scsi': + return self._mock_storagevolumes.scsi_volumes[vol]['path'] + + return MockModel._libvirt_get_vol_path(pool, vol) + + def _gen_debugreport_file(self, name): + return add_task('/plugins/kimchi/debugreports/%s' % name, + self._create_log, self.objstore, name) + + def _create_log(self, cb, name): + path = config.get_debugreports_path() + tmpf = os.path.join(path, name + '.tmp') + realf = os.path.join(path, name + '.txt') + length = random.randint(1000, 10000) + with open(tmpf, 'w') as fd: + while length: + fd.write('I am logged') + length = length - 1 + os.rename(tmpf, realf) + cb("OK", True) + + def _update_lvm_disks(self, pool_name, disks): + conn = self.conn.get() + pool = conn.storagePoolLookupByName(pool_name.encode('utf-8')) + xml = pool.XMLDesc(0) + + root = ET.fromstring(xml) + source = root.xpath('./source')[0] + + for d in disks: + dev = E.device(path=d) + source.append(dev) + + conn.storagePoolDefineXML(ET.tostring(root), 0) + + def _mock_host_shutdown(self, *name): + wok_log.info("The host system will be shutted down") + + def _mock_host_reboot(self, *name): + wok_log.info("The host system will be rebooted") + + def _mock_storagevolumes_create(self, pool, params): + vol_source = ['url', 'capacity'] + index_list = list(i for i in range(len(vol_source)) + if vol_source[i] in params) + create_param = vol_source[index_list[0]] + name = params.get('name') + if name is None and create_param == 'url': + params['name'] = os.path.basename(params['url']) + del params['url'] + params['capacity'] = 1024 + + return self._model_storagevolumes_create(pool, params) + + def _mock_storagevolumes_get_list(self, pool): + pool_info = self.storagepool_lookup(pool) + if pool_info['type'] == 'scsi': + return self._mock_storagevolumes.scsi_volumes.keys() + + return self._model_storagevolumes_get_list(pool) + + def _mock_storagevolume_lookup(self, pool, vol): + pool_info = self.storagepool_lookup(pool) + if pool_info['type'] == 'scsi': + return self._mock_storagevolumes.scsi_volumes[vol] + + return self._model_storagevolume_lookup(pool, vol) + + def _mock_storagevolume_doUpload(self, cb, vol, offset, data, data_size): + vol_path = vol.path() + + # MockModel does not create the storage volume as a file + # So create it to do the file upload + if offset == 0: + dirname = os.path.dirname(vol_path) + if not os.path.exists(dirname): + os.makedirs(dirname) + open(vol_path, 'w').close() + + try: + with open(vol_path, 'a') as fd: + fd.seek(offset) + fd.write(data) + except Exception, e: + os.remove(vol_path) + cb('', False) + raise OperationFailed("KCHVOL0029E", {"err": e.message}) + + def _mock_partitions_get_list(self): + return self._mock_partitions.partitions.keys() + + def _mock_partition_lookup(self, name): + return self._mock_partitions.partitions[name] + + def _mock_devices_get_list(self, _cap=None, _passthrough=None, + _passthrough_affected_by=None): + if _cap is None: + return self._mock_devices.devices.keys() + + if _cap == 'fc_host': + _cap = 'scsi_host' + + return [dev['name'] for dev in self._mock_devices.devices.values() + if dev['device_type'] == _cap] + + def _mock_device_lookup(self, dev_name): + return self._mock_devices.devices[dev_name] + + def _mock_packagesupdate_get_list(self): + return self._mock_swupdate.pkgs.keys() + + def _mock_packageupdate_lookup(self, pkg_name): + return self._mock_swupdate.pkgs[pkg_name] + + def _mock_host_swupdate(self, args=None): + task_id = add_task('/plugins/kimchi/host/swupdate', + self._mock_swupdate.doUpdate, self.objstore) + return self.task_lookup(task_id) + + def _mock_repositories_get_list(self): + return self._mock_repositories.repos.keys() + + def _mock_repositories_create(self, params): + # Create a repo_id if not given by user. The repo_id will follow + # the format kimchi_repo_<integer>, where integer is the number of + # seconds since the Epoch (January 1st, 1970), in UTC. + repo_id = params.get('repo_id', None) + if repo_id is None: + repo_id = "kimchi_repo_%s" % str(int(time.time() * 1000)) + params.update({'repo_id': repo_id}) + + config = params.get('config', {}) + info = {'repo_id': repo_id, + 'baseurl': params['baseurl'], + 'enabled': True, + 'config': {'repo_name': config.get('repo_name', repo_id), + 'gpgkey': config.get('gpgkey', []), + 'gpgcheck': True, + 'mirrorlist': params.get('mirrorlist', '')}} + self._mock_repositories.repos[repo_id] = info + return repo_id + + def _mock_repository_lookup(self, repo_id): + return self._mock_repositories.repos[repo_id] + + def _mock_repository_delete(self, repo_id): + del self._mock_repositories.repos[repo_id] + + def _mock_repository_enable(self, repo_id): + self._mock_repositories.repos[repo_id]['enabled'] = True + + def _mock_repository_disable(self, repo_id): + self._mock_repositories.repos[repo_id]['enabled'] = False + + def _mock_repository_update(self, repo_id, params): + self._mock_repositories.repos[repo_id].update(params) + return repo_id + + def _mock_vm_clone(self, name): + new_name = get_next_clone_name(self.vms_get_list(), name) + snapshots = MockModel._mock_snapshots.get(name, []) + MockModel._mock_snapshots[new_name] = snapshots + return self._model_vm_clone(name) + + def _mock_vmsnapshots_create(self, vm_name, params): + name = params.get('name', unicode(int(time.time()))) + params = {'vm_name': vm_name, 'name': name} + taskid = add_task(u'/plugins/kimchi/vms/%s/snapshots/%s' % + (vm_name, name), self._vmsnapshots_create_task, + self.objstore, params) + return self.task_lookup(taskid) + + def _vmsnapshots_create_task(self, cb, params): + vm_name = params['vm_name'] + name = params['name'] + parent = u'' + + snapshots = MockModel._mock_snapshots.get(vm_name, []) + for sn in snapshots: + if sn.current: + sn.current = False + parent = sn.name + + snapshots.append(MockVMSnapshot(name, {'parent': parent})) + MockModel._mock_snapshots[vm_name] = snapshots + + cb('OK', True) + + def _mock_vmsnapshots_get_list(self, vm_name): + snapshots = MockModel._mock_snapshots.get(vm_name, []) + return sorted([snap.name for snap in snapshots]) + + def _mock_currentvmsnapshot_lookup(self, vm_name): + for sn in MockModel._mock_snapshots.get(vm_name, []): + if sn.current: + return sn.info + + def _mock_vmsnapshot_lookup(self, vm_name, name): + for sn in MockModel._mock_snapshots.get(vm_name, []): + if sn.name == name: + return sn.info + + raise NotFoundError('KCHSNAP0003E', {'name': name, 'vm': vm_name}) + + def _mock_vmsnapshot_delete(self, vm_name, name): + snapshots = MockModel._mock_snapshots.get(vm_name, []) + for sn in snapshots: + if sn.name == name: + del snapshots[snapshots.index(sn)] + + MockModel._mock_snapshots[vm_name] = snapshots + + def _mock_vmsnapshot_revert(self, vm_name, name): + snapshots = MockModel._mock_snapshots.get(vm_name, []) + for sn in snapshots: + if sn.current: + sn.current = False + + for sn in snapshots: + if sn.name == name: + sn.current = True + + +class MockStorageVolumes(object): + def __init__(self): + base_path = "/dev/disk/by-path/pci-0000:0e:00.0-fc-0x20-lun" + self.scsi_volumes = {'unit:0:0:1': {'capacity': 1024, + 'format': 'unknown', + 'allocation': 512, + 'type': 'block', + 'path': base_path + '1', + 'used_by': []}, + 'unit:0:0:2': {'capacity': 2048, + 'format': 'unknown', + 'allocation': 512, + 'type': 'block', + 'path': base_path + '2', + 'used_by': []}} + + +class MockPartitions(object): + def __init__(self): + self.partitions = {"vdx": {"available": True, "name": "vdx", + "fstype": "", "path": "/dev/vdx", + "mountpoint": "", "type": "disk", + "size": "2147483648"}, + "vdz": {"available": True, "name": "vdz", + "fstype": "", "path": "/dev/vdz", + "mountpoint": "", "type": "disk", + "size": "2147483648"}} + + +class MockDevices(object): + def __init__(self): + self.devices = { + 'computer': {'device_type': 'system', + 'firmware': {'release_date': '01/01/2012', + 'vendor': 'LENOVO', + 'version': 'XXXXX (X.XX )'}, + 'hardware': {'serial': 'PXXXXX', + 'uuid': + '9d660370-820f-4241-8731-5a60c97e8aa6', + 'vendor': 'LENOVO', + 'version': 'ThinkPad T420'}, + 'name': 'computer', + 'parent': None, + 'product': '4180XXX'}, + 'pci_0000_03_00_0': {'bus': 3, + 'device_type': 'pci', + 'domain': 0, + 'driver': {'name': 'iwlwifi'}, + 'function': 0, + 'iommuGroup': 7, + 'name': 'pci_0000_03_00_0', + 'parent': 'computer', + 'path': + '/sys/devices/pci0000:00/0000:03:00.0', + 'product': { + 'description': + 'Centrino Advanced-N 6205 [Taylor Peak]', + 'id': '0x0085'}, + 'slot': 0, + 'vendor': {'description': 'Intel Corporation', + 'id': '0x8086'}}, + 'pci_0000_0d_00_0': {'bus': 13, + 'device_type': 'pci', + 'domain': 0, + 'driver': {'name': 'sdhci-pci'}, + 'function': 0, + 'iommuGroup': 7, + 'name': 'pci_0000_0d_00_0', + 'parent': 'computer', + 'path': + '/sys/devices/pci0000:00/0000:0d:00.0', + 'product': {'description': + 'PCIe SDXC/MMC Host Controller', + 'id': '0xe823'}, + 'slot': 0, + 'vendor': {'description': 'Ricoh Co Ltd', + 'id': '0x1180'}}, + 'scsi_host0': {'adapter': {'fabric_wwn': '37df6c1efa1b4388', + 'type': 'fc_host', + 'wwnn': 'efb6563f06434a98', + 'wwpn': '742f32073aab45d7'}, + 'device_type': 'scsi_host', + 'host': 0, + 'name': 'scsi_host0', + 'parent': 'computer', + 'path': '/sys/devices/pci0000:00/0000:40:00.0/0'}, + 'scsi_host1': {'adapter': {'fabric_wwn': '542efa5dced34123', + 'type': 'fc_host', + 'wwnn': 'b7433a40c9b84092', + 'wwpn': '25c1f485ae42497f'}, + 'device_type': 'scsi_host', + 'host': 0, + 'name': 'scsi_host1', + 'parent': 'computer', + 'path': '/sys/devices/pci0000:00/0000:40:00.0/1'}, + 'scsi_host2': {'adapter': {'fabric_wwn': '5c373c334c20478d', + 'type': 'fc_host', + 'wwnn': 'f2030bec4a254e6b', + 'wwpn': '07dbca4164d44096'}, + 'device_type': 'scsi_host', + 'host': 0, + 'name': 'scsi_host2', + 'parent': 'computer', + 'path': '/sys/devices/pci0000:00/0000:40:00.0/2'}} + + +class MockSoftwareUpdate(object): + def __init__(self): + self.pkgs = { + 'udevmountd': {'repository': 'openSUSE-13.1-Update', + 'version': '0.81.5-14.1', + 'arch': 'x86_64', + 'package_name': 'udevmountd'}, + 'sysconfig-network': {'repository': 'openSUSE-13.1-Extras', + 'version': '0.81.5-14.1', + 'arch': 'x86_64', + 'package_name': 'sysconfig-network'}, + 'libzypp': {'repository': 'openSUSE-13.1-Update', + 'version': '13.9.0-10.1', + 'arch': 'noarch', + 'package_name': 'libzypp'}} + self._num2update = 3 + + def doUpdate(self, cb, params): + msgs = [] + for pkg in self.pkgs.keys(): + msgs.append("Updating package %s" % pkg) + cb('\n'.join(msgs)) + time.sleep(1) + + time.sleep(2) + msgs.append("All packages updated") + cb('\n'.join(msgs), True) + + # After updating all packages any package should be listed to be + # updated, so reset self._packages + self.pkgs = {} + + +class MockRepositories(object): + def __init__(self): + self.repos = {"kimchi_repo_1392167832": + {"repo_id": "kimchi_repo_1392167832", + "enabled": True, + "baseurl": "http://www.fedora.org", + "config": {"repo_name": "kimchi_repo_1392167832", + "gpgkey": [], + "gpgcheck": True, + "mirrorlist": ""}}} + + +class MockVMSnapshot(object): + def __init__(self, name, params={}): + self.name = name + self.current = True + + self.info = {'created': params.get('created', + unicode(int(time.time()))), + 'name': name, + 'parent': params.get('parent', u''), + 'state': params.get('state', u'shutoff')} diff --git a/src/wok/plugins/kimchi/model/Makefile.am b/src/wok/plugins/kimchi/model/Makefile.am new file mode 100644 index 0000000..f4f4750 --- /dev/null +++ b/src/wok/plugins/kimchi/model/Makefile.am @@ -0,0 +1,25 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +model_PYTHON = *.py + +modeldir = $(pythondir)/wok/plugins/kimchi/model + +install-data-local: + $(MKDIR_P) $(DESTDIR)$(modeldir) diff --git a/src/wok/plugins/kimchi/model/__init__.py b/src/wok/plugins/kimchi/model/__init__.py new file mode 100644 index 0000000..ca7ede4 --- /dev/null +++ b/src/wok/plugins/kimchi/model/__init__.py @@ -0,0 +1,18 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/src/wok/plugins/kimchi/model/config.py b/src/wok/plugins/kimchi/model/config.py new file mode 100644 index 0000000..464ffae --- /dev/null +++ b/src/wok/plugins/kimchi/model/config.py @@ -0,0 +1,176 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import cherrypy +from multiprocessing.pool import ThreadPool + +from wok.basemodel import Singleton +from wok.config import config as kconfig +from wok.config import get_version +from wok.exception import NotFoundError +from wok.utils import check_url_path, run_command, wok_log + +from ..config import find_qemu_binary +from ..distroloader import DistroLoader +from ..repositories import Repositories +from ..screenshot import VMScreenshot +from ..swupdate import SoftwareUpdate +from debugreports import DebugReportsModel +from featuretests import FeatureTests, FEATURETEST_POOL_NAME +from featuretests import FEATURETEST_VM_NAME + + +class ConfigModel(object): + def __init__(self, **kargs): + pass + + def lookup(self, name): + proxy_port = kconfig.get('display', 'display_proxy_port') + return {'display_proxy_port': proxy_port, + 'version': get_version()} + + +class CapabilitiesModel(object): + __metaclass__ = Singleton + + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.qemu_stream = False + self.libvirt_stream_protocols = [] + self.fc_host_support = False + self.metadata_support = False + self.kernel_vfio = False + self.mem_hotplug_support = False + + # Subscribe function to set host capabilities to be run when cherrypy + # server is up + # It is needed because some features tests depends on the server + cherrypy.engine.subscribe('start', self._set_capabilities) + + # Subscribe function to clean any Kimchi leftovers + cherrypy.engine.subscribe('stop', self._clean_leftovers) + + def _clean_leftovers(self): + conn = self.conn.get() + FeatureTests.disable_libvirt_error_logging() + try: + dom = conn.lookupByName(FEATURETEST_VM_NAME) + dom.undefine() + except Exception: + # Any exception can be ignored here + pass + + try: + pool = conn.storagePoolLookupByName(FEATURETEST_POOL_NAME) + pool.undefine() + except Exception: + # Any exception can be ignored here + pass + + FeatureTests.enable_libvirt_error_logging() + + def _set_capabilities(self): + wok_log.info("*** Running feature tests ***") + conn = self.conn.get() + self.qemu_stream = FeatureTests.qemu_supports_iso_stream() + self.nfs_target_probe = FeatureTests.libvirt_support_nfs_probe(conn) + self.fc_host_support = FeatureTests.libvirt_support_fc_host(conn) + self.metadata_support = FeatureTests.has_metadata_support(conn) + self.kernel_vfio = FeatureTests.kernel_support_vfio() + self.mem_hotplug_support = FeatureTests.has_mem_hotplug_support(conn) + + self.libvirt_stream_protocols = [] + for p in ['http', 'https', 'ftp', 'ftps', 'tftp']: + if FeatureTests.libvirt_supports_iso_stream(conn, p): + self.libvirt_stream_protocols.append(p) + + wok_log.info("*** Feature tests completed ***") + _set_capabilities.priority = 90 + + def _qemu_support_spice(self): + qemu_path = find_qemu_binary(find_emulator=True) + out, err, rc = run_command(['ldd', qemu_path]) + if rc != 0: + wok_log.error('Failed to find qemu binary dependencies: %s', + err) + return False + for line in out.split('\n'): + if line.lstrip().startswith('libspice-server.so'): + return True + return False + + def lookup(self, *ident): + report_tool = DebugReportsModel.get_system_report_tool() + try: + SoftwareUpdate() + except Exception: + update_tool = False + else: + update_tool = True + + try: + repo = Repositories() + except Exception: + repo_mngt_tool = None + else: + repo_mngt_tool = repo._pkg_mnger.TYPE + + return {'libvirt_stream_protocols': self.libvirt_stream_protocols, + 'qemu_spice': self._qemu_support_spice(), + 'qemu_stream': self.qemu_stream, + 'screenshot': VMScreenshot.get_stream_test_result(), + 'system_report_tool': bool(report_tool), + 'update_tool': update_tool, + 'repo_mngt_tool': repo_mngt_tool, + 'federation': kconfig.get("server", "federation"), + 'auth': kconfig.get("authentication", "method"), + 'kernel_vfio': self.kernel_vfio, + 'nm_running': FeatureTests.is_nm_running(), + 'mem_hotplug_support': self.mem_hotplug_support + } + + +class DistrosModel(object): + def __init__(self, **kargs): + distroloader = DistroLoader() + self.distros = distroloader.get() + + def get_list(self): + def validate_distro(distro): + if check_url_path(distro['path']): + return distro['name'] + + n_processes = len(self.distros.keys()) + pool = ThreadPool(processes=n_processes) + map_res = pool.map_async(validate_distro, self.distros.values()) + pool.close() + pool.join() + res = list(set(map_res.get()) - set([None])) + return sorted(res) + + +class DistroModel(object): + def __init__(self, **kargs): + self._distros = DistrosModel() + + def lookup(self, name): + try: + return self._distros.distros[name] + except KeyError: + raise NotFoundError("KCHDISTRO0001E", {'name': name}) diff --git a/src/wok/plugins/kimchi/model/cpuinfo.py b/src/wok/plugins/kimchi/model/cpuinfo.py new file mode 100644 index 0000000..299e445 --- /dev/null +++ b/src/wok/plugins/kimchi/model/cpuinfo.py @@ -0,0 +1,126 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import platform +from xml.etree import ElementTree as ET + +from wok.exception import InvalidParameter, InvalidOperation +from wok.utils import run_command, wok_log + + +ARCH = 'power' if platform.machine().startswith('ppc') else 'x86' + + +def get_topo_capabilities(connect): + """ + This helper function exists solely to be overridden for + mockmodel tests. Since other modules use getCapabilies(), + it can't be overridden directly. + """ + xml = connect.getCapabilities() + capabilities = ET.fromstring(xml) + return capabilities.find('host').find('cpu').find('topology') + + +class CPUInfoModel(object): + """ + Get information about a CPU for hyperthreading (on x86) + or SMT (on POWER) for logic when creating templates and VMs. + """ + + def __init__(self, **kargs): + self.guest_threads_enabled = False + self.sockets = 0 + self.cores_present = 0 + self.cores_available = 0 + self.cores_per_socket = 0 + self.threads_per_core = 0 + self.max_threads = 0 + + self.conn = kargs['conn'] + libvirt_topology = None + try: + connect = self.conn.get() + libvirt_topology = get_topo_capabilities(connect) + except Exception as e: + wok_log.info("Unable to get CPU topology capabilities: %s" + % e.message) + return + if libvirt_topology is None: + wok_log.info("cpu_info topology not supported.") + return + + if ARCH == 'power': + # IBM PowerPC + self.guest_threads_enabled = True + out, error, rc = run_command(['ppc64_cpu', '--smt']) + if rc or 'on' in out: + # SMT has to be disabled for guest to use threads as CPUs. + # rc is always zero, whether SMT is off or on. + self.guest_threads_enabled = False + out, error, rc = run_command(['ppc64_cpu', '--cores-present']) + if not rc: + self.cores_present = int(out.split()[-1]) + out, error, rc = run_command(['ppc64_cpu', '--cores-on']) + if not rc: + self.cores_available = int(out.split()[-1]) + out, error, rc = run_command(['ppc64_cpu', '--threads-per-core']) + if not rc: + self.threads_per_core = int(out.split()[-1]) + self.sockets = self.cores_present/self.threads_per_core + if self.sockets == 0: + self.sockets = 1 + self.cores_per_socket = self.cores_present/self.sockets + else: + # Intel or AMD + self.guest_threads_enabled = True + self.sockets = int(libvirt_topology.get('sockets')) + self.cores_per_socket = int(libvirt_topology.get('cores')) + self.cores_present = self.cores_per_socket * self.sockets + self.cores_available = self.cores_present + self.threads_per_core = int(libvirt_topology.get('threads')) + + def lookup(self, ident): + return { + 'guest_threads_enabled': self.guest_threads_enabled, + 'sockets': self.sockets, + 'cores_per_socket': self.cores_per_socket, + 'cores_present': self.cores_present, + 'cores_available': self.cores_available, + 'threads_per_core': self.threads_per_core, + } + + def check_topology(self, vcpus, topology): + """ + param vcpus: should be an integer + param iso_path: the path of the guest ISO + param topology: {'sockets': x, 'cores': x, 'threads': x} + """ + sockets = topology['sockets'] + cores = topology['cores'] + threads = topology['threads'] + + if not self.guest_threads_enabled: + raise InvalidOperation("KCHCPUINF0003E") + if vcpus != sockets * cores * threads: + raise InvalidParameter("KCHCPUINF0002E") + if vcpus > self.cores_available * self.threads_per_core: + raise InvalidParameter("KCHCPUINF0001E") + if threads > self.threads_per_core: + raise InvalidParameter("KCHCPUINF0002E") diff --git a/src/wok/plugins/kimchi/model/debugreports.py b/src/wok/plugins/kimchi/model/debugreports.py new file mode 100644 index 0000000..48e6b26 --- /dev/null +++ b/src/wok/plugins/kimchi/model/debugreports.py @@ -0,0 +1,213 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import fnmatch +import glob +import logging +import os +import shutil +import subprocess +import time + +from wok.exception import InvalidParameter, NotFoundError, OperationFailed +from wok.exception import WokException +from wok.utils import add_task, wok_log +from wok.utils import run_command +from wok.model.tasks import TaskModel + +from .. import config + + +class DebugReportsModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.task = TaskModel(**kargs) + + def create(self, params): + ident = params.get('name').strip() + # Generate a name with time and millisec precision, if necessary + if ident is None or ident == "": + ident = 'report-' + str(int(time.time() * 1000)) + else: + if ident in self.get_list(): + raise InvalidParameter("KCHDR0008E", {"name": ident}) + taskid = self._gen_debugreport_file(ident) + return self.task.lookup(taskid) + + def get_list(self): + path = config.get_debugreports_path() + file_pattern = os.path.join(path, '*.*') + file_lists = glob.glob(file_pattern) + file_lists = [os.path.split(file)[1] for file in file_lists] + name_lists = [file.split('.', 1)[0] for file in file_lists] + + return name_lists + + def _gen_debugreport_file(self, name): + gen_cmd = self.get_system_report_tool() + + if gen_cmd is not None: + return add_task('/plugins/kimchi/debugreports/%s' % name, gen_cmd, + self.objstore, name) + + raise OperationFailed("KCHDR0002E") + + @staticmethod + def sosreport_generate(cb, name): + def log_error(e): + log = logging.getLogger('Model') + log.warning('Exception in generating debug file: %s', e) + + try: + command = ['sosreport', '--batch', '--name=%s' % name] + output, error, retcode = run_command(command) + + if retcode != 0: + raise OperationFailed("KCHDR0003E", {'name': name, + 'err': retcode}) + + # SOSREPORT might create file in /tmp or /var/tmp + # FIXME: The right way should be passing the tar.xz file directory + # though the parameter '--tmp-dir', but it is failing in Fedora 20 + patterns = ['/tmp/sosreport-%s-*', '/var/tmp/sosreport-%s-*'] + reports = [] + reportFile = None + for p in patterns: + reports = reports + [f for f in glob.glob(p % name)] + for f in reports: + if not fnmatch.fnmatch(f, '*.md5'): + reportFile = f + break + # Some error in sosreport happened + if reportFile is None: + wok_log.error('Debug report file not found. See sosreport ' + 'output for detail:\n%s', output) + fname = (patterns[0] % name).split('/')[-1] + raise OperationFailed('KCHDR0004E', {'name': fname}) + + md5_report_file = reportFile + '.md5' + report_file_extension = '.' + reportFile.split('.', 1)[1] + path = config.get_debugreports_path() + target = os.path.join(path, name + report_file_extension) + # Moving report + msg = 'Moving debug report file "%s" to "%s"' % (reportFile, + target) + wok_log.info(msg) + shutil.move(reportFile, target) + # Deleting md5 + msg = 'Deleting report md5 file: "%s"' % (md5_report_file) + wok_log.info(msg) + with open(md5_report_file) as f: + md5 = f.read().strip() + wok_log.info('Md5 file content: "%s"', md5) + os.remove(md5_report_file) + cb('OK', True) + return + + except WokException as e: + log_error(e) + raise + + except OSError as e: + log_error(e) + raise + + except Exception, e: + # No need to call cb to update the task status here. + # The task object will catch the exception raised here + # and update the task status there + log_error(e) + raise OperationFailed("KCHDR0005E", {'name': name, 'err': e}) + + @staticmethod + def get_system_report_tool(): + # Please add new possible debug report command here + # and implement the report generating function + # based on the new report command + report_tools = ({'cmd': 'sosreport --help', + 'fn': DebugReportsModel.sosreport_generate},) + + # check if the command can be found by shell one by one + for helper_tool in report_tools: + try: + retcode = subprocess.call(helper_tool['cmd'], shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + if retcode == 0: + return helper_tool['fn'] + except Exception, e: + wok_log.info('Exception running command: %s', e) + + return None + + +class DebugReportModel(object): + def __init__(self, **kargs): + pass + + def lookup(self, name): + path = config.get_debugreports_path() + file_pattern = os.path.join(path, name) + file_pattern = file_pattern + '.*' + try: + file_target = glob.glob(file_pattern)[0] + except IndexError: + raise NotFoundError("KCHDR0001E", {'name': name}) + + ctime = os.stat(file_target).st_mtime + ctime = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(ctime)) + file_target = os.path.split(file_target)[-1] + file_target = os.path.join("plugins/kimchi/data/debugreports", + file_target) + return {'uri': file_target, + 'ctime': ctime} + + def update(self, name, params): + path = config.get_debugreports_path() + file_pattern = os.path.join(path, name + '.*') + try: + file_source = glob.glob(file_pattern)[0] + except IndexError: + raise NotFoundError("KCHDR0001E", {'name': name}) + + file_target = file_source.replace(name, params['name']) + if os.path.isfile(file_target): + raise InvalidParameter('KCHDR0008E', {'name': params['name']}) + + shutil.move(file_source, file_target) + wok_log.info('%s renamed to %s' % (file_source, file_target)) + return params['name'] + + def delete(self, name): + path = config.get_debugreports_path() + file_pattern = os.path.join(path, name + '.*') + try: + file_target = glob.glob(file_pattern)[0] + except IndexError: + raise NotFoundError("KCHDR0001E", {'name': name}) + + os.remove(file_target) + + +class DebugReportContentModel(object): + def __init__(self, **kargs): + self._debugreport = DebugReportModel() + + def lookup(self, name): + return self._debugreport.lookup(name) diff --git a/src/wok/plugins/kimchi/model/diskutils.py b/src/wok/plugins/kimchi/model/diskutils.py new file mode 100644 index 0000000..350e6eb --- /dev/null +++ b/src/wok/plugins/kimchi/model/diskutils.py @@ -0,0 +1,75 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.exception import OperationFailed, NotFoundError +from wok.utils import wok_log + +from ..xmlutils.disk import get_vm_disk_info, get_vm_disks +from vms import VMModel, VMsModel + +""" + Functions that multiple storage-related models (e.g. VMStoragesModel, + VolumesModel) will need. +""" + + +def get_disk_used_by(objstore, conn, path): + try: + with objstore as session: + try: + used_by = session.get('storagevolume', path)['used_by'] + except (KeyError, NotFoundError): + wok_log.info('Volume %s not found in obj store.' % path) + used_by = [] + # try to find this volume in existing vm + vms_list = VMsModel.get_vms(conn) + for vm in vms_list: + dom = VMModel.get_vm(vm, conn) + storages = get_vm_disks(dom) + for disk in storages.keys(): + d_info = get_vm_disk_info(dom, disk) + if path == d_info['path']: + used_by.append(vm) + try: + session.store('storagevolume', path, + {'used_by': used_by}) + except Exception as e: + # Let the exception be raised. If we allow disks' + # used_by to be out of sync, data corruption could + # occour if a disk is added to two guests + # unknowingly. + wok_log.error('Unable to store storage volume id in' + ' objectstore due error: %s', + e.message) + raise OperationFailed('KCHVOL0017E', + {'err': e.message}) + except Exception as e: + # This exception is going to catch errors returned by 'with', + # specially ones generated by 'session.store'. It is outside + # to avoid conflict with the __exit__ function of 'with' + raise OperationFailed('KCHVOL0017E', {'err': e.message}) + return used_by + + +def set_disk_used_by(objstore, path, new_used_by): + try: + with objstore as session: + session.store('storagevolume', path, {'used_by': new_used_by}) + except Exception as e: + raise OperationFailed('KCHVOL0017E', {'err': e.message}) diff --git a/src/wok/plugins/kimchi/model/featuretests.py b/src/wok/plugins/kimchi/model/featuretests.py new file mode 100644 index 0000000..c53d1aa --- /dev/null +++ b/src/wok/plugins/kimchi/model/featuretests.py @@ -0,0 +1,259 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import cherrypy +import libvirt +import lxml.etree as ET +import platform +import subprocess +from lxml.builder import E + +from wok.rollbackcontext import RollbackContext +from wok.utils import run_command, servermethod, wok_log + + +FEATURETEST_VM_NAME = "FEATURETEST_VM" +FEATURETEST_POOL_NAME = "FEATURETEST_POOL" + +ISO_STREAM_XML = """ +<domain type='%(domain)s'> + <name>%(name)s</name> + <memory unit='KiB'>1048576</memory> + <os> + <type arch='%(arch)s'>hvm</type> + <boot dev='cdrom'/> + </os> + <devices> + <disk type='network' device='cdrom'> + <driver name='qemu' type='raw'/> + <source protocol='%(protocol)s' name='/url/path/to/iso/file'> + <host name='host.name' port='1234'/> + </source> + <target dev='hdc' bus='ide'/> + <readonly/> + <alias name='ide0-1-0'/> + <address type='drive' controller='0' bus='1' target='0' unit='0'/> + </disk> + </devices> +</domain>""" + +SIMPLE_VM_XML = """ +<domain type='%(domain)s'> + <name>%(name)s</name> + <memory unit='KiB'>10240</memory> + <os> + <type arch='%(arch)s'>hvm</type> + <boot dev='hd'/> + </os> +</domain>""" + +MAXMEM_VM_XML = """ +<domain type='%(domain)s'> + <name>%(name)s</name> + <maxMemory slots='1' unit='KiB'>20480</maxMemory> + <memory unit='KiB'>10240</memory> + <os> + <type arch='%(arch)s'>hvm</type> + <boot dev='hd'/> + </os> +</domain>""" + +DEV_MEM_XML = """ +<memory model='dimm'> + <target> + <size unit='KiB'>10240</size> + <node>0</node> + </target> +</memory>""" + +SCSI_FC_XML = """ +<pool type='scsi'> + <name>%(name)s</name> + <source> + <adapter type='fc_host' wwnn='1234567890abcdef' wwpn='abcdef1234567890'/> + </source> + <target> + <path>/dev/disk/by-path</path> + </target> +</pool> +""" + + +class FeatureTests(object): + + @staticmethod + def disable_libvirt_error_logging(): + def libvirt_errorhandler(userdata, error): + # A libvirt error handler to ignore annoying messages in stderr + pass + + # Filter functions are enable only in production env + if cherrypy.config.get('environment') != 'production': + return + # Register the error handler to hide libvirt error in stderr + libvirt.registerErrorHandler(f=libvirt_errorhandler, ctx=None) + + @staticmethod + def enable_libvirt_error_logging(): + # Filter functions are enable only in production env + if cherrypy.config.get('environment') != 'production': + return + # Unregister the error handler + libvirt.registerErrorHandler(f=None, ctx=None) + + @staticmethod + def libvirt_supports_iso_stream(conn, protocol): + conn_type = conn.getType().lower() + domain_type = 'test' if conn_type == 'test' else 'kvm' + arch = 'i686' if conn_type == 'test' else platform.machine() + arch = 'ppc64' if arch == 'ppc64le' else arch + xml = ISO_STREAM_XML % {'name': FEATURETEST_VM_NAME, + 'domain': domain_type, 'protocol': protocol, + 'arch': arch} + try: + FeatureTests.disable_libvirt_error_logging() + dom = conn.defineXML(xml) + dom.undefine() + return True + except libvirt.libvirtError, e: + wok_log.error(e.message) + return False + finally: + FeatureTests.enable_libvirt_error_logging() + + @staticmethod + def libvirt_support_nfs_probe(conn): + def _get_xml(): + obj = E.source(E.host(name='localhost'), E.format(type='nfs')) + xml = ET.tostring(obj) + return xml + try: + FeatureTests.disable_libvirt_error_logging() + conn.findStoragePoolSources('netfs', _get_xml(), 0) + except libvirt.libvirtError as e: + wok_log.error(e.message) + if e.get_error_code() == 38: + # if libvirt cannot find showmount, + # it returns 38--general system call failure + return False + finally: + FeatureTests.enable_libvirt_error_logging() + + return True + + @staticmethod + @servermethod + def qemu_supports_iso_stream(): + host = cherrypy.server.socket_host + port = cherrypy.server.socket_port + cmd = "qemu-io -r http://%s:%d/images/icon-fedora.png \ + -c 'read -v 0 512'" % (host, port) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True) + stdout, stderr = proc.communicate() + return len(stderr) == 0 + + @staticmethod + def libvirt_support_fc_host(conn): + try: + FeatureTests.disable_libvirt_error_logging() + pool = None + pool_xml = SCSI_FC_XML % {'name': FEATURETEST_POOL_NAME} + pool = conn.storagePoolDefineXML(pool_xml, 0) + except libvirt.libvirtError as e: + if e.get_error_code() == 27: + # Libvirt requires adapter name, not needed when supports to FC + return False + finally: + FeatureTests.enable_libvirt_error_logging() + pool is None or pool.undefine() + return True + + @staticmethod + def has_metadata_support(conn): + KIMCHI_META_URL = "https://github.com/kimchi-project/kimchi/" + KIMCHI_NAMESPACE = "kimchi" + with RollbackContext() as rollback: + FeatureTests.disable_libvirt_error_logging() + rollback.prependDefer(FeatureTests.enable_libvirt_error_logging) + conn_type = conn.getType().lower() + domain_type = 'test' if conn_type == 'test' else 'kvm' + arch = 'i686' if conn_type == 'test' else platform.machine() + arch = 'ppc64' if arch == 'ppc64le' else arch + dom = conn.defineXML(SIMPLE_VM_XML % {'name': FEATURETEST_VM_NAME, + 'domain': domain_type, + 'arch': arch}) + rollback.prependDefer(dom.undefine) + try: + dom.setMetadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT, + "<metatest/>", KIMCHI_NAMESPACE, + KIMCHI_META_URL, + flags=libvirt.VIR_DOMAIN_AFFECT_CURRENT) + return True + except libvirt.libvirtError: + return False + + @staticmethod + def kernel_support_vfio(): + out, err, rc = run_command(['modprobe', 'vfio-pci']) + if rc != 0: + wok_log.warning("Unable to load Kernal module vfio-pci.") + return False + return True + + @staticmethod + def is_nm_running(): + '''Tries to determine whether NetworkManager is running.''' + + out, err, rc = run_command(['nmcli', 'dev', 'status']) + if rc != 0: + return False + + return True + + @staticmethod + def has_mem_hotplug_support(conn): + ''' + A memory device can be hot-plugged or hot-unplugged since libvirt + version 1.2.14. + ''' + # Libvirt < 1.2.14 does not support memory devices, so firstly, check + # its version, then try to attach a device. These steps avoid errors + # with Libvirt 'test' driver for KVM + version = 1000000*1 + 1000*2 + 14 + if libvirt.getVersion() < version: + return False + + with RollbackContext() as rollback: + FeatureTests.disable_libvirt_error_logging() + rollback.prependDefer(FeatureTests.enable_libvirt_error_logging) + conn_type = conn.getType().lower() + domain_type = 'test' if conn_type == 'test' else 'kvm' + arch = 'i686' if conn_type == 'test' else platform.machine() + arch = 'ppc64' if arch == 'ppc64le' else arch + dom = conn.defineXML(MAXMEM_VM_XML % {'name': FEATURETEST_VM_NAME, + 'domain': domain_type, + 'arch': arch}) + rollback.prependDefer(dom.undefine) + try: + dom.attachDeviceFlags(DEV_MEM_XML, + libvirt.VIR_DOMAIN_MEM_CONFIG) + return True + except libvirt.libvirtError: + return False diff --git a/src/wok/plugins/kimchi/model/groups.py b/src/wok/plugins/kimchi/model/groups.py new file mode 100644 index 0000000..fc63d68 --- /dev/null +++ b/src/wok/plugins/kimchi/model/groups.py @@ -0,0 +1,67 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import grp + +from wok.config import config + + +class GroupsModel(object): + def __init__(self, **args): + auth_type = config.get("authentication", "method") + for klass in GroupsModel.__subclasses__(): + if auth_type == klass.auth_type: + self.grp = klass(**args) + + def get_list(self, **args): + if hasattr(self.grp, '_get_list'): + return self.grp._get_list(**args) + else: + return list() + + def validate(self, gid): + return self.grp._validate(gid) + + +class PAMGroupsModel(GroupsModel): + auth_type = 'pam' + + def __init__(self, **kargs): + pass + + def _get_list(self): + return sorted([group.gr_name + for group in grp.getgrall()]) + + def _validate(self, gid): + try: + grp.getgrnam(gid) + except KeyError: + return False + return True + + +class LDAPGroupsModel(GroupsModel): + auth_type = 'ldap' + + def __init__(self, **kargs): + pass + + def _validate(self, gid): + return False diff --git a/src/wok/plugins/kimchi/model/host.py b/src/wok/plugins/kimchi/model/host.py new file mode 100644 index 0000000..75d4de0 --- /dev/null +++ b/src/wok/plugins/kimchi/model/host.py @@ -0,0 +1,476 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import libvirt +import os +import platform +import psutil +import time +from cherrypy.process.plugins import BackgroundTask +from collections import defaultdict + +from wok.basemodel import Singleton +from wok.exception import InvalidOperation, InvalidParameter +from wok.exception import NotFoundError, OperationFailed +from wok.utils import add_task, wok_log +from wok.xmlutils.utils import xpath_get_text +from wok.model.tasks import TaskModel + +import hostdev +from .. import disks +from .. import netinfo +from ..repositories import Repositories +from ..swupdate import SoftwareUpdate +from config import CapabilitiesModel +from vms import DOM_STATE_MAP + + +HOST_STATS_INTERVAL = 1 + + +class HostModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + self.task = TaskModel(**kargs) + self.host_info = self._get_host_info() + + def _get_ppc_cpu_info(self): + res = {} + with open('/proc/cpuinfo') as f: + for line in f.xreadlines(): + # Parse CPU, CPU's revision and CPU's clock information + for key in ['cpu', 'revision', 'clock']: + if key in line: + info = line.split(':')[1].strip() + if key == 'clock': + value = float(info.split('MHz')[0].strip()) / 1000 + else: + value = info.split('(')[0].strip() + res[key] = value + + # Power machines show, for each cpu/core, a block with + # all cpu information. Here we control the scan of the + # necessary information (1st block provides + # everything), skipping the function when find all + # information. + if len(res.keys()) == 3: + return "%(cpu)s (%(revision)s) @ %(clock)s GHz\ + " % res + + return "" + + def _get_host_info(self): + res = {} + if platform.machine().startswith('ppc'): + res['cpu_model'] = self._get_ppc_cpu_info() + else: + with open('/proc/cpuinfo') as f: + for line in f.xreadlines(): + if "model name" in line: + res['cpu_model'] = line.split(':')[1].strip() + break + + res['cpus'] = 0 + res['memory'] = 0L + + # Include IBM PowerKVM name to supported distro names + _sup_distros = platform._supported_dists + ('ibm_powerkvm',) + # 'fedora' '17' 'Beefy Miracle' + distro, version, codename = platform.linux_distribution( + supported_dists=_sup_distros) + res['os_distro'] = distro + res['os_version'] = version + res['os_codename'] = unicode(codename, "utf-8") + + return res + + def lookup(self, *name): + cpus = psutil.NUM_CPUS + + # psutil is unstable on how to get the number of + # cpus, different versions call it differently + if hasattr(psutil, 'cpu_count'): + cpus = psutil.cpu_count() + + elif hasattr(psutil, '_psplatform'): + for method_name in ['_get_num_cpus', 'get_num_cpus']: + + method = getattr(psutil._psplatform, method_name, None) + if method is not None: + cpus = method() + break + + self.host_info['cpus'] = cpus + self.host_info['memory'] = psutil.phymem_usage().total + return self.host_info + + def swupdate(self, *name): + try: + swupdate = SoftwareUpdate() + except: + raise OperationFailed('KCHPKGUPD0004E') + + pkgs = swupdate.getNumOfUpdates() + if pkgs == 0: + raise OperationFailed('KCHPKGUPD0001E') + + wok_log.debug('Host is going to be updated.') + taskid = add_task('/plugins/kimchi/host/swupdate', swupdate.doUpdate, + self.objstore, None) + return self.task.lookup(taskid) + + def shutdown(self, args=None): + # Check for running vms before shutdown + running_vms = self._get_vms_list_by_state('running') + if len(running_vms) > 0: + raise OperationFailed("KCHHOST0001E") + + wok_log.info('Host is going to shutdown.') + os.system('shutdown -h now') + + def reboot(self, args=None): + # Find running VMs + running_vms = self._get_vms_list_by_state('running') + if len(running_vms) > 0: + raise OperationFailed("KCHHOST0002E") + + wok_log.info('Host is going to reboot.') + os.system('reboot') + + def _get_vms_list_by_state(self, state): + conn = self.conn.get() + return [dom.name().decode('utf-8') + for dom in conn.listAllDomains(0) + if (DOM_STATE_MAP[dom.info()[0]]) == state] + + +class HostStatsModel(object): + __metaclass__ = Singleton + + def __init__(self, **kargs): + self.host_stats = defaultdict(list) + self.host_stats_thread = BackgroundTask(HOST_STATS_INTERVAL, + self._update_host_stats) + self.host_stats_thread.start() + + def lookup(self, *name): + return {'cpu_utilization': self.host_stats['cpu_utilization'][-1], + 'memory': self.host_stats['memory'][-1], + 'disk_read_rate': self.host_stats['disk_read_rate'][-1], + 'disk_write_rate': self.host_stats['disk_write_rate'][-1], + 'net_recv_rate': self.host_stats['net_recv_rate'][-1], + 'net_sent_rate': self.host_stats['net_sent_rate'][-1]} + + def _update_host_stats(self): + preTimeStamp = self.host_stats['timestamp'] + timestamp = time.time() + # FIXME when we upgrade psutil, we can get uptime by psutil.uptime + # we get uptime by float(open("/proc/uptime").readline().split()[0]) + # and calculate the first io_rate after the OS started. + with open("/proc/uptime") as time_f: + seconds = (timestamp - preTimeStamp if preTimeStamp else + float(time_f.readline().split()[0])) + + self.host_stats['timestamp'] = timestamp + self._get_host_disk_io_rate(seconds) + self._get_host_network_io_rate(seconds) + + self._get_percentage_host_cpu_usage() + self._get_host_memory_stats() + + # store only 60 stats (1 min) + for key, value in self.host_stats.iteritems(): + if isinstance(value, list): + if len(value) == 60: + self.host_stats[key] = value[10:] + + def _get_percentage_host_cpu_usage(self): + # This is cpu usage producer. This producer will calculate the usage + # at an interval of HOST_STATS_INTERVAL. + # The psutil.cpu_percent works as non blocking. + # psutil.cpu_percent maintains a cpu time sample. + # It will update the cpu time sample when it is called. + # So only this producer can call psutil.cpu_percent in kimchi. + self.host_stats['cpu_utilization'].append(psutil.cpu_percent(None)) + + def _get_host_memory_stats(self): + virt_mem = psutil.virtual_memory() + # available: + # the actual amount of available memory that can be given + # instantly to processes that request more memory in bytes; this + # is calculated by summing different memory values depending on + # the platform (e.g. free + buffers + cached on Linux) + memory_stats = {'total': virt_mem.total, + 'free': virt_mem.free, + 'cached': virt_mem.cached, + 'buffers': virt_mem.buffers, + 'avail': virt_mem.available} + self.host_stats['memory'].append(memory_stats) + + def _get_host_disk_io_rate(self, seconds): + disk_read_bytes = self.host_stats['disk_read_bytes'] + disk_write_bytes = self.host_stats['disk_write_bytes'] + prev_read_bytes = disk_read_bytes[-1] if disk_read_bytes else 0 + prev_write_bytes = disk_write_bytes[-1] if disk_write_bytes else 0 + + disk_io = psutil.disk_io_counters(False) + read_bytes = disk_io.read_bytes + write_bytes = disk_io.write_bytes + + rd_rate = int(float(read_bytes - prev_read_bytes) / seconds + 0.5) + wr_rate = int(float(write_bytes - prev_write_bytes) / seconds + 0.5) + + self.host_stats['disk_read_rate'].append(rd_rate) + self.host_stats['disk_write_rate'].append(wr_rate) + self.host_stats['disk_read_bytes'].append(read_bytes) + self.host_stats['disk_write_bytes'].append(write_bytes) + + def _get_host_network_io_rate(self, seconds): + net_recv_bytes = self.host_stats['net_recv_bytes'] + net_sent_bytes = self.host_stats['net_sent_bytes'] + prev_recv_bytes = net_recv_bytes[-1] if net_recv_bytes else 0 + prev_sent_bytes = net_sent_bytes[-1] if net_sent_bytes else 0 + + net_ios = psutil.network_io_counters(True) + recv_bytes = 0 + sent_bytes = 0 + for key in set(netinfo.nics() + + netinfo.wlans()) & set(net_ios.iterkeys()): + recv_bytes = recv_bytes + net_ios[key].bytes_recv + sent_bytes = sent_bytes + net_ios[key].bytes_sent + + rx_rate = int(float(recv_bytes - prev_recv_bytes) / seconds + 0.5) + tx_rate = int(float(sent_bytes - prev_sent_bytes) / seconds + 0.5) + + self.host_stats['net_recv_rate'].append(rx_rate) + self.host_stats['net_sent_rate'].append(tx_rate) + self.host_stats['net_recv_bytes'].append(recv_bytes) + self.host_stats['net_sent_bytes'].append(sent_bytes) + + +class HostStatsHistoryModel(object): + def __init__(self, **kargs): + self.history = HostStatsModel(**kargs) + + def lookup(self, *name): + return {'cpu_utilization': self.history.host_stats['cpu_utilization'], + 'memory': self.history.host_stats['memory'], + 'disk_read_rate': self.history.host_stats['disk_read_rate'], + 'disk_write_rate': self.history.host_stats['disk_write_rate'], + 'net_recv_rate': self.history.host_stats['net_recv_rate'], + 'net_sent_rate': self.history.host_stats['net_sent_rate']} + + +class PartitionsModel(object): + def __init__(self, **kargs): + pass + + def get_list(self): + result = disks.get_partitions_names() + return result + + +class PartitionModel(object): + def __init__(self, **kargs): + pass + + def lookup(self, name): + return disks.get_partition_details(name) + + +class DevicesModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.caps = CapabilitiesModel(**kargs) + self.cap_map = \ + {'net': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET, + 'pci': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV, + 'scsi': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI, + 'scsi_host': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST, + 'storage': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE, + 'usb_device': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV, + 'usb': + libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE} + # TODO: when no longer supporting Libvirt < 1.0.5 distros + # (like RHEL6) remove this verification and insert the + # key 'fc_host' with the libvirt variable in the hash + # declaration above. + try: + self.cap_map['fc_host'] = \ + libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST + except AttributeError: + self.cap_map['fc_host'] = None + + def get_list(self, _cap=None, _passthrough=None, + _passthrough_affected_by=None): + if _passthrough_affected_by is not None: + # _passthrough_affected_by conflicts with _cap and _passthrough + if (_cap, _passthrough) != (None, None): + raise InvalidParameter("KCHHOST0004E") + return sorted( + self._get_passthrough_affected_devs(_passthrough_affected_by)) + + if _cap == 'fc_host': + dev_names = self._get_devices_fc_host() + else: + dev_names = self._get_devices_with_capability(_cap) + + if _passthrough is not None and _passthrough.lower() == 'true': + conn = self.conn.get() + passthrough_names = [ + dev['name'] for dev in hostdev.get_passthrough_dev_infos(conn)] + dev_names = list(set(dev_names) & set(passthrough_names)) + + dev_names.sort() + return dev_names + + def _get_devices_with_capability(self, cap): + conn = self.conn.get() + if cap is None: + cap_flag = 0 + else: + cap_flag = self.cap_map.get(cap) + if cap_flag is None: + return [] + return [name.name() for name in conn.listAllDevices(cap_flag)] + + def _get_passthrough_affected_devs(self, dev_name): + conn = self.conn.get() + info = DeviceModel(conn=self.conn).lookup(dev_name) + affected = hostdev.get_affected_passthrough_devices(conn, info) + return [dev_info['name'] for dev_info in affected] + + def _get_devices_fc_host(self): + conn = self.conn.get() + # Libvirt < 1.0.5 does not support fc_host capability + if not self.caps.fc_host_support: + ret = [] + scsi_hosts = self._get_devices_with_capability('scsi_host') + for host in scsi_hosts: + xml = conn.nodeDeviceLookupByName(host).XMLDesc(0) + path = '/device/capability/capability/@type' + if 'fc_host' in xpath_get_text(xml, path): + ret.append(host) + return ret + # Double verification to catch the case where the libvirt + # supports fc_host but does not, for some reason, recognize + # the libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST + # attribute. + if not self.cap_map['fc_host']: + return conn.listDevices('fc_host', 0) + return self._get_devices_with_capability('fc_host') + + +class DeviceModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + + def lookup(self, nodedev_name): + conn = self.conn.get() + try: + dev = conn.nodeDeviceLookupByName(nodedev_name) + except: + raise NotFoundError('KCHHOST0003E', {'name': nodedev_name}) + return hostdev.get_dev_info(dev) + + +class PackagesUpdateModel(object): + def __init__(self, **kargs): + try: + self.host_swupdate = SoftwareUpdate() + except: + self.host_swupdate = None + + def get_list(self): + if self.host_swupdate is None: + raise OperationFailed('KCHPKGUPD0004E') + + return self.host_swupdate.getUpdates() + + +class PackageUpdateModel(object): + def __init__(self, **kargs): + pass + + def lookup(self, name): + try: + swupdate = SoftwareUpdate() + except Exception: + raise OperationFailed('KCHPKGUPD0004E') + + return swupdate.getUpdate(name) + + +class RepositoriesModel(object): + def __init__(self, **kargs): + try: + self.host_repositories = Repositories() + except: + self.host_repositories = None + + def get_list(self): + if self.host_repositories is None: + raise InvalidOperation('KCHREPOS0014E') + + return sorted(self.host_repositories.getRepositories()) + + def create(self, params): + if self.host_repositories is None: + raise InvalidOperation('KCHREPOS0014E') + + return self.host_repositories.addRepository(params) + + +class RepositoryModel(object): + def __init__(self, **kargs): + try: + self._repositories = Repositories() + except: + self._repositories = None + + def lookup(self, repo_id): + if self._repositories is None: + raise InvalidOperation('KCHREPOS0014E') + + return self._repositories.getRepository(repo_id) + + def enable(self, repo_id): + if self._repositories is None: + raise InvalidOperation('KCHREPOS0014E') + + return self._repositories.enableRepository(repo_id) + + def disable(self, repo_id): + if self._repositories is None: + raise InvalidOperation('KCHREPOS0014E') + + return self._repositories.disableRepository(repo_id) + + def update(self, repo_id, params): + if self._repositories is None: + raise InvalidOperation('KCHREPOS0014E') + + return self._repositories.updateRepository(repo_id, params) + + def delete(self, repo_id): + if self._repositories is None: + raise InvalidOperation('KCHREPOS0014E') + + return self._repositories.removeRepository(repo_id) diff --git a/src/wok/plugins/kimchi/model/hostdev.py b/src/wok/plugins/kimchi/model/hostdev.py new file mode 100644 index 0000000..31211c7 --- /dev/null +++ b/src/wok/plugins/kimchi/model/hostdev.py @@ -0,0 +1,324 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os +from pprint import pformat +from pprint import pprint + +from wok.utils import wok_log +from wok.xmlutils.utils import dictize + +from libvirtconnection import LibvirtConnection + + +def _get_all_host_dev_infos(libvirt_conn): + node_devs = libvirt_conn.listAllDevices(0) + return [get_dev_info(node_dev) for node_dev in node_devs] + + +def _get_dev_info_tree(dev_infos): + devs = dict([(dev_info['name'], dev_info) for dev_info in dev_infos]) + root = None + for dev_info in dev_infos: + if dev_info['parent'] is None: + root = dev_info + continue + + try: + parent = devs[dev_info['parent']] + except KeyError: + wok_log.error('Parent %s of device %s does not exist.', + dev_info['parent'], dev_info['name']) + continue + + try: + children = parent['children'] + except KeyError: + parent['children'] = [dev_info] + else: + children.append(dev_info) + return root + + +def _is_pci_qualified(pci_dev): + # PCI bridge is not suitable to passthrough + # KVM does not support passthrough graphic card now + blacklist_classes = (0x030000, 0x060000) + + with open(os.path.join(pci_dev['path'], 'class')) as f: + pci_class = int(f.readline().strip(), 16) + + if pci_class & 0xff0000 in blacklist_classes: + return False + + return True + + +def get_passthrough_dev_infos(libvirt_conn): + ''' Get devices eligible to be passed through to VM. ''' + + def is_eligible(dev): + return dev['device_type'] in ('usb_device', 'scsi') or \ + (dev['device_type'] == 'pci' and _is_pci_qualified(dev)) + + dev_infos = _get_all_host_dev_infos(libvirt_conn) + + return [dev_info for dev_info in dev_infos if is_eligible(dev_info)] + + +def _get_same_iommugroup_devices(dev_infos, device_info): + dev_dict = dict([(dev_info['name'], dev_info) for dev_info in dev_infos]) + + def get_iommu_group(dev_info): + # Find out the iommu group of a given device. + # Child device belongs to the same iommu group as the parent device. + try: + return dev_info['iommuGroup'] + except KeyError: + pass + + parent = dev_info['parent'] + while parent is not None: + try: + parent_info = dev_dict[parent] + except KeyError: + wok_log.error("Parent %s of device %s does not exist", + parent, dev_info['name']) + break + + try: + iommuGroup = parent_info['iommuGroup'] + except KeyError: + pass + else: + return iommuGroup + + parent = parent_info['parent'] + + return None + + iommu_group = get_iommu_group(device_info) + + if iommu_group is None: + return [] + + return [dev_info for dev_info in dev_infos + if dev_info['name'] != device_info['name'] and + get_iommu_group(dev_info) == iommu_group] + + +def _get_children_devices(dev_infos, device_info): + def get_children_recursive(parent): + try: + children = parent['children'] + except KeyError: + return [] + + result = [] + for child in children: + result.append(child) + result.extend(get_children_recursive(child)) + + return result + + # Annotate every the dev_info element with children information + _get_dev_info_tree(dev_infos) + + for dev_info in dev_infos: + if dev_info['name'] == device_info['name']: + return get_children_recursive(dev_info) + + return [] + + +def get_affected_passthrough_devices(libvirt_conn, passthrough_dev): + dev_infos = _get_all_host_dev_infos(libvirt_conn) + + group_devices = _get_same_iommugroup_devices(dev_infos, passthrough_dev) + if not group_devices: + # On host without iommu group support, the affected devices should + # at least include all children devices + group_devices.extend(_get_children_devices(dev_infos, passthrough_dev)) + + return group_devices + + +def get_dev_info(node_dev): + ''' Parse the node device XML string into dict according to + http://libvirt.org/formatnode.html. + + scsi_generic is not documented in libvirt official website. Try to + parse scsi_generic according to the following libvirt path series. + https://www.redhat.com/archives/libvir-list/2013-June/msg00014.html + + scsi_target is not documented in libvirt official website. Try to + parse scsi_target according to the libvirt commit db19834a0a. + ''' + + xmlstr = node_dev.XMLDesc(0) + info = dictize(xmlstr)['device'] + dev_type = info['capability'].pop('type') + info['device_type'] = dev_type + cap_dict = info.pop('capability') + info.update(cap_dict) + info['parent'] = node_dev.parent() + + if dev_type in ('scsi', 'scsi_generic', 'scsi_target', 'system', 'usb'): + return info + + if dev_type in ('net', 'pci', 'scsi_host', 'storage', 'usb_device'): + return globals()['_get_%s_dev_info' % dev_type](info) + + wok_log.error("Unknown device type: %s", dev_type) + return info + + +def _get_net_dev_info(info): + cap = info.pop('capability') + links = {"80203": "IEEE 802.3", "80211": "IEEE 802.11"} + link_raw = cap['type'] + info['link_type'] = links.get(link_raw, link_raw) + + return info + + +def _get_pci_dev_info(info): + for k in ('vendor', 'product'): + try: + description = info[k].pop('pyval') + except KeyError: + description = None + info[k]['description'] = description + if 'path' not in info: + # Old libvirt does not provide syspath info + info['path'] = \ + "/sys/bus/pci/devices/" \ + "%(domain)04x:%(bus)02x:%(slot)02x.%(function)01x" % { + 'domain': info['domain'], 'bus': info['bus'], + 'slot': info['slot'], 'function': info['function']} + try: + info['iommuGroup'] = int(info['iommuGroup']['number']) + except KeyError: + # Old libvirt does not provide syspath info, figure it out ourselves + iommu_link = os.path.join(info['path'], 'iommu_group') + if os.path.exists(iommu_link): + iommu_path = os.path.realpath(iommu_link) + try: + info['iommuGroup'] = int(iommu_path.rsplit('/', 1)[1]) + except (ValueError, IndexError): + # No IOMMU group support at all. + pass + else: + # No IOMMU group support at all. + pass + return info + + +def _get_scsi_host_dev_info(info): + try: + cap_info = info.pop('capability') + except KeyError: + # kimchi.model.libvirtstoragepool.ScsiPoolDef assumes + # info['adapter']['type'] always exists. + info['adapter'] = {'type': ''} + return info + if isinstance(cap_info, list): + info['adapter'] = {} + for cap in cap_info: + if cap['type'] == 'vport_ops': + del cap['type'] + info['adapter']['vport_ops'] = cap + else: + info['adapter'].update(cap) + else: + info['adapter'] = cap_info + return info + + +def _get_storage_dev_info(info): + try: + cap_info = info.pop('capability') + except KeyError: + return info + + if cap_info['type'] == 'removable': + cap_info['available'] = bool(cap_info.pop('media_available')) + if cap_info['available']: + for k in ('size', 'label'): + try: + cap_info[k] = cap_info.pop('media_' + k) + except KeyError: + cap_info[k] = None + info['media'] = cap_info + return info + + +def _get_usb_device_dev_info(info): + for k in ('vendor', 'product'): + try: + info[k]['description'] = info[k].pop('pyval') + except KeyError: + # Some USB devices don't provide vendor/product description. + pass + return info + + +# For test and debug +def _print_host_dev_tree(libvirt_conn): + dev_infos = _get_all_host_dev_infos(libvirt_conn) + root = _get_dev_info_tree(dev_infos) + if root is None: + print "No device found" + return + print '-----------------' + print '\n'.join(_format_dev_node(root)) + + +def _format_dev_node(node): + try: + children = node['children'] + del node['children'] + except KeyError: + children = [] + + lines = [] + lines.extend([' ~' + line for line in pformat(node).split('\n')]) + + count = len(children) + for i, child in enumerate(children): + if count == 1: + lines.append(' \-----------------') + else: + lines.append(' +-----------------') + clines = _format_dev_node(child) + if i == count - 1: + p = ' ' + else: + p = ' |' + lines.extend([p + cline for cline in clines]) + lines.append('') + + return lines + + +if __name__ == '__main__': + libvirt_conn = LibvirtConnection('qemu:///system').get() + _print_host_dev_tree(libvirt_conn) + print 'Eligible passthrough devices:' + pprint(get_passthrough_dev_infos(libvirt_conn)) diff --git a/src/wok/plugins/kimchi/model/interfaces.py b/src/wok/plugins/kimchi/model/interfaces.py new file mode 100644 index 0000000..149afe3 --- /dev/null +++ b/src/wok/plugins/kimchi/model/interfaces.py @@ -0,0 +1,44 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.exception import NotFoundError + +from .. import netinfo +from networks import NetworksModel + + +class InterfacesModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.networks = NetworksModel(**kargs) + + def get_list(self): + return list(set(netinfo.all_favored_interfaces()) - + set(self.networks.get_all_networks_interfaces())) + + +class InterfaceModel(object): + def __init__(self, **kargs): + pass + + def lookup(self, name): + try: + return netinfo.get_interface_info(name) + except ValueError: + raise NotFoundError("KCHIFACE0001E", {'name': name}) diff --git a/src/wok/plugins/kimchi/model/libvirtconnection.py b/src/wok/plugins/kimchi/model/libvirtconnection.py new file mode 100644 index 0000000..73f3dcf --- /dev/null +++ b/src/wok/plugins/kimchi/model/libvirtconnection.py @@ -0,0 +1,136 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import cherrypy +import libvirt +import threading +import time + +from wok.utils import wok_log + + +class LibvirtConnection(object): + _connections = {} + _connectionLock = threading.Lock() + + def __init__(self, uri): + self.uri = uri + if self.uri not in LibvirtConnection._connections: + LibvirtConnection._connections[self.uri] = {} + self._connections = LibvirtConnection._connections[self.uri] + self.wrappables = self.get_wrappable_objects() + + def get_wrappable_objects(self): + """ + When a wrapped function returns an instance of another libvirt object, + we also want to wrap that object so we can catch errors that happen + when calling its methods. + """ + objs = [] + for name in ('virDomain', 'virDomainSnapshot', 'virInterface', + 'virNWFilter', 'virNetwork', 'virNodeDevice', 'virSecret', + 'virStoragePool', 'virStorageVol', 'virStream'): + try: + attr = getattr(libvirt, name) + except AttributeError: + pass + objs.append(attr) + return tuple(objs) + + def get(self, conn_id=0): + """ + Return current connection to libvirt or open a new one. Wrap all + callable libvirt methods so we can catch connection errors and handle + them by restarting the server. + """ + def wrapMethod(f): + def wrapper(*args, **kwargs): + try: + ret = f(*args, **kwargs) + return ret + except libvirt.libvirtError as e: + edom = e.get_error_domain() + ecode = e.get_error_code() + EDOMAINS = (libvirt.VIR_FROM_REMOTE, + libvirt.VIR_FROM_RPC) + ECODES = (libvirt.VIR_ERR_SYSTEM_ERROR, + libvirt.VIR_ERR_INTERNAL_ERROR, + libvirt.VIR_ERR_NO_CONNECT, + libvirt.VIR_ERR_INVALID_CONN) + if edom in EDOMAINS and ecode in ECODES: + wok_log.error('Connection to libvirt broken. ' + 'Recycling. ecode: %d edom: %d' % + (ecode, edom)) + with LibvirtConnection._connectionLock: + self._connections[conn_id] = None + raise + wrapper.__name__ = f.__name__ + wrapper.__doc__ = f.__doc__ + return wrapper + + with LibvirtConnection._connectionLock: + conn = self._connections.get(conn_id) + if not conn: + retries = 5 + while True: + retries = retries - 1 + try: + conn = libvirt.open(self.uri) + break + except libvirt.libvirtError: + wok_log.error('Unable to connect to libvirt.') + if not retries: + wok_log.error("Unable to establish connection " + "with libvirt. Please check " + "your libvirt URI which is often " + "defined in " + "/etc/libvirt/libvirt.conf") + cherrypy.engine.stop() + exit(1) + time.sleep(2) + + for name in dir(libvirt.virConnect): + method = getattr(conn, name) + if callable(method) and not name.startswith('_'): + setattr(conn, name, wrapMethod(method)) + + for cls in self.wrappables: + for name in dir(cls): + method = getattr(cls, name) + if callable(method) and not name.startswith('_'): + setattr(cls, name, wrapMethod(method)) + + self._connections[conn_id] = conn + # In case we're running into troubles with keeping the + # connections alive we should place here: + # conn.setKeepAlive(interval=5, count=3) + # However the values need to be considered wisely to not affect + # hosts which are hosting a lot of virtual machines + return conn + + def isQemuURI(self): + """ + This method will return True or Value when the system libvirt + URI is a qemu based URI. For example: + qemu:///system or qemu+tcp://someipaddress/system + """ + if self.get().getURI().startswith('qemu'): + return True + else: + return False diff --git a/src/wok/plugins/kimchi/model/libvirtstoragepool.py b/src/wok/plugins/kimchi/model/libvirtstoragepool.py new file mode 100644 index 0000000..b22856b --- /dev/null +++ b/src/wok/plugins/kimchi/model/libvirtstoragepool.py @@ -0,0 +1,264 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import libvirt +import lxml.etree as ET +import os +import tempfile +from lxml.builder import E + +from wok.exception import InvalidParameter, OperationFailed, TimeoutExpired +from wok.rollbackcontext import RollbackContext +from wok.utils import parse_cmd_output, run_command, wok_log + +from ..iscsi import TargetClient + + +class StoragePoolDef(object): + @classmethod + def create(cls, poolArgs): + for klass in cls.__subclasses__(): + if poolArgs['type'] == klass.poolType: + return klass(poolArgs) + raise OperationFailed("KCHPOOL0014E", {'type': poolArgs['type']}) + + def __init__(self, poolArgs): + self.poolArgs = poolArgs + + def prepare(self, conn): + ''' Validate pool arguments and perform preparations. Operation which + would cause side effect should be put here. Subclasses can optionally + override this method, or it always succeeds by default. ''' + pass + + @property + def xml(self): + ''' Subclasses have to override this method to actually generate the + storage pool XML definition. Should cause no side effect and be + idempotent''' + # TODO: When add new pool type, should also add the related test in + # tests/test_storagepool.py + raise OperationFailed("KCHPOOL0015E", {'pool': self}) + + +class DirPoolDef(StoragePoolDef): + poolType = 'dir' + + @property + def xml(self): + # Required parameters + # name: + # type: + # path: + pool = E.pool(type='dir') + pool.append(E.name(self.poolArgs['name'])) + pool.append(E.target(E.path(self.poolArgs['path']))) + return ET.tostring(pool, encoding='unicode', pretty_print=True) + + +class NetfsPoolDef(StoragePoolDef): + poolType = 'netfs' + + def __init__(self, poolArgs): + super(NetfsPoolDef, self).__init__(poolArgs) + self.path = '/var/lib/kimchi/nfs_mount/' + self.poolArgs['name'] + + def prepare(self, conn): + mnt_point = tempfile.mkdtemp(dir='/tmp') + export_path = "%s:%s" % ( + self.poolArgs['source']['host'], self.poolArgs['source']['path']) + mount_cmd = ["mount", "-o", 'soft,timeo=100,retrans=3,retry=0', + export_path, mnt_point] + umount_cmd = ["umount", "-f", export_path] + mounted = False + # Due to an NFS bug (See Red Hat BZ 1023059), NFSv4 exports may take + # 10-15 seconds to mount the first time. + cmd_timeout = 15 + + with RollbackContext() as rollback: + rollback.prependDefer(os.rmdir, mnt_point) + try: + run_command(mount_cmd, cmd_timeout) + rollback.prependDefer(run_command, umount_cmd, cmd_timeout) + except TimeoutExpired: + raise InvalidParameter("KCHPOOL0012E", {'path': export_path}) + with open("/proc/mounts", "rb") as f: + rawMounts = f.read() + output_items = ['dev_path', 'mnt_point', 'type'] + mounts = parse_cmd_output(rawMounts, output_items) + for item in mounts: + if 'dev_path' in item and item['dev_path'] == export_path: + mounted = True + + if not mounted: + raise InvalidParameter("KCHPOOL0013E", {'path': export_path}) + + @property + def xml(self): + # Required parameters + # name: + # type: + # source[host]: + # source[path]: + pool = E.pool(type='netfs') + pool.append(E.name(self.poolArgs['name'])) + + source = E.source() + source.append(E.host(name=self.poolArgs['source']['host'])) + source.append(E.dir(path=self.poolArgs['source']['path'])) + + pool.append(source) + pool.append(E.target(E.path(self.path))) + return ET.tostring(pool, encoding='unicode', pretty_print=True) + + +class LogicalPoolDef(StoragePoolDef): + poolType = 'logical' + + def __init__(self, poolArgs): + super(LogicalPoolDef, self).__init__(poolArgs) + self.path = '/dev/' + self.poolArgs['name'] + + @property + def xml(self): + # Required parameters + # name: + # type: + # source[devices]: + pool = E.pool(type='logical') + pool.append(E.name(self.poolArgs['name'])) + + source = E.source() + for device_path in self.poolArgs['source']['devices']: + source.append(E.device(path=device_path)) + + pool.append(source) + pool.append(E.target(E.path(self.path))) + return ET.tostring(pool, encoding='unicode', pretty_print=True) + + +class ScsiPoolDef(StoragePoolDef): + poolType = 'scsi' + + def prepare(self, conn=None): + tmp_name = self.poolArgs['source']['name'] + self.poolArgs['source']['name'] = tmp_name.replace('scsi_', '') + # fc_host adapters type are only available in libvirt >= 1.0.5 + if not self.poolArgs['fc_host_support']: + self.poolArgs['source']['adapter']['type'] = 'scsi_host' + msg = "Libvirt version <= 1.0.5. Setting SCSI host name as '%s'; "\ + "setting SCSI adapter type as 'scsi_host'; "\ + "ignoring wwnn and wwpn." % tmp_name + wok_log.info(msg) + # Path for Fibre Channel scsi hosts + self.poolArgs['path'] = '/dev/disk/by-path' + if not self.poolArgs['source']['adapter']['type']: + self.poolArgs['source']['adapter']['type'] = 'scsi_host' + + @property + def xml(self): + # Required parameters + # name: + # source[adapter][type]: + # source[name]: + # source[adapter][wwnn]: + # source[adapter][wwpn]: + # path: + pool = E.pool(type='scsi') + pool.append(E.name(self.poolArgs['name'])) + + adapter = E.adapter(type=self.poolArgs['source']['adapter']['type']) + adapter.set('name', self.poolArgs['source']['name']) + adapter.set('wwnn', self.poolArgs['source']['adapter']['wwnn']) + adapter.set('wwpn', self.poolArgs['source']['adapter']['wwpn']) + + pool.append(E.source(adapter)) + pool.append(E.target(E.path(self.poolArgs['path']))) + return ET.tostring(pool, encoding='unicode', pretty_print=True) + + +class IscsiPoolDef(StoragePoolDef): + poolType = 'iscsi' + + def prepare(self, conn): + source = self.poolArgs['source'] + if not TargetClient(**source).validate(): + msg_args = {'host': source['host'], 'target': source['target']} + raise OperationFailed("KCHISCSI0002E", msg_args) + self._prepare_auth(conn) + + def _prepare_auth(self, conn): + try: + auth = self.poolArgs['source']['auth'] + except KeyError: + return + + try: + virSecret = conn.secretLookupByUsage( + libvirt.VIR_SECRET_USAGE_TYPE_ISCSI, self.poolArgs['name']) + except libvirt.libvirtError: + secret = E.secret(ephemeral='no', private='yes') + + description = E.description('Secret for iSCSI storage pool %s' % + self.poolArgs['name']) + secret.append(description) + secret.append(E.auth(type='chap', username=auth['username'])) + + usage = E.usage(type='iscsi') + usage.append(E.target(self.poolArgs['name'])) + secret.append(usage) + virSecret = conn.secretDefineXML(ET.tostring(secret)) + + virSecret.setValue(auth['password']) + + @property + def xml(self): + # Required parameters + # name: + # type: + # source[host]: + # source[target]: + # + # Optional parameters + # source[port]: + pool = E.pool(type='iscsi') + pool.append(E.name(self.poolArgs['name'])) + + host = E.host(name=self.poolArgs['source']['host']) + port = self.poolArgs['source'].get('port') + if port is not None: + host.set('port', str(port)) + + source = E.source(host) + source.append(E.device(path=self.poolArgs['source']['target'])) + + source_auth = self.poolArgs['source'].get('auth') + if source_auth is not None: + auth = E.auth(type='chap') + auth.set('username', source_auth['username']) + + secret = E.secret(type='iscsi') + secret.set('usage', self.poolArgs['name']) + auth.append(secret) + + source.append(auth) + + pool.append(source) + pool.append(E.target(E.path('/dev/disk/by-id'))) + return ET.tostring(pool, encoding='unicode', pretty_print=True) diff --git a/src/wok/plugins/kimchi/model/model.py b/src/wok/plugins/kimchi/model/model.py new file mode 100644 index 0000000..0c94f63 --- /dev/null +++ b/src/wok/plugins/kimchi/model/model.py @@ -0,0 +1,52 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import inspect +import os + +from wok.basemodel import BaseModel +from wok.objectstore import ObjectStore +from wok.utils import import_module, listPathModules + +from libvirtconnection import LibvirtConnection + + +class Model(BaseModel): + def __init__(self, libvirt_uri=None, objstore_loc=None): + + self.objstore = ObjectStore(objstore_loc) + self.conn = LibvirtConnection(libvirt_uri) + kargs = {'objstore': self.objstore, 'conn': self.conn} + + this = os.path.basename(__file__) + this_mod = os.path.splitext(this)[0] + + models = [] + for mod_name in listPathModules(os.path.dirname(__file__)): + if mod_name.startswith("_") or mod_name == this_mod: + continue + + module = import_module('plugins.kimchi.model.' + mod_name) + members = inspect.getmembers(module, inspect.isclass) + for cls_name, instance in members: + if inspect.getmodule(instance) == module: + if cls_name.endswith('Model'): + models.append(instance(**kargs)) + + return super(Model, self).__init__(models) diff --git a/src/wok/plugins/kimchi/model/networks.py b/src/wok/plugins/kimchi/model/networks.py new file mode 100644 index 0000000..b579865 --- /dev/null +++ b/src/wok/plugins/kimchi/model/networks.py @@ -0,0 +1,382 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import ipaddr +import libvirt +import sys +import time +from xml.sax.saxutils import escape + +from wok.config import PluginPaths +from wok.exception import InvalidOperation, InvalidParameter +from wok.exception import MissingParameter, NotFoundError, OperationFailed +from wok.rollbackcontext import RollbackContext +from wok.utils import run_command, wok_log +from wok.xmlutils.utils import xpath_get_text + +from .. import netinfo +from .. import network as knetwork +from ..osinfo import defaults as tmpl_defaults +from ..xmlutils.network import create_vlan_tagged_bridge_xml +from ..xmlutils.network import to_network_xml + + +KIMCHI_BRIDGE_PREFIX = 'kb' + + +class NetworksModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + if self.conn.isQemuURI(): + self._check_default_networks() + + def _check_default_networks(self): + networks = list(set(tmpl_defaults['networks'])) + conn = self.conn.get() + + error_msg = ("Please, check the configuration in %s/template.conf to " + "ensure it lists only valid networks." % + PluginPaths('kimchi').conf_dir) + + for net_name in networks: + try: + net = conn.networkLookupByName(net_name) + except libvirt.libvirtError, e: + msg = "Fatal: Unable to find network %s." + wok_log.error(msg, net_name) + wok_log.error(error_msg) + wok_log.error("Details: %s", e.message) + sys.exit(1) + + if net.isActive() == 0: + try: + net.create() + except libvirt.libvirtError as e: + msg = "Fatal: Unable to activate network %s." + wok_log.error(msg, net_name) + wok_log.error(error_msg) + wok_log.error("Details: %s", e.message) + sys.exit(1) + + def create(self, params): + conn = self.conn.get() + name = params['name'] + if name in self.get_list(): + raise InvalidOperation("KCHNET0001E", {'name': name}) + + connection = params["connection"] + # set forward mode, isolated do not need forward + if connection != 'isolated': + params['forward'] = {'mode': connection} + + # set subnet, bridge network do not need subnet + if connection in ["nat", 'isolated']: + self._set_network_subnet(params) + + # only bridge network need bridge(linux bridge) or interface(macvtap) + if connection == 'bridge': + self._set_network_bridge(params) + + params['name'] = escape(params['name']) + xml = to_network_xml(**params) + + try: + network = conn.networkDefineXML(xml.encode("utf-8")) + network.setAutostart(True) + except libvirt.libvirtError as e: + raise OperationFailed("KCHNET0008E", + {'name': name, 'err': e.get_error_message()}) + + return name + + def get_list(self): + conn = self.conn.get() + names = conn.listNetworks() + conn.listDefinedNetworks() + return sorted(map(lambda x: x.decode('utf-8'), names)) + + def _get_available_address(self, addr_pools=[]): + invalid_addrs = [] + for net_name in self.get_list(): + network = NetworkModel.get_network(self.conn.get(), net_name) + xml = network.XMLDesc(0) + subnet = NetworkModel.get_network_from_xml(xml)['subnet'] + subnet and invalid_addrs.append(ipaddr.IPNetwork(subnet)) + addr_pools = addr_pools if addr_pools else knetwork.PrivateNets + return knetwork.get_one_free_network(invalid_addrs, addr_pools) + + def _set_network_subnet(self, params): + netaddr = params.get('subnet', '') + # lookup a free network address for nat and isolated automatically + if not netaddr: + netaddr = self._get_available_address() + if not netaddr: + raise OperationFailed("KCHNET0009E", {'name': params['name']}) + + try: + ip = ipaddr.IPNetwork(netaddr) + except ValueError: + raise InvalidParameter("KCHNET0003E", {'subent': netaddr, + 'network': params['name']}) + + if ip.ip == ip.network: + ip.ip = ip.ip + 1 + + dhcp_start = str(ip.ip + ip.numhosts / 2) + dhcp_end = str(ip.ip + ip.numhosts - 2) + params.update({'net': str(ip), + 'dhcp': {'range': {'start': dhcp_start, + 'end': dhcp_end}}}) + + def _ensure_iface_up(self, iface): + if netinfo.operstate(iface) != 'up': + _, err, rc = run_command(['ip', 'link', 'set', 'dev', iface, 'up']) + if rc != 0: + raise OperationFailed("KCHNET0020E", + {'iface': iface, 'err': err}) + # Add a delay to wait for the link change takes into effect. + for i in range(10): + time.sleep(1) + if netinfo.operstate(iface) == 'up': + break + else: + raise OperationFailed("KCHNET0021E", {'iface': iface}) + + def _set_network_bridge(self, params): + try: + iface = params['interface'] + if iface in self.get_all_networks_interfaces(): + msg_args = {'iface': iface, 'network': params['name']} + raise InvalidParameter("KCHNET0006E", msg_args) + except KeyError: + raise MissingParameter("KCHNET0004E", {'name': params['name']}) + + self._ensure_iface_up(iface) + if netinfo.is_bridge(iface): + if 'vlan_id' in params: + raise InvalidParameter('KCHNET0019E', {'name': iface}) + params['bridge'] = iface + elif netinfo.is_bare_nic(iface) or netinfo.is_bonding(iface): + if params.get('vlan_id') is None: + params['forward']['dev'] = iface + else: + params['bridge'] = \ + self._create_vlan_tagged_bridge(str(iface), + str(params['vlan_id'])) + else: + raise InvalidParameter("KCHNET0007E") + + def get_all_networks_interfaces(self): + net_names = self.get_list() + interfaces = [] + for name in net_names: + conn = self.conn.get() + network = conn.networkLookupByName(name.encode("utf-8")) + xml = network.XMLDesc(0) + net_dict = NetworkModel.get_network_from_xml(xml) + forward = net_dict['forward'] + (forward['mode'] == 'bridge' and forward['interface'] and + interfaces.append(forward['interface'][0]) is None or + interfaces.extend(forward['interface'] + forward['pf'])) + net_dict['bridge'] and interfaces.append(net_dict['bridge']) + return interfaces + + def _create_vlan_tagged_bridge(self, interface, vlan_id): + # Truncate the interface name if it exceeds 8 characters to make sure + # the length of bridge name is less than 15 (its maximum value). + br_name = KIMCHI_BRIDGE_PREFIX + interface[-8:] + '-' + vlan_id + br_xml = create_vlan_tagged_bridge_xml(br_name, interface, vlan_id) + conn = self.conn.get() + + bridges = [] + for net in conn.listAllNetworks(): + # Bridged networks do not have a bridge name + # So in those cases, libvirt raises an error when trying to get + # the bridge name + try: + bridges.append(net.bridgeName()) + except libvirt.libvirtError, e: + wok_log.error(e.message) + + if br_name in bridges: + raise InvalidOperation("KCHNET0010E", {'iface': br_name}) + + with RollbackContext() as rollback: + try: + vlan_tagged_br = conn.interfaceDefineXML(br_xml, 0) + rollback.prependDefer(vlan_tagged_br.destroy) + vlan_tagged_br.create(0) + except libvirt.libvirtError as e: + raise OperationFailed(e.message) + else: + return br_name + + +class NetworkModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + + def lookup(self, name): + network = self.get_network(self.conn.get(), name) + xml = network.XMLDesc(0) + net_dict = self.get_network_from_xml(xml) + subnet = net_dict['subnet'] + dhcp = net_dict['dhcp'] + forward = net_dict['forward'] + interface = net_dict['bridge'] + + connection = forward['mode'] or "isolated" + # FIXME, if we want to support other forward mode well. + if connection == 'bridge': + # macvtap bridge + interface = interface or forward['interface'][0] + # exposing the network on linux bridge or macvtap interface + interface_subnet = knetwork.get_dev_netaddr(interface) + subnet = subnet if subnet else interface_subnet + + # libvirt use format 192.168.0.1/24, standard should be 192.168.0.0/24 + # http://www.ovirt.org/File:Issue3.png + if subnet: + subnet = ipaddr.IPNetwork(subnet) + subnet = "%s/%s" % (subnet.network, subnet.prefixlen) + + return {'connection': connection, + 'interface': interface, + 'subnet': subnet, + 'dhcp': dhcp, + 'vms': self._get_vms_attach_to_a_network(name), + 'in_use': self._is_network_in_use(name), + 'autostart': network.autostart() == 1, + 'state': network.isActive() and "active" or "inactive", + 'persistent': True if network.isPersistent() else False} + + def _is_network_in_use(self, name): + # All the networks listed as default in template.conf file should not + # be deactivate or deleted. Otherwise, we will allow user create + # inconsistent templates from scratch + if name in tmpl_defaults['networks']: + return True + + vms = self._get_vms_attach_to_a_network(name) + return bool(vms) or self._is_network_used_by_template(name) + + def _is_network_used_by_template(self, network): + with self.objstore as session: + templates = session.get_list('template') + for tmpl in templates: + tmpl_net = session.get('template', tmpl)['networks'] + if network in tmpl_net: + return True + return False + + def _get_vms_attach_to_a_network(self, network, filter="all"): + DOM_STATE_MAP = {'nostate': 0, 'running': 1, 'blocked': 2, + 'paused': 3, 'shutdown': 4, 'shutoff': 5, + 'crashed': 6} + state = DOM_STATE_MAP.get(filter) + vms = [] + conn = self.conn.get() + for dom in conn.listAllDomains(0): + networks = self._vm_get_networks(dom) + if network.encode('utf-8') in networks and \ + (state is None or state == dom.state(0)[0]): + vms.append(dom.name()) + return vms + + def _vm_get_networks(self, dom): + xml = dom.XMLDesc(0) + xpath = "/domain/devices/interface[@type='network']/source/@network" + return xpath_get_text(xml, xpath) + + def activate(self, name): + network = self.get_network(self.conn.get(), name) + try: + network.create() + except libvirt.libvirtError, e: + raise OperationFailed('KCHNET0022E', {'name': name, + 'err': e.message}) + + def deactivate(self, name): + if self._is_network_in_use(name): + vms = self._get_vms_attach_to_a_network(name) + vms.sort() + raise InvalidOperation("KCHNET0018E", {'name': name, + 'vms': ', '.join(vms)}) + + network = self.get_network(self.conn.get(), name) + network.destroy() + + def delete(self, name): + if self._is_network_in_use(name): + vms = self._get_vms_attach_to_a_network(name) + vms.sort() + raise InvalidOperation("KCHNET0017E", {'name': name, + 'vms': ', '.join(vms)}) + + network = self.get_network(self.conn.get(), name) + if network.isActive(): + raise InvalidOperation("KCHNET0005E", {'name': name}) + + self._remove_vlan_tagged_bridge(network) + network.undefine() + + @staticmethod + def get_network(conn, name): + name = name.encode("utf-8") + try: + return conn.networkLookupByName(name) + except libvirt.libvirtError: + raise NotFoundError("KCHNET0002E", {'name': name}) + + @staticmethod + def get_network_from_xml(xml): + address = xpath_get_text(xml, "/network/ip/@address") + address = address and address[0] or '' + netmask = xpath_get_text(xml, "/network/ip/@netmask") + netmask = netmask and netmask[0] or '' + net = address and netmask and "/".join([address, netmask]) or '' + + dhcp_start = xpath_get_text(xml, "/network/ip/dhcp/range/@start") + dhcp_start = dhcp_start and dhcp_start[0] or '' + dhcp_end = xpath_get_text(xml, "/network/ip/dhcp/range/@end") + dhcp_end = dhcp_end and dhcp_end[0] or '' + dhcp = {'start': dhcp_start, 'end': dhcp_end} + + forward_mode = xpath_get_text(xml, "/network/forward/@mode") + forward_mode = forward_mode and forward_mode[0] or '' + forward_if = xpath_get_text(xml, "/network/forward/interface/@dev") + forward_pf = xpath_get_text(xml, "/network/forward/pf/@dev") + bridge = xpath_get_text(xml, "/network/bridge/@name") + bridge = bridge and bridge[0] or '' + return {'subnet': net, 'dhcp': dhcp, 'bridge': bridge, + 'forward': {'mode': forward_mode, + 'interface': forward_if, + 'pf': forward_pf}} + + def _remove_vlan_tagged_bridge(self, network): + try: + bridge = network.bridgeName() + except libvirt.libvirtError: + pass + else: + if bridge.startswith(KIMCHI_BRIDGE_PREFIX): + conn = self.conn.get() + iface = conn.interfaceLookupByName(bridge) + iface.isActive() and iface.destroy(0) + iface.undefine() diff --git a/src/wok/plugins/kimchi/model/peers.py b/src/wok/plugins/kimchi/model/peers.py new file mode 100644 index 0000000..7577364 --- /dev/null +++ b/src/wok/plugins/kimchi/model/peers.py @@ -0,0 +1,72 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import cherrypy +import re +import socket + +from wok.config import config +from wok.utils import run_command, wok_log + + +class PeersModel(object): + def __init__(self, **kargs): + # check federation feature is enabled on Kimchi server + if config.get("server", "federation") == "off": + return + + # register server on openslp + hostname = socket.getfqdn(config.get("server", "host")) + port = config.get("server", "ssl_port") + self.url = hostname + ":" + port + + cmd = ["slptool", "register", + "service:wokd://%s" % self.url] + out, error, ret = run_command(cmd) + if out and len(out) != 0: + wok_log.error("Unable to register server on openSLP." + " Details: %s" % out) + cherrypy.engine.subscribe('exit', self._peer_deregister) + + def _peer_deregister(self): + cmd = ["slptool", "deregister", + "service:wokd://%s" % self.url] + out, error, ret = run_command(cmd) + if out and len(out) != 0: + wok_log.error("Unable to deregister server on openSLP." + " Details: %s" % out) + + def get_list(self): + # check federation feature is enabled on Kimchi server + if config.get("server", "federation") == "off": + return [] + + cmd = ["slptool", "findsrvs", "service:wokd"] + out, error, ret = run_command(cmd) + if ret != 0: + return [] + + peers = [] + for server in out.strip().split("\n"): + match = re.match("service:wokd://(.*?),.*", server) + peer = match.group(1) + if peer != self.url: + peers.append("https://" + peer) + + return peers diff --git a/src/wok/plugins/kimchi/model/storagepools.py b/src/wok/plugins/kimchi/model/storagepools.py new file mode 100644 index 0000000..0db2ef4 --- /dev/null +++ b/src/wok/plugins/kimchi/model/storagepools.py @@ -0,0 +1,490 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import libvirt +import lxml.etree as ET +import sys +from lxml.builder import E + +from wok.config import config, PluginPaths +from wok.exception import InvalidOperation, MissingParameter +from wok.exception import NotFoundError, OperationFailed +from wok.utils import add_task, run_command, wok_log +from wok.xmlutils.utils import xpath_get_text + +from ..osinfo import defaults as tmpl_defaults +from ..scan import Scanner +from ..utils import pool_name_from_uri +from config import CapabilitiesModel +from host import DeviceModel +from libvirtstoragepool import StoragePoolDef + + +ISO_POOL_NAME = u'kimchi_isos' + +POOL_STATE_MAP = {0: 'inactive', + 1: 'initializing', + 2: 'active', + 3: 'degraded', + 4: 'inaccessible'} + +# Types of pools supported +STORAGE_SOURCES = {'netfs': {'addr': '/pool/source/host/@name', + 'path': '/pool/source/dir/@path'}, + 'iscsi': {'addr': '/pool/source/host/@name', + 'port': '/pool/source/host/@port', + 'path': '/pool/source/device/@path'}, + 'scsi': {'adapter_type': '/pool/source/adapter/@type', + 'adapter_name': '/pool/source/adapter/@name', + 'wwnn': '/pool/source/adapter/@wwnn', + 'wwpn': '/pool/source/adapter/@wwpn'}} + + +class StoragePoolsModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + self.scanner = Scanner(self._clean_scan) + self.scanner.delete() + self.caps = CapabilitiesModel(**kargs) + self.device = DeviceModel(**kargs) + + if self.conn.isQemuURI(): + self._check_default_pools() + + def _check_default_pools(self): + pools = {} + + default_pool = tmpl_defaults['storagepool'] + default_pool = default_pool.split('/')[-1] + + pools[default_pool] = {} + if default_pool == 'default': + pools[default_pool] = {'path': '/var/lib/libvirt/images'} + + if config.get("server", "create_iso_pool") == "true": + pools['ISO'] = {'path': '/var/lib/kimchi/isos'} + + error_msg = ("Please, check the configuration in %s/template.conf to " + "ensure it has a valid storage pool." % + PluginPaths('kimchi').conf_dir) + + conn = self.conn.get() + for pool_name in pools: + try: + pool = conn.storagePoolLookupByName(pool_name) + except libvirt.libvirtError, e: + pool_path = pools[pool_name].get('path') + if pool_path is None: + msg = "Fatal: Unable to find storage pool %s. " + error_msg + wok_log.error(msg % pool_name) + wok_log.error("Details: %s", e.message) + sys.exit(1) + + # Try to create the pool + pool = E.pool(E.name(pool_name), type='dir') + pool.append(E.target(E.path(pool_path))) + xml = ET.tostring(pool) + try: + pool = conn.storagePoolDefineXML(xml, 0) + except libvirt.libvirtError, e: + msg = "Fatal: Unable to create storage pool %s. " + msg += error_msg + wok_log.error(msg % pool_name) + wok_log.error("Details: %s", e.message) + sys.exit(1) + + # Build and set autostart value to pool + # Ignore error as the pool was already successfully created + try: + # Add build step to make sure target directory created + # The build process may fail when the pool directory + # already exists on system + pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW) + pool.setAutostart(1) + except: + pass + + if pool.isActive() == 0: + try: + pool.create(0) + except libvirt.libvirtError, e: + msg = "Fatal: Unable to craete storage pool %s. " + msg += error_msg + wok_log.error(msg % pool_name) + wok_log.error("Details: %s", e.message) + sys.exit(1) + + def get_list(self): + try: + conn = self.conn.get() + names = conn.listStoragePools() + names += conn.listDefinedStoragePools() + return sorted(map(lambda x: x.decode('utf-8'), names)) + except libvirt.libvirtError as e: + raise OperationFailed("KCHPOOL0006E", + {'err': e.get_error_message()}) + + def create(self, params): + task_id = None + conn = self.conn.get() + try: + name = params['name'] + if name == ISO_POOL_NAME: + raise InvalidOperation("KCHPOOL0031E") + + # The user may want to create a logical pool with the same name + # used before but a volume group will already exist with this name + # So check the volume group does not exist to create the pool + if params['type'] == 'logical': + vgdisplay_cmd = ['vgdisplay', name.encode('utf-8')] + output, error, returncode = run_command(vgdisplay_cmd) + # From vgdisplay error codes: + # 1 error reading VGDA + # 2 volume group doesn't exist + # 3 not all physical volumes of volume group online + # 4 volume group not found + # 5 no volume groups found at all + # 6 error reading VGDA from lvmtab + if returncode not in [2, 4, 5]: + raise InvalidOperation("KCHPOOL0036E", {'name': name}) + + if params['type'] == 'kimchi-iso': + task_id = self._do_deep_scan(params) + + if params['type'] == 'scsi': + adapter_name = params['source']['adapter_name'] + extra_params = self.device.lookup(adapter_name) + # Adds name, adapter_type, wwpn and wwnn to source information + params['source'].update(extra_params) + params['fc_host_support'] = self.caps.fc_host_support + + poolDef = StoragePoolDef.create(params) + poolDef.prepare(conn) + xml = poolDef.xml.encode("utf-8") + except KeyError, item: + raise MissingParameter("KCHPOOL0004E", + {'item': str(item), 'name': name}) + + if name in self.get_list(): + raise InvalidOperation("KCHPOOL0001E", {'name': name}) + + try: + if task_id: + # Create transient pool for deep scan + conn.storagePoolCreateXML(xml, 0) + return name + + pool = conn.storagePoolDefineXML(xml, 0) + except libvirt.libvirtError as e: + wok_log.error("Problem creating Storage Pool: %s", e) + raise OperationFailed("KCHPOOL0007E", + {'name': name, 'err': e.get_error_message()}) + + # Build and set autostart value to pool + # Ignore error as the pool was already successfully created + # The build process fails when the pool directory already exists + try: + if params['type'] in ['logical', 'dir', 'netfs', 'scsi']: + pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW) + pool.setAutostart(1) + else: + pool.setAutostart(0) + except: + pass + + if params['type'] == 'netfs': + output, error, returncode = run_command(['setsebool', '-P', + 'virt_use_nfs=1']) + if error or returncode: + wok_log.error("Unable to set virt_use_nfs=1. If you use " + "SELinux, this may prevent NFS pools from " + "being used.") + return name + + def _clean_scan(self, pool_name): + try: + conn = self.conn.get() + pool = conn.storagePoolLookupByName(pool_name.encode("utf-8")) + pool.destroy() + with self.objstore as session: + session.delete('scanning', pool_name) + except Exception, e: + err = "Exception %s occured when cleaning scan result" + wok_log.debug(err % e.message) + + def _do_deep_scan(self, params): + scan_params = dict(ignore_list=[]) + scan_params['scan_path'] = params['path'] + params['type'] = 'dir' + + for pool in self.get_list(): + try: + res = StoragePoolModel(conn=self.conn, + objstore=self.objstore).lookup(pool) + if res['state'] == 'active': + scan_params['ignore_list'].append(res['path']) + except Exception, e: + err = "Exception %s occured when get ignore path" + wok_log.debug(err % e.message) + + params['path'] = self.scanner.scan_dir_prepare(params['name']) + scan_params['pool_path'] = params['path'] + task_id = add_task('/plugins/kimchi/storagepools/%s' % ISO_POOL_NAME, + self.scanner.start_scan, self.objstore, scan_params) + # Record scanning-task/storagepool mapping for future querying + try: + with self.objstore as session: + session.store('scanning', params['name'], task_id) + return task_id + except Exception as e: + raise OperationFailed('KCHPOOL0037E', {'err': e.message}) + + +class StoragePoolModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + + @staticmethod + def get_storagepool(name, conn): + conn = conn.get() + try: + return conn.storagePoolLookupByName(name.encode("utf-8")) + except libvirt.libvirtError as e: + if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL: + raise NotFoundError("KCHPOOL0002E", {'name': name}) + else: + raise + + def _get_storagepool_vols_num(self, pool): + try: + if pool.isActive(): + pool.refresh(0) + return pool.numOfVolumes() + else: + return 0 + except libvirt.libvirtError as e: + # If something (say a busy pool) prevents the refresh, + # throwing an Exception here would prevent all pools from + # displaying information -- so return None for busy + wok_log.error("ERROR: Storage Pool get vol count: %s " + % e.get_error_message()) + wok_log.error("ERROR: Storage Pool get vol count error no: %s " + % e.get_error_code()) + return 0 + except Exception as e: + raise OperationFailed("KCHPOOL0008E", + {'name': pool.name(), + 'err': e.get_error_message()}) + + def _get_storage_source(self, pool_type, pool_xml): + source = {} + if pool_type not in STORAGE_SOURCES: + return source + + for key, val in STORAGE_SOURCES[pool_type].items(): + res = xpath_get_text(pool_xml, val) + if len(res) == 1: + source[key] = res[0] + elif len(res) == 0: + source[key] = "" + else: + source[key] = res + return source + + def _nfs_status_online(self, pool, poolArgs=None): + if not poolArgs: + xml = pool.XMLDesc(0) + pool_type = xpath_get_text(xml, "/pool/@type")[0] + source = self._get_storage_source(pool_type, xml) + poolArgs = {} + poolArgs['name'] = pool.name() + poolArgs['type'] = pool_type + poolArgs['source'] = {'path': source['path'], + 'host': source['addr']} + conn = self.conn.get() + poolDef = StoragePoolDef.create(poolArgs) + try: + poolDef.prepare(conn) + return True + except Exception: + return False + + def lookup(self, name): + pool = self.get_storagepool(name, self.conn) + info = pool.info() + autostart = True if pool.autostart() else False + persistent = True if pool.isPersistent() else False + xml = pool.XMLDesc(0) + path = xpath_get_text(xml, "/pool/target/path")[0] + pool_type = xpath_get_text(xml, "/pool/@type")[0] + source = self._get_storage_source(pool_type, xml) + # FIXME: nfs workaround - prevent any libvirt operation + # for a nfs if the corresponding NFS server is down. + if pool_type == 'netfs' and not self._nfs_status_online(pool): + wok_log.debug("NFS pool %s is offline, reason: NFS " + "server %s is unreachable.", name, source['addr']) + # Mark state as '4' => inaccessible. + info[0] = 4 + # skip calculating volumes + nr_volumes = 0 + else: + nr_volumes = self._get_storagepool_vols_num(pool) + + res = {'state': POOL_STATE_MAP[info[0]], + 'path': path, + 'source': source, + 'type': pool_type, + 'autostart': autostart, + 'capacity': info[1], + 'allocated': info[2], + 'available': info[3], + 'nr_volumes': nr_volumes, + 'persistent': persistent} + + if not pool.isPersistent(): + # Deal with deep scan generated pool + try: + with self.objstore as session: + task_id = session.get('scanning', name) + res['task_id'] = str(task_id) + res['type'] = 'kimchi-iso' + except NotFoundError: + # User created normal pool + pass + return res + + def _update_lvm_disks(self, pool_name, disks): + # check if all the disks/partitions exists in the host + for disk in disks: + lsblk_cmd = ['lsblk', disk] + output, error, returncode = run_command(lsblk_cmd) + if returncode != 0: + wok_log.error('%s is not a valid disk/partition. Could not ' + 'add it to the pool %s.', disk, pool_name) + raise OperationFailed('KCHPOOL0027E', {'disk': disk, + 'pool': pool_name}) + # add disks to the lvm pool using vgextend + virsh refresh + vgextend_cmd = ["vgextend", pool_name] + vgextend_cmd += disks + output, error, returncode = run_command(vgextend_cmd) + if returncode != 0: + msg = "Could not add disks to pool %s, error: %s" + wok_log.error(msg, pool_name, error) + raise OperationFailed('KCHPOOL0028E', {'pool': pool_name, + 'err': error}) + # refreshing pool state + pool = self.get_storagepool(pool_name, self.conn) + if pool.isActive(): + pool.refresh(0) + + def update(self, name, params): + pool = self.get_storagepool(name, self.conn) + if 'autostart' in params: + if params['autostart']: + pool.setAutostart(1) + else: + pool.setAutostart(0) + + if 'disks' in params: + # check if pool is type 'logical' + xml = pool.XMLDesc(0) + pool_type = xpath_get_text(xml, "/pool/@type")[0] + if pool_type != 'logical': + raise InvalidOperation('KCHPOOL0029E') + self._update_lvm_disks(name, params['disks']) + ident = pool.name() + return ident.decode('utf-8') + + def activate(self, name): + pool = self.get_storagepool(name, self.conn) + # FIXME: nfs workaround - do not activate a NFS pool + # if the NFS server is not reachable. + xml = pool.XMLDesc(0) + pool_type = xpath_get_text(xml, "/pool/@type")[0] + if pool_type == 'netfs' and not self._nfs_status_online(pool): + # block the user from activating the pool. + source = self._get_storage_source(pool_type, xml) + raise OperationFailed("KCHPOOL0032E", + {'name': name, 'server': source['addr']}) + return + try: + pool.create(0) + except libvirt.libvirtError as e: + raise OperationFailed("KCHPOOL0009E", + {'name': name, 'err': e.get_error_message()}) + + def _pool_used_by_template(self, pool_name): + with self.objstore as session: + templates = session.get_list('template') + for tmpl in templates: + t_info = session.get('template', tmpl) + t_pool = pool_name_from_uri(t_info['storagepool']) + if t_pool == pool_name: + return True + return False + + def deactivate(self, name): + if self._pool_used_by_template(name): + raise InvalidOperation('KCHPOOL0034E', {'name': name}) + + pool = self.get_storagepool(name, self.conn) + # FIXME: nfs workaround - do not try to deactivate a NFS pool + # if the NFS server is not reachable. + xml = pool.XMLDesc(0) + pool_type = xpath_get_text(xml, "/pool/@type")[0] + if pool_type == 'netfs' and not self._nfs_status_online(pool): + # block the user from dactivating the pool. + source = self._get_storage_source(pool_type, xml) + raise OperationFailed("KCHPOOL0033E", + {'name': name, 'server': source['addr']}) + return + try: + persistent = pool.isPersistent() + pool.destroy() + except libvirt.libvirtError as e: + raise OperationFailed("KCHPOOL0010E", + {'name': name, 'err': e.get_error_message()}) + # If pool was not persistent, then it was erased by destroy() and + # must return nothing here, to trigger _redirect() and avoid errors + if not persistent: + return "" + + def delete(self, name): + if self._pool_used_by_template(name): + raise InvalidOperation('KCHPOOL0035E', {'name': name}) + + pool = self.get_storagepool(name, self.conn) + if pool.isActive(): + raise InvalidOperation("KCHPOOL0005E", {'name': name}) + try: + pool.undefine() + except libvirt.libvirtError as e: + raise OperationFailed("KCHPOOL0011E", + {'name': name, 'err': e.get_error_message()}) + + +class IsoPoolModel(object): + def __init__(self, **kargs): + pass + + def lookup(self, name): + return {'state': 'active', + 'type': 'kimchi-iso'} diff --git a/src/wok/plugins/kimchi/model/storageservers.py b/src/wok/plugins/kimchi/model/storageservers.py new file mode 100644 index 0000000..accc5f5 --- /dev/null +++ b/src/wok/plugins/kimchi/model/storageservers.py @@ -0,0 +1,81 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.exception import NotFoundError + +from storagepools import StoragePoolModel, StoragePoolsModel + +# Types of remote storage servers supported +STORAGE_SERVERS = ['netfs', 'iscsi'] + + +class StorageServersModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.pool = StoragePoolModel(**kargs) + self.pools = StoragePoolsModel(**kargs) + + def get_list(self, _target_type=None): + if not _target_type: + target_type = STORAGE_SERVERS + else: + target_type = [_target_type] + + pools = self.pools.get_list() + + server_list = [] + for pool in pools: + try: + pool_info = self.pool.lookup(pool) + if (pool_info['type'] in target_type and + pool_info['source']['addr'] not in server_list): + # Avoid to add same server for multiple times + # if it hosts more than one storage type + server_list.append(pool_info['source']['addr']) + except NotFoundError: + pass + + return server_list + + +class StorageServerModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.pool = StoragePoolModel(**kargs) + + def lookup(self, server): + conn = self.conn.get() + pools = conn.listStoragePools() + pools += conn.listDefinedStoragePools() + for pool in pools: + try: + pool_info = self.pool.lookup(pool) + if (pool_info['type'] in STORAGE_SERVERS and + pool_info['source']['addr'] == server): + info = dict(host=server) + if (pool_info['type'] == "iscsi" and + 'port' in pool_info['source']): + info["port"] = pool_info['source']['port'] + return info + except NotFoundError: + # Avoid inconsistent pool result because of lease between list + # lookup + pass + + raise NotFoundError("KCHSR0001E", {'server': server}) diff --git a/src/wok/plugins/kimchi/model/storagetargets.py b/src/wok/plugins/kimchi/model/storagetargets.py new file mode 100644 index 0000000..4090b45 --- /dev/null +++ b/src/wok/plugins/kimchi/model/storagetargets.py @@ -0,0 +1,122 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import libvirt +import lxml.etree as ET +from lxml import objectify +from lxml.builder import E + +from wok.utils import patch_find_nfs_target, wok_log + +from config import CapabilitiesModel +from storageservers import STORAGE_SERVERS + + +class StorageTargetsModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.caps = CapabilitiesModel(**kargs) + + def get_list(self, storage_server, _target_type=None, _server_port=None): + target_list = list() + if not _target_type: + target_types = STORAGE_SERVERS + else: + target_types = [_target_type] + + for target_type in target_types: + if not self.caps.nfs_target_probe and target_type == 'netfs': + targets = patch_find_nfs_target(storage_server) + else: + xml = self._get_storage_server_spec(server=storage_server, + target_type=target_type, + server_port=_server_port) + conn = self.conn.get() + try: + ret = conn.findStoragePoolSources(target_type, xml, 0) + except libvirt.libvirtError as e: + err = "Query storage pool source fails because of %s" + wok_log.warning(err, e.get_error_message()) + continue + + targets = self._parse_target_source_result(target_type, ret) + + target_list.extend(targets) + + # Get all netfs and iscsi paths in use + used_paths = [] + try: + conn = self.conn.get() + # Get all existing ISCSI and NFS pools + pools = conn.listAllStoragePools( + libvirt.VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI | + libvirt.VIR_CONNECT_LIST_STORAGE_POOLS_NETFS) + for pool in pools: + pool_xml = pool.XMLDesc(0) + root = objectify.fromstring(pool_xml) + if root.get('type') == 'netfs' and \ + root.source.dir is not None: + used_paths.append(root.source.dir.get('path')) + elif root.get('type') == 'iscsi' and \ + root.source.device is not None: + used_paths.append(root.source.device.get('path')) + + except libvirt.libvirtError as e: + err = "Query storage pool source fails because of %s" + wok_log.warning(err, e.get_error_message()) + + # Filter target_list to not not show the used paths + target_list = [elem for elem in target_list + if elem.get('target') not in used_paths] + return [dict(t) for t in set(tuple(t.items()) for t in target_list)] + + def _get_storage_server_spec(self, **kwargs): + # Required parameters: + # server: + # target_type: + extra_args = [] + server_type = kwargs['target_type'] + if server_type == 'netfs': + extra_args.append(E.format(type='nfs')) + else: + extra_args.append(E.format(type=server_type)) + + host_attr = {"name": kwargs['server']} + server_port = kwargs.get("server_port") + if server_port is not None: + host_attr['port'] = server_port + + obj = E.source(E.host(host_attr), *extra_args) + xml = ET.tostring(obj) + return xml + + def _parse_target_source_result(self, target_type, xml_str): + root = objectify.fromstring(xml_str) + ret = [] + for source in root.getchildren(): + if target_type == 'netfs': + target_path = source.dir.get('path') + type = source.format.get('type') + if target_type == 'iscsi': + target_path = source.device.get('path') + type = target_type + host_name = source.host.get('name') + ret.append(dict(host=host_name, target_type=type, + target=target_path)) + return ret diff --git a/src/wok/plugins/kimchi/model/storagevolumes.py b/src/wok/plugins/kimchi/model/storagevolumes.py new file mode 100644 index 0000000..99b17d3 --- /dev/null +++ b/src/wok/plugins/kimchi/model/storagevolumes.py @@ -0,0 +1,542 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import contextlib +import libvirt +import lxml.etree as ET +import os +import tempfile +import threading +import time +import urllib2 +from lxml.builder import E + +from wok.exception import InvalidOperation, InvalidParameter, IsoFormatError +from wok.exception import MissingParameter, NotFoundError, OperationFailed +from wok.utils import add_task, get_next_clone_name, get_unique_file_name +from wok.utils import wok_log +from wok.xmlutils.utils import xpath_get_text +from wok.model.tasks import TaskModel + +from ..config import READONLY_POOL_TYPE +from ..isoinfo import IsoImage +from diskutils import get_disk_used_by, set_disk_used_by +from storagepools import StoragePoolModel + + +VOLUME_TYPE_MAP = {0: 'file', + 1: 'block', + 2: 'directory', + 3: 'network'} + +READ_CHUNK_SIZE = 1048576 # 1 MiB +REQUIRE_NAME_PARAMS = ['capacity'] + +upload_volumes = dict() + + +class StorageVolumesModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + self.task = TaskModel(**kargs) + + def create(self, pool_name, params): + vol_source = ['url', 'capacity'] + + name = params.get('name') + + index_list = list(i for i in range(len(vol_source)) + if vol_source[i] in params) + if len(index_list) != 1: + raise InvalidParameter("KCHVOL0018E", + {'param': ",".join(vol_source)}) + + create_param = vol_source[index_list[0]] + + # Verify if the URL is valid + if create_param == 'url': + url = params['url'] + try: + urllib2.urlopen(url).close() + except: + raise InvalidParameter('KCHVOL0022E', {'url': url}) + + all_vol_names = self.get_list(pool_name) + + if name is None: + # the methods listed in 'REQUIRE_NAME_PARAMS' cannot have + # 'name' == None + if create_param in REQUIRE_NAME_PARAMS: + raise InvalidParameter('KCHVOL0016E') + + # if 'name' is omitted - except for the methods listed in + # 'REQUIRE_NAME_PARAMS' - the default volume name will be the + # file/URL basename. + if create_param == 'url': + name = os.path.basename(params['url']) + else: + name = 'upload-%s' % int(time.time()) + + name = get_unique_file_name(all_vol_names, name) + params['name'] = name + + try: + create_func = getattr(self, '_create_volume_with_%s' % + create_param) + except AttributeError: + raise InvalidParameter("KCHVOL0019E", {'param': create_param}) + + pool_info = StoragePoolModel(conn=self.conn, + objstore=self.objstore).lookup(pool_name) + if pool_info['type'] in READONLY_POOL_TYPE: + raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']}) + if pool_info['state'] == 'inactive': + raise InvalidParameter('KCHVOL0003E', {'pool': pool_name, + 'volume': name}) + if name in all_vol_names: + raise InvalidParameter('KCHVOL0001E', {'name': name}) + + params['pool'] = pool_name + targeturi = '/plugins/kimchi/storagepools/%s/storagevolumes/%s' \ + % (pool_name, name) + taskid = add_task(targeturi, create_func, self.objstore, params) + return self.task.lookup(taskid) + + def _create_volume_with_capacity(self, cb, params): + pool_name = params.pop('pool') + vol_xml = """ + <volume> + <name>%(name)s</name> + <allocation unit='bytes'>%(allocation)s</allocation> + <capacity unit='bytes'>%(capacity)s</capacity> + <source> + </source> + <target> + <format type='%(format)s'/> + </target> + </volume> + """ + params.setdefault('allocation', 0) + params.setdefault('format', 'qcow2') + + name = params['name'] + try: + pool = StoragePoolModel.get_storagepool(pool_name, self.conn) + xml = vol_xml % params + except KeyError, item: + raise MissingParameter("KCHVOL0004E", {'item': str(item), + 'volume': name}) + + try: + pool.createXML(xml, 0) + except libvirt.libvirtError as e: + raise OperationFailed("KCHVOL0007E", + {'name': name, 'pool': pool, + 'err': e.get_error_message()}) + + vol_info = StorageVolumeModel(conn=self.conn, + objstore=self.objstore).lookup(pool_name, + name) + + vol_path = vol_info['path'] + set_disk_used_by(self.objstore, vol_info['path'], []) + + if params.get('upload', False): + upload_volumes[vol_path] = {'lock': threading.Lock(), + 'offset': 0, 'cb': cb} + cb('ready for upload') + else: + cb('OK', True) + + def _create_volume_with_url(self, cb, params): + pool_name = params['pool'] + name = params['name'] + url = params['url'] + + pool_model = StoragePoolModel(conn=self.conn, + objstore=self.objstore) + pool = pool_model.lookup(pool_name) + + if pool['type'] in ['dir', 'netfs']: + file_path = os.path.join(pool['path'], name) + else: + file_path = tempfile.mkstemp(prefix=name)[1] + + with contextlib.closing(urllib2.urlopen(url)) as response: + with open(file_path, 'w') as volume_file: + remote_size = response.info().getheader('Content-Length', '-') + downloaded_size = 0 + + try: + while True: + chunk_data = response.read(READ_CHUNK_SIZE) + if not chunk_data: + break + + volume_file.write(chunk_data) + downloaded_size += len(chunk_data) + cb('%s/%s' % (downloaded_size, remote_size)) + except (IOError, libvirt.libvirtError) as e: + if os.path.isfile(file_path): + os.remove(file_path) + + raise OperationFailed('KCHVOL0007E', {'name': name, + 'pool': pool_name, + 'err': e.message}) + + if pool['type'] in ['dir', 'netfs']: + virt_pool = StoragePoolModel.get_storagepool(pool_name, self.conn) + virt_pool.refresh(0) + else: + def _stream_handler(stream, nbytes, fd): + return fd.read(nbytes) + + virt_stream = virt_vol = None + + try: + task = self.create(pool_name, {'name': name, + 'format': 'raw', + 'capacity': downloaded_size, + 'allocation': downloaded_size}) + self.task.wait(task['id']) + virt_vol = StorageVolumeModel.get_storagevolume(pool_name, + name, + self.conn) + + virt_stream = self.conn.get().newStream(0) + virt_vol.upload(virt_stream, 0, downloaded_size, 0) + + with open(file_path) as fd: + virt_stream.sendAll(_stream_handler, fd) + + virt_stream.finish() + except (IOError, libvirt.libvirtError) as e: + try: + if virt_stream: + virt_stream.abort() + if virt_vol: + virt_vol.delete(0) + except libvirt.libvirtError, virt_e: + wok_log.error(virt_e.message) + finally: + raise OperationFailed('KCHVOL0007E', {'name': name, + 'pool': pool_name, + 'err': e.message}) + finally: + os.remove(file_path) + + vol_info = StorageVolumeModel(conn=self.conn, + objstore=self.objstore).lookup(pool_name, + name) + set_disk_used_by(self.objstore, vol_info['path'], []) + + cb('OK', True) + + def get_list(self, pool_name): + pool = StoragePoolModel.get_storagepool(pool_name, self.conn) + if not pool.isActive(): + raise InvalidOperation("KCHVOL0006E", {'pool': pool_name}) + try: + pool.refresh(0) + return sorted(map(lambda x: x.decode('utf-8'), pool.listVolumes())) + except libvirt.libvirtError as e: + raise OperationFailed("KCHVOL0008E", + {'pool': pool_name, + 'err': e.get_error_message()}) + + +class StorageVolumeModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + self.task = TaskModel(**kargs) + self.storagevolumes = StorageVolumesModel(**kargs) + self.storagepool = StoragePoolModel(**kargs) + + @staticmethod + def get_storagevolume(poolname, name, conn): + pool = StoragePoolModel.get_storagepool(poolname, conn) + if not pool.isActive(): + raise InvalidOperation("KCHVOL0006E", {'name': pool}) + try: + return pool.storageVolLookupByName(name.encode("utf-8")) + except libvirt.libvirtError as e: + if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL: + raise NotFoundError("KCHVOL0002E", {'name': name, + 'pool': poolname}) + else: + raise + + def lookup(self, pool, name): + vol = StorageVolumeModel.get_storagevolume(pool, name, self.conn) + path = vol.path() + info = vol.info() + xml = vol.XMLDesc(0) + try: + fmt = xpath_get_text(xml, "/volume/target/format/@type")[0] + except IndexError: + # Not all types of libvirt storage can provide volume format + # infomation. When there is no format information, we assume + # it's 'raw'. + fmt = 'raw' + + iso_img = None + + # 'raw' volumes from 'logical' pools may actually be 'iso'; + # libvirt always reports them as 'raw' + pool_info = self.storagepool.lookup(pool) + if pool_info['type'] == 'logical' and fmt == 'raw': + try: + iso_img = IsoImage(path) + except IsoFormatError: + # not 'iso' afterall + pass + else: + fmt = 'iso' + + used_by = get_disk_used_by(self.objstore, self.conn, path) + res = dict(type=VOLUME_TYPE_MAP[info[0]], + capacity=info[1], + allocation=info[2], + path=path, + used_by=used_by, + format=fmt) + if fmt == 'iso': + if os.path.islink(path): + path = os.path.join(os.path.dirname(path), os.readlink(path)) + os_distro = os_version = 'unknown' + try: + if iso_img is None: + iso_img = IsoImage(path) + os_distro, os_version = iso_img.probe() + bootable = True + except IsoFormatError: + bootable = False + res.update( + dict(os_distro=os_distro, os_version=os_version, path=path, + bootable=bootable)) + return res + + def wipe(self, pool, name): + volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn) + try: + volume.wipePattern(libvirt.VIR_STORAGE_VOL_WIPE_ALG_ZERO, 0) + except libvirt.libvirtError as e: + raise OperationFailed("KCHVOL0009E", + {'name': name, 'err': e.get_error_message()}) + + def delete(self, pool, name): + pool_info = StoragePoolModel(conn=self.conn, + objstore=self.objstore).lookup(pool) + if pool_info['type'] in READONLY_POOL_TYPE: + raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']}) + + volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn) + try: + volume.delete(0) + except libvirt.libvirtError as e: + raise OperationFailed("KCHVOL0010E", + {'name': name, 'err': e.get_error_message()}) + + def resize(self, pool, name, size): + volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn) + + # When decreasing the storage volume capacity, the flag + # VIR_STORAGE_VOL_RESIZE_SHRINK must be used + flags = 0 + if volume.info()[1] > size: + # FIXME: Even using VIR_STORAGE_VOL_RESIZE_SHRINK flag it is not + # possible to decrease the volume capacity due a libvirt bug + # For reference: + # - https://bugzilla.redhat.com/show_bug.cgi?id=1021802 + flags = libvirt.VIR_STORAGE_VOL_RESIZE_SHRINK + + try: + volume.resize(size, flags) + except libvirt.libvirtError as e: + raise OperationFailed("KCHVOL0011E", + {'name': name, 'err': e.get_error_message()}) + + def clone(self, pool, name, new_pool=None, new_name=None): + """Clone a storage volume. + + Arguments: + pool -- The name of the original pool. + name -- The name of the original volume. + new_pool -- The name of the destination pool (optional). If omitted, + the new volume will be created on the same pool as the + original one. + new_name -- The name of the new volume (optional). If omitted, a new + value based on the original volume's name will be used. + + Return: + A Task running the clone operation. + """ + # the same pool will be used if no pool is specified + if new_pool is None: + new_pool = pool + + # a default name based on the original name will be used if no name + # is specified + if new_name is None: + base, ext = os.path.splitext(name) + new_name = get_next_clone_name(self.storagevolumes.get_list(pool), + base, ext) + + params = {'pool': pool, + 'name': name, + 'new_pool': new_pool, + 'new_name': new_name} + taskid = add_task(u'/plugins/kimchi/storagepools/%s/storagevolumes/%s' + % (pool, new_name), self._clone_task, self.objstore, + params) + return self.task.lookup(taskid) + + def _clone_task(self, cb, params): + """Asynchronous function which performs the clone operation. + + This function copies all the data inside the original volume into the + new one. + + Arguments: + cb -- A callback function to signal the Task's progress. + params -- A dict with the following values: + "pool": The name of the original pool. + "name": The name of the original volume. + "new_pool": The name of the destination pool. + "new_name": The name of the new volume. + """ + orig_pool_name = params['pool'] + orig_vol_name = params['name'] + new_pool_name = params['new_pool'] + new_vol_name = params['new_name'] + + try: + cb('setting up volume cloning') + orig_vir_vol = StorageVolumeModel.get_storagevolume(orig_pool_name, + orig_vol_name, + self.conn) + orig_vol = self.lookup(orig_pool_name, orig_vol_name) + new_vir_pool = StoragePoolModel.get_storagepool(new_pool_name, + self.conn) + + cb('building volume XML') + root_elem = E.volume() + root_elem.append(E.name(new_vol_name)) + root_elem.append(E.capacity(unicode(orig_vol['capacity']), + unit='bytes')) + target_elem = E.target() + target_elem.append(E.format(type=orig_vol['format'])) + root_elem.append(target_elem) + new_vol_xml = ET.tostring(root_elem, encoding='utf-8', + pretty_print=True) + + cb('cloning volume') + new_vir_pool.createXMLFrom(new_vol_xml, orig_vir_vol, 0) + except (InvalidOperation, NotFoundError, libvirt.libvirtError), e: + raise OperationFailed('KCHVOL0023E', + {'name': orig_vol_name, + 'pool': orig_pool_name, + 'err': e.get_error_message()}) + + new_vol = self.lookup(new_pool_name, new_vol_name) + cb('adding volume to the object store') + set_disk_used_by(self.objstore, new_vol['path'], []) + + cb('OK', True) + + def doUpload(self, cb, vol, offset, data, data_size): + try: + st = self.conn.get().newStream(0) + vol.upload(st, offset, data_size) + st.send(data) + st.finish() + except Exception as e: + st and st.abort() + cb('', False) + + try: + vol.delete(0) + except Exception as e: + pass + + raise OperationFailed("KCHVOL0029E", {"err": e.message}) + + def update(self, pool, name, params): + chunk_data = params['chunk'].fullvalue() + chunk_size = int(params['chunk_size']) + + if len(chunk_data) != chunk_size: + raise OperationFailed("KCHVOL0026E") + + vol = StorageVolumeModel.get_storagevolume(pool, name, self.conn) + vol_path = vol.path() + vol_capacity = vol.info()[1] + + vol_data = upload_volumes.get(vol_path) + if vol_data is None: + raise OperationFailed("KCHVOL0027E", {"vol": vol_path}) + + cb = vol_data['cb'] + lock = vol_data['lock'] + with lock: + offset = vol_data['offset'] + if (offset + chunk_size) > vol_capacity: + raise OperationFailed("KCHVOL0028E") + + cb('%s/%s' % (offset, vol_capacity)) + self.doUpload(cb, vol, offset, chunk_data, chunk_size) + cb('%s/%s' % (offset + chunk_size, vol_capacity)) + + vol_data['offset'] += chunk_size + if vol_data['offset'] == vol_capacity: + del upload_volumes[vol_path] + cb('OK', True) + + +class IsoVolumesModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.storagevolume = StorageVolumeModel(**kargs) + + def get_list(self): + iso_volumes = [] + conn = self.conn.get() + pools = conn.listStoragePools() + pools += conn.listDefinedStoragePools() + + for pool_name in pools: + try: + pool = StoragePoolModel.get_storagepool(pool_name, self.conn) + pool.refresh(0) + volumes = pool.listVolumes() + except Exception, e: + # Skip inactive pools + wok_log.debug("Shallow scan: skipping pool %s because of " + "error: %s", (pool_name, e.message)) + continue + + for volume in volumes: + res = self.storagevolume.lookup(pool_name, + volume.decode("utf-8")) + if res['format'] == 'iso' and res['bootable']: + res['name'] = '%s' % volume + iso_volumes.append(res) + return iso_volumes diff --git a/src/wok/plugins/kimchi/model/templates.py b/src/wok/plugins/kimchi/model/templates.py new file mode 100644 index 0000000..4f0b204 --- /dev/null +++ b/src/wok/plugins/kimchi/model/templates.py @@ -0,0 +1,303 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import copy +import libvirt +import os +import stat + +from wok.exception import InvalidOperation, InvalidParameter +from wok.exception import NotFoundError, OperationFailed +from wok.utils import probe_file_permission_as_user, run_setfacl_set_attr +from wok.xmlutils.utils import xpath_get_text + +from ..kvmusertests import UserTests +from ..utils import pool_name_from_uri +from ..vmtemplate import VMTemplate +from cpuinfo import CPUInfoModel + + +class TemplatesModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + + def create(self, params): + name = params.get('name', '').strip() + iso = params.get('cdrom') + # check search permission + if iso and iso.startswith('/') and os.path.exists(iso): + st_mode = os.stat(iso).st_mode + if stat.S_ISREG(st_mode) or stat.S_ISBLK(st_mode): + user = UserTests().probe_user() + run_setfacl_set_attr(iso, user=user) + ret, excp = probe_file_permission_as_user(iso, user) + if ret is False: + raise InvalidParameter('KCHISO0008E', + {'filename': iso, 'user': user, + 'err': excp}) + + cpu_info = params.get('cpu_info') + if cpu_info: + topology = cpu_info.get('topology') + # Check, even though currently only topology + # is supported. + if topology: + sockets = topology['sockets'] + cores = topology['cores'] + threads = topology['threads'] + if params.get('cpus') is None: + params['cpus'] = sockets * cores * threads + # check_topoology will raise the appropriate + # exception if a topology is invalid. + CPUInfoModel(conn=self.conn).\ + check_topology(params['cpus'], topology) + + conn = self.conn.get() + pool_uri = params.get(u'storagepool', '') + if pool_uri: + try: + pool_name = pool_name_from_uri(pool_uri) + pool = conn.storagePoolLookupByName(pool_name.encode("utf-8")) + except Exception: + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_uri, + 'template': name}) + + tmp_volumes = [disk['volume'] for disk in params.get('disks', []) + if 'volume' in disk] + self.template_volume_validate(tmp_volumes, pool) + + for net_name in params.get(u'networks', []): + try: + conn.networkLookupByName(net_name.encode('utf-8')) + except Exception: + raise InvalidParameter("KCHTMPL0003E", {'network': net_name, + 'template': name}) + # Creates the template class with necessary information + # Checkings will be done while creating this class, so any exception + # will be raised here + t = LibvirtVMTemplate(params, scan=True, conn=self.conn) + name = params['name'] + try: + with self.objstore as session: + if name in session.get_list('template'): + raise InvalidOperation("KCHTMPL0001E", {'name': name}) + session.store('template', name, t.info) + except InvalidOperation: + raise + except Exception, e: + raise OperationFailed('KCHTMPL0020E', {'err': e.message}) + + return name + + def get_list(self): + with self.objstore as session: + return session.get_list('template') + + def template_volume_validate(self, tmp_volumes, pool): + kwargs = {'conn': self.conn, 'objstore': self.objstore} + pool_type = xpath_get_text(pool.XMLDesc(0), "/pool/@type")[0] + pool_name = unicode(pool.name(), 'utf-8') + + # as we discussion, we do not mix disks from 2 different types of + # storage pools, for instance: we do not create a template with 2 + # disks, where one comes from a SCSI pool and other is a .img in + # a DIR pool. + if pool_type in ['iscsi', 'scsi']: + if not tmp_volumes: + raise InvalidParameter("KCHTMPL0018E") + + storagevolumes = __import__("kimchi.model.storagevolumes", + fromlist=['']) + pool_volumes = storagevolumes.StorageVolumesModel( + **kwargs).get_list(pool_name) + vols = set(tmp_volumes) - set(pool_volumes) + if vols: + raise InvalidParameter("KCHTMPL0019E", {'pool': pool_name, + 'volume': vols}) + + +class TemplateModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + self.templates = TemplatesModel(**kargs) + + @staticmethod + def get_template(name, objstore, conn, overrides=None): + with objstore as session: + params = session.get('template', name) + if overrides: + params.update(overrides) + return LibvirtVMTemplate(params, False, conn) + + def lookup(self, name): + t = self.get_template(name, self.objstore, self.conn) + return t.validate_integrity() + + def clone(self, name): + # set default name + subfixs = [v[len(name):] for v in self.templates.get_list() + if v.startswith(name)] + indexs = [int(v.lstrip("-clone")) for v in subfixs + if v.startswith("-clone") and + v.lstrip("-clone").isdigit()] + indexs.sort() + index = "1" if not indexs else str(indexs[-1] + 1) + clone_name = name + "-clone" + index + + temp = self.lookup(name) + temp['name'] = clone_name + ident = self.templates.create(temp) + return ident + + def delete(self, name): + try: + with self.objstore as session: + session.delete('template', name) + except NotFoundError: + raise + except Exception as e: + raise OperationFailed('KCHTMPL0021E', {'err': e.message}) + + def update(self, name, params): + old_t = self.lookup(name) + new_t = copy.copy(old_t) + new_t.update(params) + + if not self._validate_updated_cpu_params(new_t): + raise InvalidParameter('KCHTMPL0025E') + + ident = name + + conn = self.conn.get() + pool_uri = new_t.get(u'storagepool', '') + + if pool_uri: + try: + pool_name = pool_name_from_uri(pool_uri) + pool = conn.storagePoolLookupByName(pool_name.encode("utf-8")) + except Exception: + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_uri, + 'template': name}) + tmp_volumes = [disk['volume'] for disk in new_t.get('disks', []) + if 'volume' in disk] + self.templates.template_volume_validate(tmp_volumes, pool) + + for net_name in params.get(u'networks', []): + try: + conn.networkLookupByName(net_name.encode('utf-8')) + except Exception: + raise InvalidParameter("KCHTMPL0003E", {'network': net_name, + 'template': name}) + + self.delete(name) + try: + ident = self.templates.create(new_t) + except: + ident = self.templates.create(old_t) + raise + return ident + + def _validate_updated_cpu_params(self, info): + # Note: cpu_info is the parent of topology. cpus is vcpus + vcpus = info['cpus'] + cpu_info = info.get('cpu_info') + # cpu_info will always be at least an empty dict + topology = cpu_info.get('topology') + if topology is None: + return True + return vcpus == topology['sockets'] * topology['cores'] * \ + topology['threads'] + + +class LibvirtVMTemplate(VMTemplate): + def __init__(self, args, scan=False, conn=None): + self.conn = conn + VMTemplate.__init__(self, args, scan) + + def _storage_validate(self): + pool_uri = self.info['storagepool'] + pool_name = pool_name_from_uri(pool_uri) + try: + conn = self.conn.get() + pool = conn.storagePoolLookupByName(pool_name.encode("utf-8")) + except libvirt.libvirtError: + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_uri, + 'template': self.name}) + + if not pool.isActive(): + raise InvalidParameter("KCHTMPL0005E", {'pool': pool_name, + 'template': self.name}) + + return pool + + def _get_all_networks_name(self): + conn = self.conn.get() + return sorted(conn.listNetworks() + conn.listDefinedNetworks()) + + def _get_all_storagepools_name(self): + conn = self.conn.get() + names = conn.listStoragePools() + conn.listDefinedStoragePools() + return sorted(map(lambda x: x.decode('utf-8'), names)) + + def _network_validate(self): + names = self.info['networks'] + for name in names: + try: + conn = self.conn.get() + network = conn.networkLookupByName(name.encode('utf-8')) + except libvirt.libvirtError: + raise InvalidParameter("KCHTMPL0003E", {'network': name, + 'template': self.name}) + + if not network.isActive(): + raise InvalidParameter("KCHTMPL0007E", {'network': name, + 'template': self.name}) + + def _get_storage_path(self): + pool = self._storage_validate() + xml = pool.XMLDesc(0) + return xpath_get_text(xml, "/pool/target/path")[0] + + def _get_storage_type(self): + pool = self._storage_validate() + xml = pool.XMLDesc(0) + return xpath_get_text(xml, "/pool/@type")[0] + + def _get_volume_path(self, pool, vol): + pool = self._storage_validate() + try: + return pool.storageVolLookupByName(vol).path() + except: + raise NotFoundError("KCHVOL0002E", {'name': vol, + 'pool': pool}) + + def fork_vm_storage(self, vm_uuid): + # Provision storage: + # TODO: Rebase on the storage API once upstream + pool = self._storage_validate() + vol_list = self.to_volume_list(vm_uuid) + try: + for v in vol_list: + # outgoing text to libvirt, encode('utf-8') + pool.createXML(v['xml'].encode('utf-8'), 0) + except libvirt.libvirtError as e: + raise OperationFailed("KCHVMSTOR0008E", {'error': e.message}) + return vol_list diff --git a/src/wok/plugins/kimchi/model/users.py b/src/wok/plugins/kimchi/model/users.py new file mode 100644 index 0000000..2fa65dd --- /dev/null +++ b/src/wok/plugins/kimchi/model/users.py @@ -0,0 +1,90 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import ldap +import pwd + +from wok.config import config +from wok.exception import NotFoundError + + +class UsersModel(object): + def __init__(self, **args): + auth_type = config.get("authentication", "method") + for klass in UsersModel.__subclasses__(): + if auth_type == klass.auth_type: + self.user = klass(**args) + + def get_list(self, **args): + return self.user._get_list(**args) + + def validate(self, user): + return self.user._validate(user) + + +class PAMUsersModel(UsersModel): + auth_type = 'pam' + + def __init__(self, **kargs): + pass + + def _get_list(self): + return [user.pw_name for user in pwd.getpwall() + if user.pw_shell.rsplit("/")[-1] not in ["nologin", "false"]] + + def _validate(self, user): + try: + return user in self._get_list() + except: + return False + + +class LDAPUsersModel(UsersModel): + auth_type = 'ldap' + + def __init__(self, **kargs): + pass + + def _get_list(self, _user_id=''): + return self._get_user(_user_id) + + def _validate(self, user): + try: + self._get_user(user) + return True + except NotFoundError: + return False + + def _get_user(self, _user_id): + ldap_server = config.get("authentication", "ldap_server").strip('"') + ldap_search_base = config.get( + "authentication", "ldap_search_base").strip('"') + ldap_search_filter = config.get( + "authentication", "ldap_search_filter", + vars={"username": _user_id.encode("utf-8")}).strip('"') + + connect = ldap.open(ldap_server) + try: + result = connect.search_s( + ldap_search_base, ldap.SCOPE_SUBTREE, ldap_search_filter) + if len(result) == 0: + raise NotFoundError("KCHAUTH0004E", {'user_id': _user_id}) + return result[0][1] + except ldap.NO_SUCH_OBJECT: + raise NotFoundError("KCHAUTH0004E", {'user_id': _user_id}) diff --git a/src/wok/plugins/kimchi/model/utils.py b/src/wok/plugins/kimchi/model/utils.py new file mode 100644 index 0000000..53d719d --- /dev/null +++ b/src/wok/plugins/kimchi/model/utils.py @@ -0,0 +1,161 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import libvirt +from lxml import etree, objectify +from lxml.builder import E, ElementMaker + +from wok.exception import OperationFailed + + +KIMCHI_META_URL = "https://github.com/kimchi-project/kimchi" +KIMCHI_NAMESPACE = "kimchi" + + +def get_vm_name(vm_name, t_name, name_list): + if vm_name: + return vm_name + for i in xrange(1, 1000): + # VM will have templace name, but without slashes + vm_name = "%s-vm-%i" % (t_name.replace('/', '-'), i) + if vm_name not in name_list: + return vm_name + raise OperationFailed("KCHUTILS0003E") + + +def get_vm_config_flag(dom, mode="persistent"): + # libvirt.VIR_DOMAIN_AFFECT_CURRENT is 0 + # VIR_DOMAIN_AFFECT_LIVE is 1, VIR_DOMAIN_AFFECT_CONFIG is 2 + flag = {"live": libvirt.VIR_DOMAIN_AFFECT_LIVE, + "persistent": libvirt.VIR_DOMAIN_AFFECT_CONFIG, + "current": libvirt.VIR_DOMAIN_AFFECT_CURRENT, + "all": libvirt.VIR_DOMAIN_AFFECT_CONFIG + + libvirt.VIR_DOMAIN_AFFECT_LIVE if dom.isActive() and + dom.isPersistent() else libvirt.VIR_DOMAIN_AFFECT_CURRENT} + + return flag[mode] + + +# avoid duplicate codes +def update_node(root, node): + old_node = root.find(node.tag) + (root.replace(old_node, node) if old_node is not None + else root.append(node)) + return root + + +def _kimchi_set_metadata_node(dom, node): + # some other tools will not let libvirt create a persistent + # configuration, raise exception. + if not dom.isPersistent(): + msg = 'The VM has not a persistent configuration' + raise OperationFailed("KCHVM0030E", + {'name': dom.name(), "err": msg}) + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE) + root = etree.fromstring(xml) + kimchi = root.find("metadata/{%s}kimchi" % KIMCHI_META_URL) + + EM = ElementMaker(namespace=KIMCHI_META_URL, + nsmap={KIMCHI_NAMESPACE: KIMCHI_META_URL}) + kimchi = EM("kimchi") if kimchi is None else kimchi + + update_node(kimchi, node) + metadata = root.find("metadata") + metadata = E.metadata() if metadata is None else metadata + update_node(metadata, kimchi) + update_node(root, metadata) + dom.connect().defineXML(etree.tostring(root)) + + +def libvirt_get_kimchi_metadata_node(dom, mode="current"): + if not metadata_exists(dom): + return None + try: + xml = dom.metadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT, + KIMCHI_META_URL, + flags=get_vm_config_flag(dom, mode)) + return etree.fromstring(xml) + except libvirt.libvirtError: + return None + + +def set_metadata_node(dom, node, metadata_support, mode="all"): + if metadata_support: + kimchi = libvirt_get_kimchi_metadata_node(dom, mode) + kimchi = E.metadata(E.kimchi()) if kimchi is None else kimchi + + update_node(kimchi, node) + kimchi_xml = etree.tostring(kimchi) + # From libvirt doc, Passing None for @metadata says to remove that + # element from the domain XML (passing the empty string leaves the + # element present). Do not support remove the old metadata. + dom.setMetadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT, kimchi_xml, + KIMCHI_NAMESPACE, KIMCHI_META_URL, + flags=get_vm_config_flag(dom, mode)) + else: + # FIXME remove this code when all distro libvirt supports metadata + # element + _kimchi_set_metadata_node(dom, node) + + +def _kimchi_get_metadata_node(dom, tag): + # some other tools will not let libvirt create a persistent + # configuration, just return empty + if not dom.isPersistent(): + return None + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE) + root = etree.fromstring(xml) + kimchi = root.find("metadata/{%s}kimchi" % KIMCHI_META_URL) + # remove the "kimchi" prefix of xml + if kimchi is not None: + for elem in kimchi.getiterator(): + if not hasattr(elem.tag, 'find'): + continue + i = elem.tag.find('}') + if i >= 0: + elem.tag = elem.tag[i+1:] + + objectify.deannotate(kimchi) + etree.cleanup_namespaces(kimchi) + return kimchi + return None + + +def get_metadata_node(dom, tag, metadata_support, mode="current"): + if metadata_support: + kimchi = libvirt_get_kimchi_metadata_node(dom, mode) + else: + # FIXME remove this code when all distro libvirt supports metadata + # element + kimchi = _kimchi_get_metadata_node(dom, tag) + + if kimchi is not None: + node = kimchi.find(tag) + if node is not None: + return etree.tostring(node) + return "" + + +def metadata_exists(dom): + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE) + root = etree.fromstring(xml) + + if root.find("metadata") is None: + return False + return True diff --git a/src/wok/plugins/kimchi/model/vmhostdevs.py b/src/wok/plugins/kimchi/model/vmhostdevs.py new file mode 100644 index 0000000..0cc6bd3 --- /dev/null +++ b/src/wok/plugins/kimchi/model/vmhostdevs.py @@ -0,0 +1,336 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import glob +import libvirt +import os +import platform +from lxml import etree, objectify +from lxml.builder import E + +from wok.exception import InvalidOperation, InvalidParameter, NotFoundError +from wok.exception import OperationFailed +from wok.rollbackcontext import RollbackContext +from wok.utils import run_command, wok_log + +from config import CapabilitiesModel +from host import DeviceModel, DevicesModel +from utils import get_vm_config_flag +from vms import DOM_STATE_MAP, VMModel + + +class VMHostDevsModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.caps = CapabilitiesModel(**kargs) + + def get_list(self, vmid): + dom = VMModel.get_vm(vmid, self.conn) + xmlstr = dom.XMLDesc(0) + root = objectify.fromstring(xmlstr) + try: + hostdev = root.devices.hostdev + except AttributeError: + return [] + + return [self._deduce_dev_name(e) for e in hostdev] + + @staticmethod + def _toint(num_str): + if num_str.startswith('0x'): + return int(num_str, 16) + elif num_str.startswith('0'): + return int(num_str, 8) + else: + return int(num_str) + + def _deduce_dev_name(self, e): + return getattr(self, '_deduce_dev_name_%s' % e.attrib['type'])(e) + + def _deduce_dev_name_pci(self, e): + attrib = {} + for field in ('domain', 'bus', 'slot', 'function'): + attrib[field] = self._toint(e.source.address.attrib[field]) + return 'pci_%(domain)04x_%(bus)02x_%(slot)02x_%(function)x' % attrib + + def _deduce_dev_name_scsi(self, e): + attrib = {} + for field in ('bus', 'target', 'unit'): + attrib[field] = self._toint(e.source.address.attrib[field]) + attrib['host'] = self._toint( + e.source.adapter.attrib['name'][len('scsi_host'):]) + return 'scsi_%(host)d_%(bus)d_%(target)d_%(unit)d' % attrib + + def _deduce_dev_name_usb(self, e): + dev_names = DevicesModel(conn=self.conn).get_list(_cap='usb_device') + usb_infos = [DeviceModel(conn=self.conn).lookup(dev_name) + for dev_name in dev_names] + + unknown_dev = None + + try: + evendor = self._toint(e.source.vendor.attrib['id']) + eproduct = self._toint(e.source.product.attrib['id']) + except AttributeError: + evendor = 0 + eproduct = 0 + else: + unknown_dev = 'usb_vendor_%s_product_%s' % (evendor, eproduct) + + try: + ebus = self._toint(e.source.address.attrib['bus']) + edevice = self._toint(e.source.address.attrib['device']) + except AttributeError: + ebus = -1 + edevice = -1 + else: + unknown_dev = 'usb_bus_%s_device_%s' % (ebus, edevice) + + for usb_info in usb_infos: + ivendor = self._toint(usb_info['vendor']['id']) + iproduct = self._toint(usb_info['product']['id']) + if evendor == ivendor and eproduct == iproduct: + return usb_info['name'] + ibus = usb_info['bus'] + idevice = usb_info['device'] + if ebus == ibus and edevice == idevice: + return usb_info['name'] + return unknown_dev + + def _passthrough_device_validate(self, dev_name): + eligible_dev_names = \ + DevicesModel(conn=self.conn).get_list(_passthrough='true') + if dev_name not in eligible_dev_names: + raise InvalidParameter('KCHVMHDEV0002E', {'dev_name': dev_name}) + + def create(self, vmid, params): + dev_name = params['name'] + self._passthrough_device_validate(dev_name) + dev_info = DeviceModel(conn=self.conn).lookup(dev_name) + + with RollbackContext() as rollback: + try: + dev = self.conn.get().nodeDeviceLookupByName(dev_name) + dev.dettach() + except Exception: + raise OperationFailed('KCHVMHDEV0005E', {'name': dev_name}) + else: + rollback.prependDefer(dev.reAttach) + + attach_device = getattr( + self, '_attach_%s_device' % dev_info['device_type']) + + info = attach_device(vmid, dev_info) + rollback.commitAll() + + return info + + def _get_pci_device_xml(self, dev_info): + if 'detach_driver' not in dev_info: + dev_info['detach_driver'] = 'kvm' + + source = E.source(E.address(domain=str(dev_info['domain']), + bus=str(dev_info['bus']), + slot=str(dev_info['slot']), + function=str(dev_info['function']))) + driver = E.driver(name=dev_info['detach_driver']) + host_dev = E.hostdev(source, driver, + mode='subsystem', type='pci', managed='yes') + + return etree.tostring(host_dev) + + @staticmethod + def _validate_pci_passthrough_env(): + # Linux kernel < 3.5 doesn't provide /sys/kernel/iommu_groups + if os.path.isdir('/sys/kernel/iommu_groups'): + if not glob.glob('/sys/kernel/iommu_groups/*'): + raise InvalidOperation("KCHVMHDEV0003E") + + # Enable virt_use_sysfs on RHEL6 and older distributions + # In recent Fedora, there is no virt_use_sysfs. + out, err, rc = run_command(['getsebool', 'virt_use_sysfs']) + if rc == 0 and out.rstrip('\n') != "virt_use_sysfs --> on": + out, err, rc = run_command(['setsebool', '-P', + 'virt_use_sysfs=on']) + if rc != 0: + wok_log.warning("Unable to turn on sebool virt_use_sysfs") + + def _attach_pci_device(self, vmid, dev_info): + self._validate_pci_passthrough_env() + + dom = VMModel.get_vm(vmid, self.conn) + # Due to libvirt limitation, we don't support live assigne device to + # vfio driver. + driver = ('vfio' if DOM_STATE_MAP[dom.info()[0]] == "shutoff" and + self.caps.kernel_vfio else 'kvm') + + # on powerkvm systems it must be vfio driver. + distro, _, _ = platform.linux_distribution() + if distro == 'IBM_PowerKVM': + driver = 'vfio' + + # Attach all PCI devices in the same IOMMU group + dev_model = DeviceModel(conn=self.conn) + devs_model = DevicesModel(conn=self.conn) + affected_names = devs_model.get_list( + _passthrough_affected_by=dev_info['name']) + passthrough_names = devs_model.get_list( + _cap='pci', _passthrough='true') + group_names = list(set(affected_names) & set(passthrough_names)) + pci_infos = [dev_model.lookup(dev_name) for dev_name in group_names] + pci_infos.append(dev_info) + + device_flags = get_vm_config_flag(dom, mode='all') + + with RollbackContext() as rollback: + for pci_info in pci_infos: + pci_info['detach_driver'] = driver + xmlstr = self._get_pci_device_xml(pci_info) + try: + dom.attachDeviceFlags(xmlstr, device_flags) + except libvirt.libvirtError: + wok_log.error( + 'Failed to attach host device %s to VM %s: \n%s', + pci_info['name'], vmid, xmlstr) + raise + rollback.prependDefer(dom.detachDeviceFlags, + xmlstr, device_flags) + rollback.commitAll() + + return dev_info['name'] + + def _get_scsi_device_xml(self, dev_info): + adapter = E.adapter(name=('scsi_host%s' % dev_info['host'])) + address = E.address(type='scsi', bus=str(dev_info['bus']), + target=str(dev_info['target']), + unit=str(dev_info['lun'])) + host_dev = E.hostdev(E.source(adapter, address), + mode='subsystem', type='scsi', sgio='unfiltered') + return etree.tostring(host_dev) + + def _attach_scsi_device(self, vmid, dev_info): + xmlstr = self._get_scsi_device_xml(dev_info) + dom = VMModel.get_vm(vmid, self.conn) + dom.attachDeviceFlags(xmlstr, get_vm_config_flag(dom, mode='all')) + return dev_info['name'] + + def _get_usb_device_xml(self, dev_info): + source = E.source( + E.vendor(id=dev_info['vendor']['id']), + E.product(id=dev_info['product']['id']), + E.address(bus=str(dev_info['bus']), + device=str(dev_info['device'])), + startupPolicy='optional') + host_dev = E.hostdev(source, mode='subsystem', + ype='usb', managed='yes') + return etree.tostring(host_dev) + + def _attach_usb_device(self, vmid, dev_info): + xmlstr = self._get_usb_device_xml(dev_info) + dom = VMModel.get_vm(vmid, self.conn) + dom.attachDeviceFlags(xmlstr, get_vm_config_flag(dom, mode='all')) + return dev_info['name'] + + +class VMHostDevModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + + def lookup(self, vmid, dev_name): + dom = VMModel.get_vm(vmid, self.conn) + xmlstr = dom.XMLDesc(0) + root = objectify.fromstring(xmlstr) + try: + hostdev = root.devices.hostdev + except AttributeError: + raise NotFoundError('KCHVMHDEV0001E', + {'vmid': vmid, 'dev_name': dev_name}) + + devsmodel = VMHostDevsModel(conn=self.conn) + + for e in hostdev: + deduced_name = devsmodel._deduce_dev_name(e) + if deduced_name == dev_name: + return {'name': dev_name, 'type': e.attrib['type']} + + raise NotFoundError('KCHVMHDEV0001E', + {'vmid': vmid, 'dev_name': dev_name}) + + def delete(self, vmid, dev_name): + dom = VMModel.get_vm(vmid, self.conn) + xmlstr = dom.XMLDesc(0) + root = objectify.fromstring(xmlstr) + + try: + hostdev = root.devices.hostdev + except AttributeError: + raise NotFoundError('KCHVMHDEV0001E', + {'vmid': vmid, 'dev_name': dev_name}) + + devsmodel = VMHostDevsModel(conn=self.conn) + pci_devs = [(devsmodel._deduce_dev_name(e), e) for e in hostdev + if e.attrib['type'] == 'pci'] + + for e in hostdev: + if devsmodel._deduce_dev_name(e) == dev_name: + xmlstr = etree.tostring(e) + dom.detachDeviceFlags( + xmlstr, get_vm_config_flag(dom, mode='all')) + if e.attrib['type'] == 'pci': + self._delete_affected_pci_devices(dom, dev_name, pci_devs) + break + else: + raise NotFoundError('KCHVMHDEV0001E', + {'vmid': vmid, 'dev_name': dev_name}) + + def _delete_affected_pci_devices(self, dom, dev_name, pci_devs): + dev_model = DeviceModel(conn=self.conn) + try: + dev_model.lookup(dev_name) + except NotFoundError: + return + + affected_names = set( + DevicesModel( + conn=self.conn).get_list(_passthrough_affected_by=dev_name)) + + for pci_name, e in pci_devs: + if pci_name in affected_names: + xmlstr = etree.tostring(e) + dom.detachDeviceFlags( + xmlstr, get_vm_config_flag(dom, mode='all')) + + +class VMHoldersModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + + def get_list(self, device_id): + devsmodel = VMHostDevsModel(conn=self.conn) + + conn = self.conn.get() + doms = conn.listAllDomains(0) + + res = [] + for dom in doms: + dom_name = dom.name() + if device_id in devsmodel.get_list(dom_name): + state = DOM_STATE_MAP[dom.info()[0]] + res.append({"name": dom_name, "state": state}) + return res diff --git a/src/wok/plugins/kimchi/model/vmifaces.py b/src/wok/plugins/kimchi/model/vmifaces.py new file mode 100644 index 0000000..87565c8 --- /dev/null +++ b/src/wok/plugins/kimchi/model/vmifaces.py @@ -0,0 +1,186 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import libvirt +import random +from lxml import etree, objectify + +from wok.exception import InvalidParameter, MissingParameter +from wok.exception import NotFoundError, InvalidOperation + +from ..xmlutils.interface import get_iface_xml +from config import CapabilitiesModel +from vms import DOM_STATE_MAP, VMModel + + +class VMIfacesModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.caps = CapabilitiesModel(**kargs) + + def get_list(self, vm): + macs = [] + for iface in self.get_vmifaces(vm, self.conn): + macs.append(iface.mac.get('address')) + return macs + + def create(self, vm, params): + conn = self.conn.get() + networks = conn.listNetworks() + conn.listDefinedNetworks() + networks = map(lambda x: x.decode('utf-8'), networks) + + if params['type'] == 'network': + network = params.get("network") + + if network is None: + raise MissingParameter('KCHVMIF0007E') + + if network not in networks: + raise InvalidParameter('KCHVMIF0002E', + {'name': vm, 'network': network}) + + macs = (iface.mac.get('address') + for iface in self.get_vmifaces(vm, self.conn)) + + # user defined customized mac address + if 'mac' in params and params['mac']: + # make sure it is unique + if params['mac'] in macs: + raise InvalidParameter('KCHVMIF0009E', + {'name': vm, 'mac': params['mac']}) + + # otherwise choose a random mac address + else: + while True: + params['mac'] = VMIfacesModel.random_mac() + if params['mac'] not in macs: + break + + dom = VMModel.get_vm(vm, self.conn) + + os_data = VMModel.vm_get_os_metadata(dom, self.caps.metadata_support) + os_version, os_distro = os_data + xml = get_iface_xml(params, conn.getInfo()[0], os_distro, os_version) + + flags = 0 + if dom.isPersistent(): + flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG + if DOM_STATE_MAP[dom.info()[0]] != "shutoff": + flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE + + dom.attachDeviceFlags(xml, flags) + + return params['mac'] + + @staticmethod + def get_vmifaces(vm, conn): + dom = VMModel.get_vm(vm, conn) + xml = dom.XMLDesc(0) + root = objectify.fromstring(xml) + + return root.devices.findall("interface") + + @staticmethod + def random_mac(): + mac = [0x52, 0x54, 0x00, + random.randint(0x00, 0x7f), + random.randint(0x00, 0xff), + random.randint(0x00, 0xff)] + return ':'.join(map(lambda x: u'%02x' % x, mac)) + + +class VMIfaceModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + + def _get_vmiface(self, vm, mac): + ifaces = VMIfacesModel.get_vmifaces(vm, self.conn) + + for iface in ifaces: + if iface.mac.get('address') == mac: + return iface + return None + + def lookup(self, vm, mac): + info = {} + + iface = self._get_vmiface(vm, mac) + if iface is None: + raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac}) + + info['type'] = iface.attrib['type'] + info['mac'] = iface.mac.get('address') + if iface.find("model") is not None: + info['model'] = iface.model.get('type') + if info['type'] == 'network': + info['network'] = iface.source.get('network') + if info['type'] == 'bridge': + info['bridge'] = iface.source.get('bridge') + + return info + + def delete(self, vm, mac): + dom = VMModel.get_vm(vm, self.conn) + iface = self._get_vmiface(vm, mac) + + if iface is None: + raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac}) + + flags = 0 + if dom.isPersistent(): + flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG + if DOM_STATE_MAP[dom.info()[0]] != "shutoff": + flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE + + dom.detachDeviceFlags(etree.tostring(iface), flags) + + def update(self, vm, mac, params): + dom = VMModel.get_vm(vm, self.conn) + iface = self._get_vmiface(vm, mac) + + if iface is None: + raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac}) + + # cannot change mac address in a running system + if DOM_STATE_MAP[dom.info()[0]] != "shutoff": + raise InvalidOperation('KCHVMIF0011E') + + # mac address is a required parameter + if 'mac' not in params: + raise MissingParameter('KCHVMIF0008E') + + # new mac address must be unique + if self._get_vmiface(vm, params['mac']) is not None: + raise InvalidParameter('KCHVMIF0009E', + {'name': vm, 'mac': params['mac']}) + + flags = 0 + if dom.isPersistent(): + flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG + + # remove the current nic + xml = etree.tostring(iface) + dom.detachDeviceFlags(xml, flags=flags) + + # add the nic with the desired mac address + iface.mac.attrib['address'] = params['mac'] + xml = etree.tostring(iface) + dom.attachDeviceFlags(xml, flags=flags) + + return [vm, params['mac']] diff --git a/src/wok/plugins/kimchi/model/vms.py b/src/wok/plugins/kimchi/model/vms.py new file mode 100644 index 0000000..f37b5d6 --- /dev/null +++ b/src/wok/plugins/kimchi/model/vms.py @@ -0,0 +1,1307 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import libvirt +import lxml.etree as ET +import os +import random +import string +import time +import uuid +from lxml import etree, objectify +from lxml.builder import E +from xml.etree import ElementTree + +from wok.config import config +from wok.exception import InvalidOperation, InvalidParameter +from wok.exception import NotFoundError, OperationFailed +from wok.rollbackcontext import RollbackContext +from wok.utils import add_task, convert_data_size, get_next_clone_name +from wok.utils import import_class, run_setfacl_set_attr, wok_log +from wok.xmlutils.utils import xpath_get_text, xml_item_update +from wok.xmlutils.utils import dictize +from wok.model.tasks import TaskModel + +from .. import model +from .. import vnc +from ..config import READONLY_POOL_TYPE +from ..kvmusertests import UserTests +from ..screenshot import VMScreenshot +from ..utils import template_name_from_uri +from ..xmlutils.cpu import get_cpu_xml, get_numa_xml +from config import CapabilitiesModel +from templates import TemplateModel +from utils import get_vm_name +from utils import get_metadata_node +from utils import set_metadata_node + + +DOM_STATE_MAP = {0: 'nostate', + 1: 'running', + 2: 'blocked', + 3: 'paused', + 4: 'shutdown', + 5: 'shutoff', + 6: 'crashed', + 7: 'pmsuspended'} + +VM_STATIC_UPDATE_PARAMS = {'name': './name', + 'cpus': './vcpu'} +VM_LIVE_UPDATE_PARAMS = {} + +XPATH_DOMAIN_DISK = "/domain/devices/disk[@device='disk']/source/@file" +XPATH_DOMAIN_DISK_BY_FILE = "./devices/disk[@device='disk']/source[@file='%s']" +XPATH_DOMAIN_NAME = '/domain/name' +XPATH_DOMAIN_MAC = "/domain/devices/interface[@type='network']/mac/@address" +XPATH_DOMAIN_MAC_BY_ADDRESS = "./devices/interface[@type='network']/"\ + "mac[@address='%s']" +XPATH_DOMAIN_MEMORY = '/domain/memory' +XPATH_DOMAIN_MEMORY_UNIT = '/domain/memory/@unit' +XPATH_DOMAIN_UUID = '/domain/uuid' + +XPATH_NUMA_CELL = './cpu/numa/cell' + + +class VMsModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + self.caps = CapabilitiesModel(**kargs) + self.task = TaskModel(**kargs) + + def create(self, params): + t_name = template_name_from_uri(params['template']) + vm_list = self.get_list() + name = get_vm_name(params.get('name'), t_name, vm_list) + # incoming text, from js json, is unicode, do not need decode + if name in vm_list: + raise InvalidOperation("KCHVM0001E", {'name': name}) + + vm_overrides = dict() + pool_uri = params.get('storagepool') + if pool_uri: + vm_overrides['storagepool'] = pool_uri + vm_overrides['fc_host_support'] = self.caps.fc_host_support + t = TemplateModel.get_template(t_name, self.objstore, self.conn, + vm_overrides) + + if not self.caps.qemu_stream and t.info.get('iso_stream', False): + raise InvalidOperation("KCHVM0005E") + + t.validate() + data = {'name': name, 'template': t, + 'graphics': params.get('graphics', {})} + taskid = add_task(u'/plugins/kimchi/vms/%s' % name, self._create_task, + self.objstore, data) + + return self.task.lookup(taskid) + + def _create_task(self, cb, params): + """ + params: A dict with the following values: + - vm_uuid: The UUID of the VM being created + - template: The template being used to create the VM + - name: The name for the new VM + """ + vm_uuid = str(uuid.uuid4()) + t = params['template'] + name = params['name'] + conn = self.conn.get() + + cb('Storing VM icon') + # Store the icon for displaying later + icon = t.info.get('icon') + if icon: + try: + with self.objstore as session: + session.store('vm', vm_uuid, {'icon': icon}) + except Exception as e: + # It is possible to continue Kimchi executions without store + # vm icon info + wok_log.error('Error trying to update database with guest ' + 'icon information due error: %s', e.message) + + # If storagepool is SCSI, volumes will be LUNs and must be passed by + # the user from UI or manually. + cb('Provisioning storage for new VM') + vol_list = [] + if t._get_storage_type() not in ["iscsi", "scsi"]: + vol_list = t.fork_vm_storage(vm_uuid) + + graphics = params.get('graphics', {}) + stream_protocols = self.caps.libvirt_stream_protocols + xml = t.to_vm_xml(name, vm_uuid, + libvirt_stream_protocols=stream_protocols, + graphics=graphics, + volumes=vol_list) + + cb('Defining new VM') + try: + conn.defineXML(xml.encode('utf-8')) + except libvirt.libvirtError as e: + if t._get_storage_type() not in READONLY_POOL_TYPE: + for v in vol_list: + vol = conn.storageVolLookupByPath(v['path']) + vol.delete(0) + raise OperationFailed("KCHVM0007E", {'name': name, + 'err': e.get_error_message()}) + + cb('Updating VM metadata') + VMModel.vm_update_os_metadata(VMModel.get_vm(name, self.conn), t.info, + self.caps.metadata_support) + cb('OK', True) + + def get_list(self): + return VMsModel.get_vms(self.conn) + + @staticmethod + def get_vms(conn): + conn_ = conn.get() + names = [dom.name().decode('utf-8') for dom in conn_.listAllDomains(0)] + names = sorted(names, key=unicode.lower) + return names + + +class VMModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + self.caps = CapabilitiesModel(**kargs) + self.vmscreenshot = VMScreenshotModel(**kargs) + self.users = import_class( + 'plugins.kimchi.model.users.UsersModel' + )(**kargs) + self.groups = import_class( + 'plugins.kimchi.model.groups.GroupsModel' + )(**kargs) + self.vms = VMsModel(**kargs) + self.task = TaskModel(**kargs) + self.storagepool = model.storagepools.StoragePoolModel(**kargs) + self.storagevolume = model.storagevolumes.StorageVolumeModel(**kargs) + self.storagevolumes = model.storagevolumes.StorageVolumesModel(**kargs) + cls = import_class('plugins.kimchi.model.vmsnapshots.VMSnapshotModel') + self.vmsnapshot = cls(**kargs) + cls = import_class('plugins.kimchi.model.vmsnapshots.VMSnapshotsModel') + self.vmsnapshots = cls(**kargs) + self.stats = {} + + def update(self, name, params): + dom = self.get_vm(name, self.conn) + dom = self._static_vm_update(dom, params) + self._live_vm_update(dom, params) + return dom.name().decode('utf-8') + + def clone(self, name): + """Clone a virtual machine based on an existing one. + + The new virtual machine will have the exact same configuration as the + original VM, except for the name, UUID, MAC addresses and disks. The + name will have the form "<name>-clone-<number>", with <number> starting + at 1; the UUID will be generated randomly; the MAC addresses will be + generated randomly with no conflicts within the original and the new + VM; and the disks will be new volumes [mostly] on the same storage + pool, with the same content as the original disks. The storage pool + 'default' will always be used when cloning SCSI and iSCSI disks and + when the original storage pool cannot hold the new volume. + + An exception will be raised if the virtual machine <name> is not + shutoff, if there is no available space to copy a new volume to the + storage pool 'default' (when there was also no space to copy it to the + original storage pool) and if one of the virtual machine's disks belong + to a storage pool not supported by Kimchi. + + Parameters: + name -- The name of the existing virtual machine to be cloned. + + Return: + A Task running the clone operation. + """ + name = name.decode('utf-8') + + # VM must be shutoff in order to clone it + info = self.lookup(name) + if info['state'] != u'shutoff': + raise InvalidParameter('KCHVM0033E', {'name': name}) + + # the new VM's name will be used as the Task's 'target_uri' so it needs + # to be defined now. + + vms_being_created = [] + + # lookup names of VMs being created right now + with self.objstore as session: + task_names = session.get_list('task') + for tn in task_names: + t = session.get('task', tn) + if t['target_uri'].startswith('/plugins/kimchi/vms/'): + uri_name = t['target_uri'].lstrip('/plugins/kimchi/vms/') + vms_being_created.append(uri_name) + + current_vm_names = self.vms.get_list() + vms_being_created + new_name = get_next_clone_name(current_vm_names, name) + + # create a task with the actual clone function + taskid = add_task(u'/plugins/kimchi/vms/%s/clone' % new_name, + self._clone_task, self.objstore, + {'name': name, 'new_name': new_name}) + + return self.task.lookup(taskid) + + def _clone_task(self, cb, params): + """Asynchronous function which performs the clone operation. + + Parameters: + cb -- A callback function to signal the Task's progress. + params -- A dict with the following values: + "name": the name of the original VM. + "new_name": the name of the new VM. + """ + name = params['name'] + new_name = params['new_name'] + vir_conn = self.conn.get() + + # fetch base XML + cb('reading source VM XML') + try: + vir_dom = vir_conn.lookupByName(name) + flags = libvirt.VIR_DOMAIN_XML_SECURE + xml = vir_dom.XMLDesc(flags).decode('utf-8') + except libvirt.libvirtError, e: + raise OperationFailed('KCHVM0035E', {'name': name, + 'err': e.message}) + + # update UUID + cb('updating VM UUID') + old_uuid = xpath_get_text(xml, XPATH_DOMAIN_UUID)[0] + new_uuid = unicode(uuid.uuid4()) + xml = xml_item_update(xml, './uuid', new_uuid) + + # update MAC addresses + cb('updating VM MAC addresses') + xml = self._clone_update_mac_addresses(xml) + + with RollbackContext() as rollback: + # copy disks + cb('copying VM disks') + xml = self._clone_update_disks(xml, rollback) + + # update objstore entry + cb('updating object store') + self._clone_update_objstore(old_uuid, new_uuid, rollback) + + # update name + cb('updating VM name') + xml = xml_item_update(xml, './name', new_name) + + # create new guest + cb('defining new VM') + try: + vir_conn.defineXML(xml) + except libvirt.libvirtError, e: + raise OperationFailed('KCHVM0035E', {'name': name, + 'err': e.message}) + + rollback.commitAll() + + cb('OK', True) + + @staticmethod + def _clone_update_mac_addresses(xml): + """Update the MAC addresses with new values in the XML descriptor of a + cloning domain. + + The new MAC addresses will be generated randomly, and their values are + guaranteed to be distinct from the ones in the original VM. + + Arguments: + xml -- The XML descriptor of the original domain. + + Return: + The XML descriptor <xml> with the new MAC addresses instead of the + old ones. + """ + old_macs = xpath_get_text(xml, XPATH_DOMAIN_MAC) + new_macs = [] + + for mac in old_macs: + while True: + new_mac = model.vmifaces.VMIfacesModel.random_mac() + # make sure the new MAC doesn't conflict with the original VM + # and with the new values on the new VM. + if new_mac not in (old_macs + new_macs): + new_macs.append(new_mac) + break + + xml = xml_item_update(xml, XPATH_DOMAIN_MAC_BY_ADDRESS % mac, + new_mac, 'address') + + return xml + + def _clone_update_disks(self, xml, rollback): + """Clone disks from a virtual machine. The disks are copied as new + volumes and the new VM's XML is updated accordingly. + + Arguments: + xml -- The XML descriptor of the original VM + new value for + "/domain/uuid". + rollback -- A rollback context so the new volumes can be removed if an + error occurs during the cloning operation. + + Return: + The XML descriptor <xml> with the new disk paths instead of the + old ones. + """ + # the UUID will be used to create the disk paths + uuid = xpath_get_text(xml, XPATH_DOMAIN_UUID)[0] + all_paths = xpath_get_text(xml, XPATH_DOMAIN_DISK) + + vir_conn = self.conn.get() + + def _delete_disk_from_objstore(path): + with self.objstore as session: + session.delete('storagevolume', path) + + domain_name = xpath_get_text(xml, XPATH_DOMAIN_NAME)[0] + + for i, path in enumerate(all_paths): + try: + vir_orig_vol = vir_conn.storageVolLookupByPath(path) + vir_pool = vir_orig_vol.storagePoolLookupByVolume() + + orig_pool_name = vir_pool.name().decode('utf-8') + orig_vol_name = vir_orig_vol.name().decode('utf-8') + except libvirt.libvirtError, e: + raise OperationFailed('KCHVM0035E', {'name': domain_name, + 'err': e.message}) + + orig_pool = self.storagepool.lookup(orig_pool_name) + orig_vol = self.storagevolume.lookup(orig_pool_name, orig_vol_name) + + new_pool_name = orig_pool_name + new_pool = orig_pool + + if orig_pool['type'] in ['dir', 'netfs', 'logical']: + # if a volume in a pool 'dir', 'netfs' or 'logical' cannot hold + # a new volume with the same size, the pool 'default' should + # be used + if orig_vol['capacity'] > orig_pool['available']: + wok_log.warning('storage pool \'%s\' doesn\'t have ' + 'enough free space to store image ' + '\'%s\'; falling back to \'default\'', + orig_pool_name, path) + new_pool_name = u'default' + new_pool = self.storagepool.lookup(u'default') + + # ...and if even the pool 'default' cannot hold a new + # volume, raise an exception + if orig_vol['capacity'] > new_pool['available']: + domain_name = xpath_get_text(xml, XPATH_DOMAIN_NAME)[0] + raise InvalidOperation('KCHVM0034E', + {'name': domain_name}) + + elif orig_pool['type'] in ['scsi', 'iscsi']: + # SCSI and iSCSI always fall back to the storage pool 'default' + wok_log.warning('cannot create new volume for clone in ' + 'storage pool \'%s\'; falling back to ' + '\'default\'', orig_pool_name) + new_pool_name = u'default' + new_pool = self.storagepool.lookup(u'default') + + # if the pool 'default' cannot hold a new volume, raise + # an exception + if orig_vol['capacity'] > new_pool['available']: + domain_name = xpath_get_text(xml, XPATH_DOMAIN_NAME)[0] + raise InvalidOperation('KCHVM0034E', {'name': domain_name}) + + else: + # unexpected storage pool type + raise InvalidOperation('KCHPOOL0014E', + {'type': orig_pool['type']}) + + # new volume name: <UUID>-<loop-index>.<original extension> + # e.g. 1234-5678-9012-3456-0.img + ext = os.path.splitext(path)[1] + new_vol_name = u'%s-%d%s' % (uuid, i, ext) + task = self.storagevolume.clone(orig_pool_name, orig_vol_name, + new_name=new_vol_name) + self.task.wait(task['id'], 3600) # 1 h + + # get the new volume path and update the XML descriptor + new_vol = self.storagevolume.lookup(new_pool_name, new_vol_name) + xml = xml_item_update(xml, XPATH_DOMAIN_DISK_BY_FILE % path, + new_vol['path'], 'file') + + # set the new disk's used_by + with self.objstore as session: + session.store('storagevolume', new_vol['path'], + {'used_by': [domain_name]}) + rollback.prependDefer(_delete_disk_from_objstore, new_vol['path']) + + # remove the new volume should an error occur later + rollback.prependDefer(self.storagevolume.delete, new_pool_name, + new_vol_name) + + return xml + + def _clone_update_objstore(self, old_uuid, new_uuid, rollback): + """Update Kimchi's object store with the cloning VM. + + Arguments: + old_uuid -- The UUID of the original VM. + new_uuid -- The UUID of the new, clonning VM. + rollback -- A rollback context so the object store entry can be removed + if an error occurs during the cloning operation. + """ + with self.objstore as session: + try: + vm = session.get('vm', old_uuid) + icon = vm['icon'] + session.store('vm', new_uuid, {'icon': icon}) + except NotFoundError: + # if we cannot find an object store entry for the original VM, + # don't store one with an empty value. + pass + else: + # we need to define a custom function to prepend to the + # rollback context because the object store session needs to be + # opened and closed correctly (i.e. "prependDefer" only + # accepts one command at a time but we need more than one to + # handle an object store). + def _rollback_objstore(): + with self.objstore as session_rb: + session_rb.delete('vm', new_uuid, ignore_missing=True) + + # remove the new object store entry should an error occur later + rollback.prependDefer(_rollback_objstore) + + def _build_access_elem(self, dom, users, groups): + auth = config.get("authentication", "method") + access_xml = get_metadata_node(dom, "access", + self.caps.metadata_support) + + auth_elem = None + + if not access_xml: + # there is no metadata element 'access' + access_elem = E.access() + else: + access_elem = ET.fromstring(access_xml) + + same_auth = access_elem.xpath('./auth[@type="%s"]' % auth) + if len(same_auth) > 0: + # there is already a sub-element 'auth' with the same type; + # update it. + auth_elem = same_auth[0] + + if users is not None: + for u in auth_elem.findall('user'): + auth_elem.remove(u) + + if groups is not None: + for g in auth_elem.findall('group'): + auth_elem.remove(g) + + if auth_elem is None: + # there is no sub-element 'auth' with the same type + # (or no 'auth' at all); create it. + auth_elem = E.auth(type=auth) + access_elem.append(auth_elem) + + if users is not None: + for u in users: + auth_elem.append(E.user(u)) + + if groups is not None: + for g in groups: + auth_elem.append(E.group(g)) + + return access_elem + + def _vm_update_access_metadata(self, dom, params): + users = groups = None + if "users" in params: + users = params["users"] + for user in users: + if not self.users.validate(user): + raise InvalidParameter("KCHVM0027E", + {'users': user}) + if "groups" in params: + groups = params["groups"] + for group in groups: + if not self.groups.validate(group): + raise InvalidParameter("KCHVM0028E", + {'groups': group}) + + if users is None and groups is None: + return + + node = self._build_access_elem(dom, users, groups) + set_metadata_node(dom, node, self.caps.metadata_support) + + def _get_access_info(self, dom): + users = groups = list() + access_xml = (get_metadata_node(dom, "access", + self.caps.metadata_support) or + """<access></access>""") + access_info = dictize(access_xml) + auth = config.get("authentication", "method") + if ('auth' in access_info['access'] and + ('type' in access_info['access']['auth'] or + len(access_info['access']['auth']) > 1)): + users = xpath_get_text(access_xml, + "/access/auth[@type='%s']/user" % auth) + groups = xpath_get_text(access_xml, + "/access/auth[@type='%s']/group" % auth) + elif auth == 'pam': + # Compatible to old permission tagging + users = xpath_get_text(access_xml, "/access/user") + groups = xpath_get_text(access_xml, "/access/group") + return users, groups + + @staticmethod + def vm_get_os_metadata(dom, metadata_support): + os_xml = (get_metadata_node(dom, "os", metadata_support) or + """<os></os>""") + os_elem = ET.fromstring(os_xml) + return (os_elem.attrib.get("version"), os_elem.attrib.get("distro")) + + @staticmethod + def vm_update_os_metadata(dom, params, metadata_support): + distro = params.get("os_distro") + version = params.get("os_version") + if distro is None: + return + os_elem = E.os({"distro": distro, "version": version}) + set_metadata_node(dom, os_elem, metadata_support) + + def _update_graphics(self, dom, xml, params): + root = objectify.fromstring(xml) + graphics = root.devices.find("graphics") + if graphics is None: + return xml + + password = params['graphics'].get("passwd") + if password is not None and len(password.strip()) == 0: + password = "".join(random.sample(string.ascii_letters + + string.digits, 8)) + + if password is not None: + graphics.attrib['passwd'] = password + + expire = params['graphics'].get("passwdValidTo") + to = graphics.attrib.get('passwdValidTo') + if to is not None: + if (time.mktime(time.strptime(to, '%Y-%m-%dT%H:%M:%S')) - + time.time() <= 0): + expire = expire if expire is not None else 30 + + if expire is not None: + expire_time = time.gmtime(time.time() + float(expire)) + valid_to = time.strftime('%Y-%m-%dT%H:%M:%S', expire_time) + graphics.attrib['passwdValidTo'] = valid_to + + if not dom.isActive(): + return ET.tostring(root, encoding="utf-8") + + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) + dom.updateDeviceFlags(etree.tostring(graphics), + libvirt.VIR_DOMAIN_AFFECT_LIVE) + return xml + + def _backup_snapshots(self, snap, all_info): + """ Append "snap" and the children of "snap" to the list "all_info". + + The list *must* always contain the parent snapshots before their + children so the function "_redefine_snapshots" can work correctly. + + Arguments: + snap -- a native domain snapshot. + all_info -- a list of dict keys: + "{'xml': <snap XML>, 'current': <is snap current?>'}" + """ + all_info.append({'xml': snap.getXMLDesc(0), + 'current': snap.isCurrent(0)}) + + for child in snap.listAllChildren(0): + self._backup_snapshots(child, all_info) + + def _redefine_snapshots(self, dom, all_info): + """ Restore the snapshots stored in "all_info" to the domain "dom". + + Arguments: + dom -- the domain which will have its snapshots restored. + all_info -- a list of dict keys, as described in "_backup_snapshots", + containing the original snapshot information. + """ + for info in all_info: + flags = libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE + + if info['current']: + flags |= libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT + + dom.snapshotCreateXML(info['xml'], flags) + + def _static_vm_update(self, dom, params): + old_xml = new_xml = dom.XMLDesc(0) + + for key, val in params.items(): + if key in VM_STATIC_UPDATE_PARAMS: + if type(val) == int: + val = str(val) + xpath = VM_STATIC_UPDATE_PARAMS[key] + new_xml = xml_item_update(new_xml, xpath, val) + + # Updating memory and NUMA if necessary, if vm is offline + if not dom.isActive(): + if 'memory' in params: + new_xml = self._update_memory_config(new_xml, params) + elif 'cpus' in params and \ + (xpath_get_text(new_xml, XPATH_NUMA_CELL + '/@memory') != []): + vcpus = params['cpus'] + new_xml = xml_item_update( + new_xml, + XPATH_NUMA_CELL, + value='0-' + str(vcpus - 1) if vcpus > 1 else '0', + attr='cpus') + + if 'graphics' in params: + new_xml = self._update_graphics(dom, new_xml, params) + + snapshots_info = [] + vm_name = dom.name() + conn = self.conn.get() + try: + if 'name' in params: + state = DOM_STATE_MAP[dom.info()[0]] + if state != 'shutoff': + msg_args = {'name': vm_name, 'new_name': params['name']} + raise InvalidParameter("KCHVM0003E", msg_args) + + lflags = libvirt.VIR_DOMAIN_SNAPSHOT_LIST_ROOTS + dflags = (libvirt.VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | + libvirt.VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) + + for virt_snap in dom.listAllSnapshots(lflags): + snapshots_info.append({'xml': virt_snap.getXMLDesc(0), + 'current': virt_snap.isCurrent(0)}) + self._backup_snapshots(virt_snap, snapshots_info) + + virt_snap.delete(dflags) + + # Undefine old vm, only if name is going to change + dom.undefine() + + dom = conn.defineXML(new_xml) + if 'name' in params: + self._redefine_snapshots(dom, snapshots_info) + except libvirt.libvirtError as e: + dom = conn.defineXML(old_xml) + if 'name' in params: + self._redefine_snapshots(dom, snapshots_info) + + raise OperationFailed("KCHVM0008E", {'name': vm_name, + 'err': e.get_error_message()}) + return dom + + def _update_memory_config(self, xml, params): + # Checks if NUMA memory is already configured, if not, checks if CPU + # element is already configured (topology). Then add NUMA element as + # apropriated + root = ET.fromstring(xml) + numa_mem = xpath_get_text(xml, XPATH_NUMA_CELL + '/@memory') + vcpus = params.get('cpus') + if numa_mem == []: + if vcpus is None: + vcpus = int(xpath_get_text(xml, + VM_STATIC_UPDATE_PARAMS['cpus'])[0]) + cpu = root.find('./cpu') + if cpu is None: + cpu = get_cpu_xml(vcpus, params['memory'] << 10) + root.insert(0, ET.fromstring(cpu)) + else: + numa_element = get_numa_xml(vcpus, params['memory'] << 10) + cpu.insert(0, ET.fromstring(numa_element)) + else: + if vcpus is not None: + xml = xml_item_update( + xml, + XPATH_NUMA_CELL, + value='0-' + str(vcpus - 1) if vcpus > 1 else '0', + attr='cpus') + root = ET.fromstring(xml_item_update(xml, XPATH_NUMA_CELL, + str(params['memory'] << 10), + attr='memory')) + + # Remove currentMemory, automatically set later by libvirt + currentMem = root.find('.currentMemory') + if currentMem is not None: + root.remove(currentMem) + + memory = root.find('.memory') + # Update/Adds maxMemory accordingly + if not self.caps.mem_hotplug_support: + if memory is not None: + memory.text = str(params['memory'] << 10) + else: + if memory is not None: + root.remove(memory) + maxMem = root.find('.maxMemory') + host_mem = self.conn.get().getInfo()[1] + slots = (host_mem - params['memory']) >> 10 + # Libvirt does not accepts slots <= 1 + if slots < 0: + raise OperationFailed("KCHVM0041E") + elif slots == 0: + slots = 1 + if maxMem is None: + max_mem_xml = E.maxMemory( + str(host_mem * 1024), + unit='Kib', + slots=str(slots)) + root.insert(0, max_mem_xml) + new_xml = ET.tostring(root, encoding="utf-8") + else: + # Update slots only + new_xml = xml_item_update(ET.tostring(root, encoding="utf-8"), + './maxMemory', + str(slots), + attr='slots') + return new_xml + return ET.tostring(root, encoding="utf-8") + + def _live_vm_update(self, dom, params): + self._vm_update_access_metadata(dom, params) + if 'memory' in params and dom.isActive(): + self._update_memory_live(dom, params) + + def _update_memory_live(self, dom, params): + # Check if host supports memory device + if not self.caps.mem_hotplug_support: + raise InvalidOperation("KCHVM0046E") + + # Check if the vm xml supports memory hotplug, if not, static update + # must be done firstly, then Kimchi is going to update the xml + xml = dom.XMLDesc(0) + numa_mem = xpath_get_text(xml, XPATH_NUMA_CELL + '/@memory') + max_mem = xpath_get_text(xml, './maxMemory') + if numa_mem == [] or max_mem == []: + raise OperationFailed('KCHVM0042E', {'name': dom.name()}) + + # Memory live update must be done in chunks of 1024 Mib or 1Gib + new_mem = params['memory'] + old_mem = int(xpath_get_text(xml, XPATH_DOMAIN_MEMORY)[0]) >> 10 + if new_mem < old_mem: + raise OperationFailed('KCHVM0043E') + if (new_mem - old_mem) % 1024 != 0: + raise OperationFailed('KCHVM0044E') + + # Check slot spaces: + total_slots = int(xpath_get_text(xml, './maxMemory/@slots')[0]) + needed_slots = (new_mem - old_mem) / 1024 + used_slots = len(xpath_get_text(xml, './devices/memory')) + if needed_slots > (total_slots - used_slots): + raise OperationFailed('KCHVM0045E') + elif needed_slots == 0: + # New memory value is same that current memory set + return + + # Finally, we are ok to hot add the memory devices + try: + self._hot_add_memory_devices(dom, needed_slots) + except Exception as e: + raise OperationFailed("KCHVM0047E", {'error': e.message}) + + def _hot_add_memory_devices(self, dom, amount): + # Hot add given number of memory devices in the guest + flags = libvirt.VIR_DOMAIN_MEM_CONFIG | libvirt.VIR_DOMAIN_MEM_LIVE + # Create memory device xml + mem_dev_xml = etree.tostring( + E.memory( + E.target( + E.size('1', unit='GiB'), + E.node('0')), + model='dimm')) + # Add chunks of 1G of memory + for i in range(amount): + dom.attachDeviceFlags(mem_dev_xml, flags) + + def _has_video(self, dom): + dom = ElementTree.fromstring(dom.XMLDesc(0)) + return dom.find('devices/video') is not None + + def _update_guest_stats(self, name): + try: + dom = VMModel.get_vm(name, self.conn) + + vm_uuid = dom.UUIDString() + info = dom.info() + state = DOM_STATE_MAP[info[0]] + + if state != 'running': + self.stats[vm_uuid] = {} + return + + if self.stats.get(vm_uuid, None) is None: + self.stats[vm_uuid] = {} + + timestamp = time.time() + prevStats = self.stats.get(vm_uuid, {}) + seconds = timestamp - prevStats.get('timestamp', 0) + self.stats[vm_uuid].update({'timestamp': timestamp}) + + self._get_percentage_cpu_usage(vm_uuid, info, seconds) + self._get_network_io_rate(vm_uuid, dom, seconds) + self._get_disk_io_rate(vm_uuid, dom, seconds) + except Exception as e: + # VM might be deleted just after we get the list. + # This is OK, just skip. + wok_log.debug('Error processing VM stats: %s', e.message) + + def _get_percentage_cpu_usage(self, vm_uuid, info, seconds): + prevCpuTime = self.stats[vm_uuid].get('cputime', 0) + + cpus = info[3] + cpuTime = info[4] - prevCpuTime + + base = (((cpuTime) * 100.0) / (seconds * 1000.0 * 1000.0 * 1000.0)) + percentage = max(0.0, min(100.0, base / cpus)) + + self.stats[vm_uuid].update({'cputime': info[4], 'cpu': percentage}) + + def _get_network_io_rate(self, vm_uuid, dom, seconds): + prevNetRxKB = self.stats[vm_uuid].get('netRxKB', 0) + prevNetTxKB = self.stats[vm_uuid].get('netTxKB', 0) + currentMaxNetRate = self.stats[vm_uuid].get('max_net_io', 100) + + rx_bytes = 0 + tx_bytes = 0 + + tree = ElementTree.fromstring(dom.XMLDesc(0)) + for target in tree.findall('devices/interface/target'): + dev = target.get('dev') + io = dom.interfaceStats(dev) + rx_bytes += io[0] + tx_bytes += io[4] + + netRxKB = float(rx_bytes) / 1000 + netTxKB = float(tx_bytes) / 1000 + + rx_stats = (netRxKB - prevNetRxKB) / seconds + tx_stats = (netTxKB - prevNetTxKB) / seconds + + rate = rx_stats + tx_stats + max_net_io = round(max(currentMaxNetRate, int(rate)), 1) + + self.stats[vm_uuid].update({'net_io': rate, 'max_net_io': max_net_io, + 'netRxKB': netRxKB, 'netTxKB': netTxKB}) + + def _get_disk_io_rate(self, vm_uuid, dom, seconds): + prevDiskRdKB = self.stats[vm_uuid].get('diskRdKB', 0) + prevDiskWrKB = self.stats[vm_uuid].get('diskWrKB', 0) + currentMaxDiskRate = self.stats[vm_uuid].get('max_disk_io', 100) + + rd_bytes = 0 + wr_bytes = 0 + + tree = ElementTree.fromstring(dom.XMLDesc(0)) + for target in tree.findall("devices/disk/target"): + dev = target.get("dev") + io = dom.blockStats(dev) + rd_bytes += io[1] + wr_bytes += io[3] + + diskRdKB = float(rd_bytes) / 1024 + diskWrKB = float(wr_bytes) / 1024 + + rd_stats = (diskRdKB - prevDiskRdKB) / seconds + wr_stats = (diskWrKB - prevDiskWrKB) / seconds + + rate = rd_stats + wr_stats + max_disk_io = round(max(currentMaxDiskRate, int(rate)), 1) + + self.stats[vm_uuid].update({'disk_io': rate, + 'max_disk_io': max_disk_io, + 'diskRdKB': diskRdKB, + 'diskWrKB': diskWrKB}) + + def lookup(self, name): + dom = self.get_vm(name, self.conn) + info = dom.info() + state = DOM_STATE_MAP[info[0]] + screenshot = None + # (type, listen, port, passwd, passwdValidTo) + graphics = self._vm_get_graphics(name) + graphics_port = graphics[2] + graphics_port = graphics_port if state == 'running' else None + try: + if state == 'running' and self._has_video(dom): + screenshot = self.vmscreenshot.lookup(name) + elif state == 'shutoff': + # reset vm stats when it is powered off to avoid sending + # incorrect (old) data + self.stats[dom.UUIDString()] = {} + except NotFoundError: + pass + + with self.objstore as session: + try: + extra_info = session.get('vm', dom.UUIDString()) + except NotFoundError: + extra_info = {} + icon = extra_info.get('icon') + + self._update_guest_stats(name) + vm_stats = self.stats.get(dom.UUIDString(), {}) + res = {} + res['cpu_utilization'] = vm_stats.get('cpu', 0) + res['net_throughput'] = vm_stats.get('net_io', 0) + res['net_throughput_peak'] = vm_stats.get('max_net_io', 100) + res['io_throughput'] = vm_stats.get('disk_io', 0) + res['io_throughput_peak'] = vm_stats.get('max_disk_io', 100) + users, groups = self._get_access_info(dom) + + if state == 'shutoff': + xml = dom.XMLDesc(0) + val = xpath_get_text(xml, XPATH_DOMAIN_MEMORY)[0] + unit_list = xpath_get_text(xml, XPATH_DOMAIN_MEMORY_UNIT) + if len(unit_list) > 0: + unit = unit_list[0] + else: + unit = 'KiB' + memory = convert_data_size(val, unit, 'MiB') + else: + memory = info[2] >> 10 + + return {'name': name, + 'state': state, + 'stats': res, + 'uuid': dom.UUIDString(), + 'memory': memory, + 'cpus': info[3], + 'screenshot': screenshot, + 'icon': icon, + # (type, listen, port, passwd, passwdValidTo) + 'graphics': {"type": graphics[0], + "listen": graphics[1], + "port": graphics_port, + "passwd": graphics[3], + "passwdValidTo": graphics[4]}, + 'users': users, + 'groups': groups, + 'access': 'full', + 'persistent': True if dom.isPersistent() else False + } + + def _vm_get_disk_paths(self, dom): + xml = dom.XMLDesc(0) + xpath = "/domain/devices/disk[@device='disk']/source/@file" + return xpath_get_text(xml, xpath) + + @staticmethod + def get_vm(name, conn): + conn = conn.get() + try: + # outgoing text to libvirt, encode('utf-8') + return conn.lookupByName(name.encode("utf-8")) + except libvirt.libvirtError as e: + if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: + raise NotFoundError("KCHVM0002E", {'name': name}) + else: + raise OperationFailed("KCHVM0009E", {'name': name, + 'err': e.message}) + + def delete(self, name): + conn = self.conn.get() + dom = self.get_vm(name, self.conn) + if not dom.isPersistent(): + raise InvalidOperation("KCHVM0036E", {'name': name}) + + self._vmscreenshot_delete(dom.UUIDString()) + paths = self._vm_get_disk_paths(dom) + info = self.lookup(name) + + if info['state'] != 'shutoff': + self.poweroff(name) + + # delete existing snapshots before deleting VM + + # libvirt's Test driver does not support the function + # "virDomainListAllSnapshots", so "VMSnapshots.get_list" will raise + # "OperationFailed" in that case. + try: + snapshot_names = self.vmsnapshots.get_list(name) + except OperationFailed, e: + wok_log.error('cannot list snapshots: %s; ' + 'skipping snapshot deleting...' % e.message) + else: + for s in snapshot_names: + self.vmsnapshot.delete(name, s) + + try: + dom.undefine() + except libvirt.libvirtError as e: + raise OperationFailed("KCHVM0021E", + {'name': name, 'err': e.get_error_message()}) + + for path in paths: + try: + vol = conn.storageVolLookupByPath(path) + pool = vol.storagePoolLookupByVolume() + xml = pool.XMLDesc(0) + pool_type = xpath_get_text(xml, "/pool/@type")[0] + if pool_type not in READONLY_POOL_TYPE: + vol.delete(0) + # Update objstore to remove the volume + with self.objstore as session: + session.delete('storagevolume', path, + ignore_missing=True) + except libvirt.libvirtError as e: + wok_log.error('Unable to get storage volume by path: %s' % + e.message) + except Exception as e: + raise OperationFailed('KCHVOL0017E', {'err': e.message}) + + try: + with self.objstore as session: + if path in session.get_list('storagevolume'): + used_by = session.get('storagevolume', path)['used_by'] + used_by.remove(name) + session.store('storagevolume', path, + {'used_by': used_by}) + except Exception as e: + raise OperationFailed('KCHVOL0017E', {'err': e.message}) + + try: + with self.objstore as session: + session.delete('vm', dom.UUIDString(), ignore_missing=True) + except Exception as e: + # It is possible to delete vm without delete its database info + wok_log.error('Error deleting vm information from database: ' + '%s', e.message) + + vnc.remove_proxy_token(name) + + def start(self, name): + # make sure the ISO file has read permission + dom = self.get_vm(name, self.conn) + xml = dom.XMLDesc(0) + xpath = "/domain/devices/disk[@device='cdrom']/source/@file" + isofiles = xpath_get_text(xml, xpath) + + user = UserTests.probe_user() + for iso in isofiles: + run_setfacl_set_attr(iso, user=user) + + dom = self.get_vm(name, self.conn) + try: + dom.create() + except libvirt.libvirtError as e: + raise OperationFailed("KCHVM0019E", + {'name': name, 'err': e.get_error_message()}) + + def poweroff(self, name): + dom = self.get_vm(name, self.conn) + try: + dom.destroy() + except libvirt.libvirtError as e: + raise OperationFailed("KCHVM0020E", + {'name': name, 'err': e.get_error_message()}) + + def shutdown(self, name): + dom = self.get_vm(name, self.conn) + try: + dom.shutdown() + except libvirt.libvirtError as e: + raise OperationFailed("KCHVM0029E", + {'name': name, 'err': e.get_error_message()}) + + def reset(self, name): + dom = self.get_vm(name, self.conn) + try: + dom.reset(flags=0) + except libvirt.libvirtError as e: + raise OperationFailed("KCHVM0022E", + {'name': name, 'err': e.get_error_message()}) + + def _vm_get_graphics(self, name): + dom = self.get_vm(name, self.conn) + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) + + expr = "/domain/devices/graphics/@type" + res = xpath_get_text(xml, expr) + graphics_type = res[0] if res else None + + expr = "/domain/devices/graphics/@listen" + res = xpath_get_text(xml, expr) + graphics_listen = res[0] if res else None + + graphics_port = graphics_passwd = graphics_passwdValidTo = None + if graphics_type: + expr = "/domain/devices/graphics[@type='%s']/@port" + res = xpath_get_text(xml, expr % graphics_type) + graphics_port = int(res[0]) if res else None + + expr = "/domain/devices/graphics[@type='%s']/@passwd" + res = xpath_get_text(xml, expr % graphics_type) + graphics_passwd = res[0] if res else None + + expr = "/domain/devices/graphics[@type='%s']/@passwdValidTo" + res = xpath_get_text(xml, expr % graphics_type) + if res: + to = time.mktime(time.strptime(res[0], '%Y-%m-%dT%H:%M:%S')) + graphics_passwdValidTo = to - time.mktime(time.gmtime()) + + return (graphics_type, graphics_listen, graphics_port, + graphics_passwd, graphics_passwdValidTo) + + def connect(self, name): + # (type, listen, port, passwd, passwdValidTo) + graphics_port = self._vm_get_graphics(name)[2] + if graphics_port is not None: + vnc.add_proxy_token(name, graphics_port) + else: + raise OperationFailed("KCHVM0010E", {'name': name}) + + def _vmscreenshot_delete(self, vm_uuid): + screenshot = VMScreenshotModel.get_screenshot(vm_uuid, self.objstore, + self.conn) + screenshot.delete() + try: + with self.objstore as session: + session.delete('screenshot', vm_uuid) + except Exception as e: + # It is possible to continue Kimchi executions without delete + # screenshots + wok_log.error('Error trying to delete vm screenshot from ' + 'database due error: %s', e.message) + + def suspend(self, name): + """Suspend the virtual machine's execution and puts it in the + state 'paused'. Use the function "resume" to restore its state. + If the VM is not running, an exception will be raised. + + Parameters: + name -- the name of the VM to be suspended. + """ + vm = self.lookup(name) + if vm['state'] != 'running': + raise InvalidOperation('KCHVM0037E', {'name': name}) + + vir_dom = self.get_vm(name, self.conn) + + try: + vir_dom.suspend() + except libvirt.libvirtError, e: + raise OperationFailed('KCHVM0038E', {'name': name, + 'err': e.message}) + + def resume(self, name): + """Resume the virtual machine's execution and puts it in the + state 'running'. The VM should have been suspended previously by the + function "suspend" and be in the state 'paused', otherwise an exception + will be raised. + + Parameters: + name -- the name of the VM to be resumed. + """ + vm = self.lookup(name) + if vm['state'] != 'paused': + raise InvalidOperation('KCHVM0039E', {'name': name}) + + vir_dom = self.get_vm(name, self.conn) + + try: + vir_dom.resume() + except libvirt.libvirtError, e: + raise OperationFailed('KCHVM0040E', {'name': name, + 'err': e.message}) + + +class VMScreenshotModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + + def lookup(self, name): + dom = VMModel.get_vm(name, self.conn) + d_info = dom.info() + vm_uuid = dom.UUIDString() + if DOM_STATE_MAP[d_info[0]] != 'running': + raise NotFoundError("KCHVM0004E", {'name': name}) + + screenshot = self.get_screenshot(vm_uuid, self.objstore, self.conn) + img_path = screenshot.lookup() + # screenshot info changed after scratch generation + try: + with self.objstore as session: + session.store('screenshot', vm_uuid, screenshot.info) + except Exception as e: + # It is possible to continue Kimchi executions without store + # screenshots + wok_log.error('Error trying to update database with guest ' + 'screenshot information due error: %s', e.message) + return img_path + + @staticmethod + def get_screenshot(vm_uuid, objstore, conn): + try: + with objstore as session: + try: + params = session.get('screenshot', vm_uuid) + except NotFoundError: + params = {'uuid': vm_uuid} + session.store('screenshot', vm_uuid, params) + except Exception as e: + # The 'except' outside of 'with' is necessary to catch possible + # exception from '__exit__' when calling 'session.store' + # It is possible to continue Kimchi vm executions without + # screenshots + wok_log.error('Error trying to update database with guest ' + 'screenshot information due error: %s', e.message) + return LibvirtVMScreenshot(params, conn) + + +class LibvirtVMScreenshot(VMScreenshot): + def __init__(self, vm_uuid, conn): + VMScreenshot.__init__(self, vm_uuid) + self.conn = conn + + def _generate_scratch(self, thumbnail): + def handler(stream, buf, opaque): + fd = opaque + os.write(fd, buf) + + fd = os.open(thumbnail, os.O_WRONLY | os.O_TRUNC | os.O_CREAT, 0644) + try: + conn = self.conn.get() + dom = conn.lookupByUUIDString(self.vm_uuid) + vm_name = dom.name() + stream = conn.newStream(0) + dom.screenshot(stream, 0, 0) + stream.recvAll(handler, fd) + except libvirt.libvirtError: + try: + stream.abort() + except: + pass + raise NotFoundError("KCHVM0006E", {'name': vm_name}) + else: + stream.finish() + finally: + os.close(fd) diff --git a/src/wok/plugins/kimchi/model/vmsnapshots.py b/src/wok/plugins/kimchi/model/vmsnapshots.py new file mode 100644 index 0000000..fff1908 --- /dev/null +++ b/src/wok/plugins/kimchi/model/vmsnapshots.py @@ -0,0 +1,204 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import libvirt +import lxml.etree as ET +import time +from lxml import objectify +from lxml.builder import E + +from wok.exception import InvalidOperation, NotFoundError, OperationFailed +from wok.utils import add_task +from wok.xmlutils.utils import xpath_get_text +from wok.model.tasks import TaskModel + +from vms import DOM_STATE_MAP, VMModel +from vmstorages import VMStorageModel, VMStoragesModel + + +class VMSnapshotsModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + self.task = TaskModel(**kargs) + self.vmstorages = VMStoragesModel(**kargs) + self.vmstorage = VMStorageModel(**kargs) + + def create(self, vm_name, params={}): + """Create a snapshot with the current domain state. + + The VM must be stopped and contain only disks with format 'qcow2'; + otherwise an exception will be raised. + + Parameters: + vm_name -- the name of the VM where the snapshot will be created. + params -- a dict with the following values: + "name": The snapshot name (optional). If omitted, a default value + based on the current time will be used. + + Return: + A Task running the operation. + """ + vir_dom = VMModel.get_vm(vm_name, self.conn) + if DOM_STATE_MAP[vir_dom.info()[0]] != u'shutoff': + raise InvalidOperation('KCHSNAP0001E', {'vm': vm_name}) + + # if the VM has a non-CDROM disk with type 'raw', abort. + for storage_name in self.vmstorages.get_list(vm_name): + storage = self.vmstorage.lookup(vm_name, storage_name) + type = storage['type'] + format = storage['format'] + + if type != u'cdrom' and format != u'qcow2': + raise InvalidOperation('KCHSNAP0010E', {'vm': vm_name, + 'format': format}) + + name = params.get('name', unicode(int(time.time()))) + + task_params = {'vm_name': vm_name, 'name': name} + taskid = add_task(u'/plugins/kimchi/vms/%s/snapshots/%s' % (vm_name, + name), self._create_task, self.objstore, task_params) + return self.task.lookup(taskid) + + def _create_task(self, cb, params): + """Asynchronous function which actually creates the snapshot. + + Parameters: + cb -- a callback function to signal the Task's progress. + params -- a dict with the following values: + "vm_name": the name of the VM where the snapshot will be created. + "name": the snapshot name. + """ + vm_name = params['vm_name'] + name = params['name'] + + cb('building snapshot XML') + root_elem = E.domainsnapshot() + root_elem.append(E.name(name)) + xml = ET.tostring(root_elem, encoding='utf-8') + + try: + cb('fetching snapshot domain') + vir_dom = VMModel.get_vm(vm_name, self.conn) + cb('creating snapshot') + vir_dom.snapshotCreateXML(xml, 0) + except (NotFoundError, OperationFailed, libvirt.libvirtError), e: + raise OperationFailed('KCHSNAP0002E', + {'name': name, 'vm': vm_name, + 'err': e.message}) + + cb('OK', True) + + def get_list(self, vm_name): + vir_dom = VMModel.get_vm(vm_name, self.conn) + + try: + vir_snaps = vir_dom.listAllSnapshots(0) + return sorted([s.getName().decode('utf-8') for s in vir_snaps], + key=unicode.lower) + except libvirt.libvirtError, e: + raise OperationFailed('KCHSNAP0005E', + {'vm': vm_name, 'err': e.message}) + + +class VMSnapshotModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + + def lookup(self, vm_name, name): + vir_snap = self.get_vmsnapshot(vm_name, name) + + try: + snap_xml_str = vir_snap.getXMLDesc(0).decode('utf-8') + except libvirt.libvirtError, e: + raise OperationFailed('KCHSNAP0004E', {'name': name, + 'vm': vm_name, + 'err': e.message}) + + snap_xml = objectify.fromstring(snap_xml_str) + + try: + parent = unicode(snap_xml.parent.name) + except AttributeError: + parent = u'' + + return {'created': unicode(snap_xml.creationTime), + 'name': unicode(snap_xml.name), + 'parent': parent, + 'state': unicode(snap_xml.state)} + + def delete(self, vm_name, name): + try: + vir_snap = self.get_vmsnapshot(vm_name, name) + vir_snap.delete(0) + except libvirt.libvirtError, e: + raise OperationFailed('KCHSNAP0006E', {'name': name, + 'vm': vm_name, + 'err': e.message}) + + def revert(self, vm_name, name): + try: + vir_dom = VMModel.get_vm(vm_name, self.conn) + vir_snap = self.get_vmsnapshot(vm_name, name) + vir_dom.revertToSnapshot(vir_snap, 0) + + # get vm name recorded in the snapshot and return new uri params + vm_new_name = xpath_get_text(vir_snap.getXMLDesc(0), + 'domain/name')[0] + return [vm_new_name, name] + except libvirt.libvirtError, e: + raise OperationFailed('KCHSNAP0009E', {'name': name, + 'vm': vm_name, + 'err': e.message}) + + def get_vmsnapshot(self, vm_name, name): + vir_dom = VMModel.get_vm(vm_name, self.conn) + + try: + return vir_dom.snapshotLookupByName(name, 0) + except libvirt.libvirtError, e: + code = e.get_error_code() + if code == libvirt.VIR_ERR_NO_DOMAIN_SNAPSHOT: + raise NotFoundError('KCHSNAP0003E', {'name': name, + 'vm': vm_name}) + else: + raise OperationFailed('KCHSNAP0004E', {'name': name, + 'vm': vm_name, + 'err': e.message}) + + +class CurrentVMSnapshotModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.vmsnapshot = VMSnapshotModel(**kargs) + + def lookup(self, vm_name): + vir_dom = VMModel.get_vm(vm_name, self.conn) + + try: + vir_snap = vir_dom.snapshotCurrent(0) + snap_name = vir_snap.getName().decode('utf-8') + except libvirt.libvirtError, e: + if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN_SNAPSHOT: + return {} + + raise OperationFailed('KCHSNAP0008E', + {'vm': vm_name, 'err': e.message}) + + return self.vmsnapshot.lookup(vm_name, snap_name) diff --git a/src/wok/plugins/kimchi/model/vmstorages.py b/src/wok/plugins/kimchi/model/vmstorages.py new file mode 100644 index 0000000..bec16c6 --- /dev/null +++ b/src/wok/plugins/kimchi/model/vmstorages.py @@ -0,0 +1,252 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import string +from lxml import etree + +from wok.exception import InvalidOperation, InvalidParameter, NotFoundError +from wok.exception import OperationFailed +from wok.utils import wok_log + +from ..osinfo import lookup +from ..xmlutils.disk import get_device_node, get_disk_xml +from ..xmlutils.disk import get_vm_disk_info, get_vm_disks +from config import CapabilitiesModel +from diskutils import get_disk_used_by, set_disk_used_by +from storagevolumes import StorageVolumeModel +from utils import get_vm_config_flag +from vms import DOM_STATE_MAP, VMModel + + +HOTPLUG_TYPE = ['scsi', 'virtio'] + + +def _get_device_bus(dev_type, dom, metadata_support): + try: + version, distro = VMModel.vm_get_os_metadata(dom, metadata_support) + except: + version, distro = ('unknown', 'unknown') + return lookup(distro, version)[dev_type+'_bus'] + + +class VMStoragesModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + self.caps = CapabilitiesModel(**kargs) + + def _get_available_bus_address(self, bus_type, vm_name): + if bus_type not in ['ide']: + return dict() + # libvirt limitation of just 1 ide controller + # each controller have at most 2 buses and each bus 2 units. + dom = VMModel.get_vm(vm_name, self.conn) + disks = self.get_list(vm_name) + valid_id = [('0', '0'), ('0', '1'), ('1', '0'), ('1', '1')] + controller_id = '0' + for dev_name in disks: + disk = get_device_node(dom, dev_name) + if disk.target.attrib['bus'] == 'ide': + controller_id = disk.address.attrib['controller'] + bus_id = disk.address.attrib['bus'] + unit_id = disk.address.attrib['unit'] + if (bus_id, unit_id) in valid_id: + valid_id.remove((bus_id, unit_id)) + continue + if not valid_id: + raise OperationFailed('KCHVMSTOR0014E', + {'type': 'ide', 'limit': 4}) + else: + address = {'controller': controller_id, + 'bus': valid_id[0][0], 'unit': valid_id[0][1]} + return dict(address=address) + + def create(self, vm_name, params): + vol_model = None + # Path will never be blank due to API.json verification. + # There is no need to cover this case here. + if not ('vol' in params) ^ ('path' in params): + raise InvalidParameter("KCHVMSTOR0017E") + + dom = VMModel.get_vm(vm_name, self.conn) + params['bus'] = _get_device_bus(params['type'], dom, + self.caps.metadata_support) + params['format'] = 'raw' + + dev_list = [dev for dev, bus in get_vm_disks(dom).iteritems() + if bus == params['bus']] + dev_list.sort() + if len(dev_list) == 0: + params['index'] = 0 + else: + char = dev_list.pop()[2] + params['index'] = string.ascii_lowercase.index(char) + 1 + + if (params['bus'] not in HOTPLUG_TYPE and + DOM_STATE_MAP[dom.info()[0]] != 'shutoff'): + raise InvalidOperation('KCHVMSTOR0011E') + + if params.get('vol'): + try: + pool = params['pool'] + vol_model = StorageVolumeModel(conn=self.conn, + objstore=self.objstore) + vol_info = vol_model.lookup(pool, params['vol']) + except KeyError: + raise InvalidParameter("KCHVMSTOR0012E") + except Exception as e: + raise InvalidParameter("KCHVMSTOR0015E", {'error': e}) + if len(vol_info['used_by']) != 0: + raise InvalidParameter("KCHVMSTOR0016E") + + valid_format = { + "disk": ["raw", "bochs", "qcow", "qcow2", "qed", "vmdk"], + "cdrom": "iso"} + + if vol_info['type'] == 'file': + if (params['type'] == 'disk' and + vol_info['format'] in valid_format[params['type']]): + params['format'] = vol_info['format'] + else: + raise InvalidParameter("KCHVMSTOR0018E", + {"format": vol_info['format'], + "type": params['type']}) + + params['path'] = vol_info['path'] + params['disk'] = vol_info['type'] + + params.update(self._get_available_bus_address(params['bus'], vm_name)) + + # Add device to VM + dev, xml = get_disk_xml(params) + try: + conn = self.conn.get() + dom = conn.lookupByName(vm_name) + dom.attachDeviceFlags(xml, get_vm_config_flag(dom, 'all')) + except Exception as e: + raise OperationFailed("KCHVMSTOR0008E", {'error': e.message}) + + # Don't put a try-block here. Let the exception be raised. If we + # allow disks used_by to be out of sync, data corruption could + # occour if a disk is added to two guests unknowingly. + if params.get('vol'): + used_by = vol_info['used_by'] + used_by.append(vm_name) + set_disk_used_by(self.objstore, params['path'], used_by) + + return dev + + def get_list(self, vm_name): + dom = VMModel.get_vm(vm_name, self.conn) + return get_vm_disks(dom).keys() + + +class VMStorageModel(object): + def __init__(self, **kargs): + self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + self.caps = CapabilitiesModel(**kargs) + + def lookup(self, vm_name, dev_name): + # Retrieve disk xml and format return dict + dom = VMModel.get_vm(vm_name, self.conn) + return get_vm_disk_info(dom, dev_name) + + def delete(self, vm_name, dev_name): + conn = self.conn.get() + + try: + bus_type = self.lookup(vm_name, dev_name)['bus'] + dom = conn.lookupByName(vm_name) + except NotFoundError: + raise + + if (bus_type not in HOTPLUG_TYPE and + DOM_STATE_MAP[dom.info()[0]] != 'shutoff'): + raise InvalidOperation('KCHVMSTOR0011E') + + try: + disk = get_device_node(dom, dev_name) + path = get_vm_disk_info(dom, dev_name)['path'] + if path is None or len(path) < 1: + path = self.lookup(vm_name, dev_name)['path'] + # This has to be done before it's detached. If it wasn't + # in the obj store, its ref count would have been updated + # by get_disk_used_by() + if path is not None: + used_by = get_disk_used_by(self.objstore, self.conn, path) + else: + wok_log.error("Unable to decrement volume used_by on" + " delete because no path could be found.") + dom.detachDeviceFlags(etree.tostring(disk), + get_vm_config_flag(dom, 'all')) + except Exception as e: + raise OperationFailed("KCHVMSTOR0010E", {'error': e.message}) + + if used_by is not None and vm_name in used_by: + used_by.remove(vm_name) + set_disk_used_by(self.objstore, path, used_by) + else: + wok_log.error("Unable to update %s:%s used_by on delete." + % (vm_name, dev_name)) + + def update(self, vm_name, dev_name, params): + old_disk_used_by = None + new_disk_used_by = None + + dom = VMModel.get_vm(vm_name, self.conn) + + dev_info = self.lookup(vm_name, dev_name) + if dev_info['type'] != 'cdrom': + raise InvalidOperation("KCHVMSTOR0006E") + + params['path'] = params.get('path', '') + old_disk_path = dev_info['path'] + new_disk_path = params['path'] + if new_disk_path != old_disk_path: + # An empty path means a CD-ROM was empty or ejected: + if old_disk_path is not '': + old_disk_used_by = get_disk_used_by( + self.objstore, self.conn, old_disk_path) + if new_disk_path is not '': + new_disk_used_by = get_disk_used_by( + self.objstore, self.conn, new_disk_path) + + dev_info.update(params) + dev, xml = get_disk_xml(dev_info) + + try: + dom.updateDeviceFlags(xml, get_vm_config_flag(dom, 'all')) + except Exception as e: + raise OperationFailed("KCHVMSTOR0009E", {'error': e.message}) + + try: + if old_disk_used_by is not None and \ + vm_name in old_disk_used_by: + old_disk_used_by.remove(vm_name) + set_disk_used_by(self.objstore, old_disk_path, + old_disk_used_by) + if new_disk_used_by is not None: + new_disk_used_by.append(vm_name) + set_disk_used_by(self.objstore, new_disk_path, + new_disk_used_by) + except Exception as e: + wok_log.error("Unable to update dev used_by on update due to" + " %s:" % e.message) + return dev diff --git a/src/wok/plugins/kimchi/netinfo.py b/src/wok/plugins/kimchi/netinfo.py new file mode 100644 index 0000000..c5746d7 --- /dev/null +++ b/src/wok/plugins/kimchi/netinfo.py @@ -0,0 +1,216 @@ +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import ethtool +import glob +import os + + +NET_PATH = '/sys/class/net' +NIC_PATH = '/sys/class/net/*/device' +BRIDGE_PATH = '/sys/class/net/*/bridge' +BONDING_PATH = '/sys/class/net/*/bonding' +WLAN_PATH = '/sys/class/net/*/wireless' +NET_BRPORT = '/sys/class/net/%s/brport' +NET_MASTER = '/sys/class/net/%s/master' +NET_STATE = '/sys/class/net/%s/carrier' +PROC_NET_VLAN = '/proc/net/vlan/' +BONDING_SLAVES = '/sys/class/net/%s/bonding/slaves' +BRIDGE_PORTS = '/sys/class/net/%s/brif' + + +def wlans(): + return [b.split('/')[-2] for b in glob.glob(WLAN_PATH)] + + +def is_wlan(iface): + return iface in wlans() + + +# FIXME if we do not want to list usb nic +def nics(): + return list(set([b.split('/')[-2] for b in glob.glob(NIC_PATH)]) - + set(wlans())) + + +def is_nic(iface): + return iface in nics() + + +def bondings(): + return [b.split('/')[-2] for b in glob.glob(BONDING_PATH)] + + +def is_bonding(iface): + return iface in bondings() + + +def vlans(): + return list(set([b.split('/')[-1] + for b in glob.glob(NET_PATH + '/*')]) & + set([b.split('/')[-1] + for b in glob.glob(PROC_NET_VLAN + '*')])) + + +def is_vlan(iface): + return iface in vlans() + + +def bridges(): + return [b.split('/')[-2] for b in glob.glob(BRIDGE_PATH)] + + +def is_bridge(iface): + return iface in bridges() + + +def all_interfaces(): + return [d.rsplit("/", 1)[-1] for d in glob.glob(NET_PATH + '/*')] + + +def slaves(bonding): + with open(BONDING_SLAVES % bonding) as bonding_file: + res = bonding_file.readline().split() + return res + + +def ports(bridge): + return os.listdir(BRIDGE_PORTS % bridge) + + +def is_brport(nic): + return os.path.exists(NET_BRPORT % nic) + + +def is_bondlave(nic): + return os.path.exists(NET_MASTER % nic) + + +def operstate(dev): + link_status = link_detected(dev) + return "down" if link_status == "n/a" else "up" + + +def link_detected(dev): + # try to read interface carrier (link) status + try: + with open(NET_STATE % dev) as dev_file: + carrier = dev_file.readline().strip() + # when IOError is raised, interface is down + except IOError: + return "n/a" + + # if value is 1, interface up with cable connected + # 0 corresponds to interface up with cable disconnected + return "yes" if carrier == '1' else "no" + + +def get_vlan_device(vlan): + """ Return the device of the given VLAN. """ + dev = None + + if os.path.exists(PROC_NET_VLAN + vlan): + with open(PROC_NET_VLAN + vlan) as vlan_file: + for line in vlan_file: + if "Device:" in line: + dummy, dev = line.split() + break + return dev + + +def get_bridge_port_device(bridge): + """Return the nics list that belongs to bridge.""" + # br --- v --- bond --- nic1 + if bridge not in bridges(): + raise ValueError('unknown bridge %s' % bridge) + nics = [] + for port in ports(bridge): + if port in vlans(): + device = get_vlan_device(port) + if device in bondings(): + nics.extend(slaves(device)) + else: + nics.append(device) + if port in bondings(): + nics.extend(slaves(port)) + else: + nics.append(port) + return nics + + +def aggregated_bridges(): + return [bridge for bridge in bridges() if + (set(get_bridge_port_device(bridge)) & set(nics()))] + + +def bare_nics(): + "The nic is not a port of a bridge or a slave of bond." + return [nic for nic in nics() if not (is_brport(nic) or is_bondlave(nic))] + + +def is_bare_nic(iface): + return iface in bare_nics() + + +# The nic will not be exposed when it is a port of a bridge or +# a slave of bond. +# The bridge will not be exposed when all it's port are tap. +def all_favored_interfaces(): + return aggregated_bridges() + bare_nics() + bondings() + + +def get_interface_type(iface): + # FIXME if we want to get more device type + # just support nic, bridge, bondings and vlan, for we just + # want to expose this 4 kinds of interface + try: + if is_nic(iface): + return "nic" + if is_bonding(iface): + return "bonding" + if is_bridge(iface): + return "bridge" + if is_vlan(iface): + return "vlan" + return 'unknown' + except IOError: + return 'unknown' + + +def get_interface_info(iface): + if iface not in ethtool.get_devices(): + raise ValueError('unknown interface: %s' % iface) + + ipaddr = '' + netmask = '' + try: + ipaddr = ethtool.get_ipaddr(iface) + netmask = ethtool.get_netmask(iface) + except IOError: + pass + + iface_link_detected = link_detected(iface) + iface_status = 'active' if iface_link_detected != "n/a" else "inactive" + + return {'name': iface, + 'type': get_interface_type(iface), + 'status': iface_status, + 'link_detected': iface_link_detected, + 'ipaddr': ipaddr, + 'netmask': netmask} diff --git a/src/wok/plugins/kimchi/network.py b/src/wok/plugins/kimchi/network.py new file mode 100644 index 0000000..1433b8a --- /dev/null +++ b/src/wok/plugins/kimchi/network.py @@ -0,0 +1,62 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import ethtool +import ipaddr + + +APrivateNets = ipaddr.IPNetwork("10.0.0.0/8") +BPrivateNets = ipaddr.IPNetwork("172.16.0.0/12") +CPrivateNets = ipaddr.IPNetwork('192.168.0.0/16') +PrivateNets = [CPrivateNets, BPrivateNets, APrivateNets] +DefaultNetsPool = [ipaddr.IPNetwork('192.168.122.0/23'), + ipaddr.IPNetwork('192.168.124.0/22'), + ipaddr.IPNetwork('192.168.128.0/17')] + + +def get_dev_netaddr(dev): + info = ethtool.get_interfaces_info(dev)[0] + return (info.ipv4_address and + "%s/%s" % (info.ipv4_address, info.ipv4_netmask) or '') + + +def get_dev_netaddrs(): + nets = [] + for dev in ethtool.get_devices(): + devnet = get_dev_netaddr(dev) + devnet and nets.append(ipaddr.IPNetwork(devnet)) + return nets + + +# used_nets should include all the subnet allocated in libvirt network +# will get host network by get_dev_netaddrs +def get_one_free_network(used_nets, nets_pool=PrivateNets): + def _get_free_network(nets, used_nets): + for net in nets.subnet(new_prefix=24): + if not any(net.overlaps(used) for used in used_nets): + return str(net) + return None + + used_nets = used_nets + get_dev_netaddrs() + for nets in nets_pool: + net = _get_free_network(nets, used_nets) + if net: + return net + return None diff --git a/src/wok/plugins/kimchi/osinfo.py b/src/wok/plugins/kimchi/osinfo.py new file mode 100644 index 0000000..5b1277c --- /dev/null +++ b/src/wok/plugins/kimchi/osinfo.py @@ -0,0 +1,213 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import copy +import glob +import os +import psutil +from collections import defaultdict +from configobj import ConfigObj +from distutils.version import LooseVersion + +from wok.config import PluginPaths + + +SUPPORTED_ARCHS = {'x86': ('i386', 'i686', 'x86_64'), + 'power': ('ppc', 'ppc64'), + 'ppc64le': ('ppc64le')} + + +template_specs = {'x86': {'old': dict(disk_bus='ide', + nic_model='e1000', sound_model='ich6'), + 'modern': dict(disk_bus='virtio', + nic_model='virtio', + sound_model='ich6')}, + 'power': {'old': dict(disk_bus='scsi', + nic_model='spapr-vlan', + cdrom_bus='scsi', + kbd_type="kbd", + kbd_bus='usb', mouse_bus='usb', + tablet_bus='usb', memory=1280), + 'modern': dict(disk_bus='virtio', + nic_model='virtio', + cdrom_bus='scsi', + kbd_bus='usb', + kbd_type="kbd", + mouse_bus='usb', tablet_bus='usb', + memory=1280)}, + 'ppc64le': {'old': dict(disk_bus='virtio', + nic_model='virtio', + cdrom_bus='scsi', + kbd_bus='usb', + kbd_type="keyboard", + mouse_bus='usb', tablet_bus='usb', + memory=1280), + 'modern': dict(disk_bus='virtio', + nic_model='virtio', + cdrom_bus='scsi', + kbd_bus='usb', + kbd_type="keyboard", + mouse_bus='usb', tablet_bus='usb', + memory=1280)}} + + +custom_specs = {'fedora': {'22': dict(video_model='qxl')}} + + +modern_version_bases = {'x86': {'debian': '6.0', 'ubuntu': '7.10', + 'opensuse': '10.3', 'centos': '5.3', + 'rhel': '6.0', 'fedora': '16', 'gentoo': '0', + 'sles': '11', 'arch': '0'}, + 'power': {'rhel': '6.5', 'fedora': '19', + 'ubuntu': '14.04', + 'opensuse': '13.1', + 'sles': '11sp3'}, + 'ppc64le': {'rhel': '6.5', 'fedora': '19', + 'ubuntu': '14.04', + 'opensuse': '13.1', + 'sles': '11sp3'}} + + +icon_available_distros = [icon[5:-4] for icon in glob.glob1('%s/images/' + % PluginPaths('kimchi').ui_dir, 'icon-*.png')] + + +def _get_tmpl_defaults(): + """ + ConfigObj returns a dict like below when no changes were made in the + template configuration file (template.conf) + + {'main': {}, 'storage': {'disk.0': {}}, 'processor': {}, 'graphics': {}} + + The default values should be like below: + + {'main': {'networks': ['default'], 'memory': '1024'}, + 'storage': {'pool': 'default', + 'disk.0': {'format': 'qcow2', 'size': '10'}}, + 'processor': {'cpus': '1'}, + 'graphics': {'type': 'spice', 'listen': '127.0.0.1'}} + """ + # Create dict with default values + tmpl_defaults = defaultdict(dict) + tmpl_defaults['main']['networks'] = ['default'] + tmpl_defaults['main']['memory'] = 1024 + tmpl_defaults['storage']['pool'] = 'default' + tmpl_defaults['storage']['disk.0'] = {'size': 10, 'format': 'qcow2'} + tmpl_defaults['processor']['cpus'] = 1 + tmpl_defaults['graphics'] = {'type': 'vnc', 'listen': '127.0.0.1'} + + default_config = ConfigObj(tmpl_defaults) + + # Load template configuration file + config_file = os.path.join(PluginPaths('kimchi').conf_dir, 'template.conf') + config = ConfigObj(config_file) + + # Merge default configuration with file configuration + default_config.merge(config) + + # Create a dict with default values according to data structure + # expected by VMTemplate + defaults = {'domain': 'kvm', 'arch': os.uname()[4], + 'cdrom_bus': 'ide', 'cdrom_index': 2, 'mouse_bus': 'ps2'} + + # Parse main section to get networks and memory values + main_section = default_config.pop('main') + defaults.update(main_section) + + # Parse storage section to get storage pool and disks values + storage_section = default_config.pop('storage') + defaults['storagepool'] = '/plugins/kimchi/storagepools/' + \ + storage_section.pop('pool') + defaults['disks'] = [] + for disk in storage_section.keys(): + data = storage_section[disk] + data['index'] = int(disk.split('.')[1]) + defaults['disks'].append(data) + + # Parse processor section to get cpus and cpu_topology values + processor_section = default_config.pop('processor') + defaults['cpus'] = processor_section.pop('cpus') + defaults['cpu_info'] = {} + if len(processor_section.keys()) > 0: + defaults['cpu_info']['topology'] = processor_section + + # Update defaults values with graphics values + defaults['graphics'] = default_config.pop('graphics') + + return defaults + + +# Set defaults values according to template.conf file +defaults = _get_tmpl_defaults() + + +def _get_arch(): + for arch, sub_archs in SUPPORTED_ARCHS.iteritems(): + if os.uname()[4] in sub_archs: + return arch + + +def get_template_default(template_type, field): + host_arch = _get_arch() + # Assuming 'power' = 'ppc64le' because lookup() does the same, + # claiming libvirt compatibility. + host_arch = 'power' if host_arch == 'ppc64le' else host_arch + tmpl_defaults = copy.deepcopy(defaults) + tmpl_defaults.update(template_specs[host_arch][template_type]) + return tmpl_defaults[field] + + +def lookup(distro, version): + """ + Lookup all parameters needed to run a VM of a known or unknown operating + system type and version. The data is constructed by starting with the + 'defaults' and merging the parameters given for the identified OS. If + known, a link to a remote install CD is added. + """ + params = copy.deepcopy(defaults) + params['os_distro'] = distro + params['os_version'] = version + arch = _get_arch() + + # Setting maxMemory of the VM, which will be equal total Host memory in Kib + params['max_memory'] = psutil.TOTAL_PHYMEM >> 10 + + # set up arch to ppc64 instead of ppc64le due to libvirt compatibility + if params["arch"] == "ppc64le": + params["arch"] = "ppc64" + + if distro in modern_version_bases[arch]: + if LooseVersion(version) >= LooseVersion( + modern_version_bases[arch][distro]): + params.update(template_specs[arch]['modern']) + else: + params.update(template_specs[arch]['old']) + else: + params['os_distro'] = params['os_version'] = "unknown" + params.update(template_specs[arch]['old']) + + # Get custom specifications + params.update(custom_specs.get(distro, {}).get(version, {})) + + if distro in icon_available_distros: + params['icon'] = 'plugins/kimchi/images/icon-%s.png' % distro + else: + params['icon'] = 'plugins/kimchi/images/icon-vm.png' + + return params diff --git a/src/wok/plugins/kimchi/po/LINGUAS b/src/wok/plugins/kimchi/po/LINGUAS new file mode 100644 index 0000000..3fcb18f --- /dev/null +++ b/src/wok/plugins/kimchi/po/LINGUAS @@ -0,0 +1,11 @@ +en_US +pt_BR +zh_CN +de_DE +es_ES +fr_FR +it_IT +ja_JP +ko_KR +ru_RU +zh_TW diff --git a/src/wok/plugins/kimchi/po/Makefile.in.in b/src/wok/plugins/kimchi/po/Makefile.in.in new file mode 100644 index 0000000..d01fb31 --- /dev/null +++ b/src/wok/plugins/kimchi/po/Makefile.in.in @@ -0,0 +1,398 @@ +# Makefile for PO directory in any package using GNU gettext. +# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper@gnu.ai.mit.edu> +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU General Public +# License but which still want to provide support for the GNU gettext +# functionality. +# Please note that the actual code of GNU gettext is covered by the GNU +# General Public License and is *not* in the public domain. +# +# Origin: gettext-0.18 +GETTEXT_MACRO_VERSION = 0.18 + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ + +SHELL = /bin/sh +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +datadir = @datadir@ +localedir = @prefix@/share/locale +gettextsrcdir = $(datadir)/gettext/po + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +# We use $(MKDIR_P). +# This macro uses the 'mkdir -p' command if possible. Otherwise, it falls back +# on invoking install-sh with the -d option, so your package should contain +# install-sh as described under AC_PROG_INSTALL. +mkinstalldirs = $(SHELL) @install_sh@ -d +install_sh = $(SHELL) @install_sh@ +MKDIR_P = @MKDIR_P@ +MKDIR_P = @MKDIR_P@ + +GMSGFMT_ = @GMSGFMT@ +GMSGFMT_no = @GMSGFMT@ +GMSGFMT_yes = @GMSGFMT_015@ +GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) +MSGFMT_ = @MSGFMT@ +MSGFMT_no = @MSGFMT@ +MSGFMT_yes = @MSGFMT_015@ +MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) +XGETTEXT_ = @XGETTEXT@ +XGETTEXT_no = @XGETTEXT@ +XGETTEXT_yes = @XGETTEXT_015@ +XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) +MSGMERGE = msgmerge +MSGMERGE_UPDATE = @MSGMERGE@ --update +MSGINIT = msginit +MSGCONV = msgconv +MSGFILTER = msgfilter + +POFILES = @POFILES@ +GMOFILES = @GMOFILES@ +UPDATEPOFILES = @UPDATEPOFILES@ +DUMMYPOFILES = @DUMMYPOFILES@ +DISTFILES.common = Makefile.in.in \ +$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) +DISTFILES = $(DISTFILES.common) Makevars POTFILES.in gen-pot.in \ +$(POFILES) $(GMOFILES) \ +$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) + +POTFILES = \ + +CATALOGS = @CATALOGS@ + +# Makevars gets inserted here. (Don't remove this line!) + +.SUFFIXES: +.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update + +.po.mo: + @echo "$(MSGFMT) -c -o $@ $<"; \ + $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ + +.po.gmo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \ + cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo + +.sin.sed: + sed -e '/^#/d' $< > t-$@ + mv t-$@ $@ + + +all: check-macro-version update-gmo all-@USE_NLS@ + +all-yes: stamp-po +all-no: + +# Ensure that the gettext macros and this Makefile.in.in are in sync. +check-macro-version: + @test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \ + || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \ + exit 1; \ + } + +# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no +# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because +# we don't want to bother translators with empty POT files). We assume that +# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. +# In this case, stamp-po is a nop (i.e. a phony target). + +# stamp-po is a timestamp denoting the last time at which the CATALOGS have +# been loosely updated. Its purpose is that when a developer or translator +# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, +# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent +# invocations of "make" will do nothing. This timestamp would not be necessary +# if updating the $(CATALOGS) would always touch them; however, the rule for +# $(POFILES) has been designed to not touch files that don't need to be +# changed. +stamp-po: $(srcdir)/$(DOMAIN).pot + test ! -f $(srcdir)/$(DOMAIN).pot || \ + test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) + @test ! -f $(srcdir)/$(DOMAIN).pot || { \ + echo "touch stamp-po" && \ + echo timestamp > stamp-poT && \ + mv stamp-poT stamp-po; \ + } + +# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', +# otherwise packages like GCC can not be built if only parts of the source +# have been downloaded. + +$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in + $(srcdir)/gen-pot $(POTFILES) + +# This rule has no dependencies: we don't need to update $(DOMAIN).pot at +# every "make" invocation, only create it when it is missing. +# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. +$(srcdir)/$(DOMAIN).pot: + $(MAKE) $(DOMAIN).pot-update + +# This target rebuilds a PO file if $(DOMAIN).pot has changed. +# Note that a PO file is not touched if it doesn't need to be changed. +$(POFILES): $(srcdir)/$(DOMAIN).pot + @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ + if test -f "$(srcdir)/$${lang}.po"; then \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \ + cd $(srcdir) \ + && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ + $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ + *) \ + $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \ + esac; \ + }; \ + else \ + $(MAKE) $${lang}.po-create; \ + fi + + +install: install-exec install-data +install-exec: +install-data: install-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(MKDIR_P) $(DESTDIR)$(gettextsrcdir); \ + for file in $(DISTFILES.common) Makevars.template; do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + for file in Makevars; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +install-data-no: all +install-data-yes: all + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(MKDIR_P) $(DESTDIR)$$dir; \ + if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ + $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ + echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ + fi; \ + done; \ + done + +install-strip: install + +installdirs: installdirs-exec installdirs-data +installdirs-exec: +installdirs-data: installdirs-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(MKDIR_P) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi +installdirs-data-no: +installdirs-data-yes: + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(MKDIR_P) $(DESTDIR)$$dir; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + fi; \ + done; \ + done + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: uninstall-exec uninstall-data +uninstall-exec: +uninstall-data: uninstall-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + for file in $(DISTFILES.common) Makevars.template; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +uninstall-data-no: +uninstall-data-yes: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + done; \ + done + +check: all + +info dvi ps pdf html tags TAGS ctags CTAGS ID: + +mostlyclean: + rm -f remove-potcdate.sed + rm -f stamp-poT + rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f stamp-po $(GMOFILES) + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: + $(MAKE) update-po + @$(MAKE) dist2 +# This is a separate target because 'update-po' must be executed before. +dist2: stamp-po $(DISTFILES) + dists="$(DISTFILES)"; \ + if test "$(PACKAGE)" = "gettext-tools"; then \ + dists="$$dists Makevars.template"; \ + fi; \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + dists="$$dists $(DOMAIN).pot stamp-po"; \ + fi; \ + if test -f $(srcdir)/ChangeLog; then \ + dists="$$dists ChangeLog"; \ + fi; \ + for i in 0 1 2 3 4 5 6 7 8 9; do \ + if test -f $(srcdir)/ChangeLog.$$i; then \ + dists="$$dists ChangeLog.$$i"; \ + fi; \ + done; \ + if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ + for file in $$dists; do \ + if test -f $$file; then \ + cp -p $$file $(distdir) || exit 1; \ + else \ + cp -p $(srcdir)/$$file $(distdir) || exit 1; \ + fi; \ + done + +update-po: Makefile + $(MAKE) $(DOMAIN).pot-update + test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) + $(MAKE) update-gmo + +# General rule for creating PO files. + +.nop.po-create: + @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ + echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ + exit 1 + +# General rule for updating PO files. + +.nop.po-update: + @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ + if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ + cd $(srcdir); \ + if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ + $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ + *) \ + $(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ + esac; \ + }; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +$(DUMMYPOFILES): + +update-gmo: Makefile $(GMOFILES) + @: + +# Recreate Makefile by invoking config.status. Explicitly invoke the shell, +# because execution permission bits may not work on the current file system. +# Use @SHELL@, which is the shell determined by autoconf for the use by its +# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient. +Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ + cd $(top_builddir) \ + && @SHELL@ ./config.status $(subdir)/$@.in po-directories + +force: + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/wok/plugins/kimchi/po/Makevars b/src/wok/plugins/kimchi/po/Makevars new file mode 100644 index 0000000..c29a807 --- /dev/null +++ b/src/wok/plugins/kimchi/po/Makevars @@ -0,0 +1,41 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = kimchi + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = project-kimchi@googlegroups.com + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = diff --git a/src/wok/plugins/kimchi/po/POTFILES.in b/src/wok/plugins/kimchi/po/POTFILES.in new file mode 100644 index 0000000..92eef1e --- /dev/null +++ b/src/wok/plugins/kimchi/po/POTFILES.in @@ -0,0 +1,3 @@ +# List of source files which contain translatable strings. +i18n.py +ui/pages/*.tmpl diff --git a/src/wok/plugins/kimchi/po/de_DE.po b/src/wok/plugins/kimchi/po/de_DE.po new file mode 100644 index 0000000..d3f3cc3 --- /dev/null +++ b/src/wok/plugins/kimchi/po/de_DE.po @@ -0,0 +1,2288 @@ +# English translations for kimchi package. +# Copyright (C) 2013 ORGANIZATION +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2013-07-11 17:32-0400\n" +"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" +"Language-Team: English\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: de_DE\n" +"Generated-By: pygettext.py 1.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "" + +msgid "Unknown \"_cap\" specified" +msgstr "" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "Fehler beim Abrufen von Blockeinheiten. Details: %(err)s" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "Fehler beim Abrufen von Blockeinheitinformationen f��r %(device)s." + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "Distro-Datei konnte nicht gefunden werden: %(filename)s" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "" +"Distro-Datei konnte nicht analysiert werden: %(filename)s. Stellen Sie " +"sicher, dass es sich um eine JSON-Datei handelt." + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "Fehler beim Anmelden bei iSCSI-Hostziel %(portal)s. Details: %(err)s" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "Anmeldung bei iSCSI-Host %(host)s Ziel %(target)s nicht m��glich" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "Die ISO-Datei %(filename)s ist nicht bootf��hig" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "Die ISO-Datei %(filename)s hat keinen g��ltigen El Torito-Bootsatz" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "Ung��ltiger El Torito-Pr��feintrag in ISO-Datei %(filename)s" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "Ung��ltiger El Torito-Boot-Indikator in ISO-Datei %(filename)s" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" +"Unerwarteter Datentr��gertyp f��r Prim��rdatentr��ger in ISO-Datei %(filename)s" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" +"Ung��ltiges Format beim Lesen des Datentr��gerdeskriptors in ISO-Datei %" +"(filename)s" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" +"Der Hypervisor hat nicht die Berechtigung, die ISO-Datei %(filename)s zu " +"verwenden. Verschieben Sie sie entweder nach /var/lib/libvirt oder setzen " +"Sie, sofern m��glich, die Suchberechtigung auf Dateizugriffssteuerungslisten " +"f��r den Benutzer '%(user)s' oder f��gen Sie '%(user)s' der ISO-Pfadgruppe " +"hinzu oder (nicht empfohlen) 'chmod -R o+x 'path_to_iso'. Details: %(err)s" + +msgid "An error occurred when probing image OS information." +msgstr "" + +msgid "No OS information found in given image." +msgstr "" + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "Virtuelle Maschine %(name)s ist bereits vorhanden" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "Virtuelle Maschine %(name)s ist nicht vorhanden" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" +"Screenshot f��r gestoppte virtuelle Maschine %(name)s konnte nicht abgerufen " +"werden" + +msgid "Remote ISO image is not supported by this server." +msgstr "Fernes ISO-Image wird von diesem Server nicht unterst��tzt." + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Virtuelle Maschine %(name)s konnte nicht erstellt werden. Details: %(err)s" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Virtuelle Maschine %(name)s konnte nicht erstellt werden. Details: %(err)s" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Virtuelle Maschine %(name)s konnte nicht abgerufen werden. Details: %(err)s" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "" +"Verbindung zur abgeschalteten Maschine %(name)s konnte nicht hergestellt " +"werden." + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "Zu ��berwachende Grafikadresse muss IPv4 oder IPv6 sein" + +msgid "Specify a template to create a virtual machine from" +msgstr "Vorlage angeben, aus der eine virtuelle Maschine erstellt werden soll" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Virtuelle Maschine %(name)s konnte nicht gestartet werden. Details: %(err)s" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Virtuelle Maschine %(name)s konnte nicht gestoppt werden. Details: %(err)s" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Virtuelle Maschine %(name)s konnte nicht gel��scht werden. Details: %(err)s" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Virtuelle Maschine %(name)s konnte nicht umbenannt werden. Details: %(err)s" + +msgid "User name list must be an array" +msgstr "" + +msgid "User name must be a string" +msgstr "Netzname muss eine Zeichenfolge sein" + +msgid "Group name list must be an array" +msgstr "" + +msgid "Group name must be a string" +msgstr "Netzname muss eine Zeichenfolge sein" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "Benutzer '%(users)s' ist nicht vorhanden." + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "Benutzer '%(groups)s' ist nicht vorhanden." + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Virtuelle Maschine %(name)s konnte nicht gestoppt werden. Details: %(err)s" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Virtuelle Maschine %(name)s konnte nicht gestartet werden. Details: %(err)s" + +msgid "The guest console password must be a string." +msgstr "" + +msgid "The life time for the guest console password must be a number." +msgstr "" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" + +msgid "\"name\" should be a device name string" +msgstr "" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "" +"Schnittstelle %(iface)s ist in virtueller Maschine %(name)s nicht vorhanden" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" +"Das f��r die virtuelle Maschine %(name)s angegebene Netz %(network)s ist " +"nicht vorhanden" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "Unterst��tzter Schnittstellentyp einer virtuellen Maschine ist nur Netz" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" +"Netzname f��r Schnittstelle einer virtuellen Maschine muss eine Zeichenfolge " +"sein" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" +"Ung��ltige Netzmodellkarte f��r Schnittstelle einer virtuellen Maschine " +"angegeben" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" +"Geben Sie Typ und Netz an, um eine neue Schnittstelle f��r eine virtuelle " +"Maschine hinzuzuf��gen" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "Vorlage %(name)s ist bereits vorhanden" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" +"Das f��r Vorlage %(template)s angegebene Netz '%(network)s' ist nicht " +"vorhanden" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "" +"Der f��r Vorlage %(template)s angegebene Speicherpool '%(pool)s' ist nicht " +"vorhanden" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "" +"Der f��r Vorlage %(template)s angegebene Speicherpool '%(pool)s' ist nicht " +"aktiv" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "Ung��ltiger Parameter '%(param)s' f��r CD-ROM angegeben." + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" +"Das f��r Vorlage %(template)s angegebene Netz %(network)s ist nicht aktiv" + +msgid "Template name must be a string" +msgstr "Vorlagenname muss eine Zeichenfolge sein" + +msgid "Template icon must be a path to the image" +msgstr "Vorlagensymbol muss ein Pfad zum Image sein" + +msgid "Template distribution must be a string" +msgstr "Vorlagenverteilung muss eine Zeichenfolge sein" + +msgid "Template distribution version must be a string" +msgstr "Vorlagenverteilungsversion muss eine Zeichenfolge sein" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "Die Anzahl der CPUs muss eine Ganzzahl sein" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "Speicherkapazit��t (MB) muss eine Ganzzahl gr����er als 512 sein" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "Vorlagen-CD-ROM muss eine lokale oder ferne ISO-Datei sein" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "Ung��ltiger Speicherpool-URI %(value)s f��r Vorlage angegeben" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "Geben Sie ein ISO-Image als CD-ROM an, um eine Vorlage zu erstellen" + +msgid "All networks for the template must be specified in a list." +msgstr "Alle Netze f��r die Vorlage m��ssen in einer Liste angegeben werden." + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "" +"Vorlage kann aufgrund des folgenden Fehlers nicht erstellt werden: %(err)s" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "" +"Vorlage kann aufgrund des folgenden Fehlers nicht gel��scht werden: %(err)s" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "" + +msgid "Template base image must be a valid local image file" +msgstr "Vorlagen-CD-ROM muss eine lokale oder ferne ISO-Datei sein" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "Speicherpool %(name)s ist bereits vorhanden" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "Speicherpool %(name)s ist nicht vorhanden" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "Geben Sie %(item)s an, um den Speicherpool %(name)s zu erstellen" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "Aktiver Speicherpool %(name)s konnte nicht gel��scht werden" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "Speicherpools konnten nicht aufgelistet werden. Details: %(err)s" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "Speicherpool %(name)s konnte nicht erstellt werden. Details: %(err)s" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "" +"Anzahl der Speicherdatentr��ger im Speicherpool %(name)s konnte nicht " +"abgerufen werden. Details: %(err)s" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "Speicherpool %(name)s konnte nicht aktiviert werden. Details: %(err)s" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "" +"Speicherpool %(name)s konnte nicht inaktiviert werden. Details: %(err)s" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "Speicherpool %(name)s konnte nicht gel��scht werden. Details: %(err)s" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" +"NFS-Pool konnte nicht erstellt werden, weil Exportpfad %(path)s beim Mounten " +"blockieren kann" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" +"NFS-Pool konnte nicht erstellt werden, weil das Mounten des Exportpfads%" +"(path)s fehlgeschlagen ist" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "Nicht unterst��tzter Speicherpooltyp: %(type)s" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" + +msgid "Storage pool path must be a string" +msgstr "Speicherpoolpfad muss eine Zeichenfolge sein" + +msgid "Storage pool host must be a IP or hostname" +msgstr "Speicherpoolhost muss eine IP oder ein Hostname sein" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" + +msgid "Storage pool devices parameter must be a list" +msgstr "Einheitenparameter des Speicherpools muss eine Liste sein" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "Ziel-IQN eines iSCSI-Pools muss eine Zeichenfolge sein" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" +"Port eines fernen Speicherservers muss eine Ganzzahl zwischen 1 und 65535 " +"sein" + +msgid "iSCSI target username must be a string" +msgstr "" + +msgid "iSCSI target password must be a string" +msgstr "" + +msgid "Specify name and type to create a storage pool" +msgstr "Geben Sie Name und Typ an, um einen Speicherpool zu erstellen" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "" +"%(disk)s ist keine g��ltige Platte/Partition. Sie konnte nicht hinzugef��gt " +"werden zum Pool %(pool)s." + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "" +"Die Parameterplatten k��nnen nur f��r den logischen Speicherpool aktualisiert " +"werden." + +msgid "The SCSI host adapter name must be a string." +msgstr "Der Name des SCSI-Hostadapters muss eine Zeichenfolge sein." + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "Der Speicherpool kimchi_isos ist f��r die interne Verwendung reserviert" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"Der NFS-Speicherpool %(name)s konnte nicht aktiviert werden. NFS-Server %" +"(server)s ist nicht erreichbar." + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"Der NFS-Speicherpool %(name)s konnte nicht inaktiviert werden. NFS-Server %" +"(server)s ist nicht erreichbar." + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "" +"Pool %(name)s konnte nicht inaktiviert werden, weil er einigen Vorlagen " +"zugeordnet ist" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "" +"Pool %(name)s konnte nicht gel��scht werden, weil er einigen Vorlagen " +"zugeordnet ist" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "" +"Eine Datentr��gergruppe mit dem Namen '%(name)s' ist bereits vorhanden. " +"W��hlen Sie einen anderen Namen aus, um den logischen Pool zu erstellen." + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "" +"Datenbank mit Tiefenscaninformationen kann aufgrund des folgenden Fehlers " +"nicht aktualisiert werden: %(err)s" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "Speicherdatentr��ger %(name)s ist bereits vorhanden" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "" +"Speicherdatentr��ger %(name)s ist nicht im Speicherpool %(pool)s vorhanden" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "Geben Sie %(item)s an, um Speicherdatentr��ger %(volume)s zu erstellen" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "" +"Speicherdatentr��ger konnten nicht aufgelistet werden, weil Speicherpool %" +"(pool)s nicht aktiv ist" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "" +"Speicherdatentr��ger %(name)s konnte nicht in Speicherpool %(pool)s erstellt " +"werden. Details: %(err)s" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "" +"Speicherdatentr��ger konnten nicht in Speicherpool %(pool)s aufgelistet " +"werden. Details: %(err)s" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "" +"Speicherdatentr��ger %(name)s konnten nicht bereinigt werden. Details: %(err)s" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "" +"Speicherdatentr��ger %(name)s konnte nicht gel��scht werden. Details: %(err)s" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "" +"Gr����e des Speicherdatentr��gers %(name)s konnte nicht ge��ndert werden. " +"Details: %(err)s" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "" +"Speichertyp %(type)s unterst��tzt nicht das Erstellen und L��schen von " +"Datentr��gern" + +msgid "Storage volume name must be a string" +msgstr "Name des Speicherdatentr��gers muss eine Zeichenfolge sein" + +msgid "Storage volume allocation must be an integer number" +msgstr "Zuordnung des Speicherdatentr��gers muss eine Ganzzahl sein" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" + +msgid "Storage volume requires a volume name" +msgstr "Speicherdatentr��ger erfordert einen Datentr��gernamen" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "" +"Datenbank mit Datentr��gerinformationen kann aufgrund des folgenden Fehlers " +"nicht aktualisiert werden: %(err)s" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "" + +msgid "Storage volume capacity must be an integer number." +msgstr "" + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "" + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "Schnittstelle %(name)s ist nicht vorhanden" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "Netz %(name)s ist bereits vorhanden" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "Netz %(name)s ist nicht vorhanden" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" +"Das f��r das Netz %(network)s angegebene Teilnetz %(subnet)s ist nicht g��ltig." + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" +"Geben Sie eine Netzschnittstelle an, um ��berbr��cktes Netz %(name)s zu " +"erstellen" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "Aktives Netz %(name)s konnte nicht gel��scht werden" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" +"Die f��r das Netz %(network)s angegebene Schnittstelle %(iface)s wird bereits " +"verwendet" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "Schnittstelle sollte blo��es NIC, Bonding oder Br��ckeneinheit sein." + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "Netz %(name)s konnte nicht erstellt werden. Details: %(err)s" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "Es konnte keine freie IP-Adresse f��r Netz '%(name)s' gefunden werden" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "Unterst��tzte Netztypen sind Isoliert, NAT und Br��cke" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "" +"Teilnetz des Netzes muss eine Zeichenfolge mit IP-Adresse und Pr��fix oder " +"Netzmaske sein" + +msgid "Network interface must be a string" +msgstr "Netzschnittstelle muss eine Zeichenfolge sein" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "Netz-VLAN-ID muss eine Ganzzahl zwischen 1 und 4094 sein" + +msgid "Specify name and type to create a Network" +msgstr "Geben Sie Name und Typ an, um ein Netz zu erstellen" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" +"Netz %(name)s konnte nicht inaktiviert werden. Es sind einige virtuellen " +"Maschinen %(vms)s und/oder Vorlagen mit diesem Netz verkn��pft." + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" +"Netz %(name)s konnte nicht inaktiviert werden. Es sind einige virtuellen " +"Maschinen %(vms)s und/oder Vorlagen mit diesem Netz verkn��pft." + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "Br��ckeneinheit %(name)s kann nicht die Trunkeinheit eines VLAN sein." + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "Schnittstelle %(iface)s konnte nicht aktiviert werden: %(err)s." + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "" +"Schnittstelle %(iface)s konnte nicht aktiviert werden. Bitte ��berpr��fen Sie " +"den Status der physischen Verbindung." + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "Debugbericht %(name)s ist nicht vorhanden" + +msgid "Debug report tool not found in system" +msgstr "Debugberichtstool nicht im System gefunden" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "Debugbericht %(name)s konnte nicht erstellt werden. Details: %(err)s." + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "Debugbericht %(name)s konnte nicht generiert werden. Details: %(err)s" + +msgid "You should give a name for the debug report file." +msgstr "" + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "" +"Eine Datentr��gergruppe mit dem Namen '%(name)s' ist bereits vorhanden. " +"W��hlen Sie einen anderen Namen aus, um den logischen Pool zu erstellen." + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "Speicherserver %(server)s wurde nicht von Kimchi verwendet" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "Distro '%(name)s' ist nicht vorhanden" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "Partition %(name)s ist nicht im Host vorhanden" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" +"Hostmaschine konnte nicht heruntergefahren werden, weil virtuelle Maschinen " +"ausgef��hrt werden" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" +"Hostmaschine konnte nicht neu gestartet werden, weil virtuelle Maschinen " +"ausgef��hrt werden" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "Knoteneinheit '%(name)s' nicht gefunden" + +msgid "Conflicting flag filters specified." +msgstr "" + +msgid "No packages marked for update" +msgstr "Keine Pakete f��r Aktualisierung markiert" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "Paket %(name)s ist nicht f��r Aktualisierung markiert." + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "" +"Fehler beim Abrufen von Paketen, die f��r die Aktualsierung markiert sind. " +"Details: %(err)s" + +msgid "There is no compatible package manager for this system." +msgstr "Es gibt keinen kompatiblen Paketmanager f��r dieses System." + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "Ung��ltiger URI %(uri)s" + +msgid "Unable to choose a virtual machine name" +msgstr "" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "Ung��ltiger Speichertyp. Unterst��tzte Typen: 'cdrom'" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" + +msgid "Only CDROM path can be update." +msgstr "" + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "Fehler beim Erstellen einer neuen Speichereinheit: %(error)s" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "Fehler beim Aktualisieren einer Speichereinheit: %(error)s" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "Fehler beim Entfernen einer Speichereinheit: %(error)s" + +msgid "Do not support IDE device hot plug" +msgstr "" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "" +"Geben Sie Typ und Pfad an, um einen neuen Datentr��ger f��r eine virtuelle " +"Maschine hinzuzf��gen" + +msgid "Specify path to update virtual machine disk" +msgstr "" +"Geben Sie einen Pfad an, um die Platte der virtuellen Maschine zu " +"aktualisieren" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" + +msgid "Volume already in use by other virtual machine." +msgstr "" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "" +"Geben Sie Typ und Pfad an, um einen neuen Datentr��ger f��r eine virtuelle " +"Maschine hinzuzf��gen" + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" + +msgid "YUM Repository ID must be one word only string." +msgstr "" +"YUM-Repository-ID darf nur ein aus einer Zeichenfolge bestehendes Wort sein." + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "Repository-URL muss ein http://-, ftp://- oder file://-URL sein." + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "" +"Repository-Konfiguration ist ein W��rterbuch mit bestimmten Werten " +"hinsichtlich Repository-Typ." + +msgid "Distribution to DEB repository must be a string" +msgstr "Verteilung an DEB-Repository muss eine Zeichenfolge sein" + +msgid "Components to DEB repository must be listed in a array" +msgstr "Komponenten f��r DEB-Repository m��ssen in einem Array aufgelistet sein" + +msgid "Components to DEB repository must be a string" +msgstr "Komponenten f��r DEB-Repository m��ssen eine Zeichenfolge sein" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "Name des YUM-Repositorys muss eine Zeichenfolge sein." + +msgid "GPG check must be a boolean value." +msgstr "GPG-Pr��fung muss ein boolescher Wert sein." + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "GPG-Schl��ssel muss ein URL sein, der auf die ASCII-Armor-Datei zeigt." + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "Repository %(repo_id)s konnte nicht aktualisiert werden." + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "Repository %(repo_id)s ist nicht vorhanden." + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "Repository-Verwaltungstool wurde f��r Ihr System nicht erkannt." + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "Repository %(repo_id)s ist bereits aktiviert." + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "Repository %(repo_id)s ist bereits inaktiviert." + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "Repository %(repo_id)s konnte nicht entfernt werden." + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "" +"Repository-Konfigurationsdatei %(repo_file)s konnte nicht geschrieben werden" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "" +"Geben Sie die Repository-Verteilung an, um ein DEB-Repository zu erstellen." + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "Repository %(repo_id)s konnte nicht aktiviert werden." + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "Repository %(repo_id)s konnte nicht inaktiviert werden." + +msgid "YUM Repository ID already exists" +msgstr "YUM-Repository-ID ist bereits vorhanden" + +msgid "YUM Repository name must be a string" +msgstr "YUM-Repository-Name muss eine Zeichenfolge sein" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "Repositorys konnten nicht aufgelistet werden. Details: '%(err)s'" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "" +"Repository-Informationen konnten nicht abgerufen werden. Details: '%(err)s'" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "Repository konnte nicht hinzugef��gt werden. Details: '%(err)s'" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "Repository konnte nicht entfernt werden. Details: '%(err)s'" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" + +msgid "The number of vCPUs is too large for this system." +msgstr "" + +msgid "Invalid vCPU/topology combination." +msgstr "" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "" + +msgid "ERROR CODE" +msgstr "FEHLERCODE" + +msgid "REASON" +msgstr "GRUND" + +msgid "STACK" +msgstr "STACK" + +msgid "Go to Homepage" +msgstr "Gehe zu Homepage" + +msgid "Create a New Virtual Machine" +msgstr "Neue virtuelle Maschine erstellen" + +msgid "Virtual Machine Name" +msgstr "Name der virtuellen Maschine" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" +"Der f��r die Kennzeichnung der virtuellen Maschine verwendete Name. Falls er " +"ausgelassen wird, wird ein Name anhand der verwendeten Vorlage ausgew��hlt." + +msgid "Template" +msgstr "Vorlage" + +msgid "Please create a template first." +msgstr "Erstellen Sie zun��chst eine Vorlage." + +msgid "Create a Template" +msgstr "Vorlage erstellen" + +msgid "Please choose a template." +msgstr "W��hlen Sie eine Vorlage aus." + +msgid "OS" +msgstr "BS" + +msgid "OS Version" +msgstr "BS-Version" + +msgid "CPUS" +msgstr "CPUS" + +msgid "Memory" +msgstr "Speicher" + +msgid "Create" +msgstr "Erstellen" + +msgid "Creating..." +msgstr "" + +msgid "Cancel" +msgstr "Abbrechen" + +msgid "Edit Guest" +msgstr "Gast bearbeiten" + +msgid "General" +msgstr "Allgemein" + +msgid "Storage" +msgstr "Speicher" + +msgid "Interface" +msgstr "Schnittstelle" + +msgid "Permission" +msgstr "Version" + +msgid "Host PCI Device" +msgstr "" + +msgid "Snapshot" +msgstr "" + +msgid "Name" +msgstr "Name" + +msgid "CPUs" +msgstr "CPUs" + +msgid "Memory (MB)" +msgstr "Speicher" + +msgid "Icon" +msgstr "Symbol" + +msgid "Device" +msgstr "Einheitenname" + +msgid "Path" +msgstr "NFS-Pfad" + +msgid "Network" +msgstr "Netz" + +msgid "Type" +msgstr "Typ" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "" + +msgid "Selected system users and groups" +msgstr "" + +msgid "User" +msgstr "" + +msgid "All" +msgstr "Alle" + +msgid "To Add" +msgstr "" + +msgid "Added" +msgstr "" + +msgid "filter" +msgstr "" + +msgid "Product" +msgstr "" + +msgid "Vendor" +msgstr "Anbieter" + +msgid "Created" +msgstr "" + +msgid "Save" +msgstr "Speichern" + +msgid "Replace" +msgstr "Ersetzen" + +msgid "Detach" +msgstr "Abh��ngen" + +msgid "revert" +msgstr "" + +msgid "Start" +msgstr "Starten" + +msgid "Reset" +msgstr "Zur��cksetzen" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "" + +msgid "Actions" +msgstr "Aktionen" + +msgid "Connect" +msgstr "Verbinden" + +msgid "Clone" +msgstr "" + +msgid "Edit" +msgstr "Bearbeiten" + +msgid "Shut Down" +msgstr "Herunterfahren" + +msgid "Delete" +msgstr "L��schen" + +msgid "CPU" +msgstr "CPU" + +msgid "Disk I/O" +msgstr "Platten-E/A" + +msgid "Network I/O" +msgstr "Netz-E/A" + +msgid "Livetile" +msgstr "Live Tile" + +msgid "No guests found." +msgstr "Keine G��ste gefunden." + +msgid "Add a Storage Device to VM" +msgstr "Speichereinheit zur virtuellen Maschine hinzuf��gen" + +msgid "Device Type" +msgstr "Einheitentyp" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "Der Einheitentyp. Derzeit wird nur \"cdrom\" unterst��tzt." + +msgid "Storage Pool" +msgstr "Speicherpool" + +msgid "Storage pool which volume located in" +msgstr "Speicherpoolpfad muss eine Zeichenfolge sein" + +msgid "Storage Volume" +msgstr "Speicherpoolname" + +msgid "Storage volume to be attached" +msgstr "Name des Speicherdatentr��gers muss eine Zeichenfolge sein" + +msgid "File Path" +msgstr "Dateipfad" + +msgid "The ISO file path in the server for CDROM." +msgstr "Der ISO-Dateipfad auf dem Server f��r die CD-ROM." + +msgid "Attach" +msgstr "Anh��ngen" + +msgid "Shut down" +msgstr "Herunterfahren" + +msgid "Restart" +msgstr "Erneut starten" + +msgid "Basic Information" +msgstr "Basisinformationen" + +msgid "OS Distro" +msgstr "BS-Distro" + +msgid "OS Code Name" +msgstr "BS-Codename" + +msgid "Processor" +msgstr "Prozessor" + +msgid "CPU(s)" +msgstr "" + +msgid "System Statistics" +msgstr "Systemstatistik" + +msgid "Software Updates" +msgstr "Software-Updates" + +msgid "Update Progress" +msgstr "Aktualisierungsfortschritt" + +msgid "Repositories" +msgstr "Repositorys" + +msgid "Debug Reports" +msgstr "Debugberichte" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "" +"Der Benutzername oder das Kennwort, den bzw. das Sie eingegeben haben, ist " +"falsch. Versuchen Sie es bitte erneut." + +msgid "This field is required." +msgstr "Dieses Feld ist erforderlich." + +msgid "Log in" +msgstr "Anmelden" + +msgid "Logging in..." +msgstr "Wird angemeldet..." + +msgid "Host" +msgstr "Host" + +msgid "Guests" +msgstr "G��ste" + +msgid "Templates" +msgstr "Vorlagen" + +msgid "Failed to get application configuration" +msgstr "Anwendungskonfiguration konnte nicht abgerufen werden" + +msgid "This is not a valid Linux path" +msgstr "Dies ist kein g��ltiger Linux-Pfad" + +msgid "This is not a valid URL." +msgstr "Dies ist kein g��ltiger URL." + +msgid "No such data available." +msgstr "Keine solchen Daten verf��gbar." + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" +"Hostsystem kann nicht kontaktiert werden. Pr��fen Sie, ob das Hostsystem " +"aktiv ist und obNetzkonnektivit��t besteht. HTTP-Anforderungsantwort %1. " + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "L��schbest��tigung" + +msgid "OK" +msgstr "OK" + +msgid "Confirm" +msgstr "Best��tigen" + +msgid "Warning" +msgstr "Warnung" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "Wird geladen..." + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "Wiederholen" + +msgid "Detailed message:" +msgstr "Detaillierte Meldung:" + +msgid "No ISO found" +msgstr "" + +msgid "This is not a valid ISO file." +msgstr "Dies ist keine g��ltige ISO-Datei." + +msgid "This may take a long time. Do you want to continue?" +msgstr "Dies wird einige Zeit dauern. M��chten Sie fortfahren?" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "Hiermit wird die Vorlage dauerhaft gel��scht. M��chten Sie fortfahren?" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" +"System konnte nicht heruntergefahren werden, weil einige virtuellen " +"Maschinen ausgef��hrt werden!" + +msgid "Max:" +msgstr "Max:" + +msgid "Utilization" +msgstr "Auslastung" + +msgid "Available" +msgstr "Verf��gbar" + +msgid "Read Rate" +msgstr "Leserate" + +msgid "Write Rate" +msgstr "Schreibrate" + +msgid "Received" +msgstr "Empfangen" + +msgid "Sent" +msgstr "Gesendet" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"Durch das Herunterfahren oder Neustarten des Hosts k��nnen ungesicherte " +"Arbeiten verloren gehen. M��chten Sie mit dem Herunterfahren/Neustarten " +"fortfahren?" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"Repository wird dauerhaft entfernt und kann nicht wiederhergestellt werden. " +"M��chten Sie fortfahren?" + +msgid "ID" +msgstr "ID" + +msgid "Base URL" +msgstr "Basis-URL" + +msgid "Is Mirror" +msgstr "Ist Spiegel" + +msgid "URL Args" +msgstr "URL-Args" + +msgid "Enabled" +msgstr "Aktiviert" + +msgid "GPG Check" +msgstr "GPG-Pr��fung" + +msgid "GPG Key" +msgstr "GPG-Schl��ssel" + +msgid "Add" +msgstr "Hinzuf��gen" + +msgid "Remove" +msgstr "Entfernen" + +msgid "Enable" +msgstr "Aktivieren" + +msgid "Disable" +msgstr "Inaktivieren" + +msgid "Package Name" +msgstr "Paketname" + +msgid "Version" +msgstr "Version" + +msgid "Architecture" +msgstr "Architektur" + +msgid "Repository" +msgstr "Repository" + +msgid "Update All" +msgstr "Alle aktualisieren" + +msgid "Updating..." +msgstr "Wird aktualisiert..." + +msgid "Failed to retrieve packages update information." +msgstr "" + +msgid "Failed to update package(s)." +msgstr "Pakete konnten nicht aktualisiert werden." + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"Debugbericht wird dauerhaft entfernt und kann nicht wiederhergestellt " +"werden. M��chten Sie fortfahren?" + +msgid "Generated Time" +msgstr "Generierte Zeit" + +msgid "Generate" +msgstr "Generieren" + +msgid "Generating..." +msgstr "Wird generiert..." + +msgid "Rename" +msgstr "Umbenennen" + +msgid "Download" +msgstr "Herunterladen" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "" +"Berichtsname darf nur Buchstaben, Zahlen und/oder Bindestriche ('-') " +"enthalten." + +msgid "Pending..." +msgstr "Wird geladen..." + +msgid "Report name is the same as the original one." +msgstr "" + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "" +"Hiermit werden die virtuelle Maschine und deren virtuellen Platten gel��scht. " +"Diese Operation kann nicht r��ckg��ngig gemacht werden. M��chten Sie fortfahren?" + +msgid "Power off Confirmation" +msgstr "L��schbest��tigung" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" + +msgid "Reset Confirmation" +msgstr "L��schbest��tigung" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" + +msgid "Shut Down Confirmation" +msgstr "L��schbest��tigung" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "Hiermit wird die Vorlage dauerhaft gel��scht. M��chten Sie fortfahren?" + +msgid "Virtual Machine delete Confirmation" +msgstr "" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" +"Diese CD-ROM wird dauerhaft abgeh��ngt und Sie k��nnen sie neu anh��ngen. " +"M��chten Sie mit dem Abh��ngen fortfahren?" + +msgid "Attaching..." +msgstr "Wird angeh��ngt..." + +msgid "Replacing..." +msgstr "Wird ersetzt..." + +msgid "Successfully attached!" +msgstr "Erfolgreich angeh��ngt!" + +msgid "Successfully replaced!" +msgstr "Erfolgreich ersetzt!" + +msgid "Successfully detached!" +msgstr "Erfolgreich abgeh��ngt!" + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" + +msgid "interface:" +msgstr "" + +msgid "address:" +msgstr "" + +msgid "link_type:" +msgstr "" + +msgid "block:" +msgstr "" + +msgid "drive_type:" +msgstr "" + +msgid "model:" +msgstr "" + +msgid "Affected devices:" +msgstr "" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "Die VLAN-ID muss zwischen 1 und 4094 liegen." + +msgid "unavailable" +msgstr "nicht verf��gbar" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "" +"Diese Aktion unterbricht die Netzkonnektivit��t f��r jede virtuelle Maschine, " +"die von diesem Netz abh��ngt." + +msgid "Create a network" +msgstr "Netz erstellen" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"Dieser Speicherpool ist nicht permanent. Durch diese Aktion wird er nicht " +"inaktiviert, sondern permanent gel��scht. M��chten Sie fortfahren?" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "" +"Hiermit wird der Speicherpool dauerhaft gel��scht. M��chten Sie fortfahren?" + +msgid "This storage pool is empty." +msgstr "Dieser Speicherpool ist leer." + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "" +"Hiermit wird Ihre Platte formatiert und Sie verlieren s��mtliche Daten " +"darauf. Sind Sie sicher, dass Sie fortfahren m��chten? " + +msgid "SCSI Fibre Channel" +msgstr "SCSI-Fibre Channel" + +msgid "No SCSI adapters found." +msgstr "Keine SCSI-Adapter gefunden." + +msgid "Loading iSCSI targets..." +msgstr "" + +msgid "No iSCSI found. Please input one." +msgstr "" + +msgid "Failed to load iSCSI targets." +msgstr "" + +msgid "The storage pool name can not be blank." +msgstr "Der Speicherpoolname darf nicht leer sein." + +msgid "The storage pool path can not be blank." +msgstr "Der Speicherpoolpfad darf nicht leer sein." + +msgid "NFS server mount path can not be blank." +msgstr "Der Mountpfad des NFS-Servers darf nicht leer sein." + +msgid "Invalid NFS mount path." +msgstr "Ung��ltiger NFS-Mountpfad." + +msgid "No logical device selected." +msgstr "Keine logische Einheit ausgew��hlt." + +msgid "The iSCSI target can not be blank." +msgstr "Das iSCSI-Ziel darf nicht leer sein." + +msgid "Server name can not be blank." +msgstr "Servername darf nicht leer sein." + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "" + +msgid "Looking for available partitions ..." +msgstr "Es wird nach verf��gbaren Partitionen gesucht..." + +msgid "No available partitions found." +msgstr "Keine g��ltigen Partitionen gefunden." + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"Dieser Speicherpool ist nicht permanent. Durch diese Aktion wird er nicht " +"inaktiviert, sondern permanent gel��scht. M��chten Sie fortfahren?" + +msgid "Unable to retrieve partitions information." +msgstr "" +"Repository-Informationen konnten nicht abgerufen werden. Details: '%(err)s'" + +msgid "In progress..." +msgstr "" + +msgid "Failed!" +msgstr "" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" + +msgid "Disk pool or volume cannot be blank." +msgstr "Der Speicherpoolname darf nicht leer sein." + +msgid "Filter" +msgstr "" + +msgid "Network Name" +msgstr "Netzname" + +msgid "State" +msgstr "Status" + +msgid "Network Type" +msgstr "Netztyp" + +msgid "Address Space" +msgstr "Adressraum" + +msgid "Name should not contain '/' and '\"'." +msgstr "Ung��ltiger Speicherpoolname. Er darf nicht '/' enthalten." + +msgid "Isolated: no external network connection" +msgstr "Isolatiert: keine physisische Netzverbindung" + +msgid "NAT: outbound physical network connection only" +msgstr "NAT: nur ausgehende physische Netzverbindung" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "" +"��berbr��ckt: Virtuelle Maschinen sind direkt mit physischem Netz verbunden" + +msgid "(No interfaces found)" +msgstr "" + +msgid "Destination" +msgstr "Ziel:" + +msgid "Enable VLAN" +msgstr "Virtuelles LAN (VLAN) aktivieren:" + +msgid "VLAN ID" +msgstr "VLAN-ID:" + +msgid "Stop" +msgstr "Stoppen" + +msgid "Generate a New Debug Report" +msgstr "Neuen Debugbericht erstellen" + +msgid "Report Name" +msgstr "Berichtsname" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" +"Der Name, mit dem der Bericht gekennzeichnet wird. Falls er ausgelassen " +"wird, wird ein Name basierend auf der aktuellen Zeit ausgew��hlt. Der Name " +"darf Buchstaben, Zahlen und Bindestriche (\"-\") enthalten." + +msgid "Rename a Debug Report" +msgstr "Neuen Debugbericht erstellen" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" +"Der Name, mit dem der Bericht gekennzeichnet wird. Falls er ausgelassen " +"wird, wird ein Name basierend auf der aktuellen Zeit ausgew��hlt. Der Name " +"darf Buchstaben, Zahlen und Bindestriche (\"-\") enthalten." + +msgid "Submit" +msgstr "" + +msgid "Add a Repository" +msgstr "Repository hinzuf��gen" + +msgid "Identifier" +msgstr "Kennung" + +msgid "Single word, unique identifier for the repository." +msgstr "Einzelnes Wort, eindeutige Kennung f��r das Repository." + +msgid "Textual name for the repository." +msgstr "Textname f��r das Repository." + +msgid "URL" +msgstr "URL" + +msgid "Required Field" +msgstr "Erforderliches Feld" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "URL zum Repository. Unterst��tzte Protokolle sind http, ftp und file." + +msgid "Repository is a mirror" +msgstr "Repository ist ein Spiegel." + +msgid "Distribution" +msgstr "Verteilung" + +msgid "Distribution of the DEB repository." +msgstr "Verteilung des DEB-Repositorys." + +msgid "Components" +msgstr "Komponenten" + +msgid "List of components in DEB repository." +msgstr "Liste der Komponenten im DEB-Repository." + +msgid "Edit Repository" +msgstr "Repository bearbeiten" + +msgid "Mirror List URL" +msgstr "Spiegellisten-URL" + +msgid "Yes" +msgstr "Ja" + +msgid "No" +msgstr "Nein" + +msgid "Capacity" +msgstr "Kapazit��t" + +msgid "Allocated" +msgstr "Zugeordnet" + +msgid "Location" +msgstr "Position" + +msgid "Device path" +msgstr "Einheitenpfad" + +msgid "active" +msgstr "aktiv" + +msgid "inactive" +msgstr "inaktiv" + +msgid "Deactivate" +msgstr "Inaktivieren" + +msgid "Activate" +msgstr "Aktivieren" + +msgid "Add Volume" +msgstr "" + +msgid "Extend" +msgstr "" + +msgid "Undefine" +msgstr "Definition aufheben" + +msgid "Format" +msgstr "Format:" + +msgid "Allocation" +msgstr "Zuordnung:" + +msgid "Define a New Storage Pool" +msgstr "Neuen Speicherpool definieren" + +msgid "Storage Pool Name" +msgstr "Speicherpoolname" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "" +"Der Name, mit dem die Speicherpools gekennzeichnet werden. Er darf nicht " +"leer sein." + +msgid "Storage Pool Type" +msgstr "Speicherpooltyp" + +msgid "Storage Path" +msgstr "Speicherpfad" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "" +"Der Pfad des Speicherpools. Jeder Speicherpool muss einen eindeutigen Pfad " +"haben." + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "" +"Kimchi versucht, das Verzeichnis zu erstellen, wenn es noch nicht in Ihrem " +"System vorhanden ist." + +msgid "NFS Server IP" +msgstr "NFS-Server-IP" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" +"IP oder Hostname des NFS-Servers. Diese(r) kann eingegeben oder aus dem " +"Verlauf ausgew��hlt werden." + +msgid "NFS Path" +msgstr "NFS-Pfad" + +msgid "The NFS exported path on NFS server." +msgstr "Der NFS-Exportpfad auf dem NFS-Server." + +msgid "iSCSI Server" +msgstr "iSCSI-Server" + +msgid "Server" +msgstr "Server" + +msgid "Port" +msgstr "Port" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "IP oder Hostname des iSCSI-Servers. Diese(r) darf nicht leer sein." + +msgid "Target" +msgstr "Ziel" + +msgid "The iSCSI target on iSCSI server" +msgstr "Das iSCSI-Ziel auf dem iSCSI-Server" + +msgid "Add iSCSI Authentication" +msgstr "iSCSI-Authentifizierung hinzuf��gen" + +msgid "iSCSI Authentication" +msgstr "iSCSI-Authentifizierung" + +msgid "User Name" +msgstr "Benutzername" + +msgid "Password" +msgstr "Kennwort" + +msgid "SCSI Adapter" +msgstr "SCSI-Adapter" + +msgid "Please, wait..." +msgstr "Bitte warten..." + +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + +msgid "Add Template" +msgstr "Vorlage hinzuf��gen" + +msgid "Where is the source media for this template? " +msgstr "Wo ist der Quellendatentr��ger f��r diese Vorlage?" + +msgid "Local ISO Image" +msgstr "Lokales ISO-Image" + +msgid "Local Image File" +msgstr "" + +msgid "Remote ISO Image" +msgstr "Fernes ISO-Image" + +msgid "Search ISOs" +msgstr "ISOs suchen" + +msgid "The following ISOs are available:" +msgstr "Die folgenden ISOs sind verf��gbar:" + +msgid "OS: " +msgstr "BS: " + +msgid "Version: " +msgstr "Version: " + +msgid "Size: " +msgstr "Gr����e: " + +msgid "Search more ISOs" +msgstr "Weitere ISOs suchen" + +msgid "Create Templates from Selected ISO" +msgstr "Vorlagen aus ausgew��hltem ISO erstellen" + +msgid "I want to use a specific ISO file" +msgstr "Ich m��chte eine bestimmte ISO-Datei verwenden" + +msgid "Loading default remote ISOs ..." +msgstr "Standardm����ige ferne ISOs werden geladen ..." + +msgid "Arch: " +msgstr "Arch: " + +msgid "I want to use a custom URL" +msgstr "Ich m��chte einen benutzerdefinierten URL verwenden" + +msgid "Edit Template" +msgstr "Vorlage bearbeiten" + +msgid "CDROM" +msgstr "CD-ROM" + +msgid "Image File" +msgstr "" + +msgid "Graphics" +msgstr "Grafik" + +msgid "Disk(GB)" +msgstr "" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "CPU-Anzahl" + +msgid "Manually set CPU topology" +msgstr "" + +msgid "Cores" +msgstr "" + +msgid "Threads" +msgstr "" + +msgid "No templates found." +msgstr "Keine Vorlagen gefunden." + +#~ msgid "Delete is not allowed for %(resource)s" +#~ msgstr "L��schen ist nicht zul��ssig f��r %(resource)s" + +#~ msgid "%(resource)s does not implement update method" +#~ msgstr "%(resource)s implementiert keine Aktualisierungsmethode" + +#~ msgid "Create is not allowed for %(resource)s" +#~ msgstr "Erstellen ist nicht zul��ssig f��r %(resource)s" + +#~ msgid "Unable to parse JSON request" +#~ msgstr "JSON-Anfrage konnte nicht analysiert werden" + +#~ msgid "This API only supports JSON" +#~ msgstr "Diese API unterst��tzt nur JSON" + +#~ msgid "Datastore is not initiated in the model object." +#~ msgstr "Datenspeicher wird nicht im Modellobjekt initialisiert." + +#~ msgid "Unable to start task due error: %(err)s" +#~ msgstr "" +#~ "Task kann aufgrund des folgenden Fehlers nicht gestartet werden: %(err)s" + +#~ msgid "" +#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" +#~ msgstr "" +#~ "Authentifizierung f��r Benutzer '%(username)s' fehlgeschlagen. " +#~ "[Fehlercode: %(code)s]" + +#~ msgid "You are not authorized to access Kimchi" +#~ msgstr "Sie sind nicht berechtigt, auf Kimchi zuzugreifen" + +#~ msgid "Specify %(item)s to login into Kimchi" +#~ msgstr "Geben Sie %(item)s an, um sich bei Kimchi anzumelden" + +#~ msgid "Unable to find %(item)s in datastore" +#~ msgstr "%(item)s konnten nicht im Datenspeicher gefunden werden" + +#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +#~ msgstr "" +#~ "Zeitlimit��berschreitung beim Ausf��hren des Befehls '%(cmd)s' nach %" +#~ "(seconds)s Sekunden" + +#~ msgid "Help" +#~ msgstr "Hilfe" + +#~ msgid "About" +#~ msgstr "Informationen" + +#~ msgid "Log out" +#~ msgstr "Abmelden" + +#~ msgid "Version:" +#~ msgstr "Version:" diff --git a/src/wok/plugins/kimchi/po/en_US.po b/src/wok/plugins/kimchi/po/en_US.po new file mode 100644 index 0000000..a5d0d44 --- /dev/null +++ b/src/wok/plugins/kimchi/po/en_US.po @@ -0,0 +1,2075 @@ +# English translations for kimchi package. +# Copyright (C) 2013 ORGANIZATION +# Adam Litke <agl@us.ibm.com>, 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2013-07-11 17:32-0400\n" +"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" +"Language-Team: English\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en_US\n" +"Generated-By: pygettext.py 1.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "" + +msgid "Unknown \"_cap\" specified" +msgstr "" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" + +msgid "An error occurred when probing image OS information." +msgstr "" + +msgid "No OS information found in given image." +msgstr "" + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" + +msgid "Remote ISO image is not supported by this server." +msgstr "" + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" + +msgid "Specify a template to create a virtual machine from" +msgstr "" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "" + +msgid "User name list must be an array" +msgstr "" + +msgid "User name must be a string" +msgstr "" + +msgid "Group name list must be an array" +msgstr "" + +msgid "Group name must be a string" +msgstr "" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "" + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "" + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "" + +msgid "The guest console password must be a string." +msgstr "" + +msgid "The life time for the guest console password must be a number." +msgstr "" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" + +msgid "\"name\" should be a device name string" +msgstr "" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" + +msgid "Template name must be a string" +msgstr "" + +msgid "Template icon must be a path to the image" +msgstr "" + +msgid "Template distribution must be a string" +msgstr "" + +msgid "Template distribution version must be a string" +msgstr "" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "" + +msgid "All networks for the template must be specified in a list." +msgstr "" + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "" + +msgid "Template base image must be a valid local image file" +msgstr "" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" + +msgid "Storage pool path must be a string" +msgstr "" + +msgid "Storage pool host must be a IP or hostname" +msgstr "" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" + +msgid "Storage pool devices parameter must be a list" +msgstr "" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" + +msgid "iSCSI target username must be a string" +msgstr "" + +msgid "iSCSI target password must be a string" +msgstr "" + +msgid "Specify name and type to create a storage pool" +msgstr "" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "" + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "" + +msgid "The SCSI host adapter name must be a string." +msgstr "" + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "" + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "" + +msgid "Storage volume name must be a string" +msgstr "" + +msgid "Storage volume allocation must be an integer number" +msgstr "" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" + +msgid "Storage volume requires a volume name" +msgstr "" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "" + +msgid "Storage volume capacity must be an integer number." +msgstr "" + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "" + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "" + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "" + +msgid "Network interface must be a string" +msgstr "" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "" + +msgid "Specify name and type to create a Network" +msgstr "" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "" + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "" + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "" + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "" + +msgid "Debug report tool not found in system" +msgstr "" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "" + +msgid "You should give a name for the debug report file." +msgstr "" + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "" + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "" + +msgid "Conflicting flag filters specified." +msgstr "" + +msgid "No packages marked for update" +msgstr "" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "" + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "" + +msgid "There is no compatible package manager for this system." +msgstr "" + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "" + +msgid "Unable to choose a virtual machine name" +msgstr "" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" + +msgid "Only CDROM path can be update." +msgstr "" + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "" + +msgid "Do not support IDE device hot plug" +msgstr "" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "" + +msgid "Specify path to update virtual machine disk" +msgstr "" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" + +msgid "Volume already in use by other virtual machine." +msgstr "" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "" + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" + +msgid "YUM Repository ID must be one word only string." +msgstr "" + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "" + +msgid "Distribution to DEB repository must be a string" +msgstr "" + +msgid "Components to DEB repository must be listed in a array" +msgstr "" + +msgid "Components to DEB repository must be a string" +msgstr "" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "" + +msgid "GPG check must be a boolean value." +msgstr "" + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "" + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "" + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "" + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "" + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "" + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "" + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "" + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "" + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "" + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "" + +msgid "YUM Repository ID already exists" +msgstr "" + +msgid "YUM Repository name must be a string" +msgstr "" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" + +msgid "The number of vCPUs is too large for this system." +msgstr "" + +msgid "Invalid vCPU/topology combination." +msgstr "" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "" + +msgid "ERROR CODE" +msgstr "" + +msgid "REASON" +msgstr "" + +msgid "STACK" +msgstr "" + +msgid "Go to Homepage" +msgstr "" + +msgid "Create a New Virtual Machine" +msgstr "" + +msgid "Virtual Machine Name" +msgstr "" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" + +msgid "Template" +msgstr "" + +msgid "Please create a template first." +msgstr "" + +msgid "Create a Template" +msgstr "" + +msgid "Please choose a template." +msgstr "" + +msgid "OS" +msgstr "" + +msgid "OS Version" +msgstr "" + +msgid "CPUS" +msgstr "" + +msgid "Memory" +msgstr "" + +msgid "Create" +msgstr "" + +msgid "Creating..." +msgstr "" + +msgid "Cancel" +msgstr "" + +msgid "Edit Guest" +msgstr "" + +msgid "General" +msgstr "" + +msgid "Storage" +msgstr "" + +msgid "Interface" +msgstr "" + +msgid "Permission" +msgstr "" + +msgid "Host PCI Device" +msgstr "" + +msgid "Snapshot" +msgstr "" + +msgid "Name" +msgstr "" + +msgid "CPUs" +msgstr "" + +msgid "Memory (MB)" +msgstr "" + +msgid "Icon" +msgstr "" + +msgid "Device" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Network" +msgstr "" + +msgid "Type" +msgstr "" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "" + +msgid "Selected system users and groups" +msgstr "" + +msgid "User" +msgstr "" + +msgid "All" +msgstr "" + +msgid "To Add" +msgstr "" + +msgid "Added" +msgstr "" + +msgid "filter" +msgstr "" + +msgid "Product" +msgstr "" + +msgid "Vendor" +msgstr "" + +msgid "Created" +msgstr "" + +msgid "Save" +msgstr "" + +msgid "Replace" +msgstr "" + +msgid "Detach" +msgstr "" + +msgid "revert" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "" + +msgid "Actions" +msgstr "" + +msgid "Connect" +msgstr "" + +msgid "Clone" +msgstr "" + +msgid "Edit" +msgstr "" + +msgid "Shut Down" +msgstr "" + +msgid "Delete" +msgstr "" + +msgid "CPU" +msgstr "" + +msgid "Disk I/O" +msgstr "" + +msgid "Network I/O" +msgstr "" + +msgid "Livetile" +msgstr "" + +msgid "No guests found." +msgstr "" + +msgid "Add a Storage Device to VM" +msgstr "" + +msgid "Device Type" +msgstr "" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "" + +msgid "Storage Pool" +msgstr "" + +msgid "Storage pool which volume located in" +msgstr "" + +msgid "Storage Volume" +msgstr "" + +msgid "Storage volume to be attached" +msgstr "" + +msgid "File Path" +msgstr "" + +msgid "The ISO file path in the server for CDROM." +msgstr "" + +msgid "Attach" +msgstr "" + +msgid "Shut down" +msgstr "" + +msgid "Restart" +msgstr "" + +msgid "Basic Information" +msgstr "" + +msgid "OS Distro" +msgstr "" + +msgid "OS Code Name" +msgstr "" + +msgid "Processor" +msgstr "" + +msgid "CPU(s)" +msgstr "" + +msgid "System Statistics" +msgstr "" + +msgid "Software Updates" +msgstr "" + +msgid "Update Progress" +msgstr "" + +msgid "Repositories" +msgstr "" + +msgid "Debug Reports" +msgstr "" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "" + +msgid "This field is required." +msgstr "" + +msgid "Log in" +msgstr "" + +msgid "Logging in..." +msgstr "" + +msgid "Host" +msgstr "" + +msgid "Guests" +msgstr "" + +msgid "Templates" +msgstr "" + +msgid "Failed to get application configuration" +msgstr "" + +msgid "This is not a valid Linux path" +msgstr "" + +msgid "This is not a valid URL." +msgstr "" + +msgid "No such data available." +msgstr "" + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "" + +msgid "OK" +msgstr "" + +msgid "Confirm" +msgstr "" + +msgid "Warning" +msgstr "" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "" + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "" + +msgid "Detailed message:" +msgstr "" + +msgid "No ISO found" +msgstr "" + +msgid "This is not a valid ISO file." +msgstr "" + +msgid "This may take a long time. Do you want to continue?" +msgstr "" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" + +msgid "Max:" +msgstr "" + +msgid "Utilization" +msgstr "" + +msgid "Available" +msgstr "" + +msgid "Read Rate" +msgstr "" + +msgid "Write Rate" +msgstr "" + +msgid "Received" +msgstr "" + +msgid "Sent" +msgstr "" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" + +msgid "ID" +msgstr "" + +msgid "Base URL" +msgstr "" + +msgid "Is Mirror" +msgstr "" + +msgid "URL Args" +msgstr "" + +msgid "Enabled" +msgstr "" + +msgid "GPG Check" +msgstr "" + +msgid "GPG Key" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Remove" +msgstr "" + +msgid "Enable" +msgstr "" + +msgid "Disable" +msgstr "" + +msgid "Package Name" +msgstr "" + +msgid "Version" +msgstr "" + +msgid "Architecture" +msgstr "" + +msgid "Repository" +msgstr "" + +msgid "Update All" +msgstr "" + +msgid "Updating..." +msgstr "" + +msgid "Failed to retrieve packages update information." +msgstr "" + +msgid "Failed to update package(s)." +msgstr "" + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" + +msgid "Generated Time" +msgstr "" + +msgid "Generate" +msgstr "" + +msgid "Generating..." +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Download" +msgstr "" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "" + +msgid "Pending..." +msgstr "" + +msgid "Report name is the same as the original one." +msgstr "" + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "" + +msgid "Power off Confirmation" +msgstr "" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" + +msgid "Reset Confirmation" +msgstr "" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" + +msgid "Shut Down Confirmation" +msgstr "" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "" + +msgid "Virtual Machine delete Confirmation" +msgstr "" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" + +msgid "Attaching..." +msgstr "" + +msgid "Replacing..." +msgstr "" + +msgid "Successfully attached!" +msgstr "" + +msgid "Successfully replaced!" +msgstr "" + +msgid "Successfully detached!" +msgstr "" + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" + +msgid "interface:" +msgstr "" + +msgid "address:" +msgstr "" + +msgid "link_type:" +msgstr "" + +msgid "block:" +msgstr "" + +msgid "drive_type:" +msgstr "" + +msgid "model:" +msgstr "" + +msgid "Affected devices:" +msgstr "" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "" + +msgid "unavailable" +msgstr "" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "" + +msgid "Create a network" +msgstr "" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "" + +msgid "This storage pool is empty." +msgstr "" + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "" + +msgid "SCSI Fibre Channel" +msgstr "" + +msgid "No SCSI adapters found." +msgstr "" + +msgid "Loading iSCSI targets..." +msgstr "" + +msgid "No iSCSI found. Please input one." +msgstr "" + +msgid "Failed to load iSCSI targets." +msgstr "" + +msgid "The storage pool name can not be blank." +msgstr "" + +msgid "The storage pool path can not be blank." +msgstr "" + +msgid "NFS server mount path can not be blank." +msgstr "" + +msgid "Invalid NFS mount path." +msgstr "" + +msgid "No logical device selected." +msgstr "" + +msgid "The iSCSI target can not be blank." +msgstr "" + +msgid "Server name can not be blank." +msgstr "" + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "" + +msgid "Looking for available partitions ..." +msgstr "" + +msgid "No available partitions found." +msgstr "" + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" + +msgid "Unable to retrieve partitions information." +msgstr "" + +msgid "In progress..." +msgstr "" + +msgid "Failed!" +msgstr "" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" + +msgid "Disk pool or volume cannot be blank." +msgstr "" + +msgid "Filter" +msgstr "" + +msgid "Network Name" +msgstr "" + +msgid "State" +msgstr "" + +msgid "Network Type" +msgstr "" + +msgid "Address Space" +msgstr "" + +msgid "Name should not contain '/' and '\"'." +msgstr "" + +msgid "Isolated: no external network connection" +msgstr "" + +msgid "NAT: outbound physical network connection only" +msgstr "" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "" + +msgid "(No interfaces found)" +msgstr "" + +msgid "Destination" +msgstr "" + +msgid "Enable VLAN" +msgstr "" + +msgid "VLAN ID" +msgstr "" + +msgid "Stop" +msgstr "" + +msgid "Generate a New Debug Report" +msgstr "" + +msgid "Report Name" +msgstr "" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" + +msgid "Rename a Debug Report" +msgstr "" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" + +msgid "Submit" +msgstr "" + +msgid "Add a Repository" +msgstr "" + +msgid "Identifier" +msgstr "" + +msgid "Single word, unique identifier for the repository." +msgstr "" + +msgid "Textual name for the repository." +msgstr "" + +msgid "URL" +msgstr "" + +msgid "Required Field" +msgstr "" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "" + +msgid "Repository is a mirror" +msgstr "" + +msgid "Distribution" +msgstr "" + +msgid "Distribution of the DEB repository." +msgstr "" + +msgid "Components" +msgstr "" + +msgid "List of components in DEB repository." +msgstr "" + +msgid "Edit Repository" +msgstr "" + +msgid "Mirror List URL" +msgstr "" + +msgid "Yes" +msgstr "" + +msgid "No" +msgstr "" + +msgid "Capacity" +msgstr "" + +msgid "Allocated" +msgstr "" + +msgid "Location" +msgstr "" + +msgid "Device path" +msgstr "" + +msgid "active" +msgstr "" + +msgid "inactive" +msgstr "" + +msgid "Deactivate" +msgstr "" + +msgid "Activate" +msgstr "" + +msgid "Add Volume" +msgstr "" + +msgid "Extend" +msgstr "" + +msgid "Undefine" +msgstr "" + +msgid "Format" +msgstr "" + +msgid "Allocation" +msgstr "" + +msgid "Define a New Storage Pool" +msgstr "" + +msgid "Storage Pool Name" +msgstr "" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "" + +msgid "Storage Pool Type" +msgstr "" + +msgid "Storage Path" +msgstr "" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "" + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "" + +msgid "NFS Server IP" +msgstr "" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" + +msgid "NFS Path" +msgstr "" + +msgid "The NFS exported path on NFS server." +msgstr "" + +msgid "iSCSI Server" +msgstr "" + +msgid "Server" +msgstr "" + +msgid "Port" +msgstr "" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "" + +msgid "Target" +msgstr "" + +msgid "The iSCSI target on iSCSI server" +msgstr "" + +msgid "Add iSCSI Authentication" +msgstr "" + +msgid "iSCSI Authentication" +msgstr "" + +msgid "User Name" +msgstr "" + +msgid "Password" +msgstr "" + +msgid "SCSI Adapter" +msgstr "" + +msgid "Please, wait..." +msgstr "" + +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + +msgid "Add Template" +msgstr "" + +msgid "Where is the source media for this template? " +msgstr "" + +msgid "Local ISO Image" +msgstr "" + +msgid "Local Image File" +msgstr "" + +msgid "Remote ISO Image" +msgstr "" + +msgid "Search ISOs" +msgstr "" + +msgid "The following ISOs are available:" +msgstr "" + +msgid "OS: " +msgstr "" + +msgid "Version: " +msgstr "" + +msgid "Size: " +msgstr "" + +msgid "Search more ISOs" +msgstr "" + +msgid "Create Templates from Selected ISO" +msgstr "" + +msgid "I want to use a specific ISO file" +msgstr "" + +msgid "Loading default remote ISOs ..." +msgstr "" + +msgid "Arch: " +msgstr "" + +msgid "I want to use a custom URL" +msgstr "" + +msgid "Edit Template" +msgstr "" + +msgid "CDROM" +msgstr "" + +msgid "Image File" +msgstr "" + +msgid "Graphics" +msgstr "" + +msgid "Disk(GB)" +msgstr "" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "" + +msgid "Manually set CPU topology" +msgstr "" + +msgid "Cores" +msgstr "" + +msgid "Threads" +msgstr "" + +msgid "No templates found." +msgstr "" diff --git a/src/wok/plugins/kimchi/po/es_ES.po b/src/wok/plugins/kimchi/po/es_ES.po new file mode 100644 index 0000000..d71e621 --- /dev/null +++ b/src/wok/plugins/kimchi/po/es_ES.po @@ -0,0 +1,2305 @@ +# English translations for kimchi package. +# Copyright (C) 2013 ORGANIZATION +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2013-07-11 17:32-0400\n" +"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" +"Language-Team: English\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es_ES\n" +"Generated-By: pygettext.py 1.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "" + +msgid "Unknown \"_cap\" specified" +msgstr "" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "" +"Se ha producido un error al obtener dispositivos de bloque. Detalles: %(err)s" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" +"Se ha producido un error al obtener informaci��n de dispositivo de bloque " +"para %(device)s." + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "No se puede encontrar el archivo distro: %(filename)s" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "" +"No se puede analizar el archivo distro: %(filename)s. Aseg��rese de que es un " +"archivo JSON." + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" +"No se puede iniciar la sesi��n en %(portal)s del destino de host iSCSI. " +"Detalles: %(err)s" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "" +"No se puede iniciar la sesi��n en el destino %(target)s del %(host)s host de " +"iSCSI" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "El archivo ISO %(filename)s no es arrancable" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" +"El archivo ISO %(filename)s no tiene un registro de arranque de El Torito " +"v��lido" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "Entrada de validaci��n de El Torito no v��lida en ISO %(filename)s" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "Indicador de arranque de El Torito no v��lido en ISO %(filename)s" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" +"Tipo de volumen inesperado para el volumen primario en ISO %(filename)s" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" +"Formato incorrecto mientras se le��a el descriptor de volumen en ISO %" +"(filename)s" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" +"El hipervisor no tiene permiso para utilizar este ISO %(filename)s. " +"Considere moverlo a /var/lib/libvirt, o establezca el permiso de b��squeda en " +"listas de control de accesos de archivo para el usuario '%(user)s' si es " +"posible, o a��ada el '%(user)s' al grupo de v��as de acceso ISO, o (no " +"recomendado) 'chmod -R o+x 'path_to_iso'.Detalles: %(err)s" + +msgid "An error occurred when probing image OS information." +msgstr "" + +msgid "No OS information found in given image." +msgstr "" + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "La m��quina virtual %(name)s ya existe" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "La m��quina virtual %(name)s no existe" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" +"No se puede recuperar la captura de pantalla para la m��quina virtual " +"detenida %(name)s" + +msgid "Remote ISO image is not supported by this server." +msgstr "La imagen ISO remota no est�� soportada por este servidor." + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "No se puede crear la m��quina virtual %(name)s. Detalles: %(err)s" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "No se puede crear la m��quina virtual %(name)s. Detalles: %(err)s" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "No se puede recuperar la m��quina virtual %(name)s. Detalles: %(err)s" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" +"La direcci��n de gr��ficos en que hay que estar a la escucha debe ser IPv4 o " +"IPv6" + +msgid "Specify a template to create a virtual machine from" +msgstr "" +"Especifique una plantilla a partir de la que se crear�� una m��quina virtual" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "No se puede iniciar la m��quina virtual %(name)s. Detalles: %(err)s" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "No se puede detener la m��quina virtual %(name)s. Detalles: %(err)s" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "No se puede suprimir la m��quina virtual %(name)s. Detalles: %(err)s" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "No se puede redenominar la m��quina virtual %(name)s. Detalles: %(err)s" + +msgid "User name list must be an array" +msgstr "" + +msgid "User name must be a string" +msgstr "El nombre de red debe ser una serie" + +msgid "Group name list must be an array" +msgstr "" + +msgid "Group name must be a string" +msgstr "El nombre de red debe ser una serie" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "El usuario '%(users)s' no existe." + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "El usuario '%(groups)s' no existe." + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "No se puede detener la m��quina virtual %(name)s. Detalles: %(err)s" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "No se puede iniciar la m��quina virtual %(name)s. Detalles: %(err)s" + +msgid "The guest console password must be a string." +msgstr "" + +msgid "The life time for the guest console password must be a number." +msgstr "" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" + +msgid "\"name\" should be a device name string" +msgstr "" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "La interfaz %(iface)s no existe en la m��quina virtual %(name)s" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" +"La red %(network)s especificada para la m��quina virtual %(name)s no existe" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "El tipo de interfaces de m��quina virtual soportado es de red solamente" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" +"El nombre de red para la interfaz de m��quina virtual debe ser una serie" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" +"Especificada tarjeta de modelo de red no v��lida para la interfaz de m��quina " +"virtual" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" +"Especifique el tipo y la red para a��adir una interfaz de m��quina virtual " +"nueva" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "La plantilla %(name)s ya existe" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" +"La red '%(network)s' especificada para la plantilla %(template)s no existe" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "" +"La agrupaci��n de almacenamiento %(pool)s especificada para la plantilla %" +"(template)s no existe" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "" +"La agrupaci��n de almacenamiento %(pool)s especificada para la plantilla %" +"(template)s no est�� activa" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "Par��metro no v��lido '%(param)s' especificado para CDROM." + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" +"La red %(network)s especificada para la plantilla %(template)s no est�� activa" + +msgid "Template name must be a string" +msgstr "El nombre de plantilla debe ser una serie" + +msgid "Template icon must be a path to the image" +msgstr "El icono de plantilla debe ser una v��a de acceso a la imagen" + +msgid "Template distribution must be a string" +msgstr "La distribuci��n de plantilla debe ser una serie" + +msgid "Template distribution version must be a string" +msgstr "La versi��n de distribuci��n de plantilla debe ser una serie" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "El n��mero de CPUs debe ser un entero" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "La cantidad de memoria (MB) debe ser un entero mayor que 512" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "El CDROM de plantilla debe ser un archivo ISO local o remoto" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "" +"URI de agrupaci��n de almacenamiento no v��lido %(value)s especificado para la " +"plantilla" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "Especifique una imagen de ISO como CDROM para crear una plantilla" + +msgid "All networks for the template must be specified in a list." +msgstr "Todas las redes para la plantilla deben especificarse en una lista." + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "No se puede crear la plantilla debido a un error: %(err)s" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "No se puede suprimir la plantilla debido a un error: %(err)s" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "" + +msgid "Template base image must be a valid local image file" +msgstr "El CDROM de plantilla debe ser un archivo ISO local o remoto" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "La agrupaci��n de almacenamiento %(name)s ya existe" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "La agrupaci��n de almacenamiento %(name)s no existe" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "" +"Especifique %(item)s para poder crear la agrupaci��n de almacenamiento %(name)" +"s" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "No se puede suprimir la agrupaci��n de almacenamiento activa %(name)s" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "No se pueden listar agrupaciones de almacenamiento. Detalles: %(err)s" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "" +"No se puede crear la agrupaci��n de almacenamiento %(name)s. Detalles: %(err)s" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "" +"No se puede obtener el n��mero de vol��menes de almacenamiento en la " +"agrupaci��n de almacenamiento %(name)s. Detalles: %(err)s" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "" +"No se puede activar la agrupaci��n de almacenamiento %(name)s. Detalles: %" +"(err)s" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "" +"No se puede desactivar la agrupaci��n de almacenamiento %(name)s. Detalles: %" +"(err)s" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "" +"No se puede suprimir la agrupaci��n de almacenamiento %(name)s. Detalles: %" +"(err)s" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" +"No se puede crear la agrupaci��n de NFS ya que la v��a de acceso de " +"exportaci��n %(path)s podr��a bloquearse durante el montaje" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" +"No se puede crear la agrupaci��n de NFS ya que el montaje de la v��a de acceso " +"de exportaci��n %(path)s ha fallado" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "Tipo de agrupaci��n de almacenamiento no soportado: %(type)s" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" + +msgid "Storage pool path must be a string" +msgstr "La v��a de acceso de la agrupaci��n de almacenamiento debe ser una serie" + +msgid "Storage pool host must be a IP or hostname" +msgstr "" +"El host de la agrupaci��n de almacenamiento debe ser un IP o nombre de host" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" + +msgid "Storage pool devices parameter must be a list" +msgstr "" +"El par��metro de los dispositivos de agrupaci��n de almacenamiento debe ser " +"una lista" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "El IQN destino de una agrupaci��n de iSCSI debe ser una serie" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" +"El puerto de un servidor de almacenamiento remoto debe ser un entero entre 1 " +"y 65535" + +msgid "iSCSI target username must be a string" +msgstr "" + +msgid "iSCSI target password must be a string" +msgstr "" + +msgid "Specify name and type to create a storage pool" +msgstr "" +"Especifique el nombre y el tipo para crear una agrupaci��n de almacenamiento" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "" +"%(disk)s no es un disco/partici��n. No se ha podido a��adir a la agrupaci��n %" +"(pool)s." + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "" +"Los discos de par��metro s��lo pueden actualizarse para la agrupaci��n de " +"almacenamiento l��gico." + +msgid "The SCSI host adapter name must be a string." +msgstr "El nombre del adaptador de host SCSI debe ser una serie." + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "" +"La agrupaci��n de almacenamiento kimchi_isos est�� reservada para uso interno" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"No se puede activar la agrupaci��n de almacenamiento NFS %(name)s. El " +"servidor NFS %(server)s est�� fuera de alcance." + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"No se puede desactivar la agrupaci��n de almacenamiento NFS %(name)s. El " +"servidor NFS %(server)s est�� fuera de alcance." + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "" +"No se puede desactivar la agrupaci��n %(name)s ya que est�� asociada con " +"algunas plantillas" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "" +"No se puede suprimir la agrupaci��n %(name)s ya que est�� asociada con algunas " +"plantillas" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "" +"Un grupo de vol��menes denominado '%(name)s' ya existe. Elija otro nombre " +"para crear la agrupaci��n l��gica." + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "" +"No se puede actualizar la base de datos con la informaci��n de exploraci��n " +"profunda debido a un error: %(err)s" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "El volumen de almacenamiento %(name)s ya existe" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "" +"El volumen de almacenamiento %(name)s no existe en la agrupaci��n de " +"almacenamiento %(pool)s" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "" +"Especifique %(item)s para poder crear el volumen de almacenamiento %(volume)s" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "" +"No se pueden listar los vol��menes de almacenamiento porque la agrupaci��n de " +"almacenamiento %(pool)s no est�� activa" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "" +"No se puede crear el volumen de almacenamiento %(name)s en la agrupaci��n de " +"almacenamiento %(pool)s. Detalles: %(err)s" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "" +"No se pueden listar vol��menes de almacenamiento en la agrupaci��n de " +"almacenamiento %(pool)s. Detalles: %(err)s" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "" +"No se pueden borrar los vol��menes de almacenamiento %(name)s. Detalles: %" +"(err)s" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "" +"No se puede suprimir el volumen de almacenamiento %(name)s. Detalles: %(err)s" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "" +"No se puede redimensionar el volumen de almacenamiento %(name)s. Detalles: %" +"(err)s" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "" +"El tipo de almacenamiento %(type)s no da soporte a crear y suprimir vol��menes" + +msgid "Storage volume name must be a string" +msgstr "El nombre de volumen de almacenamiento debe ser una serie" + +msgid "Storage volume allocation must be an integer number" +msgstr "La asignaci��n de volumen de almacenamiento debe ser un n��mero entero" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" + +msgid "Storage volume requires a volume name" +msgstr "El volumen de almacenamiento requiere un nombre de volumen" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "" +"No se puede actualizar la base de datos con la informaci��n de volumen de " +"almacenamiento debido a un error: %(err)s" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "" + +msgid "Storage volume capacity must be an integer number." +msgstr "" + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "" + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "La interfaz %(name)s no existe" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "La red %(name)s ya existe" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "La red %(name)s no existe" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" +"La subred %(subnet)s especificada para la red %(network)s no es v��lida." + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "Especifique una interfaz de red para crear una red puenteada %(name)s" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "No se puede suprimir la red activa %(name)s" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" +"La interfaz %(iface)s especificada para la red %(network)s ya est�� en uso" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "La interfaz debe ser dispositivo de puente, enlazado o NIC simple." + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "No se puede crear la red %(name)s. Detalles: %(err)s" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "No se puede encontrar una direcci��n IP libre para la red '%(name)s'" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "La interfaz %(iface)s ya existe" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "Los tipos de red soportados son aislada, NAT y puente" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "" +"La subred de red debe ser una serie con direcci��n IP y prefijo o m��scara de " +"red" + +msgid "Network interface must be a string" +msgstr "La interfaz de red debe ser una serie" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "El ID de VLAN de red debe ser un entero entre 1 y 4094" + +msgid "Specify name and type to create a Network" +msgstr "Especifique el nombre y el tipo para crear una red" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" +"No se puede suprimir la red %(name)s. Hay algunas m��quinas virtuales %(vms)s " +"y/o plantillas enlazadas a esta red." + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" +"No se puede desactivar la red %(name)s. Hay algunas m��quinas virtuales %(vms)" +"s y/o plantillas enlazadas a esta red." + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "" +"El dispositivo de puente %(name)s no puede ser el dispositivo de conexi��n " +"troncal de una VLAN." + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "No se puede activar la interfaz %(iface)s: %(err)s." + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "" +"No se puede activar la interfaz %(iface)s. Compruebe el estado del enlace " +"f��sico." + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "El informe de depuraci��n %(name)s no existe" + +msgid "Debug report tool not found in system" +msgstr "Herramienta de informes de depuraci��n no encontrada en el sistema" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "" +"No se puede crear el informe de depuraci��n %(name)s. Detalles: %(err)s." + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "" +"No se puede generar el informe de depuraci��n %(name)s. Detalles: %(err)s" + +msgid "You should give a name for the debug report file." +msgstr "" + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "" +"Un grupo de vol��menes denominado '%(name)s' ya existe. Elija otro nombre " +"para crear la agrupaci��n l��gica." + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "Kimchi no utilizaba el servidor de almacenamiento %(server)s" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "Distro '%(name)s' no existe" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "La partici��n %(name)s no existe en el host" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" +"No se puede concluir la m��quina host ya que hay m��quinas virtuales en " +"ejecuci��n" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" +"No se puede rearrancar la m��quina host ya que hay m��quinas virtuales en " +"ejecuci��n" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "No se ha encontrado el dispositivo de nodo '%(name)s'" + +msgid "Conflicting flag filters specified." +msgstr "" + +msgid "No packages marked for update" +msgstr "No hay paquetes marcados para su actualizaci��n" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "El paquete %(name)s no est�� marcado para su actualizaci��n." + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "" +"Se ha producido un error al obtener paquetes marcados para su actualizaci��n. " +"Detalles: %(err)s" + +msgid "There is no compatible package manager for this system." +msgstr "No hay ning��n gestor de paquetes compatible para este sistema." + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "URI %(uri)s no v��lido" + +msgid "Unable to choose a virtual machine name" +msgstr "" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "Tipo de almacenamiento no v��lido. Tipos soportados: 'cdrom'" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" + +msgid "Only CDROM path can be update." +msgstr "" + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "" +"Se ha producido un error al crear el nuevo dispositivo de almacenamiento: %" +"(error)s" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "" +"Se ha producido un error al actualizar el dispositivo de almacenamiento: %" +"(error)s" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "" +"Se ha producido un error al eliminar el dispositivo de almacenamiento: %" +"(error)s" + +msgid "Do not support IDE device hot plug" +msgstr "" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "" +"Especifique el tipo y la v��a de acceso para a��adir un disco de m��quina " +"virtual nuevo" + +msgid "Specify path to update virtual machine disk" +msgstr "" +"Especifique la v��a de acceso para actualizar el disco de m��quina virtual" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" + +msgid "Volume already in use by other virtual machine." +msgstr "" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "" +"Especifique el tipo y la v��a de acceso para a��adir un disco de m��quina " +"virtual nuevo" + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" + +msgid "YUM Repository ID must be one word only string." +msgstr "El ID de repositorio YUM debe ser una serie de una sola palabra." + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "El URL de repositorio debe ser http://, ftp:// o archivo:// URL." + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "" +"La configuraci��n de repositorio es un diccionario con valores espec��ficos " +"seg��n el tipo de repositorio." + +msgid "Distribution to DEB repository must be a string" +msgstr "El repositorio de Distribuci��n a DEB debe ser una serie" + +msgid "Components to DEB repository must be listed in a array" +msgstr "El repositorio de Componentes a DEB debe estar listado en una matriz" + +msgid "Components to DEB repository must be a string" +msgstr "El repositorio de Componentes a DEB debe ser una serie" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "El nombre del repositorio YUM debe ser una serie." + +msgid "GPG check must be a boolean value." +msgstr "La comprobaci��n de GPG debe ser un valor booleano." + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "La clave GPG debe ser un URL que apunta al archivo blindado por ASCII." + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "No se ha podido actualizar el repositorio %(repo_id)s." + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "El repositorio %(repo_id)s no existe." + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "" +"La herramienta de gesti��n de repositorio no se ha reconocido para su sistema." + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "El repositorio %(repo_id)s ya est�� habilitado." + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "El repositorio %(repo_id)s ya est�� inhabilitado." + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "No se ha podido eliminar el repositorio %(repo_id)s." + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "" +"No se ha podido grabar el archivo de configuraci��n del repositorio %" +"(repo_file)s" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "" +"Especifique la distribuci��n del repositorio para crear un repositorio de DEB." + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "No se ha podido habilitar el repositorio %(repo_id)s." + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "No se ha podido inhabilitar el repositorio %(repo_id)s." + +msgid "YUM Repository ID already exists" +msgstr "El ID de repositorio de YUM ya existe" + +msgid "YUM Repository name must be a string" +msgstr "El nombre del repositorio de YUM debe ser una serie" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "No se pueden listar repositorios. Detalles: '%(err)s'" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "No se puede recuperar informaci��n del repositorio. Detalles: '%(err)s'" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "No se puede a��adir el repositorio. Detalles: '%(err)s'" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "No se puede eliminar el repositorio. Detalles: '%(err)s'" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" + +msgid "The number of vCPUs is too large for this system." +msgstr "" + +msgid "Invalid vCPU/topology combination." +msgstr "" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "" + +msgid "ERROR CODE" +msgstr "C��DIGO DE ERROR" + +msgid "REASON" +msgstr "RAZ��N" + +msgid "STACK" +msgstr "PILA" + +msgid "Go to Homepage" +msgstr "Ir a la p��gina inicial" + +msgid "Create a New Virtual Machine" +msgstr "Crear una nueva m��quina virtual" + +msgid "Virtual Machine Name" +msgstr "Nombre de m��quina virtual" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" +"El nombre que se utiliza para identificar la m��quina virtual. Si se omite, " +"se elegir�� un nombre bas��ndose en la plantilla utilizada." + +msgid "Template" +msgstr "Plantilla" + +msgid "Please create a template first." +msgstr "Cree una plantilla primero." + +msgid "Create a Template" +msgstr "Crear una plantilla" + +msgid "Please choose a template." +msgstr "Elija una plantilla." + +msgid "OS" +msgstr "SO" + +msgid "OS Version" +msgstr "Versi��n del SO" + +msgid "CPUS" +msgstr "CPUS" + +msgid "Memory" +msgstr "Memoria" + +msgid "Create" +msgstr "Crear" + +msgid "Creating..." +msgstr "" + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Edit Guest" +msgstr "Editar invitado" + +msgid "General" +msgstr "General" + +msgid "Storage" +msgstr "Almacenamiento" + +msgid "Interface" +msgstr "Interfaz" + +msgid "Permission" +msgstr "Versi��n" + +msgid "Host PCI Device" +msgstr "" + +msgid "Snapshot" +msgstr "" + +msgid "Name" +msgstr "Nombre" + +msgid "CPUs" +msgstr "CPUs" + +msgid "Memory (MB)" +msgstr "Memoria" + +msgid "Icon" +msgstr "Icono" + +msgid "Device" +msgstr "Nombre de dispositivo" + +msgid "Path" +msgstr "V��a de acceso NFS" + +msgid "Network" +msgstr "Red" + +msgid "Type" +msgstr "Tipo" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "" + +msgid "Selected system users and groups" +msgstr "" + +msgid "User" +msgstr "" + +msgid "All" +msgstr "Todo" + +msgid "To Add" +msgstr "" + +msgid "Added" +msgstr "" + +msgid "filter" +msgstr "" + +msgid "Product" +msgstr "" + +msgid "Vendor" +msgstr "Proveedor" + +msgid "Created" +msgstr "" + +msgid "Save" +msgstr "Guardar" + +msgid "Replace" +msgstr "Sustituir" + +msgid "Detach" +msgstr "Desconectar" + +msgid "revert" +msgstr "" + +msgid "Start" +msgstr "Iniciar" + +msgid "Reset" +msgstr "Restablecer" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "" + +msgid "Actions" +msgstr "Acciones" + +msgid "Connect" +msgstr "Conectar" + +msgid "Clone" +msgstr "" + +msgid "Edit" +msgstr "Editar" + +msgid "Shut Down" +msgstr "Concluir" + +msgid "Delete" +msgstr "Suprimir" + +msgid "CPU" +msgstr "CPU" + +msgid "Disk I/O" +msgstr "E/S de disco" + +msgid "Network I/O" +msgstr "E/S de red" + +msgid "Livetile" +msgstr "Livetile" + +msgid "No guests found." +msgstr "No se ha encontrado invitados." + +msgid "Add a Storage Device to VM" +msgstr "A��adir un dispositivo de almacenamiento a VM" + +msgid "Device Type" +msgstr "Tipo de dispositivo" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "El tipo de dispositivo. Actualmente s��lo est�� soportado \"cdrom\"." + +msgid "Storage Pool" +msgstr "Agrupaci��n de almacenamiento" + +msgid "Storage pool which volume located in" +msgstr "La v��a de acceso de la agrupaci��n de almacenamiento debe ser una serie" + +msgid "Storage Volume" +msgstr "Nombre de agrupaci��n de almacenamiento" + +msgid "Storage volume to be attached" +msgstr "El nombre de volumen de almacenamiento debe ser una serie" + +msgid "File Path" +msgstr "V��a de acceso de archivo" + +msgid "The ISO file path in the server for CDROM." +msgstr "La v��a de acceso del archivo ISO en el servidor para el CDROM." + +msgid "Attach" +msgstr "Conectar" + +msgid "Shut down" +msgstr "Concluir" + +msgid "Restart" +msgstr "Reiniciar" + +msgid "Basic Information" +msgstr "Informaci��n b��sica" + +msgid "OS Distro" +msgstr "Distro de SO" + +msgid "OS Code Name" +msgstr "Nombre de c��digo de SO" + +msgid "Processor" +msgstr "Procesador" + +msgid "CPU(s)" +msgstr "" + +msgid "System Statistics" +msgstr "Estad��sticas del sistema" + +msgid "Software Updates" +msgstr "Actualizaciones de software" + +msgid "Update Progress" +msgstr "Actualizar progreso" + +msgid "Repositories" +msgstr "Repositorios" + +msgid "Debug Reports" +msgstr "Informes de depuraci��n" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "" +"El nombre de usuario o contrase��a que ha especificado es incorrecto. Por " +"favor, vuelva a intentarlo." + +msgid "This field is required." +msgstr "Este campo es obligatorio." + +msgid "Log in" +msgstr "Iniciar sesi��n" + +msgid "Logging in..." +msgstr "Iniciando sesi��n..." + +msgid "Host" +msgstr "Host" + +msgid "Guests" +msgstr "Invitados" + +msgid "Templates" +msgstr "Plantillas" + +msgid "Failed to get application configuration" +msgstr "No se ha podido obtener la configuraci��n de la aplicaci��n" + +msgid "This is not a valid Linux path" +msgstr "No es una v��a de acceso de Linux v��lida" + +msgid "This is not a valid URL." +msgstr "No es un URL v��lido." + +msgid "No such data available." +msgstr "No hay datos de ese tipo disponibles." + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" +"No se puede contactar con el sistema host, Verifique que el sistema host " +"est�� activo y que tiene conectividad de red con ��l. Respuesta de solicitud " +"HTTP %1. " + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "Confirmaci��n de supresi��n" + +msgid "OK" +msgstr "Aceptar" + +msgid "Confirm" +msgstr "Confirmar" + +msgid "Warning" +msgstr "Aviso" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "Cargando..." + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "Reintentar" + +msgid "Detailed message:" +msgstr "Mensaje detallado:" + +msgid "No ISO found" +msgstr "" + +msgid "This is not a valid ISO file." +msgstr "No es un archivo ISO v��lido." + +msgid "This may take a long time. Do you want to continue?" +msgstr "Tardar�� mucho tiempo. ��Desea continuar?" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "Esto suprimir�� permanentemente la plantilla. ��Desea continuar?" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" +"No se puede concluir el sistema ya que hay algunas m��quinas virtuales en " +"ejecuci��n." + +msgid "Max:" +msgstr "M��x.:" + +msgid "Utilization" +msgstr "Utilizaci��n" + +msgid "Available" +msgstr "Disponible" + +msgid "Read Rate" +msgstr "Velocidad de lectura" + +msgid "Write Rate" +msgstr "Velocidad de escritura" + +msgid "Received" +msgstr "Recibido" + +msgid "Sent" +msgstr "Enviado" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"Concluir o reiniciar el host har�� que se pierda el trabajo no guardado. " +"��Desea continuar para concluir/reiniciar?" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"El repositorio se eliminar�� de forma permanente y no se puede recuperar. " +"��Desea continuar?" + +msgid "ID" +msgstr "ID" + +msgid "Base URL" +msgstr "URL base" + +msgid "Is Mirror" +msgstr "Es duplicado" + +msgid "URL Args" +msgstr "Args de URL" + +msgid "Enabled" +msgstr "Habilitado" + +msgid "GPG Check" +msgstr "Comprobaci��n GPG" + +msgid "GPG Key" +msgstr "Clave GPG" + +msgid "Add" +msgstr "A��adir" + +msgid "Remove" +msgstr "Eliminar" + +msgid "Enable" +msgstr "Habilitar" + +msgid "Disable" +msgstr "Inhabilitar" + +msgid "Package Name" +msgstr "Nombre de paquete" + +msgid "Version" +msgstr "Versi��n" + +msgid "Architecture" +msgstr "Arquitectura" + +msgid "Repository" +msgstr "Repositorio" + +msgid "Update All" +msgstr "Actualizar todo" + +msgid "Updating..." +msgstr "Actualizando..." + +msgid "Failed to retrieve packages update information." +msgstr "" + +msgid "Failed to update package(s)." +msgstr "No se han podido actualizar paquetes." + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"El informe de depuraci��n se eliminar�� permanentemente y no se puede " +"recuperar. ��Desea continuar?" + +msgid "Generated Time" +msgstr "Tiempo generado" + +msgid "Generate" +msgstr "Generar" + +msgid "Generating..." +msgstr "Generando..." + +msgid "Rename" +msgstr "Redenominar" + +msgid "Download" +msgstr "Descargar" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "" +"El nombre de informe debe contener s��lo letras, d��gitos y/o gui��n ('-')." + +msgid "Pending..." +msgstr "Cargando..." + +msgid "Report name is the same as the original one." +msgstr "" + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "" +"Esto suprimir�� la m��quina virtual y sus discos virtuales. Esta operaci��n no " +"puede deshacerse. ��Desea continuar?" + +msgid "Power off Confirmation" +msgstr "Confirmaci��n de supresi��n" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" + +msgid "Reset Confirmation" +msgstr "Confirmaci��n de supresi��n" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" + +msgid "Shut Down Confirmation" +msgstr "Confirmaci��n de supresi��n" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "Esto suprimir�� permanentemente la plantilla. ��Desea continuar?" + +msgid "Virtual Machine delete Confirmation" +msgstr "" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" +"Este CDROM se desconectar�� de forma permanente pero puede volver a " +"conectarlo. ��Desea continuar para desconectarlo?" + +msgid "Attaching..." +msgstr "Conectando..." + +msgid "Replacing..." +msgstr "Sustituyendo..." + +msgid "Successfully attached!" +msgstr "��Conectado correctamente!" + +msgid "Successfully replaced!" +msgstr "��Sustituido correctamente!" + +msgid "Successfully detached!" +msgstr "��Desconectado correctamente!" + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" + +msgid "interface:" +msgstr "" + +msgid "address:" +msgstr "" + +msgid "link_type:" +msgstr "" + +msgid "block:" +msgstr "" + +msgid "drive_type:" +msgstr "" + +msgid "model:" +msgstr "" + +msgid "Affected devices:" +msgstr "" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "El ID de VLAN debe estar entre 1 y 4094." + +msgid "unavailable" +msgstr "no disponible" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "" +"Esta acci��n interrumpir�� la conectividad de red para cualquier m��quina " +"virtual que dependa de esta red." + +msgid "Create a network" +msgstr "Crear una red" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"Esta agrupaci��n de almacenamiento no es persistente. En lugar de desactivar, " +"esta acci��n la suprimir�� permanentemente. ��Desea continuar?" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "" +"Esto suprimir�� permanentemente la agrupaci��n de almacenamiento. ��Desea " +"continuar?" + +msgid "This storage pool is empty." +msgstr "Esta agrupaci��n de almacenamiento est�� vac��a." + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "" +"Dar�� formato al disco y se perder��n los datos que tenga en ��l. ��Est�� seguro " +"de que desea continuar? " + +msgid "SCSI Fibre Channel" +msgstr "Canal de fibra de SCSI" + +msgid "No SCSI adapters found." +msgstr "No se han encontrado adaptadores SCSI." + +msgid "Loading iSCSI targets..." +msgstr "" + +msgid "No iSCSI found. Please input one." +msgstr "" + +msgid "Failed to load iSCSI targets." +msgstr "" + +msgid "The storage pool name can not be blank." +msgstr "El nombre de la agrupaci��n de almacenamiento no puede estar en blanco." + +msgid "The storage pool path can not be blank." +msgstr "" +"La v��a de acceso de la agrupaci��n de almacenamiento no puede estar en blanco." + +msgid "NFS server mount path can not be blank." +msgstr "La v��a de acceso de montaje del servidor NFS no puede estar en blanco." + +msgid "Invalid NFS mount path." +msgstr "V��a de acceso de montaje de NFS no v��lida." + +msgid "No logical device selected." +msgstr "No se ha seleccionado ning��n dispositivo l��gico." + +msgid "The iSCSI target can not be blank." +msgstr "El destino iSCSI no puede estar en blanco." + +msgid "Server name can not be blank." +msgstr "El nombre de servidor no puede estar en blanco." + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "" + +msgid "Looking for available partitions ..." +msgstr "Buscando particiones disponibles..." + +msgid "No available partitions found." +msgstr "No se han encontrado particiones disponibles." + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"Esta agrupaci��n de almacenamiento no es persistente. En lugar de desactivar, " +"esta acci��n la suprimir�� permanentemente. ��Desea continuar?" + +msgid "Unable to retrieve partitions information." +msgstr "No se puede recuperar informaci��n del repositorio. Detalles: '%(err)s'" + +msgid "In progress..." +msgstr "" + +msgid "Failed!" +msgstr "" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" + +msgid "Disk pool or volume cannot be blank." +msgstr "El nombre de la agrupaci��n de almacenamiento no puede estar en blanco." + +msgid "Filter" +msgstr "" + +msgid "Network Name" +msgstr "Nombre de red" + +msgid "State" +msgstr "Estado" + +msgid "Network Type" +msgstr "Tipo de red" + +msgid "Address Space" +msgstr "Espacio de direcciones" + +msgid "Name should not contain '/' and '\"'." +msgstr "" +"Nombre de agrupaci��n de almacenamiento no v��lido. No debe contener '/'." + +msgid "Isolated: no external network connection" +msgstr "Aislado: no hay conexi��n de red f��sica" + +msgid "NAT: outbound physical network connection only" +msgstr "NAT: conexi��n de red f��sica saliente solamente" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "" +"Puenteado: Las m��quinas virtuales est��n conectadas a la red f��sica " +"directamente" + +msgid "(No interfaces found)" +msgstr "" + +msgid "Destination" +msgstr "Destino:" + +msgid "Enable VLAN" +msgstr "Habilitar VLAN:" + +msgid "VLAN ID" +msgstr "ID de VLAN:" + +msgid "Stop" +msgstr "Detener" + +msgid "Generate a New Debug Report" +msgstr "Generar un Informe de depuraci��n nuevo" + +msgid "Report Name" +msgstr "Nombre de informe" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" +"El nombre que se utiliza para identificar el informe. Si se omite, se " +"elegir�� un nombre bas��ndose en la hora actual. El nombre puede contener: " +"letras, d��gitos y gui��n (\"-\")." + +msgid "Rename a Debug Report" +msgstr "Generar un Informe de depuraci��n nuevo" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" +"El nombre que se utiliza para identificar el informe. Si se omite, se " +"elegir�� un nombre bas��ndose en la hora actual. El nombre puede contener: " +"letras, d��gitos y gui��n (\"-\")." + +msgid "Submit" +msgstr "" + +msgid "Add a Repository" +msgstr "A��adir un repositorio" + +msgid "Identifier" +msgstr "Identificador" + +msgid "Single word, unique identifier for the repository." +msgstr "Identificador exclusivo de una sola palabra para el repositorio." + +msgid "Textual name for the repository." +msgstr "Nombre textual para el repositorio." + +msgid "URL" +msgstr "URL" + +msgid "Required Field" +msgstr "Campo obligatorio" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "URL al repositorio. Los protocolos soportados son http, ftp y archivo." + +msgid "Repository is a mirror" +msgstr "El repositorio es un duplicado." + +msgid "Distribution" +msgstr "Distribuci��n" + +msgid "Distribution of the DEB repository." +msgstr "Distribuci��n del repositorio DEB." + +msgid "Components" +msgstr "Componentes" + +msgid "List of components in DEB repository." +msgstr "Lista de componentes en el repositorio DEB." + +msgid "Edit Repository" +msgstr "Editar repositorio" + +msgid "Mirror List URL" +msgstr "URL de lista duplicada" + +msgid "Yes" +msgstr "S��" + +msgid "No" +msgstr "No" + +msgid "Capacity" +msgstr "Capacidad" + +msgid "Allocated" +msgstr "Asignado" + +msgid "Location" +msgstr "Ubicaci��n" + +msgid "Device path" +msgstr "V��a de acceso del dispositivo" + +msgid "active" +msgstr "activo" + +msgid "inactive" +msgstr "inactivo" + +msgid "Deactivate" +msgstr "Desactivar" + +msgid "Activate" +msgstr "Activar" + +msgid "Add Volume" +msgstr "" + +msgid "Extend" +msgstr "" + +msgid "Undefine" +msgstr "No definir" + +msgid "Format" +msgstr "Formato:" + +msgid "Allocation" +msgstr "Asignado:" + +msgid "Define a New Storage Pool" +msgstr "Definir una agrupaci��n de almacenamiento nueva" + +msgid "Storage Pool Name" +msgstr "Nombre de agrupaci��n de almacenamiento" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "" +"El nombre que se utiliza para identificar las agrupaciones de almacenamiento " +"y no debe estar vac��o." + +msgid "Storage Pool Type" +msgstr "Tipo de agrupaci��n de almacenamiento" + +msgid "Storage Path" +msgstr "V��a de acceso de almacenamiento" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "" +"La v��a de acceso de la agrupaci��n de almacenamiento. Cada agrupaci��n de " +"almacenamiento debe tener una v��a de acceso exclusiva." + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "Kimchi intentar�� crear el directorio cuando no existe en el sistema." + +msgid "NFS Server IP" +msgstr "IP de Servidor NFS" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" +"IP o nombre de host de servidor NFS. Puede especificarse o elegirse del " +"historial." + +msgid "NFS Path" +msgstr "V��a de acceso NFS" + +msgid "The NFS exported path on NFS server." +msgstr "La v��a de acceso exportada de NFS en el servidor NFS." + +msgid "iSCSI Server" +msgstr "Servidor iSCSI" + +msgid "Server" +msgstr "Servidor" + +msgid "Port" +msgstr "Puerto" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "IP o nombre de host de servidor iSCSI. No debe estar vac��o." + +msgid "Target" +msgstr "Destino" + +msgid "The iSCSI target on iSCSI server" +msgstr "El destino iSCSI en el servidor iSCSI" + +msgid "Add iSCSI Authentication" +msgstr "A��adir Autenticaci��n iSCSI" + +msgid "iSCSI Authentication" +msgstr "Autenticaci��n iSCSI" + +msgid "User Name" +msgstr "Nombre de usuario" + +msgid "Password" +msgstr "Contrase��a" + +msgid "SCSI Adapter" +msgstr "Adaptador SCSI" + +msgid "Please, wait..." +msgstr "Por favor, espere..." + +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + +msgid "Add Template" +msgstr "A��adir plantilla" + +msgid "Where is the source media for this template? " +msgstr "��D��nde est�� el soporte de origen para esta plantilla?" + +msgid "Local ISO Image" +msgstr "Imagen ISO local" + +msgid "Local Image File" +msgstr "" + +msgid "Remote ISO Image" +msgstr "Imagen ISO remota" + +msgid "Search ISOs" +msgstr "Buscar ISOs" + +msgid "The following ISOs are available:" +msgstr "Las siguientes ISO est��n disponibles:" + +msgid "OS: " +msgstr "SO: " + +msgid "Version: " +msgstr "Versi��n: " + +msgid "Size: " +msgstr "Tama��o: " + +msgid "Search more ISOs" +msgstr "Buscar m��s ISO" + +msgid "Create Templates from Selected ISO" +msgstr "Crear plantillas a partir de ISO seleccionadas" + +msgid "I want to use a specific ISO file" +msgstr "Deseo utilizar un archivo ISO espec��fico" + +msgid "Loading default remote ISOs ..." +msgstr "Cargando ISO remotas predeterminadas ..." + +msgid "Arch: " +msgstr "Arch: " + +msgid "I want to use a custom URL" +msgstr "Deseo utilizar un URL personalizado" + +msgid "Edit Template" +msgstr "Editar plantilla" + +msgid "CDROM" +msgstr "CDROM" + +msgid "Image File" +msgstr "" + +msgid "Graphics" +msgstr "Gr��ficos" + +msgid "Disk(GB)" +msgstr "" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "N��mero de CPU" + +msgid "Manually set CPU topology" +msgstr "" + +msgid "Cores" +msgstr "" + +msgid "Threads" +msgstr "" + +msgid "No templates found." +msgstr "No se han encontrado plantillas." + +#~ msgid "Delete is not allowed for %(resource)s" +#~ msgstr "Suprimir no est�� permitido para %(resource)s" + +#~ msgid "%(resource)s does not implement update method" +#~ msgstr "%(resource)s no implementa m��todo de actualizaci��n" + +#~ msgid "Create is not allowed for %(resource)s" +#~ msgstr "Crear no est�� permitido para %(resource)s" + +#~ msgid "Unable to parse JSON request" +#~ msgstr "No se puede analizar la solicitud JSON" + +#~ msgid "This API only supports JSON" +#~ msgstr "Esta API s��lo da soporte a JSON" + +#~ msgid "Datastore is not initiated in the model object." +#~ msgstr "El almac��n de datos no se ha iniciado en el objeto de modelo." + +#~ msgid "Unable to start task due error: %(err)s" +#~ msgstr "No se puede iniciar la tarea debido a un error: %(err)s" + +#~ msgid "" +#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" +#~ msgstr "" +#~ "La autenticaci��n ha fallado para el usuario '%(username)s'. [C��digo de " +#~ "error: %(code)s]" + +#~ msgid "You are not authorized to access Kimchi" +#~ msgstr "No tiene autorizaci��n para acceder a Kimchi" + +#~ msgid "Specify %(item)s to login into Kimchi" +#~ msgstr "Especifique %(item)s para iniciar la sesi��n en Kimchi" + +#~ msgid "Unable to find %(item)s in datastore" +#~ msgstr "No se puede encontrar %(item)s en el almac��n de datos" + +#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +#~ msgstr "" +#~ "Tiempo de espera excedido al ejecutar el mandato '%(cmd)s' despu��s de %" +#~ "(seconds)s segundos" + +#~ msgid "Help" +#~ msgstr "Ayuda" + +#~ msgid "About" +#~ msgstr "Acerca de" + +#~ msgid "Log out" +#~ msgstr "Finalizar sesi��n" + +#~ msgid "Version:" +#~ msgstr "Versi��n:" diff --git a/src/wok/plugins/kimchi/po/fr_FR.po b/src/wok/plugins/kimchi/po/fr_FR.po new file mode 100644 index 0000000..b996e8a --- /dev/null +++ b/src/wok/plugins/kimchi/po/fr_FR.po @@ -0,0 +1,2338 @@ +# English translations for kimchi package. +# Copyright (C) 2013 ORGANIZATION +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2014-08-27 21:30+0000\n" +"Last-Translator: BobSynfig\n" +"Language-Team: French (http://www.transifex.com/projects/p/kimchi/language/" +"fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: fr_FR\n" +"Generated-By: pygettext.py 1.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "Param��tre inconnu %(value)s" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "" + +msgid "Unknown \"_cap\" specified" +msgstr "\"_cap\" sp��cifi��e inconnue" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "\"_passthrough\" doit ��tre \"true\" ou \"false\"" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "\"_passthrough_affected_by\" doit ��tre un nom de p��riph��rique" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "Erreur durant l'acc��s aux p��riph��riques de bloc. D��tails: %(err)s" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" +"Erreur durant l'obtention de l'information sur le p��riph��rique de bloc %" +"(device)s." + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "Impossible de trouver le fichier de distro: %(filename)s" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "" +"Impossible de parser le fichier de distro: %(filename)s. Veuillez vous " +"assurer qu'il s'agit d'un fichier JSON." + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" +"Impossible de se connecter �� l'h��te cible iSCSI %(portal)s. D��tails: %(err)s " + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "Impossible de se connecter �� l'h��te iSCSI %(host)s cible %(target)s" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "Impossible de trouver le fichier ISO %(filename)s" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "Le fichier ISO %(filename)s n'est pas bootable" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" +"Le fichier ISO %(filename)s n'a pas d'enregistrement de boot El Torito valide" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "Entr��e de validation El Torito invalide dans l'ISO %(filename)s" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "Indicateur de boot El Torito invalide dans l'ISO %(filename)s" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" +"Type de volume inattendu pour le volume primaire dans l'ISO %(filename)s" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" +"Mauvais format durant la lecture du descripteur de volume dans l'ISO %" +"(filename)s" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" +"L'hyperviseur n'a pas la permission d'utiliser cet ISO %(filename)s. " +"Veuillez consid��rer de le d��placer sous /var/lib/libvirt,, ou de d��finir la " +"permission de recherche sur les listes de contrpole d'acc��s fichier pour " +"l'utilisateur '%(user)s' si possible, ou ajouter le '%(user)s' au groupe de " +"chemins d'ISO, ou (non recommand��) 'chmod -R o+x 'chemin_vers_iso'.D��tails: " +"%(err)s" + +msgid "An error occurred when probing image OS information." +msgstr "" +"Une erreur est survenue lors de la d��tection de l'information d'OS de " +"l'image." + +msgid "No OS information found in given image." +msgstr "Aucune information d'OS trouv��e sur l'image donn��e." + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "Impossible de lire le fichier image %(filename)s" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" +"Le fichier image doit ��tre un fichier existant sur le syst��me. %(filename)s " +"n'est pas une donn��e valide." + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "La machine virtuelle %(name)s existe d��j��" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "La machine virtuelle %(name)s n'existe pas" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" +"Impossible de renommer la machine virtuelle %(name)s. Le nom %(new_name)s " +"est d��ja utilis�� ou la machine virtuelle n'est pas ��teinte." + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" +"Impossible de r��cup��rer une capture d'��cran pour la machine virtuelle " +"stopp��e %(name)s" + +msgid "Remote ISO image is not supported by this server." +msgstr "L'image ISO distante n'est pas support��e par le serveur." + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "Copie d'��cran non support��e par la machine virtuelle %(name)s" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "Impossible de cr��er la machine virtuelle %(name)s. D��tails: %(err)s" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Impossible de mettre �� jour la machine virtuelle %(name)s. D��tails: %(err)s" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Impossible de r��cup��rer la machine virtuelle %(name)s. D��tails: %(err)s" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "Impossible de se connecter �� la machine virtuelle ��teinte %(name)s." + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "L'adresse d'��coute du graphics doit ��tre IPv4 ou IPv6" + +msgid "Specify a template to create a virtual machine from" +msgstr "Sp��cifier un mod��le �� partir duquel cr��er une machine virtuelle" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "Impossible de d��marrer la machine virtuelle %(name)s. D��tails: %(err)s" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Impossible de mettre hors tension la machine virtuelle %(name)s. D��tails: %" +"(err)s" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Impossible de supprimer la machine virtuelle %(name)s. D��tails: %(err)s" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Impossible de r��initrialiser la machine virtuelle %(name)s. D��tails: %(err)s" + +msgid "User name list must be an array" +msgstr "" + +msgid "User name must be a string" +msgstr "Le nom d'utilisateur doit ��tre une cha��ne de caract��res" + +msgid "Group name list must be an array" +msgstr "" + +msgid "Group name must be a string" +msgstr "Le nom de groupe doit ��tre une cha��ne de caract��res" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "Le(s) utilisateur(s) '%(users)s' n'existe(nt) pas" + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "Le(s) groupe(s) '%(groups)s' n'existe(nt) pas" + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "Impossible d'��teindre la machine virtuelle %(name)s. D��tails: %(err)s" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Impossible d'acc��der aux metadata de la machine virtuelle %(name)s. D��tails: " +"%(err)s" + +msgid "The guest console password must be a string." +msgstr "Le mot de passe de console invit��e doit ��tre une cha��ne de caract��res." + +msgid "The life time for the guest console password must be a number." +msgstr "La dur��e de vie du mot de passe de console invit��e doit ��tre un nombre" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" +"La machine virtuelle %(vmid)s ne peut pas contenir le p��riph��rique h��te " +"directement assign�� %(dev_name)s." + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" +"The p��riph��rique h��te %(dev_name)s ne peut ��tre directement assign�� �� la " +"machine virtuelle" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" + +msgid "\"name\" should be a device name string" +msgstr "\"name\" doit ��tre un nom de p��riph��rique" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "L'interface %(iface)s n'existe pas dans la machine virtuelle %(name)s" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" +"Le r��seau %(network)s sp��cifi�� pour la machine virtuelle %(name)s n'existe " +"pas" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "" +"Le type d'interface de machine virtuelle support�� est r��seau uniquement" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" +"Le nom de r��seau pour l'interface de la machine virtuelle doit ��tre une " +"cha��ne de caract��res" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" +"Mod��le de carte r��seau sp��cifi�� invalide pour l'interface de machine " +"virtuelle" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" +"Sp��cifier le type et le r��seau �� ajouter �� la nouvelle interface de la " +"machine virtuelle" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "Le mod��le %(name)s existe d��j��" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" +"Le r��seau '%(network)s' sp��cifi�� pour le mod��le %(template)s n'existe pas" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "" +"Le pool de stockage sp��cifi�� %(pool)s pour le mod��le %(template)s n'existe " +"pas" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "" +"Le pool de stockage sp��cifi�� %(pool)s pour le mod��le %(template)s n'est pas " +"actif" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "Param��tres '%(param)s' sp��cifi�� invalide pour le CDROM" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" +"Le r��seau %(network)s sp��cifi�� pour le mod��le %(template)s n'est pas actif" + +msgid "Template name must be a string" +msgstr "Le mod��le de nom doit ��tre une cha��ne de caract��res" + +msgid "Template icon must be a path to the image" +msgstr "Le mod��le d'icone doit ��tre un chemin vers l'image" + +msgid "Template distribution must be a string" +msgstr "Le mod��le de distribution doit ��tre une cha��ne de caract��res" + +msgid "Template distribution version must be a string" +msgstr "" +"Le mod��le de version de distribution doit ��tre une cha��ne de caract��res" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "Le nombre de CPU doit ��tre un nombre entier sup��rieur �� 0" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "La quantit�� de m��moire (Mo) doit ��tre un nombre entier sup��rieur �� 512" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "Le CDROM mod��le doit ��tre un fichier ISO local ou distant" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "URI %(value)s du pool de stockage sp��cifi��e invalide pour le mod��le" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "" +"Sp��cifiez une image ISO comme CDROM ou une image de base pour cr��er un mod��le" + +msgid "All networks for the template must be specified in a list." +msgstr "Tous les r��seaux pour le mod��le doivent ��tre sp��cifi��s dans une liste" + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "Le volume %(volume)s n'est pas dans le pool de stockage %(pool)s" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "Impossible de cr��er le mod��le �� cause de l'erreur: %(err)s" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "Impossilbe de supprimer le mod��le �� cause de l'erreur: %(err)s" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "La taille de disque doit ��tre un entier sup��rieur �� 1Go." + +msgid "Template base image must be a valid local image file" +msgstr "L'image de base de mod��le doit petre un fichier image local valide" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "Ne peut identifier le format de l'image de base %(path)s" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" +"Dans la topologie de CPU, chaque ��l��ment doit ��tre un entier strictement " +"positif." + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "Le pool de stockage %(name)s existe d��j��" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "Le pool de stockage %(name)s n'existe pas" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "Sp��cifier %(item)s afin de cr��er le pool de stockage %(name)s" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "Impossible de supprimer le pool de stockage actif %(name)s" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "Impossible de lister les pools de stockage. D��tails: %(err)s" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "Impossilble de cr��er le pool de stockage %(name)s. D��tails: %(err)s" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "" +"Impossible d'obtenir le nombre de volumes de stockage dans le pool de " +"stockage%(name)s. D��tails: %(err)s" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "Impossible d'activer le pool de stockage %(name)s. D��tails: %(err)s" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "" +"Impossible de d��sactiver le pool de stockage %(name)s. D��tails: %(err)s" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "" +"Impossible de supprimer le pool de stockage %(name)s. D��tails: %(err)s " + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" +"Impossible de cr��er le Pool NFS du fait que le chemin d'export %(path)s " +"pourrait se bloquer durant le montage" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" +"Impossible de cr��er le pool NFS du fait que le montage du chemin d'export %" +"(path)s a ��chou��" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "Type de pool de stockage non support��: %(type)s" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" +"Les types de pool de stockage support��s sont: dir, netfs, logical, iscsi, " +"isci et kimchi-iso" + +msgid "Storage pool path must be a string" +msgstr "Le chemin du pool de stockage doit ��tre une cha��ne de caract��res" + +msgid "Storage pool host must be a IP or hostname" +msgstr "L'h��te du pool de stockage doit ��tre une IP ou un nom d'h��te" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" + +msgid "Storage pool devices parameter must be a list" +msgstr "Le param��tre de p��riph��rique de pool de stockage doit ��tre une list" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "La cible IQN d'un pool iSCSI doit ��tre une cha��ne de caract��res" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" +"Le port d'un serveur de stockage distant doit ��tre un nombre entier entre 1 " +"et 65535" + +msgid "iSCSI target username must be a string" +msgstr "" +"Le nom d'utilisateur de la cible iSCSI doit ��tre une cha��ne de caract��res" + +msgid "iSCSI target password must be a string" +msgstr "Le mot de passe de la cible iSCSI doit ��tre une cha��ne de caract��res" + +msgid "Specify name and type to create a storage pool" +msgstr "Sp��cifier un nom et un type pour cr��er un pool de stockage" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "" +"%(disk)s n'est pas un(e) disque/partition valide. N'a pu l'ajouter au pool %" +"(pool)s." + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "Impossible d'agrandir le pool logique %(pool)s. D��tails: %(err)s" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "" +"Les disques en param��tre peuvent seulement ��tre mis �� jour pour un pool de " +"stockage logique." + +msgid "The SCSI host adapter name must be a string." +msgstr "Le nom d'adaptateur de l'h��te SCSI doit ��tre une chapine de caract��res" + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "Le pool de stockage kimchi_isos est r��serv�� �� un usage interne" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"Impossible d'activer le pool de stockage NFS%(name)s. Le serveur NFS %" +"(server)s n'est pas joignable." + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"Impossible de d��sactiver le pool de stockage NFS%(name)s. Le serveur NFS %" +"(server)s n'est pas joignable." + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "" +"Impossible de d��sactiver le pool %(name)s du fait qu'il est associ�� �� des " +"mod��les" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "" +"Impossible de supprimer le pool %(name)s du fait qu'il est associ�� �� des " +"mod��les" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "" +"Un groupe de volume appel�� '%(name)s' existe d��j��. Veuillez choisir un autre " +"nom pour cr��er le pool logique." + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "" +"Impossible de mettre �� jour la base de donn��es avec les informations de scan " +"profond �� cause de l'erreur: %(err)s" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "Le volume de stockage %(name)s existe d��j��" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "" +"Le volume de stockage %(name)s n'existe pas dans le pool de stockage %(pool)s" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" +"Impossible de cr��er le volume de stockage %(volume)s car le pool de stockage " +"%(pool)s n'est pas actif" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "Sp��cifier %(item)s afin de cr��er le volume de stockage %(volume)s" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "" +"Impossible de lister les volumes de stockage car le pool de stockage %(pool)" +"s n'est pas actif" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "" +"Impossible de cr��er le volume de stockage %(name)s dans le pool de stockage %" +"(pool)s. D��tails: %(err)s" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "" +"Impossible de lister les volumes de stockage dans le pool de stockage %(pool)" +"s. D��tails: %(err)s" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "Impossible de wiper les volumes de stockage %(name)s. D��tails: %(err)s" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "" +"Impossible de supprimer le volume de stockage %(name)s. D��tails: %(err)s " + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "" +"Impossible de redimensionner le volume de stockage %(name)s. D��tails: %(err)s" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "" +"Le type de stockage %(type)s ne supporte pas ni la cr��ation ni la " +"suppression de volume" + +msgid "Storage volume name must be a string" +msgstr "Le nom de volume de stockage doit ��tre une cha��ne de caract��res" + +msgid "Storage volume allocation must be an integer number" +msgstr "L'allocation de volume de stockage doit ��tre une nombre entier" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" + +msgid "Storage volume requires a volume name" +msgstr "Le volume de stockage requiert un nom de volume" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "" +"Impossible de mettre �� jour la base de donn��es avec les informations du " +"volume de stockage �� cause de l'erreur: %(err)s" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "Seulement un seul des param��tre %(param)s peut ��tre sp��cifi��" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "La cr��ation de volume avec %(param)s n'est pas support��e" + +msgid "Storage volume capacity must be an integer number." +msgstr "La capacit�� du volume de stockage doit ��tre un nombre entier." + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" +"L'URL du volume de stockage doit ��tre http://, https://, ftp:// ou ftps://." + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "Impossible d'acc��der au fichier %(url)s. Veuillez le v��rifier." + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "L'interface %(name)s n'existe pas" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "Le r��seau %(name)s existe d��j��" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "Le r��seau %(name)s n'existe pas" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" +"Le sous-r��seau %(subnet)s sp��cifi�� pour le r��seau %(network)s n'est pas " +"valide" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "Sp��cifier une interface r��seau pour cr��er le r��seau bridge %(name)s" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "Impossible de supprimer le r��seau actif %(name)s" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" +"L'interface %(iface)s sp��cifi��e pour le r��seau %(network)s est d��j�� utilis��e" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "L'interface doit ��tre un p��riph��rique NIC vide, bonding ou bridg��." + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "Impossible de cr��er le r��seau %(name)s. D��tails: %(err)s" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "Impossible de trouver une adresse IP libre pour le r��seau '%(name)s'" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "L'interface %(iface)s existe d��j��" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "Les types de r��seaux support��s sont isolated, NAT et bridge" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "" +"Le sous-r��seau doit ��tre une chaine de caract��res avec une adresse IP et un " +"pr��fixe ou un masque de r��seau" + +msgid "Network interface must be a string" +msgstr "L'interface de r��seau doit ��tre une cha��ne de caract��res" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "L'ID de VLAN du r��seau doit ��tre un nombre entier entre 1 et 4094" + +msgid "Specify name and type to create a Network" +msgstr "Sp��cifiez un nom et un type pour cr��er un r��seau" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" +"Impossible de supprimer le r��seau %(name)s. Il y a des machines virtuelles %" +"(vms)s et/ou des mod��les li��s �� ce r��seau. " + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" +"Impossible de d��sactiver r��seau %(name)s. Il y a des machines virtuelles%" +"(vms)s et/ou des mod��les li��s �� ce r��seau. " + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "" +"Le p��riph��rique bridge %(name)s ne peut ��tre le p��riph��rique tronc d'un VLAN." + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "��chec durant l'activation de l'interface %(iface)s: %(err)s." + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "" +"��chec durant l'activation de l'interface %(iface)s. Veuillez v��rifier le " +"statut du lien physique." + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "Le rapport de d��boggage %(name)s n'existe pas" + +msgid "Debug report tool not found in system" +msgstr "L'outil de rapport de d��boggage n'a pas ��t�� trouv�� dans le syst��me" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "" +"Impossible de cr��er le rapport de d��boggage %(name)s. D��tails: %(err)s." + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "" +"Impossible de trouver un rapport de d��boggage avec le nom fourni %(name)s" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "" +"Impossible de g��n��rer le rapport de d��boggage %(name)s. D��tails: %(err)s" + +msgid "You should give a name for the debug report file." +msgstr "Vous devriez donner un nom au fichier de rapport de d��boggage." + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" +"Le nom du rapport de d��boggage doit ��tre une cha��ne de caract��res. Seulement " +"les lettres, chiffres, blanc soulign�� ('_') et tirets ('-') sont accept��s." + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "" +"Le rapport de d��boggage avec le nom sp��cifi�� \"%(name)s\" existe d��j��. " +"Veuillez en utiliser un autre." + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "Le server de stockage %(server)s n'��tait pas utilis�� par Kimchi" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "La distro '%(name)s' n'existe pas" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "La partition %(name)s n'existe pas sur cet h��te" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" +"Impossible d'��teindre la machine h��te car des machines virtuelles en sont " +"cours d'ex��cution" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" +"Impossible de red��marrer la machine h��te car des machines virtuelles en sont " +"cours d'ex��cution" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "P��riph��rique de noeud '%(name)s' non trouv��" + +msgid "Conflicting flag filters specified." +msgstr "Filtres incompatibles sp��cifi��s." + +msgid "No packages marked for update" +msgstr "Aucun paquet marqu�� pour mise �� jour" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "Le paquet %(name)s n'est pas marqu�� pour mise �� jour" + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "" +"Erreur durant la r��cup��ration des paquets marqu��s pour la mise�� jour. " +"D��tails: %(err)s" + +msgid "There is no compatible package manager for this system." +msgstr "Il n'y a pas de gestionnaire de paquets compatible avec ce syst��me." + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "URI %(uri)s invalide" + +msgid "Unable to choose a virtual machine name" +msgstr "Impossible de s��lectionner un nom de machine virtuelle" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "Type de stockage invalide. Les Types support��s sont: 'cdrom', 'disk'" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" + +msgid "Only CDROM path can be update." +msgstr "Seulement le chemin d'un CDROM peut ��tre modifi��." + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "" +"Le p��riph��rique de stockage %(dev_name)s n'existe pas dans la machine " +"virtuelle %(vm_name)s" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "" +"Erreur durant la cr��ation du nouveau p��riph��rique de stockage: %(error)s" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "Erreur durant la mise �� jour du p��riph��rique de stockage: %(error)s" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "Erreur durant le retrait du p��riph��rique de stockage: %(error)s" + +msgid "Do not support IDE device hot plug" +msgstr "Ne pas supporter le branchement �� chaud de p��riph��rique IDE" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "" +"Sp��cifier le type et le chemin ou le type et le pool/volume pour ajouter un " +"nouveau disque de machine virtuelle." + +msgid "Specify path to update virtual machine disk" +msgstr "Sp��cifier un chemin pour mettre �� jour le disque de machine virtuelle" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" +"La limitation de %(limit)s p��riph��riques a ��t�� atteinte pour le contr��leur " +"de type %(type)s " + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" + +msgid "Volume already in use by other virtual machine." +msgstr "" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "" +"Seul un chemin ou pool/volume peut ��tre sp��cifi�� pour ajouter un nouveau " +"disque de machine virtuelle" + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" +"Le volume de format %(format)s s��lectionn�� ne correspond pas au type de " +"stockage %(type)s" + +msgid "YUM Repository ID must be one word only string." +msgstr "" +"L'ID du d��p��t YUM doit ��tre une cha��ne de caract��res ne comportant qu'un " +"seul mot" + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "L'URL du d��p��t doit ��tre une URL en http://, ftp:// ou file://." + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "" +"La configuration du d��p��t est un dictionaire avec des valeurs sp��cifiques en " +"accord avec le type de d��p��t." + +msgid "Distribution to DEB repository must be a string" +msgstr "" +"La distribution dans le nom de d��p��t DEB doit ��tre une cha��ne de caract��res" + +msgid "Components to DEB repository must be listed in a array" +msgstr "Les composants dans le d��p��t DEB doivent ��tre list��s dans un tableau" + +msgid "Components to DEB repository must be a string" +msgstr "Les composants dans le d��p��t DEB doivent ��tre une cha��ne de caract��res" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "Le nom du d��p��t YUM doit ��tre une cha��ne de caract��res" + +msgid "GPG check must be a boolean value." +msgstr "La v��rification GPG doit ��tre une valeur bool��enne." + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "La cl�� GPG doit ��tre une URL pointant vers un fichier ASCII non arm��." + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "Ne peut mettre �� jour le d��p��t %(repo_id)s." + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "Le d��p��t %(repo_id)s n'existe pas." + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "L'outil de gestion de d��p��t n'a pas ��t�� reconnu pour votre syst��me." + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "Le d��p��t %(repo_id)s est d��j�� activ��." + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "Le d��p��t %(repo_id)s est d��j�� d��sactiv��." + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "Ne peut supprimer le d��p��t %(repo_id)s. " + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "Ne peut ��crire le fichier de configuration du d��p��t %(repo_file)s" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "Sp��cifier la distribution du d��p��t afin de cr��er un d��p��t DEB." + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "Ne peut activer le d��p��t %(repo_id)s." + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "Ne peut d��sactiver le d��p��t %(repo_id)s." + +msgid "YUM Repository ID already exists" +msgstr "L'ID du d��p��t YUM existe d��j��" + +msgid "YUM Repository name must be a string" +msgstr "Le nom du d��p��t YUM doit ��tre une cha��ne de caract��res" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "Impossible de lister les d��p��ts. D��tails: '%(err)s'" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "Impossible de r��cup��rer les informations du d��p��t. D��tails: '%(err)s'" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "Impossible d'ajouter un d��p��t. D��tails: '%(err)s'" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "Impossible de supprimer un d��p��t. D��tails: '%(err)s'" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" +"��l��ments de configurations: %(items)s ne sont pas support��s par le " +"gestionnaire de d��p��t" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" + +msgid "The number of vCPUs is too large for this system." +msgstr "" + +msgid "Invalid vCPU/topology combination." +msgstr "" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "" + +msgid "ERROR CODE" +msgstr "ERROR CODE" + +msgid "REASON" +msgstr "REASON" + +msgid "STACK" +msgstr "STACK" + +msgid "Go to Homepage" +msgstr "Aller �� la page d'accueil" + +msgid "Create a New Virtual Machine" +msgstr "Cr��er une nouvelle Machine Virtuelle" + +msgid "Virtual Machine Name" +msgstr "Nom de Machine Virtuelle" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" +"Le nm est utilis�� pour identifier une machine virtuelle. Si omis, un nom " +"sera choisi en se basant sur le mod��le utilis��." + +msgid "Template" +msgstr "Mod��le" + +msgid "Please create a template first." +msgstr "Veuillez d'abord cr��er un mod��le." + +msgid "Create a Template" +msgstr "Cr��er un mod��le" + +msgid "Please choose a template." +msgstr "Veuillez choisir un mod��le" + +msgid "OS" +msgstr "OS" + +msgid "OS Version" +msgstr "Version de l'OS" + +msgid "CPUS" +msgstr "CPUS" + +msgid "Memory" +msgstr "M��moire" + +msgid "Create" +msgstr "Cr��er" + +msgid "Creating..." +msgstr "Cr��ation en cours..." + +msgid "Cancel" +msgstr "Annuler" + +msgid "Edit Guest" +msgstr "��diter l'Invit��" + +msgid "General" +msgstr "G��n��ral" + +msgid "Storage" +msgstr "Stockage" + +msgid "Interface" +msgstr "Interface" + +msgid "Permission" +msgstr "Permission" + +msgid "Host PCI Device" +msgstr "P��riph��rique PCI H��te" + +msgid "Snapshot" +msgstr "" + +msgid "Name" +msgstr "Nom" + +msgid "CPUs" +msgstr "CPUs" + +msgid "Memory (MB)" +msgstr "M��moire (Mo)" + +msgid "Icon" +msgstr "Icone" + +msgid "Device" +msgstr "P��riph��rique" + +msgid "Path" +msgstr "Chemin" + +msgid "Network" +msgstr "R��seau" + +msgid "Type" +msgstr "Type" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "Utilisateurs et groupes syst��mes disponibles" + +msgid "Selected system users and groups" +msgstr "Utilisateurs et groupes syst��mes s��lectionn��s" + +msgid "User" +msgstr "" + +msgid "All" +msgstr "Tous" + +msgid "To Add" +msgstr "�� Ajouter" + +msgid "Added" +msgstr "Ajouter" + +msgid "filter" +msgstr "Filtre" + +msgid "Product" +msgstr "Produit" + +msgid "Vendor" +msgstr "Vendeur" + +msgid "Created" +msgstr "" + +msgid "Save" +msgstr "Enregistrer" + +msgid "Replace" +msgstr "Remplacer" + +msgid "Detach" +msgstr "D��tacher" + +msgid "revert" +msgstr "" + +msgid "Start" +msgstr "D��marrer" + +msgid "Reset" +msgstr "R��initialiser" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "Mettre hors tension" + +msgid "Actions" +msgstr "Actions" + +msgid "Connect" +msgstr "Connecter" + +msgid "Clone" +msgstr "Cloner" + +msgid "Edit" +msgstr "��diter" + +msgid "Shut Down" +msgstr "��teindre" + +msgid "Delete" +msgstr "Supprimer" + +msgid "CPU" +msgstr "CPU" + +msgid "Disk I/O" +msgstr "E/S Disque" + +msgid "Network I/O" +msgstr "E/S R��seau" + +msgid "Livetile" +msgstr "Livetile" + +msgid "No guests found." +msgstr "Aucun invit�� trouv��." + +msgid "Add a Storage Device to VM" +msgstr "Ajouter un P��riph��rique de Stockage �� la VM" + +msgid "Device Type" +msgstr "Type de P��riph��rique" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "" +"Le type de p��riph��rique. Actuellement, \"cdrom\" et \"disk\" sont support��s." + +msgid "Storage Pool" +msgstr "Pool de Stockage" + +msgid "Storage pool which volume located in" +msgstr "Pool de Stockage dans lequel le volume est situ��" + +msgid "Storage Volume" +msgstr "Volume de Stockage" + +msgid "Storage volume to be attached" +msgstr "Le volume de stockage �� attacher" + +msgid "File Path" +msgstr "Chemin de Fichier" + +msgid "The ISO file path in the server for CDROM." +msgstr "Le chemin de fichier ISO sur le serveur comme CDROM." + +msgid "Attach" +msgstr "Attacher" + +msgid "Shut down" +msgstr "��teindre" + +msgid "Restart" +msgstr "Red��marrer" + +msgid "Basic Information" +msgstr "Informations de Base" + +msgid "OS Distro" +msgstr "Distro de l'OS" + +msgid "OS Code Name" +msgstr "Nom de code de l'OS" + +msgid "Processor" +msgstr "Processeur" + +msgid "CPU(s)" +msgstr "" + +msgid "System Statistics" +msgstr "Statistiques Syst��me" + +msgid "Software Updates" +msgstr "Mises �� jour Logiciel" + +msgid "Update Progress" +msgstr "Progr��s de la Mise �� Jour" + +msgid "Repositories" +msgstr "D��p��ts" + +msgid "Debug Reports" +msgstr "Rapports de D��boggage" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "" +"Le nom d'utilisateur ou le mot de passe que vous avez entr�� est incorrect. " +"Veuillez essayer �� nouveau." + +msgid "This field is required." +msgstr "Ce champ est requis." + +msgid "Log in" +msgstr "Se connecter" + +msgid "Logging in..." +msgstr "En cours de connexion..." + +msgid "Host" +msgstr "H��te" + +msgid "Guests" +msgstr "Invit��s" + +msgid "Templates" +msgstr "Mod��les" + +msgid "Failed to get application configuration" +msgstr "��chec lors de l'obtention de la configuration de l'application" + +msgid "This is not a valid Linux path" +msgstr "Ce n'est pas un chemin Linux valide" + +msgid "This is not a valid URL." +msgstr "Ce n'est pas une URL valide." + +msgid "No such data available." +msgstr "De telles donn��es ne sont pas disponibles." + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" +"Ne peut contacter le syst��me h��te. V��rifiez que le syst��me h��te est allum�� " +"et que vous avez une connectivit�� r��seau avec lui. R��ponse de requ��te HTTP %" +"1." + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "Confirmation de Suppression" + +msgid "OK" +msgstr "OK" + +msgid "Confirm" +msgstr "Confirmer" + +msgid "Warning" +msgstr "Avertissement" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "Chargement en cours..." + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "Essayer �� nouveau" + +msgid "Detailed message:" +msgstr "Message d��taill��:" + +msgid "No ISO found" +msgstr "Aucune ISO d��tect��e" + +msgid "This is not a valid ISO file." +msgstr "Ce n'est pas un fichier ISO valide." + +msgid "This may take a long time. Do you want to continue?" +msgstr "Cela va prendre un long moment. Voulez-vous continuer ?" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" +"Cela va supprimer de mani��re permanent le mod��le. Souhaites-vous continuer ?" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" +"Impossible d'��teindre le syst��me du fait que certaines machines virtuelles " +"sont lanc��es !" + +msgid "Max:" +msgstr "Max:" + +msgid "Utilization" +msgstr "Utilisation" + +msgid "Available" +msgstr "Disponible" + +msgid "Read Rate" +msgstr "Taux en Lecture" + +msgid "Write Rate" +msgstr "Taux en ��criture" + +msgid "Received" +msgstr "Re��u" + +msgid "Sent" +msgstr "Envoy��" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"��teindre ou red��marrer l'h��te causera la perte de tout travail non " +"enregistr��. Continuer �� ��teindre/red��marrer ?" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"Le d��p��t sera retir�� de fa��on permanente et ne pourra ��tre r��tabli. Voulez-" +"vous continuer ?" + +msgid "ID" +msgstr "ID" + +msgid "Base URL" +msgstr "URL de base" + +msgid "Is Mirror" +msgstr "Est un miroir" + +msgid "URL Args" +msgstr "Arguments d'URL" + +msgid "Enabled" +msgstr "Activ��" + +msgid "GPG Check" +msgstr "V��rification GPG" + +msgid "GPG Key" +msgstr "Cl�� GPG" + +msgid "Add" +msgstr "Ajouter" + +msgid "Remove" +msgstr "Retirer" + +msgid "Enable" +msgstr "Activer" + +msgid "Disable" +msgstr "D��sactiver" + +msgid "Package Name" +msgstr "Nom de paquet" + +msgid "Version" +msgstr "Version" + +msgid "Architecture" +msgstr "Architecture" + +msgid "Repository" +msgstr "D��p��t" + +msgid "Update All" +msgstr "Tout mettre �� jour" + +msgid "Updating..." +msgstr "En cours de mise �� jour..." + +msgid "Failed to retrieve packages update information." +msgstr "��chec de r��cup��ration des informations de mise-��-jour des paquets." + +msgid "Failed to update package(s)." +msgstr "��chec durant la mise �� jour du/des paquet(s)" + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"Le rapport de d��boggage sera enlev�� de fa��on permanente et ne pourra ��tre " +"r��tabli. Voulez-vous continuer ?" + +msgid "Generated Time" +msgstr "Horodatage de g��n��ration" + +msgid "Generate" +msgstr "G��n��rer" + +msgid "Generating..." +msgstr "En cours de g��n��ration..." + +msgid "Rename" +msgstr "Renommer" + +msgid "Download" +msgstr "T��l��charger" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "" +"Le nom de rapport devrait contenir uniquement des lettres, nombres, " +"soulignement ('_') et/ou tiret ('-')." + +msgid "Pending..." +msgstr "En attente..." + +msgid "Report name is the same as the original one." +msgstr "Le nom du rapport est le m��me que celui d'origine." + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "" +"Cela va supprimer la machine virtuelle et tous ses disques virtuels. Cette " +"op��ration est irr��versible. Voulez-vous continuer ?" + +msgid "Power off Confirmation" +msgstr "Confirmation de mise hors tension" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" +"Cette action pourrait produire des r��sultats ind��sirables, par exemple un " +"cache disque non flush�� dans l'invit��. Voulez-vous continuer ?" + +msgid "Reset Confirmation" +msgstr "Confirmation de R��initialisation" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" +"Il y a un risque de perte de donn��es caus��es par une r��initialisation sans " +"extinction de l'OS invit��. Voulez-vous continuer ?" + +msgid "Shut Down Confirmation" +msgstr "Confirmation d'Extinction" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "" +"Noter que l'OS invit�� pourrait ignorer cette requ��te. Voulez-vous continuer ?" + +msgid "Virtual Machine delete Confirmation" +msgstr "Confirmation de suppression de Machine Virtuelle" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" +"Ce CDROM sera d��tach�� de fa��on permanente et vous pourrez le r��-attacher. " +"Continuer le d��tachement ?" + +msgid "Attaching..." +msgstr "En cours d'attachement..." + +msgid "Replacing..." +msgstr "En cours de Remplacement..." + +msgid "Successfully attached!" +msgstr "Attach�� avec succ��s !" + +msgid "Successfully replaced!" +msgstr "Remplac�� avec succ��s !" + +msgid "Successfully detached!" +msgstr "D��tach�� avec Succ��s !" + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" +"Ce disque sera d��finitivement d��tach�� et peut ��tre r��-attach��. Continuer �� " +"le d��tacher ?" + +msgid "interface:" +msgstr "" + +msgid "address:" +msgstr "" + +msgid "link_type:" +msgstr "" + +msgid "block:" +msgstr "" + +msgid "drive_type:" +msgstr "" + +msgid "model:" +msgstr "" + +msgid "Affected devices:" +msgstr "" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "L'id du VLAN doit ��tre entre 1 et 4094." + +msgid "unavailable" +msgstr "non disponible" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "" +"Cette action va interrompre la connectivit�� r��seau pour tout machine " +"virtuelle qui d��pend de ce r��seau." + +msgid "Create a network" +msgstr "Cr��er un r��seau" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"Ce r��seau n'est pas persistant. Au lieu de s'arr��ter, cette actionva le " +"suppromer de mani��re permanente. Voulez-vous continuer ?" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "" +"Cela va effacer de mani��re permanente le pool de stockage. Voulez-vous " +"continuer ?" + +msgid "This storage pool is empty." +msgstr "Ce pool de stockage est vide." + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "" +"Cela va formater votre disque et vous allez perdre toutes les donn��es qui " +"s'y trouvent, ��tes-vous s��r de continuer ?" + +msgid "SCSI Fibre Channel" +msgstr "Canal Fibre SCSI" + +msgid "No SCSI adapters found." +msgstr "Aucun adaptateur SCSI trouv��." + +msgid "Loading iSCSI targets..." +msgstr "" + +msgid "No iSCSI found. Please input one." +msgstr "" + +msgid "Failed to load iSCSI targets." +msgstr "" + +msgid "The storage pool name can not be blank." +msgstr "Le nom de pool de stockage ne peut ��tre vierge." + +msgid "The storage pool path can not be blank." +msgstr "Le chemin de pool de stockage ne peut ��tre vierge." + +msgid "NFS server mount path can not be blank." +msgstr "Le chemin de montage du serveur NFS ne peut ��tre vierge." + +msgid "Invalid NFS mount path." +msgstr "Chemin de montage NFS invalide." + +msgid "No logical device selected." +msgstr "Aucun p��riph��rique logique s��lectionn��." + +msgid "The iSCSI target can not be blank." +msgstr "La cible iSCSI ne peut ��tre vierge." + +msgid "Server name can not be blank." +msgstr "Le nom de serveur ne peut ��tre vierge." + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "" + +msgid "Looking for available partitions ..." +msgstr "En cours de recherche de partitions disponibles..." + +msgid "No available partitions found." +msgstr "Aucune partition disponible trouv��e." + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"Le pool de stockage n'est pas persistent. Au lieu de le d��sactiver, cette " +"action va le supprimer de mani��re permanente. Voulez-vous continuer ?" + +msgid "Unable to retrieve partitions information." +msgstr "Impossible de r��cup��rer les informations des partitions." + +msgid "In progress..." +msgstr "En cours..." + +msgid "Failed!" +msgstr "��chec!" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" +"Le chemin de CDROM doit ��tre un chemin local/distant valide et ne peut ��tre " +"virge." + +msgid "Disk pool or volume cannot be blank." +msgstr "Le pool de disque ou le volume ne peut ��tre vierge." + +#, fuzzy +msgid "Filter" +msgstr "Filtre" + +msgid "Network Name" +msgstr "Nom de R��seau" + +msgid "State" +msgstr "��tat" + +msgid "Network Type" +msgstr "Type de R��seau" + +msgid "Address Space" +msgstr "Espace d'adressage" + +msgid "Name should not contain '/' and '\"'." +msgstr "Le nom ne devrait pas contenir '/' et '\"'." + +msgid "Isolated: no external network connection" +msgstr "Isol��: pas de connexion �� un r��seau externe" + +msgid "NAT: outbound physical network connection only" +msgstr "NAT: connexion physique au r��seau sortant uniquement" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "" +"Bridg��: Les macines virtuelles sont connect��es directement au r��seau physique" + +msgid "(No interfaces found)" +msgstr "(Aucune interface trouv��e)" + +msgid "Destination" +msgstr "Destination" + +msgid "Enable VLAN" +msgstr "Activer le VLAN" + +msgid "VLAN ID" +msgstr "ID de VLAN" + +msgid "Stop" +msgstr "Arr��ter" + +msgid "Generate a New Debug Report" +msgstr "G��n��rer un Nouveau Rapport de D��boggage" + +msgid "Report Name" +msgstr "Nom du Rapport" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" +"Le nom utilis�� pour identifier le rapport. Si omis, un nom sera choisi bas�� " +"sur l'heure courante. Le nom peut contenir des lettres, des nombres, le " +"soulignement (\"_\") et le tiret (\"-\")." + +msgid "Rename a Debug Report" +msgstr "Renommer un Rapport de D��boggage" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" +"Le nom utilis�� pour identifer le rapport. Le nom peut contenir des lettres, " +"nombres et tirets (\"-\")." + +msgid "Submit" +msgstr "Soumettre" + +msgid "Add a Repository" +msgstr "Ajouter un D��p��t" + +msgid "Identifier" +msgstr "Identificateur" + +msgid "Single word, unique identifier for the repository." +msgstr "Mot unique, identifiant unique pour le d��p��t." + +msgid "Textual name for the repository." +msgstr "Nom textuel pour le d��p��t." + +msgid "URL" +msgstr "URL" + +msgid "Required Field" +msgstr "Champ requis" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "URL du d��p��t. Les protocoles support��s sont http, ftp et ficheir." + +msgid "Repository is a mirror" +msgstr "Le d��p��t est un miroir" + +msgid "Distribution" +msgstr "Distribution" + +msgid "Distribution of the DEB repository." +msgstr "Distribution du d��p��t DEB." + +msgid "Components" +msgstr "Composants" + +msgid "List of components in DEB repository." +msgstr "Liste des composants dans le d��p��t DEB." + +msgid "Edit Repository" +msgstr "Editer le D��p��t" + +msgid "Mirror List URL" +msgstr "URL de Liste de Miroir" + +msgid "Yes" +msgstr "Oui" + +msgid "No" +msgstr "Non" + +msgid "Capacity" +msgstr "Capacit��" + +msgid "Allocated" +msgstr "Allou��" + +msgid "Location" +msgstr "Emplacement" + +msgid "Device path" +msgstr "Chemin du P��riph��rique" + +msgid "active" +msgstr "actif" + +msgid "inactive" +msgstr "inactif" + +msgid "Deactivate" +msgstr "D��sactiver" + +msgid "Activate" +msgstr "Activer" + +msgid "Add Volume" +msgstr "Ajouter un Volume" + +msgid "Extend" +msgstr "��tendre" + +msgid "Undefine" +msgstr "Supprimer" + +msgid "Format" +msgstr "Format" + +msgid "Allocation" +msgstr "Allocation" + +msgid "Define a New Storage Pool" +msgstr "D��finir un Nouveau Pool de Stockage" + +msgid "Storage Pool Name" +msgstr "Nom de Pool de Stockage" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "" +"Le nom utilis�� pour identifier les pools de stockage, et il ne doit pas ��tre " +"vide." + +msgid "Storage Pool Type" +msgstr "Type de Pool de Stockage" + +msgid "Storage Path" +msgstr "Chemin de Stockage" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "" +"Le chemin du Pool de Stockage. Chaque Pool de Stockage doit avoir un chemin " +"unique." + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "" +"Kimchi va essayer de cr��er un r��pertoire quand il n'existe pas d��j�� dans " +"votre syst��me." + +msgid "NFS Server IP" +msgstr "IP du Serveur NFS" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" +"IP du Serveur NFS ou nom d'h��te. Il peut ��tre saisi ou entr�� �� partir de " +"l'historique." + +msgid "NFS Path" +msgstr "Chemin NFS" + +msgid "The NFS exported path on NFS server." +msgstr "Le chemin NFS export�� sur le serveur NFS." + +msgid "iSCSI Server" +msgstr "Serveur iSCSI" + +msgid "Server" +msgstr "Serveur" + +msgid "Port" +msgstr "Port" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "IP du Serveur iSCSI ou nom d'h��te. Il ne devrait pas ��tre vide." + +msgid "Target" +msgstr "Cible" + +msgid "The iSCSI target on iSCSI server" +msgstr "La cible iSCSI sur le serveur iSCSI" + +msgid "Add iSCSI Authentication" +msgstr "Ajouter l'Authentification iSCSI" + +msgid "iSCSI Authentication" +msgstr "Authentification iSCSI" + +msgid "User Name" +msgstr "Nom d'Utilisateur" + +msgid "Password" +msgstr "Mot de Passe" + +msgid "SCSI Adapter" +msgstr "Adaptateur SCSI" + +msgid "Please, wait..." +msgstr "Veuillez patienter..." + +msgid "Add a Volume to Storage Pool" +msgstr "iAjouter un Volume au Pool de Stockage" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "Saisir une URL distante ici" + +msgid "Upload a file" +msgstr "Charger un fichier" + +msgid "Choose the file you want to upload." +msgstr "" + +msgid "Add Template" +msgstr "Ajouter un Mod��le" + +msgid "Where is the source media for this template? " +msgstr "O�� se trouve le media source pour le mod��le ?" + +msgid "Local ISO Image" +msgstr "Image ISO Locale" + +msgid "Local Image File" +msgstr "Fichier Image Local" + +msgid "Remote ISO Image" +msgstr "Image ISO Distante" + +msgid "Search ISOs" +msgstr "Rechercher des ISOs" + +msgid "The following ISOs are available:" +msgstr "Les ISOs suivants sont disponibles:" + +msgid "OS: " +msgstr "OS: " + +msgid "Version: " +msgstr "Version: " + +msgid "Size: " +msgstr "Taille: " + +msgid "Search more ISOs" +msgstr "Chercher plus d'ISOs" + +msgid "Create Templates from Selected ISO" +msgstr "Cr��er des mod��les depuis l'ISO s��lectionn��" + +msgid "I want to use a specific ISO file" +msgstr "Je veux utiliser un fichier ISO sp��cifique" + +msgid "Loading default remote ISOs ..." +msgstr "Chargement des ISOs distants par d��faut en cours..." + +msgid "Arch: " +msgstr "Arch: " + +msgid "I want to use a custom URL" +msgstr "Je veux utiliser une URL personnalis��e" + +msgid "Edit Template" +msgstr "��diter un Mod��le" + +msgid "CDROM" +msgstr "CDROM" + +msgid "Image File" +msgstr "Fichier Image" + +msgid "Graphics" +msgstr "Graphiques" + +msgid "Disk(GB)" +msgstr "" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "Nombre de CPU" + +msgid "Manually set CPU topology" +msgstr "" + +msgid "Cores" +msgstr "" + +msgid "Threads" +msgstr "" + +msgid "No templates found." +msgstr "Aucun mod��le trouv��." + +#~ msgid "Delete is not allowed for %(resource)s" +#~ msgstr "La suppression n'est pas autoris��e pour %(resource)s" + +#~ msgid "%(resource)s does not implement update method" +#~ msgstr "%(resource)s n'impl��mente pas de m��thode de mise �� jour" + +#~ msgid "Create is not allowed for %(resource)s" +#~ msgstr "La cr��ation n'est pas autoris��e pour %(resource)s" + +#~ msgid "Unable to parse JSON request" +#~ msgstr "Impossible de parser la requ��te JSON" + +#~ msgid "This API only supports JSON" +#~ msgstr "Cette API supporte uniquement le JSON" + +#~ msgid "Parameters does not match requirement in schema: %(err)s" +#~ msgstr "" +#~ "Les param��tres ne correspondent pas �� ce qui est requis dans le sch��ma: %" +#~ "(err)s" + +#~ msgid "You don't have permission to perform this operation." +#~ msgstr "Vous n'avez pas la permission d'effectuer cette op��ration." + +#~ msgid "Datastore is not initiated in the model object." +#~ msgstr "Le magasin de donn��es n'est pas initi�� dans l'objet mod��le." + +#~ msgid "Unable to start task due error: %(err)s" +#~ msgstr "Impossible de d��marrer la t��che �� cause de l'erreur: %(err)s" + +#~ msgid "" +#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" +#~ msgstr "" +#~ "L'authentification a ��chou�� pour l'utilisateur '%(username)s'. [Code " +#~ "d'Erreur: %(code)s]" + +#~ msgid "You are not authorized to access Kimchi" +#~ msgstr "Vous n'��tes pas autoris�� �� acc��der �� Kimchi" + +#~ msgid "Specify %(item)s to login into Kimchi" +#~ msgstr "Sp��cifiez %(item)s pour vous logguer dans Kimchi" + +#~ msgid "Unable to find %(item)s in datastore" +#~ msgstr "Impossible de trouver %(item)s dans le magasin de donn��es" + +#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +#~ msgstr "" +#~ "Timeout durant l'ex��cution de la commande '%(cmd)s' apr��s %(seconds)s " +#~ "secondes" + +#~ msgid "Help" +#~ msgstr "Aide" + +#~ msgid "About" +#~ msgstr "A propos..." + +#~ msgid "Log out" +#~ msgstr "Se d��connecter" + +#~ msgid "Version:" +#~ msgstr "Version:" + +#~ msgid "Session timeout, please re-login." +#~ msgstr "Session expir��e, veuillez vous reconnecter." diff --git a/src/wok/plugins/kimchi/po/gen-pot.in b/src/wok/plugins/kimchi/po/gen-pot.in new file mode 100644 index 0000000..0e3cd10 --- /dev/null +++ b/src/wok/plugins/kimchi/po/gen-pot.in @@ -0,0 +1,9 @@ +#!/bin/bash + +for src in $@; do + if [ ${src: -3} == ".py" ]; then + cat $src + else + cat $src | @CHEETAH@ compile - + fi +done | xgettext --no-location -o kimchi.pot -L Python - diff --git a/src/wok/plugins/kimchi/po/it_IT.po b/src/wok/plugins/kimchi/po/it_IT.po new file mode 100644 index 0000000..257c306 --- /dev/null +++ b/src/wok/plugins/kimchi/po/it_IT.po @@ -0,0 +1,2274 @@ +# English translations for kimchi package. +# Copyright (C) 2013 ORGANIZATION +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2013-07-11 17:32-0400\n" +"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" +"Language-Team: English\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: it_IT\n" +"Generated-By: pygettext.py 1.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "" + +msgid "Unknown \"_cap\" specified" +msgstr "" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "" +"Errore durante il richiamo dei dispositivi del blocco. Dettagli: %(err)s" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" +"Errore durante il richiamo delle informazioni sul dispositivo del blocco per " +"%(device)s." + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "Impossibile trovare il file distro: %(filename)s" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "" +"Impossibile analizzare il file distro: %(filename)s. Verificare che sia un " +"file JSON." + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" +"Impossibile accedere a %(portal)s di destinazione host iSCSI. Dettagli: %" +"(err)s" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "Impossibile accedere alla destinazione %(target)s host %(host)s iSCSI" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "Il file ISO %(filename)s non �� avviabile" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "Il file ISO %(filename)s non ha un record di avvio El Torito valido" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "Voce di convalida El Torito non valida in ISO %(filename)s" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "Indicatore di avvio El Torito non valido in ISO %(filename)s" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "Tipo di volume imprevisto per il volume primario in ISO %(filename)s" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" +"Formato non corretto durante la lettura del descrittore volume in ISO %" +"(filename)s" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" +"L'hypervisor non dispone dell'autorizzazione per utilizzare questo ISO %" +"(filename)s. Spostarlo in /var/lib/libvirt o impostare l'autorizzazione di " +"ricerca per gli elenchi di controllo accesso ai file per l'utente '%(user)" +"s', se possibile, o aggiungere '%(user)s' al gruppo percorso ISO o (non " +"consigliato) 'chmod -R o+x 'path_to_iso'. Dettagli: %(err)s" + +msgid "An error occurred when probing image OS information." +msgstr "" + +msgid "No OS information found in given image." +msgstr "" + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "Macchina virtuale %(name)s gi�� esistente" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "La macchina virtuale %(name)s non esiste" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" +"Impossibile richiamare l'immagine per la macchina virtuale arrestata %(name)s" + +msgid "Remote ISO image is not supported by this server." +msgstr "L'immagine ISO remota non �� supportata da questo server." + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "Impossibile creare la macchina virtuale %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "Impossibile creare la macchina virtuale %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Impossibile richiamare la macchina virtuale %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" +"L'indirizzo dei grafici su cui rimanere in ascolto deve essere IPv4 o IPv6" + +msgid "Specify a template to create a virtual machine from" +msgstr "Specificare un modello da cui creare una macchina virtuale" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "Impossibile avviare la macchina virtuale %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "Impossibile arrestare la macchina virtuale %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "Impossibile eliminare la macchina virtuale %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "" +"Impossibile ridenominare la macchina virtuale %(name)s. Dettagli: %(err)s" + +msgid "User name list must be an array" +msgstr "" + +msgid "User name must be a string" +msgstr "Il nome della rete deve essere una stringa" + +msgid "Group name list must be an array" +msgstr "" + +msgid "Group name must be a string" +msgstr "Il nome della rete deve essere una stringa" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "L'utente '%(users)s' non esiste." + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "L'utente '%(groups)s' non esiste." + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "Impossibile arrestare la macchina virtuale %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "Impossibile avviare la macchina virtuale %(name)s. Dettagli: %(err)s" + +msgid "The guest console password must be a string." +msgstr "" + +msgid "The life time for the guest console password must be a number." +msgstr "" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" + +msgid "\"name\" should be a device name string" +msgstr "" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "L'interfaccia %(iface)s non esiste nella macchina virtuale %(name)s" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" +"La rete %(network)s specificata per la macchina virtuale %(name)s non esiste" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "" +"Il tipo supportato per le interfacce della macchina virtuale �� solo rete" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" +"Il nome di rete per l'interfaccia della macchina virtuale deve essere una " +"stringa" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" +"Scheda modello di rete non valida per l'interfaccia della macchina virtuale" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" +"Specificare il tipo e la rete per aggiungere una nuova interfaccia della " +"macchina virtuale" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "Modello %(name)s gi�� esistente" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" +"La rete '%(network)s' specificata per il modello %(template)s non esiste" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "" +"Il pool di memoria %(pool)s specificato per il modello %(template)s non " +"esiste" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "" +"Il pool di memoria %(pool)s specificato per il modello %(template)s non �� " +"attivo" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "Parametro non valido %(param)s' specificato per CDROM." + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" +"La rete %(network)s specificata per il modello %(template)s non �� attiva" + +msgid "Template name must be a string" +msgstr "Il nome del modello deve essere una stringa" + +msgid "Template icon must be a path to the image" +msgstr "L'icona del modello deve essere un percorso all'immagine" + +msgid "Template distribution must be a string" +msgstr "La distribuzione del modello deve essere una stringa" + +msgid "Template distribution version must be a string" +msgstr "La versione della distribuzione del modello deve essere una stringa" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "Il numero di CPU deve essere un numero intero" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "" +"La quantit�� di memoria (MB) deve essere un numero intero maggiore di 512" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "Il CDROM del modello deve essere un file ISO locale o remoto" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "URI pool di memoria non valido: %(value)s specificato per il modello" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "Specificare un'immagine ISO come CDROM per creare un modello" + +msgid "All networks for the template must be specified in a list." +msgstr "Tutte le reti per il modello devono essere specificate in un elenco." + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "Impossibile creare il modello a causa dell'errore: %(err)s" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "Impossibile eliminare il modello a causa dell'errore: %(err)s" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "" + +msgid "Template base image must be a valid local image file" +msgstr "Il CDROM del modello deve essere un file ISO locale o remoto" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "Pool di memoria %(name)s gi�� esistente" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "Il pool di memoria %(name)s non esiste" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "Specificare %(item)s per poter creare il pool di memoria %(name)s" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "Impossibile eliminare il pool di memoria attivo %(name)s" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "Impossibile elencare i pool di memoria. Dettagli: %(err)s" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "Impossibile creare il pool di memoria %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "" +"Impossibile ottenere il numero di volumi di memoria nel pool di memoria %" +"(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "Impossibile attivare il pool di memoria %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "Impossibile disattivare il pool di memoria %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "Impossibile eliminare il pool di memoria %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" +"Impossibile creare il pool NFS poich�� il percorso di esportazione %(path)s " +"potrebbe bloccarsi durante il montaggio" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" +"Impossibile creare il pool NFS poich�� il montaggio del percorso di " +"esportazione %(path)s ha avuto esito negativo" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "Tipo di pool di memoria non supportato: %(type)s" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" + +msgid "Storage pool path must be a string" +msgstr "Il percorso del pool di memoria deve essere una stringa" + +msgid "Storage pool host must be a IP or hostname" +msgstr "L'host del pool di memoria deve essere un nome host o IP" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" + +msgid "Storage pool devices parameter must be a list" +msgstr "Il parametro dispositivi pool di memoria deve essere un elenco" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "L'IQN di destinazione di un pool iSCSI deve essere una stringa" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" +"La porta di un server di memoria remoto deve essere un numero intero tra 1 e " +"65535" + +msgid "iSCSI target username must be a string" +msgstr "" + +msgid "iSCSI target password must be a string" +msgstr "" + +msgid "Specify name and type to create a storage pool" +msgstr "Specificare nome e tipo per creare un pool di memoria" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "" +"%(disk)s non �� un disco/partizione valido. Impossibile aggiungerlo al pool %" +"(pool)s." + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "" +"Solo il parametro dischi pu�� essere aggiornato per il pool di memoria logico." + +msgid "The SCSI host adapter name must be a string." +msgstr "Il nome adattatore host SCSI deve essere una stringa." + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "Il pool di memoria kimchi_isos �� riservato per uso interno" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"Impossibile attivare il pool di memoria NFS %(name)s. Il server NFS %(server)" +"s �� irraggiungibile." + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"Impossibile disattivare il pool di memoria NFS %(name)s. Il server NFS %" +"(server)s �� irraggiungibile." + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "" +"Impossibile disattivare il pool %(name)s poich�� �� associato ad alcuni modelli" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "" +"Impossibile eliminare il pool %(name)s poich�� �� associato ad alcuni modelli" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "" +"Un gruppo di volumi denominato '%(name)s' esiste gi��. Scegliere un altro " +"nome per creare il pool logico." + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "" +"Impossibile aggiornare il database con informazioni approfondite sulla " +"scansione a causa dell'errore: %(err)s" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "Volume di memoria %(name)s gi�� esistente" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "Il volume di memoria %(name)s non esiste nel pool di memoria %(pool)s" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "Specificare %(item)s per poter creare il volume di memoria %(volume)s" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "" +"Impossibile elencare i volumi di memoria poich�� il pool di memoria %(pool)s " +"non �� attivo" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "" +"Impossibile creare il volume di memoria %(name)s nel pool di memoria %(pool)" +"s. Dettagli: %(err)s" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "" +"Impossibile elencare i volumi di memoria nel pool di memoria %(pool)s. " +"Dettagli: %(err)s" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "Impossibile ripulire i volumi di memoria %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "Impossibile eliminare il volume di memoria %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "" +"Impossibile ridimensionare il volume di memoria %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "" +"Il tipo di memoria %(type)s non supporta la creazione ed eliminazione del " +"volume" + +msgid "Storage volume name must be a string" +msgstr "Il nome del volume di memoria deve essere una stringa" + +msgid "Storage volume allocation must be an integer number" +msgstr "L'assegnazione del volume di memoria deve essere un numero intero" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" + +msgid "Storage volume requires a volume name" +msgstr "Il volume di memoria richiede un nome volume" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "" +"Impossibile aggiornare il database con informazioni sul volume di memoria a " +"causa dell'errore: %(err)s" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "" + +msgid "Storage volume capacity must be an integer number." +msgstr "" + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "" + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "L'interfaccia %(name)s non esiste" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "Rete %(name)s gi�� esistente" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "La rete %(name)s non esiste" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" +"La sottorete %(subnet)s specificata per la rete %(network)s non �� valida ." + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" +"Specificare un'interfaccia di rete per creare la rete con bridge %(name)s" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "Impossibile eliminare la rete attiva %(name)s" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" +"L'interfaccia %(iface)s specificata per la rete %(network)s �� gi�� in uso" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "" +"L'interfaccia deve essere un dispositivo bridge o di collegamento NIC bare-" +"metal." + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "Impossibile creare la rete %(name)s. Dettagli: %(err)s" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "Impossibile trovare un indirizzo IP libero per la rete '%(name)s'" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "L'interfaccia %(iface)s gi�� esistente." + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "I tipi di rete supportati sono isolata, NAT e bridge" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "" +"La sottorete della rete deve essere una stringa con indirizzo IP e prefisso " +"o maschera di rete" + +msgid "Network interface must be a string" +msgstr "L'interfaccia di rete deve essere una stringa" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "L'ID VLAN di rete deve essere un numero intero tra 1 e 4094" + +msgid "Specify name and type to create a Network" +msgstr "Specificare nome e tipo per creare una rete" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" +"Impossibile eliminare la rete %(name)s. Ci sono alcune macchine virtuali %" +"(vms)s e/o modelli collegati a tale rete." + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" +"Impossibile disattivare la rete %(name)s. Ci sono alcune macchine virtualie %" +"(vms)s e/o modelli collegati a tale rete." + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "" +"Il dispositivo bridge %(name)s non pu�� essere il dispositivo trunk di una " +"VLAN." + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "Impossibile attivare l'interfaccia %(iface)s: %(err)s." + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "" +"Impossibile attivare l'interfaccia %(iface)s. Controllare lo stato del link " +"fisico." + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "Il report di debug %(name)s non esiste" + +msgid "Debug report tool not found in system" +msgstr "Strumento report di debug non trovato nel sistema" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "Impossibile creare il report di debug %(name)s. Dettagli: %(err)s." + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "Impossibile generare il report di debug %(name)s. Dettagli: %(err)s" + +msgid "You should give a name for the debug report file." +msgstr "" + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "" +"Un gruppo di volumi denominato '%(name)s' esiste gi��. Scegliere un altro " +"nome per creare il pool logico." + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "Il server di memoria %(server)s non �� stato utilizzato da Kimchi" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "Distro '%(name)s' non esistente" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "La partizione %(name)s non esiste nell'host" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" +"Impossibile arrestare la macchina host poich�� sono presenti macchine " +"virtuali in esecuzione" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" +"Impossibile riavviare la macchina host poich�� sono presenti macchine " +"virtuali in esecuzione" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "Dispositivo nodo '%(name)s' non trovato" + +msgid "Conflicting flag filters specified." +msgstr "" + +msgid "No packages marked for update" +msgstr "Nessun pacchetto contrassegnato per l'aggiornamento" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "Il pacchetto %(name)s non �� contrassegnato per l'aggiornamento." + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "" +"Errore durante il richiamo dei pacchetti contrassegnati per l'aggiornamento. " +"Dettagli: %(err)s" + +msgid "There is no compatible package manager for this system." +msgstr "Non �� presente un gestore pacchetti compatibile per questo sistema." + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "URI %(uri)s non valido" + +msgid "Unable to choose a virtual machine name" +msgstr "" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "Tipo di memoria non valido. I tipi supportati sono: 'cdrom'" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" + +msgid "Only CDROM path can be update." +msgstr "" + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "" +"Errore durante la creazione del nuovo dispositivo di memoria: %(error)s" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "Errore durante l'aggiornamento del dispositivo di memoria: %(error)s" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "Errore durante la rimozione del dispositivo di memoria: %(error)s" + +msgid "Do not support IDE device hot plug" +msgstr "" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "" +"Specificare tipo e percorso per aggiungere un nuovo disco della macchina " +"virtuale" + +msgid "Specify path to update virtual machine disk" +msgstr "" +"Specificare il percorso per aggiornare il disco della macchina virtuale" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" + +msgid "Volume already in use by other virtual machine." +msgstr "" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "" +"Specificare tipo e percorso per aggiungere un nuovo disco della macchina " +"virtuale" + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" + +msgid "YUM Repository ID must be one word only string." +msgstr "L'ID repository YUM deve essere una stringa di una sola parola." + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "L'URL del repository deve essere http://, ftp:// o file:// URL." + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "" +"La configurazione del repository �� un dizionario con valori specifici in " +"base al tipo di repository." + +msgid "Distribution to DEB repository must be a string" +msgstr "La distribuzione al repository DEB deve essere una stringa" + +msgid "Components to DEB repository must be listed in a array" +msgstr "I componenti per il repository DEB devono essere elencati in un array" + +msgid "Components to DEB repository must be a string" +msgstr "I componenti per il repository DEB devono essere una stringa" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "Il nome del repository YUM deve essere una stringa." + +msgid "GPG check must be a boolean value." +msgstr "Il controllo GPG deve essere un valore booleano." + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "La chiave GPG deve essere un URL che punta al file blindato ASCII." + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "Impossibile aggiornare il repository %(repo_id)s." + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "Il repository %(repo_id)s non esiste." + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "" +"Lo strumento di gestione del repository non �� stato riconosciuto per il " +"sistema." + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "Il repository %(repo_id)s �� gi�� abilitato." + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "Il repository %(repo_id)s �� gi�� disabilitato." + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "Impossibile rimuovere il repository %(repo_id)s." + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "" +"Impossibile scrivere il file di configurazione del repository %(repo_file)s" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "" +"Specificare la distribuzione del repository per poter creare un repository " +"DEB." + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "Impossibile abilitare il repository %(repo_id)s." + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "Impossibile disabilitare il repository %(repo_id)s." + +msgid "YUM Repository ID already exists" +msgstr "ID repository YUM gi�� esistente" + +msgid "YUM Repository name must be a string" +msgstr "Il nome del repository YUM deve essere una stringa" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "Impossibile elencare i repository. Dettagli: '%(err)s'" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "" +"Impossibile richiamare le informazioni sul repository. Dettagli: '%(err)s'" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "Impossibile aggiungere il repository. Dettagli: '%(err)s'" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "Impossibile rimuovere il repository. Dettagli: '%(err)s'" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" + +msgid "The number of vCPUs is too large for this system." +msgstr "" + +msgid "Invalid vCPU/topology combination." +msgstr "" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "" + +msgid "ERROR CODE" +msgstr "CODICE DI ERRORE" + +msgid "REASON" +msgstr "CAUSA" + +msgid "STACK" +msgstr "STACK" + +msgid "Go to Homepage" +msgstr "Vai alla home page" + +msgid "Create a New Virtual Machine" +msgstr "Crea una nuova macchina virtuale" + +msgid "Virtual Machine Name" +msgstr "Nome macchina virtuale" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" +"Il nome utilizzato per identificare la macchina virtuale. Se il nome viene " +"omesso ne verr�� scelto uno in base al modello utilizzato." + +msgid "Template" +msgstr "Modello" + +msgid "Please create a template first." +msgstr "Creare prima un modello." + +msgid "Create a Template" +msgstr "Crea un modello" + +msgid "Please choose a template." +msgstr "Scegliere un modello." + +msgid "OS" +msgstr "SO" + +msgid "OS Version" +msgstr "Versione SO" + +msgid "CPUS" +msgstr "CPUS" + +msgid "Memory" +msgstr "Memoria" + +msgid "Create" +msgstr "Crea" + +msgid "Creating..." +msgstr "" + +msgid "Cancel" +msgstr "Annulla" + +msgid "Edit Guest" +msgstr "Modifica guest" + +msgid "General" +msgstr "Generale" + +msgid "Storage" +msgstr "Memoria" + +msgid "Interface" +msgstr "Interfaccia" + +msgid "Permission" +msgstr "Versione" + +msgid "Host PCI Device" +msgstr "" + +msgid "Snapshot" +msgstr "" + +msgid "Name" +msgstr "Nome" + +msgid "CPUs" +msgstr "CPU" + +msgid "Memory (MB)" +msgstr "Memoria" + +msgid "Icon" +msgstr "Icona" + +msgid "Device" +msgstr "Nome dispositivo" + +msgid "Path" +msgstr "Percorso NFS" + +msgid "Network" +msgstr "Rete" + +msgid "Type" +msgstr "Tipo" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "" + +msgid "Selected system users and groups" +msgstr "" + +msgid "User" +msgstr "" + +msgid "All" +msgstr "Tutti" + +msgid "To Add" +msgstr "" + +msgid "Added" +msgstr "" + +msgid "filter" +msgstr "" + +msgid "Product" +msgstr "" + +msgid "Vendor" +msgstr "Fornitore" + +msgid "Created" +msgstr "" + +msgid "Save" +msgstr "Salva" + +msgid "Replace" +msgstr "Sostituisci" + +msgid "Detach" +msgstr "Scollega" + +msgid "revert" +msgstr "" + +msgid "Start" +msgstr "Avvia" + +msgid "Reset" +msgstr "Reimposta" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "" + +msgid "Actions" +msgstr "Azioni" + +msgid "Connect" +msgstr "Connetti" + +msgid "Clone" +msgstr "" + +msgid "Edit" +msgstr "Modifica" + +msgid "Shut Down" +msgstr "Arresta" + +msgid "Delete" +msgstr "Elimina" + +msgid "CPU" +msgstr "CPU" + +msgid "Disk I/O" +msgstr "I/O disco" + +msgid "Network I/O" +msgstr "I/O di rete" + +msgid "Livetile" +msgstr "Riquadro animato" + +msgid "No guests found." +msgstr "Nessuna macchina guest trovata." + +msgid "Add a Storage Device to VM" +msgstr "Aggiungi un dispositivo di memoria alla VM" + +msgid "Device Type" +msgstr "Tipo dispositivo" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "Il tipo di dispositivo. Attualmente, �� supportato solo \"cdrom\"." + +msgid "Storage Pool" +msgstr "Pool di memoria" + +msgid "Storage pool which volume located in" +msgstr "Il percorso del pool di memoria deve essere una stringa" + +msgid "Storage Volume" +msgstr "Nome pool di memoria" + +msgid "Storage volume to be attached" +msgstr "Il nome del volume di memoria deve essere una stringa" + +msgid "File Path" +msgstr "Percorso file" + +msgid "The ISO file path in the server for CDROM." +msgstr "Il percorso file ISO nel server per CDROM." + +msgid "Attach" +msgstr "Allega" + +msgid "Shut down" +msgstr "Arresta" + +msgid "Restart" +msgstr "Riavvia" + +msgid "Basic Information" +msgstr "Informazioni di base" + +msgid "OS Distro" +msgstr "Distro SO" + +msgid "OS Code Name" +msgstr "Nome codice SO" + +msgid "Processor" +msgstr "Processore" + +msgid "CPU(s)" +msgstr "" + +msgid "System Statistics" +msgstr "Statistiche di sistema" + +msgid "Software Updates" +msgstr "Aggiornamenti del software" + +msgid "Update Progress" +msgstr "Avanzamento aggiornamento" + +msgid "Repositories" +msgstr "Repository" + +msgid "Debug Reports" +msgstr "Report di debug" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "" +"Il nome utente o la password immessi non sono corretti. Ripetere " +"l'operazione." + +msgid "This field is required." +msgstr "Questo campo �� obbligatorio." + +msgid "Log in" +msgstr "Accedi" + +msgid "Logging in..." +msgstr "Accesso in corso..." + +msgid "Host" +msgstr "Host" + +msgid "Guests" +msgstr "Guest" + +msgid "Templates" +msgstr "Modelli" + +msgid "Failed to get application configuration" +msgstr "Richiamo della configurazione dell'applicazione non riuscito" + +msgid "This is not a valid Linux path" +msgstr "Non �� un percorso Linux valido" + +msgid "This is not a valid URL." +msgstr "Non �� un URL valido." + +msgid "No such data available." +msgstr "Dati indicati non disponibili." + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" +"Impossibile contattare il sistema host. Verificare che il sistema host sia " +"attivo e che si disponga della connettivit�� di rete per tale sistema. " +"Risposta alla richiesta HTTP %1. " + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "Conferma eliminazione" + +msgid "OK" +msgstr "OK" + +msgid "Confirm" +msgstr "Conferma" + +msgid "Warning" +msgstr "Avvertenza" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "Caricamento in corso..." + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "Riprova" + +msgid "Detailed message:" +msgstr "Messaggio dettagliato:" + +msgid "No ISO found" +msgstr "" + +msgid "This is not a valid ISO file." +msgstr "Non �� un file ISO valido." + +msgid "This may take a long time. Do you want to continue?" +msgstr "Richieder�� molto tempo. Continuare?" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "L'azione eliminer�� permanentemente il modello. Continuare?" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" +"Impossibile arrestare il sistema poich�� sono in esecuzione alcune macchine " +"virtuali." + +msgid "Max:" +msgstr "Massimo:" + +msgid "Utilization" +msgstr "Utilizzo" + +msgid "Available" +msgstr "Disponibile" + +msgid "Read Rate" +msgstr "Velocit�� di lettura" + +msgid "Write Rate" +msgstr "Velocit�� di scrittura" + +msgid "Received" +msgstr "Ricevuti" + +msgid "Sent" +msgstr "Inviati" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"L'arresto o il riavvio dell'host provocher�� la perdita del lavoro non " +"salvato. Continuare con l'arresto o il riavvio?" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"Il repository verr�� rimosso permanentemente e non potr�� essere ripristinato. " +"Si desidera continuare?" + +msgid "ID" +msgstr "ID" + +msgid "Base URL" +msgstr "URL di base" + +msgid "Is Mirror" +msgstr "�� speculare" + +msgid "URL Args" +msgstr "Argomenti URL" + +msgid "Enabled" +msgstr "Abilitato" + +msgid "GPG Check" +msgstr "Controllo GPG" + +msgid "GPG Key" +msgstr "Chiave GPG" + +msgid "Add" +msgstr "Aggiungi" + +msgid "Remove" +msgstr "Rimuovi" + +msgid "Enable" +msgstr "Abilita" + +msgid "Disable" +msgstr "Disabilita" + +msgid "Package Name" +msgstr "Nome pacchetto" + +msgid "Version" +msgstr "Versione" + +msgid "Architecture" +msgstr "Architettura" + +msgid "Repository" +msgstr "Repository" + +msgid "Update All" +msgstr "Aggiorna tutto" + +msgid "Updating..." +msgstr "Aggiornamento in corso..." + +msgid "Failed to retrieve packages update information." +msgstr "" + +msgid "Failed to update package(s)." +msgstr "Aggiornamento dei pacchetti non riuscito." + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"Il report del debug verr�� rimosso permanentemente e non potr�� essere " +"ripristinato. Si desidera continuare?" + +msgid "Generated Time" +msgstr "Ora di creazione" + +msgid "Generate" +msgstr "Crea" + +msgid "Generating..." +msgstr "Creazione in corso..." + +msgid "Rename" +msgstr "Ridenomina" + +msgid "Download" +msgstr "Scarica" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "" +"Il nome del report pu�� contenere solo lettere, cifre e/o trattini ('-')." + +msgid "Pending..." +msgstr "Caricamento in corso..." + +msgid "Report name is the same as the original one." +msgstr "" + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "" +"L'operazione eliminer�� la macchina virtuale e i relativi dischi virtuali e " +"non �� reversibile. Continuare?" + +msgid "Power off Confirmation" +msgstr "Conferma eliminazione" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" + +msgid "Reset Confirmation" +msgstr "Conferma eliminazione" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" + +msgid "Shut Down Confirmation" +msgstr "Conferma eliminazione" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "L'azione eliminer�� permanentemente il modello. Continuare?" + +msgid "Virtual Machine delete Confirmation" +msgstr "" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" +"Il CDROM verr�� scollegato permanentemente e non sar�� possibile ricollegarlo. " +"Continuare con lo scollegamento?" + +msgid "Attaching..." +msgstr "Collegamento in corso..." + +msgid "Replacing..." +msgstr "Sostituzione in corso..." + +msgid "Successfully attached!" +msgstr "Collegamento riuscito." + +msgid "Successfully replaced!" +msgstr "Sostituzione riuscita." + +msgid "Successfully detached!" +msgstr "Scollegamento riuscito." + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" + +msgid "interface:" +msgstr "" + +msgid "address:" +msgstr "" + +msgid "link_type:" +msgstr "" + +msgid "block:" +msgstr "" + +msgid "drive_type:" +msgstr "" + +msgid "model:" +msgstr "" + +msgid "Affected devices:" +msgstr "" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "L'ID VLAN deve essere compreso tra 1 e 4094." + +msgid "unavailable" +msgstr "non disponibile" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "" +"L'azione interromper�� la connettivit�� di rete per qualsiasi macchina " +"virtuale che dipende da questa rete." + +msgid "Create a network" +msgstr "Crea una rete" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"Il pool di memoria non �� permanente. Invece di disattivarlo, l'azione lo " +"eliminer�� permanentemente. Continuare?" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "L'azione eliminer�� permanentemente il pool di memoria. Continuare?" + +msgid "This storage pool is empty." +msgstr "Il pool di memoria �� vuoto." + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "" +"Il disco verr�� formattato e tutti i dati su di esso andranno persi, sicuri " +"di voler continuare? " + +msgid "SCSI Fibre Channel" +msgstr "Canale a fibre ottiche SCSI" + +msgid "No SCSI adapters found." +msgstr "Nessun adattatore SCSI trovato." + +msgid "Loading iSCSI targets..." +msgstr "" + +msgid "No iSCSI found. Please input one." +msgstr "" + +msgid "Failed to load iSCSI targets." +msgstr "" + +msgid "The storage pool name can not be blank." +msgstr "Il campo per il nome del pool di memoria non pu�� essere vuoto." + +msgid "The storage pool path can not be blank." +msgstr "Il campo per il percorso del pool di memoria non pu�� essere vuoto." + +msgid "NFS server mount path can not be blank." +msgstr "" +"Il campo per il percorso di montaggio del server NFS non pu�� essere vuoto." + +msgid "Invalid NFS mount path." +msgstr "Percorso di montaggio NFS non valido." + +msgid "No logical device selected." +msgstr "Nessun dispositivo logico selezionato." + +msgid "The iSCSI target can not be blank." +msgstr "Il campo per la destinazione iSCSI non pu�� essere vuoto." + +msgid "Server name can not be blank." +msgstr "Il campo per il nome del server non pu�� essere vuoto." + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "" + +msgid "Looking for available partitions ..." +msgstr "Ricerca di partizioni disponibili in corso..." + +msgid "No available partitions found." +msgstr "Nessuna partizione disponibile trovata." + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"Il pool di memoria non �� permanente. Invece di disattivarlo, l'azione lo " +"eliminer�� permanentemente. Continuare?" + +msgid "Unable to retrieve partitions information." +msgstr "" +"Impossibile richiamare le informazioni sul repository. Dettagli: '%(err)s'" + +msgid "In progress..." +msgstr "" + +msgid "Failed!" +msgstr "" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" + +msgid "Disk pool or volume cannot be blank." +msgstr "Il campo per il nome del pool di memoria non pu�� essere vuoto." + +msgid "Filter" +msgstr "" + +msgid "Network Name" +msgstr "Nome rete" + +msgid "State" +msgstr "Stato" + +msgid "Network Type" +msgstr "Tipo di Rete" + +msgid "Address Space" +msgstr "Spazio indirizzo" + +msgid "Name should not contain '/' and '\"'." +msgstr "Nome pool di memoria non valido. Non deve contenere '/'." + +msgid "Isolated: no external network connection" +msgstr "Isolata: nessuna connessione di rete fisica" + +msgid "NAT: outbound physical network connection only" +msgstr "NAT: solo connessione di rete fisica in uscita" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "" +"Con bridge: le macchine virtuali sono connesse direttamente alla rete fisica" + +msgid "(No interfaces found)" +msgstr "" + +msgid "Destination" +msgstr "Destinazione:" + +msgid "Enable VLAN" +msgstr "Abilita VLAN:" + +msgid "VLAN ID" +msgstr "ID VLAN:" + +msgid "Stop" +msgstr "Arresta" + +msgid "Generate a New Debug Report" +msgstr "Crea un nuovo report di debug" + +msgid "Report Name" +msgstr "Nome report" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" +"Il nome utilizzato per identificare il report. Se il nome viene omesso, ne " +"viene scelto uno in base all'ora corrente. Il nome pu�� contenere lettere, " +"cifre e trattini (\"-\")." + +msgid "Rename a Debug Report" +msgstr "Crea un nuovo report di debug" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" +"Il nome utilizzato per identificare il report. Se il nome viene omesso, ne " +"viene scelto uno in base all'ora corrente. Il nome pu�� contenere lettere, " +"cifre e trattini (\"-\")." + +msgid "Submit" +msgstr "" + +msgid "Add a Repository" +msgstr "Aggiungi un repository" + +msgid "Identifier" +msgstr "Identificativo" + +msgid "Single word, unique identifier for the repository." +msgstr "Identificativo univoco di una sola parola per il repository." + +msgid "Textual name for the repository." +msgstr "Nome in formato testo per il repository." + +msgid "URL" +msgstr "URL" + +msgid "Required Field" +msgstr "Campo obbligatorio" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "URL al repository. I protocolli supportati sono http, ftp e file." + +msgid "Repository is a mirror" +msgstr "Il repository �� un elemento speculare." + +msgid "Distribution" +msgstr "Distribuzione" + +msgid "Distribution of the DEB repository." +msgstr "Distribuzione del repository DEB." + +msgid "Components" +msgstr "Componenti" + +msgid "List of components in DEB repository." +msgstr "Elenco di componenti nel repository DEB." + +msgid "Edit Repository" +msgstr "Modifica repository" + +msgid "Mirror List URL" +msgstr "URL elenco elementi speculari" + +msgid "Yes" +msgstr "S��" + +msgid "No" +msgstr "No" + +msgid "Capacity" +msgstr "Capacit��" + +msgid "Allocated" +msgstr "Assegnato" + +msgid "Location" +msgstr "Ubicazione" + +msgid "Device path" +msgstr "Percorso dispositivo" + +msgid "active" +msgstr "attivo" + +msgid "inactive" +msgstr "non attivo" + +msgid "Deactivate" +msgstr "Disattiva" + +msgid "Activate" +msgstr "Attiva" + +msgid "Add Volume" +msgstr "" + +msgid "Extend" +msgstr "" + +msgid "Undefine" +msgstr "Rimuovi definizione" + +msgid "Format" +msgstr "Formato:" + +msgid "Allocation" +msgstr "Allocazione:" + +msgid "Define a New Storage Pool" +msgstr "Definisci un nuovo pool di memoria" + +msgid "Storage Pool Name" +msgstr "Nome pool di memoria" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "" +"Il nome utilizzato per identificare i pool di memoria; il campo non deve " +"essere vuoto." + +msgid "Storage Pool Type" +msgstr "Tipo di pool di memoria" + +msgid "Storage Path" +msgstr "Percorso di memoria" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "" +"Il percorso del pool di memoria. Ogni pool di memoria deve avere un percorso " +"univoco." + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "" +"Kimchi tenter�� di creare la directory nel caso non esista ancora sul sistema." + +msgid "NFS Server IP" +msgstr "IP server NFS" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" +"Il nome host o l'indirizzo IP del server NFS. �� possibile immetterlo o " +"sceglierlo dalla cronologia." + +msgid "NFS Path" +msgstr "Percorso NFS" + +msgid "The NFS exported path on NFS server." +msgstr "Il percorso esportato NFS sul server NFS." + +msgid "iSCSI Server" +msgstr "Server iSCSI" + +msgid "Server" +msgstr "Server" + +msgid "Port" +msgstr "Porta" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "" +"Il nome host o l'indirizzo IP del server iSCSI. Il campo non deve essere " +"vuoto." + +msgid "Target" +msgstr "Destinazione" + +msgid "The iSCSI target on iSCSI server" +msgstr "La destinazione iSCSI sul server iSCSI" + +msgid "Add iSCSI Authentication" +msgstr "Aggiungi autenticazione iSCSI" + +msgid "iSCSI Authentication" +msgstr "Autenticazione iSCSI" + +msgid "User Name" +msgstr "Nome utente" + +msgid "Password" +msgstr "Password" + +msgid "SCSI Adapter" +msgstr "Adattatore SCSI" + +msgid "Please, wait..." +msgstr "Attendere..." + +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + +msgid "Add Template" +msgstr "Aggiungi modello" + +msgid "Where is the source media for this template? " +msgstr "Dov'�� il supporto di origine per questo modello?" + +msgid "Local ISO Image" +msgstr "Immagine ISO locale" + +msgid "Local Image File" +msgstr "" + +msgid "Remote ISO Image" +msgstr "Immagine ISO remota" + +msgid "Search ISOs" +msgstr "Ricerca ISO" + +msgid "The following ISOs are available:" +msgstr "Sono disponibili i seguenti file ISO:" + +msgid "OS: " +msgstr "SO: " + +msgid "Version: " +msgstr "Versione: " + +msgid "Size: " +msgstr "Dimensione: " + +msgid "Search more ISOs" +msgstr "Ricerca pi�� ISO" + +msgid "Create Templates from Selected ISO" +msgstr "Crea modelli da ISO selezionato" + +msgid "I want to use a specific ISO file" +msgstr "Utilizzare un file ISO specifico" + +msgid "Loading default remote ISOs ..." +msgstr "Caricamento di ISO remoti predefiniti in corso..." + +msgid "Arch: " +msgstr "Arch: " + +msgid "I want to use a custom URL" +msgstr "Utilizzare un URL personalizzato" + +msgid "Edit Template" +msgstr "Modifica modello" + +msgid "CDROM" +msgstr "CDROM" + +msgid "Image File" +msgstr "" + +msgid "Graphics" +msgstr "Grafici" + +msgid "Disk(GB)" +msgstr "" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "Numero CPU" + +msgid "Manually set CPU topology" +msgstr "" + +msgid "Cores" +msgstr "" + +msgid "Threads" +msgstr "" + +msgid "No templates found." +msgstr "Nessun modello trovato." + +#~ msgid "Delete is not allowed for %(resource)s" +#~ msgstr "Eliminazione non consentita per %(resource)s" + +#~ msgid "%(resource)s does not implement update method" +#~ msgstr "%(resource)s non implementa il metodo di aggiornamento" + +#~ msgid "Create is not allowed for %(resource)s" +#~ msgstr "Creazione non consentita per %(resource)s" + +#~ msgid "Unable to parse JSON request" +#~ msgstr "Impossibile analizzare la richiesta JSON" + +#~ msgid "This API only supports JSON" +#~ msgstr "L'API supporta solo JSON" + +#~ msgid "Datastore is not initiated in the model object." +#~ msgstr "Archivio dati non inizializzato nell'oggetto modello." + +#~ msgid "Unable to start task due error: %(err)s" +#~ msgstr "Impossibile avviare l'attivit�� a causa dell'errore: %(err)s" + +#~ msgid "" +#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" +#~ msgstr "" +#~ "Autenticazione non riuscita per l'utente '%(username)s'. [Codice di " +#~ "errore: %(code)s]" + +#~ msgid "You are not authorized to access Kimchi" +#~ msgstr "Non si dispone dell'autorizzazione ad accedere a Kimchi" + +#~ msgid "Specify %(item)s to login into Kimchi" +#~ msgstr "Specificare %(item)s per accedere a Kimchi" + +#~ msgid "Unable to find %(item)s in datastore" +#~ msgstr "Impossibile trovare %(item)s nell'archivio dati" + +#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +#~ msgstr "" +#~ "�� stato raggiunto il timeout durante l'esecuzione del comando '%(cmd)s' " +#~ "dopo %(seconds)s secondi" + +#~ msgid "Help" +#~ msgstr "Guida" + +#~ msgid "About" +#~ msgstr "Info su" + +#~ msgid "Log out" +#~ msgstr "Disconnetti" + +#~ msgid "Version:" +#~ msgstr "Versione:" diff --git a/src/wok/plugins/kimchi/po/ja_JP.po b/src/wok/plugins/kimchi/po/ja_JP.po new file mode 100644 index 0000000..a3d3be3 --- /dev/null +++ b/src/wok/plugins/kimchi/po/ja_JP.po @@ -0,0 +1,2269 @@ +# English translations for kimchi package. +# Copyright (C) 2013 ORGANIZATION +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2013-07-11 17:32-0400\n" +"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" +"Language-Team: English\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ja_JP\n" +"Generated-By: pygettext.py 1.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "" + +msgid "Unknown \"_cap\" specified" +msgstr "" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "" +"������������������������������������������������������������������������������������������������: %(err)s" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" +"%(device)s ���������������������������������������������������������������������������������������������������" + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "������������������������������������������������ %(filename)s ������������������������" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "" +"������������������������������������������������ %(filename)s ���������������������������JSON ������������" +"���������������������������������������������" + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" +"iSCSI ��������������������������� %(portal)s ���������������������������������������: %(err)s" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "iSCSI ��������� %(host)s ��������������� %(target)s ������������������������������" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "ISO ������������ %(filename)s ������������������������������������������" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" +"ISO ������������ %(filename)s ������������������ El Torito ������������������������������������������" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "��������� El Torito ������������������������ ISO %(filename)s ���������������" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "��������� El Torito ������������������������������������ ISO %(filename)s ���������������" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" +"1 ������������������������������������������������������������������ ISO %(filename)s ���������������" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" +"��������������������������������������������� ISO %(filename)s ���������������������������������������" +"������������������������������������" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" +"��������������������������������� ISO %(filename)s ������������������������������������������/var/lib/" +"libvirt ���������������������������������������������������������������%(user)s���������������������������" +"���������������������������������������������������������%(user)s������ISO ���������������������������������" +"���������������������chmod -R o+x path_to_iso������������ (���������������������) ���������������" +"������������: %(err)s" + +msgid "An error occurred when probing image OS information." +msgstr "" + +msgid "No OS information found in given image." +msgstr "" + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "��������������� %(name)s ������������������������" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "��������������� %(name)s ���������������������" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "��������������������������������� %(name)s ���������������������������������������������������������" + +msgid "Remote ISO image is not supported by this server." +msgstr "������������ ISO ������������������������������������������������������������������������������" + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "��������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "��������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "��������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" +"listen ���������������������������������������������������IPv4 ��������� IPv6 ���������������������������" +"���" + +msgid "Specify a template to create a virtual machine from" +msgstr "���������������������������������������������������������������������������������" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "��������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "��������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "��������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "��������������� %(name)s ���������������������������������������: %(err)s" + +msgid "User name list must be an array" +msgstr "" + +msgid "User name must be a string" +msgstr "���������������������������������������������������������������������" + +msgid "Group name list must be an array" +msgstr "" + +msgid "Group name must be a string" +msgstr "���������������������������������������������������������������������" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "���������������%(users)s���������������������������" + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "���������������%(groups)s���������������������������" + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "��������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "��������������� %(name)s ���������������������������������: %(err)s" + +msgid "The guest console password must be a string." +msgstr "" + +msgid "The life time for the guest console password must be a number." +msgstr "" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" + +msgid "\"name\" should be a device name string" +msgstr "" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "������������������������ %(iface)s ������������������ %(name)s ������������������������" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" +"��������������� %(name)s ��������������������������������������������� %(network)s ���������������������" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"���" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"���������" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "������������������ %(name)s ������������������������" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" +"������������������ %(template)s ������������������������������������������������%(network)s������������" +"������������" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "" +"������������������ %(template)s ������������������������������������������������������ %(pool)s ������" +"���������������" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "" +"������������������ %(template)s ������������������������������������������������������ %(pool)s ������" +"���������������������������������" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "CDROM ���������������������������������������������%(param)s���������������������" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" +"������������������ %(template)s ��������������������������������������������� %(network)s ���������" +"������������������������������" + +msgid "Template name must be a string" +msgstr "���������������������������������������������������������������������" + +msgid "Template icon must be a path to the image" +msgstr "���������������������������������������������������������������������������������������" + +msgid "Template distribution must be a string" +msgstr "������������������������������������������������������������������������������������������������������" + +msgid "Template distribution version must be a string" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "CPU ������������������������������������������" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "������������������ (MB ������) ������512 ���������������������������������������������������" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "" +"������������������ CDROM ��������������������������������������� ISO ���������������������������������������" +"���" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "" +"������������������������������������ URI %(value)s ������������������������������������������������" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "" +"CDROM ������������������������������������������������������ ISO ���������������������������������������" + +msgid "All networks for the template must be specified in a list." +msgstr "������������������������������������������������������������������������������������������������������" + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "���������������������������������������������������������������������: %(err)s" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "���������������������������������������������������������������������: %(err)s" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "" + +msgid "Template base image must be a valid local image file" +msgstr "" +"������������������ CDROM ��������������������������������������� ISO ���������������������������������������" +"���" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "��������������������������� %(name)s ������������������������" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "��������������������������� %(name)s ���������������������" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "" +"��������������������������� %(name)s ������������������������������%(item)s ���������������������������" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "��������������������������������������������� %(name)s ������������������������" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "���������������������������������������������������������������: %(err)s" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "��������������������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "" +"��������������������������� %(name)s ������������������������������������������������������������������������" +"���:%(err)s" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "��������������������������� %(name)s ���������������������������������������������: %(err)s" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "��������������������������� %(name)s ������������������������������������������������: %(err)s" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "��������������������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" +"��������������������������������������������� %(path)s ���������������������������������������������������" +"������NFS ���������������������������������" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" +"��������������������������� %(path)s ���������������������������������������NFS ���������������������������" +"������" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "���������������������������������������������������������������������: %(type)s" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" + +msgid "Storage pool path must be a string" +msgstr "������������������������������������������������������������������������������������" + +msgid "Storage pool host must be a IP or hostname" +msgstr "���������������������������������������������IP ���������������������������������������������������" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" + +msgid "Storage pool devices parameter must be a list" +msgstr "���������������������������������������������������������������������������������������������������������" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "iSCSI ��������������������������� IQN ������������������������������������������������" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" +"���������������������������������������������������������������1 ������ 65535 ���������������������������������" +"������������" + +msgid "iSCSI target username must be a string" +msgstr "" + +msgid "iSCSI target password must be a string" +msgstr "" + +msgid "Specify name and type to create a storage pool" +msgstr "������������������������������������������������������������������������������������������������" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "" +"%(disk)s ���������������������������/��������������������������������������������������� %(pool)s ������" +"������������������������������" + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "" +"���������������������������������������������������������������������������������������������������������������" +"������" + +msgid "The SCSI host adapter name must be a string." +msgstr "SCSI ���������������������������������������������������������������������������������" + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "��������������������������� kimchi_isos ������������������������������������������������������" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"NFS ��������������������������� %(name)s ���������������������������������������NFS ������������ %" +"(server)s ���������������������������" + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"NFS ��������������������������� %(name)s ������������������������������������������NFS ������������ %" +"(server)s ���������������������������" + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "" +"��������� %(name)s ������������������������������������������������������������������������������������������" +"���������������������" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "" +"��������� %(name)s ������������������������������������������������������������������������������������������" +"������" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "" +"���������%(name)s���������������������������������������������������������������������������������������������" +"���������������������������������������������������" + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "" +"���������������������������������������������������������������������������������������������������������: %" +"(err)s" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "��������������������������������� %(name)s ������������������������" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "" +"��������������������������������� %(name)s ��������������������������������� %(pool)s ������������������" +"���" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "" +"��������������������������������� %(volume)s ������������������������������%(item)s ���������������������" +"������" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "" +"��������������������������� %(pool)s ������������������������������������������������������������������������" +"���������������������������" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "" +"��������������������������������� %(name)s ������������������������������ %(pool)s ���������������������" +"������������: %(err)s" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "" +"��������������������������� %(pool)s ���������������������������������������������������������������������" +"���: %(err)s" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "��������������������������� %(name)s ������������������������������������: %(err)s" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "��������������������������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "��������������������������������� %(name)s ������������������������������������������: %(err)s" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "" +"��������������������������� %(type)s ������������������������������������������������������������������������" +"���������" + +msgid "Storage volume name must be a string" +msgstr "������������������������������������������������������������������������������������" + +msgid "Storage volume allocation must be an integer number" +msgstr "������������������������������������������������������������������������������������" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" + +msgid "Storage volume requires a volume name" +msgstr "������������������������������������������������������������������������" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "" +"���������������������������������������������������������������������������������������������������������������: %" +"(err)s" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "" + +msgid "Storage volume capacity must be an integer number." +msgstr "" + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "" + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "������������������������ %(name)s ���������������������" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "������������������ %(name)s ������������������������" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "������������������ %(name)s ���������������������" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" +"������������������ %(network)s ������������������������������������������ %(subnet)s ������������������" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" +"������������������������������������ %(name)s ���������������������������������������������������������" +"���������������������������������������" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "������������������������������������ %(name)s ������������������������" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" +"������������������ %(network)s ��������������������������������������������������� %(iface)s ���������" +"���������������������������" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "" +"��������������������������������� NIC���������������������������������������������������������������������������" +"������" + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "������������������ %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "���������������������%(name)s��������������� IP ���������������������������������������" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "���������������������������������������������������������������������NAT������������������������������" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "" +"������������������������������������������IP ������������������������������������������������������������������" +"������������������������������������������������������" + +msgid "Network interface must be a string" +msgstr "���������������������������������������������������������������������������������������������" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "������������������ VLAN ID ������1 ������ 4094 ���������������������������������������������" + +msgid "Specify name and type to create a Network" +msgstr "���������������������������������������������������������������������������������������" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "" +"��������������������������� %(name)s ������VLAN ������������������������������������������������������������" +"������" + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "������������������������ %(iface)s ���������������������������������: %(err)s���" + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "" +"������������������������ %(iface)s ���������������������������������������������������������������������������" +"������������" + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "��������������������������� %(name)s ������������������������" + +msgid "Debug report tool not found in system" +msgstr "������������������������������������������������������������������������������" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "��������������������������� %(name)s ���������������������������������: %(err)s" + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "��������������������������� %(name)s ���������������������������������: %(err)s" + +msgid "You should give a name for the debug report file." +msgstr "" + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "" +"���������%(name)s���������������������������������������������������������������������������������������������" +"���������������������������������������������������" + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "" +"������������������������������ %(server)s ������Kimchi ������������������������������������������������" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "������������������������������������%(name)s������������������������" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "��������������������� %(name)s ������������������������������������" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "���������������������������������������������������������������������������������������������������������" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "������������������������������������������������������������������������������������������������" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "���������������������������%(name)s���������������������������" + +msgid "Conflicting flag filters specified." +msgstr "" + +msgid "No packages marked for update" +msgstr "���������������������������������������������������������������������������������" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "��������������� %(name)s ���������������������������������������������������������������" + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������������: %(err)s" + +msgid "There is no compatible package manager for this system." +msgstr "���������������������������������������������������������������������������������������" + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "��������� URI %(uri)s" + +msgid "Unable to choose a virtual machine name" +msgstr "" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "" +"���������������������������������������������������������������������������������������cdrom������������" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" + +msgid "Only CDROM path can be update." +msgstr "" + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "" +"���������������������������������������������������������������������������������������������������: %(error)s" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "" +"������������������������������������������������������������������������������������������: %(error)s" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "" +"������������������������������������������������������������������������������������������: %(error)s" + +msgid "Do not support IDE device hot plug" +msgstr "" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "������������������������������������������������������������������������������������������������" + +msgid "Specify path to update virtual machine disk" +msgstr "���������������������������������������������������������������������������������������" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" + +msgid "Volume already in use by other virtual machine." +msgstr "" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "������������������������������������������������������������������������������������������������" + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" + +msgid "YUM Repository ID must be one word only string." +msgstr "YUM ������������������ ID ������1 ���������������������������������������������������������������" + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "" +"������������������ URL ��� http://���ftp://������������ file:// URL ���������������������������" +"������" + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������������������" + +msgid "Distribution to DEB repository must be a string" +msgstr "" +"DEB ������������������������������������������������������������������������������������������������������������" + +msgid "Components to DEB repository must be listed in a array" +msgstr "" +"DEB ������������������������������������������������������������������������������������������������������������" +"������" + +msgid "Components to DEB repository must be a string" +msgstr "DEB ������������������������������������������������������������������������������������������������" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "YUM ������������������������������������������������������������������������" + +msgid "GPG check must be a boolean value." +msgstr "GPG ������������������������������������������������������������" + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "GPG ���������ASCII ��������������������������������������� URL ���������������������������������" + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "������������������ %(repo_id)s ������������������������������������" + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "������������������ %(repo_id)s ������������������������" + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "���������������������������������������������������������������������������������������" + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "������������������ %(repo_id)s ���������������������������������������" + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "������������������ %(repo_id)s ���������������������������������������" + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "������������������ %(repo_id)s ������������������������������������" + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "" +"������������������������������������ %(repo_file)s ������������������������������������������������" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "" +"DEB ������������������������������������������������������������������������������������������������������������" +"������������������������" + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "������������������ %(repo_id)s ���������������������������������������" + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "������������������ %(repo_id)s ���������������������������������������" + +msgid "YUM Repository ID already exists" +msgstr "YUM ������������������ ID ������������������������" + +msgid "YUM Repository name must be a string" +msgstr "YUM ���������������������������������������������������������������������" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "������������������������������������������������������: ���%(err)s���" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "���������������������������������������������������������: ���%(err)s���" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "���������������������������������������������������: ���%(err)s���" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "���������������������������������������������������: ���%(err)s���" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" + +msgid "The number of vCPUs is too large for this system." +msgstr "" + +msgid "Invalid vCPU/topology combination." +msgstr "" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "" + +msgid "ERROR CODE" +msgstr "���������������������" + +msgid "REASON" +msgstr "������" + +msgid "STACK" +msgstr "������������" + +msgid "Go to Homepage" +msgstr "������������������������������������" + +msgid "Create a New Virtual Machine" +msgstr "������������������������������" + +msgid "Virtual Machine Name" +msgstr "������������������" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������������������������������������������������" + +msgid "Template" +msgstr "������������������" + +msgid "Please create a template first." +msgstr "������������������������������������������������������" + +msgid "Create a Template" +msgstr "���������������������������" + +msgid "Please choose a template." +msgstr "������������������������������������������������" + +msgid "OS" +msgstr "OS" + +msgid "OS Version" +msgstr "OS ���������������" + +msgid "CPUS" +msgstr "CPU" + +msgid "Memory" +msgstr "������������" + +msgid "Create" +msgstr "������" + +msgid "Creating..." +msgstr "" + +msgid "Cancel" +msgstr "������" + +msgid "Edit Guest" +msgstr "������������������" + +msgid "General" +msgstr "������" + +msgid "Storage" +msgstr "���������������" + +msgid "Interface" +msgstr "������������������������" + +msgid "Permission" +msgstr "���������������" + +msgid "Host PCI Device" +msgstr "" + +msgid "Snapshot" +msgstr "" + +msgid "Name" +msgstr "������" + +msgid "CPUs" +msgstr "CPU" + +msgid "Memory (MB)" +msgstr "������������" + +msgid "Icon" +msgstr "������������" + +msgid "Device" +msgstr "���������������" + +msgid "Path" +msgstr "NFS ������" + +msgid "Network" +msgstr " ������������������" + +msgid "Type" +msgstr "���������" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "" + +msgid "Selected system users and groups" +msgstr "" + +msgid "User" +msgstr "" + +msgid "All" +msgstr "���������" + +msgid "To Add" +msgstr "" + +msgid "Added" +msgstr "" + +msgid "filter" +msgstr "" + +msgid "Product" +msgstr "" + +msgid "Vendor" +msgstr "������������" + +msgid "Created" +msgstr "" + +msgid "Save" +msgstr "������" + +msgid "Replace" +msgstr "������" + +msgid "Detach" +msgstr "������������" + +msgid "revert" +msgstr "" + +msgid "Start" +msgstr "������" + +msgid "Reset" +msgstr "������������" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "" + +msgid "Actions" +msgstr "���������������" + +msgid "Connect" +msgstr "������" + +msgid "Clone" +msgstr "" + +msgid "Edit" +msgstr "������" + +msgid "Shut Down" +msgstr "���������������������" + +msgid "Delete" +msgstr "������" + +msgid "CPU" +msgstr "CPU" + +msgid "Disk I/O" +msgstr "���������������������" + +msgid "Network I/O" +msgstr "���������������������������" + +msgid "Livetile" +msgstr "������������������" + +msgid "No guests found." +msgstr "������������������������������������" + +msgid "Add a Storage Device to VM" +msgstr "VM ������������������������������������������" + +msgid "Device Type" +msgstr "������������������������" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "������������������������������������������������������������������ \"cdrom\" ���������������" + +msgid "Storage Pool" +msgstr "���������������������������" + +msgid "Storage pool which volume located in" +msgstr "������������������������������������������������������������������������������������" + +msgid "Storage Volume" +msgstr "������������������������������" + +msgid "Storage volume to be attached" +msgstr "������������������������������������������������������������������������������������" + +msgid "File Path" +msgstr "���������������������" + +msgid "The ISO file path in the server for CDROM." +msgstr "��������������������� CDROM ��� ISO ������������������������" + +msgid "Attach" +msgstr "������" + +msgid "Shut down" +msgstr "���������������������" + +msgid "Restart" +msgstr "���������" + +msgid "Basic Information" +msgstr "������������" + +msgid "OS Distro" +msgstr "OS ���������������������������������" + +msgid "OS Code Name" +msgstr "OS ������������" + +msgid "Processor" +msgstr "������������������" + +msgid "CPU(s)" +msgstr "" + +msgid "System Statistics" +msgstr "������������������������" + +msgid "Software Updates" +msgstr "������������������������" + +msgid "Update Progress" +msgstr "���������������������" + +msgid "Repositories" +msgstr "������������������" + +msgid "Debug Reports" +msgstr "���������������������������" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "���������������������������������������������������������������������������������������������������������" + +msgid "This field is required." +msgstr "���������������������������������������" + +msgid "Log in" +msgstr "������������" + +msgid "Logging in..." +msgstr "���������������������������..." + +msgid "Host" +msgstr "���������" + +msgid "Guests" +msgstr "���������" + +msgid "Templates" +msgstr "������������������" + +msgid "Failed to get application configuration" +msgstr "���������������������������������������������������������������" + +msgid "This is not a valid Linux path" +msgstr "��������� Linux ���������������������������" + +msgid "This is not a valid URL." +msgstr "��������� URL ������������������������" + +msgid "No such data available." +msgstr "���������������������������������������������" + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������������������������������������������������������������������HTTP ������������ %1" + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "���������������" + +msgid "OK" +msgstr "OK" + +msgid "Confirm" +msgstr "������" + +msgid "Warning" +msgstr "������" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "������������������������..." + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "���������" + +msgid "Detailed message:" +msgstr "���������������������:" + +msgid "No ISO found" +msgstr "" + +msgid "This is not a valid ISO file." +msgstr "��������� ISO ������������������������������������" + +msgid "This may take a long time. Do you want to continue?" +msgstr "������������������������������������������������������������������������?" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "���������������������������������������������������������������������?" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" +"������������������������������������������������������������������������������������������������������������������!" + +msgid "Max:" +msgstr "������:" + +msgid "Utilization" +msgstr "���������" + +msgid "Available" +msgstr "������������" + +msgid "Read Rate" +msgstr "������������������" + +msgid "Write Rate" +msgstr "������������������" + +msgid "Received" +msgstr "������������" + +msgid "Sent" +msgstr "������������" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"���������������������/������������������������������?" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"���������������������������������������������������������������������������������������������������������?" + +msgid "ID" +msgstr "ID" + +msgid "Base URL" +msgstr "��������� URL" + +msgid "Is Mirror" +msgstr "���������" + +msgid "URL Args" +msgstr "URL ������" + +msgid "Enabled" +msgstr "������������" + +msgid "GPG Check" +msgstr "GPG ������������" + +msgid "GPG Key" +msgstr "GPG ���" + +msgid "Add" +msgstr "������" + +msgid "Remove" +msgstr "������" + +msgid "Enable" +msgstr "������������" + +msgid "Disable" +msgstr "������������" + +msgid "Package Name" +msgstr "������������������" + +msgid "Version" +msgstr "���������������" + +msgid "Architecture" +msgstr "������������������������" + +msgid "Repository" +msgstr "������������������" + +msgid "Update All" +msgstr "���������������" + +msgid "Updating..." +msgstr "���������������������..." + +msgid "Failed to retrieve packages update information." +msgstr "" + +msgid "Failed to update package(s)." +msgstr "���������������������������������������������������" + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"������������������������������������������������������������������������������������������������������������������?" + +msgid "Generated Time" +msgstr "������������" + +msgid "Generate" +msgstr "������" + +msgid "Generating..." +msgstr "���������������������..." + +msgid "Rename" +msgstr "������������" + +msgid "Download" +msgstr "������������������" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "��������������������������������������������������������������������������������� (-) ���������������" + +msgid "Pending..." +msgstr "������������������������..." + +msgid "Report name is the same as the original one." +msgstr "" + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������������������������?" + +msgid "Power off Confirmation" +msgstr "���������������" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" + +msgid "Reset Confirmation" +msgstr "���������������" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" + +msgid "Shut Down Confirmation" +msgstr "���������������" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "���������������������������������������������������������������������?" + +msgid "Virtual Machine delete Confirmation" +msgstr "" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" +"������ CDROM ������������������������������������������������������������������������������������������������?" + +msgid "Attaching..." +msgstr "���������������������..." + +msgid "Replacing..." +msgstr "���������������������..." + +msgid "Successfully attached!" +msgstr "���������������������������!" + +msgid "Successfully replaced!" +msgstr "���������������������������!" + +msgid "Successfully detached!" +msgstr "������������������������������!" + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" + +msgid "interface:" +msgstr "" + +msgid "address:" +msgstr "" + +msgid "link_type:" +msgstr "" + +msgid "block:" +msgstr "" + +msgid "drive_type:" +msgstr "" + +msgid "model:" +msgstr "" + +msgid "Affected devices:" +msgstr "" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "VLAN ID ������1 ������ 4094 ���������������������������������������" + +msgid "unavailable" +msgstr "������������" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������������������" + +msgid "Create a network" +msgstr "���������������������������" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"���������������������������������������������������������������������������������?" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "������������������������������������������������������������������������������?" + +msgid "This storage pool is empty." +msgstr "������������������������������������������������" + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "" +"���������������������������������������������������������������������������������������������������������������?" + +msgid "SCSI Fibre Channel" +msgstr "SCSI ������������������������������" + +msgid "No SCSI adapters found." +msgstr "SCSI ������������������������������������������" + +msgid "Loading iSCSI targets..." +msgstr "" + +msgid "No iSCSI found. Please input one." +msgstr "" + +msgid "Failed to load iSCSI targets." +msgstr "" + +msgid "The storage pool name can not be blank." +msgstr "���������������������������������������������������������������������������������" + +msgid "The storage pool path can not be blank." +msgstr "���������������������������������������������������������������������������������������" + +msgid "NFS server mount path can not be blank." +msgstr "NFS ���������������������������������������������������������������������������������������" + +msgid "Invalid NFS mount path." +msgstr "NFS ���������������������������������������" + +msgid "No logical device selected." +msgstr "���������������������������������������������������" + +msgid "The iSCSI target can not be blank." +msgstr "iSCSI ������������������������������������������������������������������" + +msgid "Server name can not be blank." +msgstr "������������������������������������������������������������������" + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "" + +msgid "Looking for available partitions ..." +msgstr "���������������������������������������������������������..." + +msgid "No available partitions found." +msgstr "���������������������������������������������������������������" + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"���������������������������������������������������������������������������������?" + +msgid "Unable to retrieve partitions information." +msgstr "���������������������������������������������������������: ���%(err)s���" + +msgid "In progress..." +msgstr "" + +msgid "Failed!" +msgstr "" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" + +msgid "Disk pool or volume cannot be blank." +msgstr "���������������������������������������������������������������������������������" + +msgid "Filter" +msgstr "" + +msgid "Network Name" +msgstr "���������������������" + +msgid "State" +msgstr "������" + +msgid "Network Type" +msgstr "������������������������������" + +msgid "Address Space" +msgstr "���������������������������" + +msgid "Name should not contain '/' and '\"'." +msgstr "" + +msgid "Isolated: no external network connection" +msgstr "������: ������������������������������������" + +msgid "NAT: outbound physical network connection only" +msgstr "NAT: ���������������������������������������������������������" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "������������: ������������������������������������������������������������������" + +msgid "(No interfaces found)" +msgstr "" + +msgid "Destination" +msgstr "������:" + +msgid "Enable VLAN" +msgstr "VLAN ������������������������:" + +msgid "VLAN ID" +msgstr "VLAN ID:" + +msgid "Stop" +msgstr "������" + +msgid "Generate a New Debug Report" +msgstr "������������������������������������������" + +msgid "Report Name" +msgstr "���������������" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"��������������������������������������������������������������������� (-) ������������������������" + +msgid "Rename a Debug Report" +msgstr "������������������������������������������" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"��������������������������������������������������������������������� (-) ������������������������" + +msgid "Submit" +msgstr "" + +msgid "Add a Repository" +msgstr "���������������������������" + +msgid "Identifier" +msgstr "ID" + +msgid "Single word, unique identifier for the repository." +msgstr "��������������������������� ID ������������������������������" + +msgid "Textual name for the repository." +msgstr "���������������������������������������" + +msgid "URL" +msgstr "URL" + +msgid "Required Field" +msgstr "���������������������" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "" +"��������������������� URL ��������������������������������������������������� http���ftp������������ file " +"���������" + +msgid "Repository is a mirror" +msgstr "���������������������������������������" + +msgid "Distribution" +msgstr "���������������������������������" + +msgid "Distribution of the DEB repository." +msgstr "DEB ���������������������������������������������������������" + +msgid "Components" +msgstr "���������������������" + +msgid "List of components in DEB repository." +msgstr "DEB ������������������������������������������������������������" + +msgid "Edit Repository" +msgstr "���������������������������" + +msgid "Mirror List URL" +msgstr "��������������������� URL" + +msgid "Yes" +msgstr " ������" + +msgid "No" +msgstr " ���������" + +msgid "Capacity" +msgstr "������" + +msgid "Allocated" +msgstr "������������������" + +msgid "Location" +msgstr "������������������" + +msgid "Device path" +msgstr "���������������������" + +msgid "active" +msgstr "���������������" + +msgid "inactive" +msgstr "������������������" + +msgid "Deactivate" +msgstr "���������������������������" + +msgid "Activate" +msgstr "������������������������" + +msgid "Add Volume" +msgstr "" + +msgid "Extend" +msgstr "" + +msgid "Undefine" +msgstr "���������������������" + +msgid "Format" +msgstr "������������������:" + +msgid "Allocation" +msgstr "������������:" + +msgid "Define a New Storage Pool" +msgstr "������������������������������������������" + +msgid "Storage Pool Name" +msgstr "������������������������������" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������" + +msgid "Storage Pool Type" +msgstr "���������������������������������������" + +msgid "Storage Path" +msgstr "������������������������" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "" +"���������������������������������������������������������������������������������������������������������������" +"������" + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "" +"���������������������������������������������������������������Kimchi ���������������������������������" + +msgid "NFS Server IP" +msgstr "NFS ������������ IP" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" +"NFS ������������ IP ������������������������������������������������������������������������������������������" +"���������������" + +msgid "NFS Path" +msgstr "NFS ������" + +msgid "The NFS exported path on NFS server." +msgstr "NFS ������������ NFS ������������������������������������������������" + +msgid "iSCSI Server" +msgstr "iSCSI ������������" + +msgid "Server" +msgstr "������������" + +msgid "Port" +msgstr "���������" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "iSCSI ������������ IP ���������������������������������������������������������������" + +msgid "Target" +msgstr "���������������" + +msgid "The iSCSI target on iSCSI server" +msgstr "iSCSI ������������������ iSCSI ���������������" + +msgid "Add iSCSI Authentication" +msgstr "iSCSI ���������������" + +msgid "iSCSI Authentication" +msgstr "iSCSI ������" + +msgid "User Name" +msgstr "���������������" + +msgid "Password" +msgstr "���������������" + +msgid "SCSI Adapter" +msgstr "SCSI ���������������" + +msgid "Please, wait..." +msgstr "���������������������..." + +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + +msgid "Add Template" +msgstr "���������������������������" + +msgid "Where is the source media for this template? " +msgstr "������������������������������������������������������������������������������?" + +msgid "Local ISO Image" +msgstr "������������ ISO ������������" + +msgid "Local Image File" +msgstr "" + +msgid "Remote ISO Image" +msgstr "������������ ISO ������������" + +msgid "Search ISOs" +msgstr "ISO ���������" + +msgid "The following ISOs are available:" +msgstr "������ ISO ���������������������:" + +msgid "OS: " +msgstr "OS: " + +msgid "Version: " +msgstr "���������������: " + +msgid "Size: " +msgstr "���������: " + +msgid "Search more ISOs" +msgstr "ISO ������������������" + +msgid "Create Templates from Selected ISO" +msgstr "������������ ISO ���������������������������������" + +msgid "I want to use a specific ISO file" +msgstr "��������� ISO ���������������������������" + +msgid "Loading default remote ISOs ..." +msgstr "������������������������������ ISO ���������������������������..." + +msgid "Arch: " +msgstr "������������������������: " + +msgid "I want to use a custom URL" +msgstr "������������ URL ���������������" + +msgid "Edit Template" +msgstr "���������������������������" + +msgid "CDROM" +msgstr "CDROM" + +msgid "Image File" +msgstr "" + +msgid "Graphics" +msgstr "���������������������" + +msgid "Disk(GB)" +msgstr "" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "CPU ���" + +msgid "Manually set CPU topology" +msgstr "" + +msgid "Cores" +msgstr "" + +msgid "Threads" +msgstr "" + +msgid "No templates found." +msgstr "���������������������������������������������" + +#~ msgid "Delete is not allowed for %(resource)s" +#~ msgstr "%(resource)s ���������������������������������" + +#~ msgid "%(resource)s does not implement update method" +#~ msgstr "%(resource)s ������������������������������������������������" + +#~ msgid "Create is not allowed for %(resource)s" +#~ msgstr "%(resource)s ���������������������������������" + +#~ msgid "Unable to parse JSON request" +#~ msgstr "JSON ������������������������������" + +#~ msgid "This API only supports JSON" +#~ msgstr "������ API ��� JSON ���������������������������" + +#~ msgid "Datastore is not initiated in the model object." +#~ msgstr "������������������������������������������������������������������������������������������" + +#~ msgid "Unable to start task due error: %(err)s" +#~ msgstr "������������������������������������������������������������: %(err)s" + +#~ msgid "" +#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" +#~ msgstr "" +#~ "���������������%(username)s������������������������������������[���������������������: %(code)s]" + +#~ msgid "You are not authorized to access Kimchi" +#~ msgstr "Kimchi ������������������������������������������������" + +#~ msgid "Specify %(item)s to login into Kimchi" +#~ msgstr "Kimchi ������������������������������%(item)s ������������������" + +#~ msgid "Unable to find %(item)s in datastore" +#~ msgstr "%(item)s ������������������������������������������������" + +#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +#~ msgstr "" +#~ "���������������%(cmd)s������������������������������������%(seconds)s ������������������������������" +#~ "������������������������" + +#~ msgid "Help" +#~ msgstr "���������" + +#~ msgid "About" +#~ msgstr "������������" + +#~ msgid "Log out" +#~ msgstr "���������������" + +#~ msgid "Version:" +#~ msgstr "���������������: " diff --git a/src/wok/plugins/kimchi/po/kimchi.pot b/src/wok/plugins/kimchi/po/kimchi.pot new file mode 100755 index 0000000..d4605c7 --- /dev/null +++ b/src/wok/plugins/kimchi/po/kimchi.pot @@ -0,0 +1,2074 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "" + +msgid "Unknown \"_cap\" specified" +msgstr "" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" + +msgid "An error occurred when probing image OS information." +msgstr "" + +msgid "No OS information found in given image." +msgstr "" + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" + +msgid "Remote ISO image is not supported by this server." +msgstr "" + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" + +msgid "Specify a template to create a virtual machine from" +msgstr "" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "" + +msgid "User name list must be an array" +msgstr "" + +msgid "User name must be a string" +msgstr "" + +msgid "Group name list must be an array" +msgstr "" + +msgid "Group name must be a string" +msgstr "" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "" + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "" + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "" + +msgid "The guest console password must be a string." +msgstr "" + +msgid "The life time for the guest console password must be a number." +msgstr "" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" + +msgid "\"name\" should be a device name string" +msgstr "" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" + +msgid "Template name must be a string" +msgstr "" + +msgid "Template icon must be a path to the image" +msgstr "" + +msgid "Template distribution must be a string" +msgstr "" + +msgid "Template distribution version must be a string" +msgstr "" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "" + +msgid "All networks for the template must be specified in a list." +msgstr "" + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "" + +msgid "Template base image must be a valid local image file" +msgstr "" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" + +msgid "Storage pool path must be a string" +msgstr "" + +msgid "Storage pool host must be a IP or hostname" +msgstr "" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" + +msgid "Storage pool devices parameter must be a list" +msgstr "" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" + +msgid "iSCSI target username must be a string" +msgstr "" + +msgid "iSCSI target password must be a string" +msgstr "" + +msgid "Specify name and type to create a storage pool" +msgstr "" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "" + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "" + +msgid "The SCSI host adapter name must be a string." +msgstr "" + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "" + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "" + +msgid "Storage volume name must be a string" +msgstr "" + +msgid "Storage volume allocation must be an integer number" +msgstr "" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" + +msgid "Storage volume requires a volume name" +msgstr "" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "" + +msgid "Storage volume capacity must be an integer number." +msgstr "" + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "" + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "" + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "" + +msgid "Network interface must be a string" +msgstr "" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "" + +msgid "Specify name and type to create a Network" +msgstr "" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "" + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "" + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "" + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "" + +msgid "Debug report tool not found in system" +msgstr "" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "" + +msgid "You should give a name for the debug report file." +msgstr "" + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "" + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "" + +msgid "Conflicting flag filters specified." +msgstr "" + +msgid "No packages marked for update" +msgstr "" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "" + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "" + +msgid "There is no compatible package manager for this system." +msgstr "" + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "" + +msgid "Unable to choose a virtual machine name" +msgstr "" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" + +msgid "Only CDROM path can be update." +msgstr "" + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "" + +msgid "Do not support IDE device hot plug" +msgstr "" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "" + +msgid "Specify path to update virtual machine disk" +msgstr "" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" + +msgid "Volume already in use by other virtual machine." +msgstr "" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "" + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" + +msgid "YUM Repository ID must be one word only string." +msgstr "" + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "" + +msgid "Distribution to DEB repository must be a string" +msgstr "" + +msgid "Components to DEB repository must be listed in a array" +msgstr "" + +msgid "Components to DEB repository must be a string" +msgstr "" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "" + +msgid "GPG check must be a boolean value." +msgstr "" + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "" + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "" + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "" + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "" + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "" + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "" + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "" + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "" + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "" + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "" + +msgid "YUM Repository ID already exists" +msgstr "" + +msgid "YUM Repository name must be a string" +msgstr "" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" + +msgid "The number of vCPUs is too large for this system." +msgstr "" + +msgid "Invalid vCPU/topology combination." +msgstr "" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "" + +msgid "ERROR CODE" +msgstr "" + +msgid "REASON" +msgstr "" + +msgid "STACK" +msgstr "" + +msgid "Go to Homepage" +msgstr "" + +msgid "Create a New Virtual Machine" +msgstr "" + +msgid "Virtual Machine Name" +msgstr "" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" + +msgid "Template" +msgstr "" + +msgid "Please create a template first." +msgstr "" + +msgid "Create a Template" +msgstr "" + +msgid "Please choose a template." +msgstr "" + +msgid "OS" +msgstr "" + +msgid "OS Version" +msgstr "" + +msgid "CPUS" +msgstr "" + +msgid "Memory" +msgstr "" + +msgid "Create" +msgstr "" + +msgid "Creating..." +msgstr "" + +msgid "Cancel" +msgstr "" + +msgid "Edit Guest" +msgstr "" + +msgid "General" +msgstr "" + +msgid "Storage" +msgstr "" + +msgid "Interface" +msgstr "" + +msgid "Permission" +msgstr "" + +msgid "Host PCI Device" +msgstr "" + +msgid "Snapshot" +msgstr "" + +msgid "Name" +msgstr "" + +msgid "CPUs" +msgstr "" + +msgid "Memory (MB)" +msgstr "" + +msgid "Icon" +msgstr "" + +msgid "Device" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Network" +msgstr "" + +msgid "Type" +msgstr "" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "" + +msgid "Selected system users and groups" +msgstr "" + +msgid "User" +msgstr "" + +msgid "All" +msgstr "" + +msgid "To Add" +msgstr "" + +msgid "Added" +msgstr "" + +msgid "filter" +msgstr "" + +msgid "Product" +msgstr "" + +msgid "Vendor" +msgstr "" + +msgid "Created" +msgstr "" + +msgid "Save" +msgstr "" + +msgid "Replace" +msgstr "" + +msgid "Detach" +msgstr "" + +msgid "revert" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "" + +msgid "Actions" +msgstr "" + +msgid "Connect" +msgstr "" + +msgid "Clone" +msgstr "" + +msgid "Edit" +msgstr "" + +msgid "Shut Down" +msgstr "" + +msgid "Delete" +msgstr "" + +msgid "CPU" +msgstr "" + +msgid "Disk I/O" +msgstr "" + +msgid "Network I/O" +msgstr "" + +msgid "Livetile" +msgstr "" + +msgid "No guests found." +msgstr "" + +msgid "Add a Storage Device to VM" +msgstr "" + +msgid "Device Type" +msgstr "" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "" + +msgid "Storage Pool" +msgstr "" + +msgid "Storage pool which volume located in" +msgstr "" + +msgid "Storage Volume" +msgstr "" + +msgid "Storage volume to be attached" +msgstr "" + +msgid "File Path" +msgstr "" + +msgid "The ISO file path in the server for CDROM." +msgstr "" + +msgid "Attach" +msgstr "" + +msgid "Shut down" +msgstr "" + +msgid "Restart" +msgstr "" + +msgid "Basic Information" +msgstr "" + +msgid "OS Distro" +msgstr "" + +msgid "OS Code Name" +msgstr "" + +msgid "Processor" +msgstr "" + +msgid "CPU(s)" +msgstr "" + +msgid "System Statistics" +msgstr "" + +msgid "Software Updates" +msgstr "" + +msgid "Update Progress" +msgstr "" + +msgid "Repositories" +msgstr "" + +msgid "Debug Reports" +msgstr "" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "" + +msgid "This field is required." +msgstr "" + +msgid "Log in" +msgstr "" + +msgid "Logging in..." +msgstr "" + +msgid "Host" +msgstr "" + +msgid "Guests" +msgstr "" + +msgid "Templates" +msgstr "" + +msgid "Failed to get application configuration" +msgstr "" + +msgid "This is not a valid Linux path" +msgstr "" + +msgid "This is not a valid URL." +msgstr "" + +msgid "No such data available." +msgstr "" + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "" + +msgid "OK" +msgstr "" + +msgid "Confirm" +msgstr "" + +msgid "Warning" +msgstr "" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "" + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "" + +msgid "Detailed message:" +msgstr "" + +msgid "No ISO found" +msgstr "" + +msgid "This is not a valid ISO file." +msgstr "" + +msgid "This may take a long time. Do you want to continue?" +msgstr "" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" + +msgid "Max:" +msgstr "" + +msgid "Utilization" +msgstr "" + +msgid "Available" +msgstr "" + +msgid "Read Rate" +msgstr "" + +msgid "Write Rate" +msgstr "" + +msgid "Received" +msgstr "" + +msgid "Sent" +msgstr "" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" + +msgid "ID" +msgstr "" + +msgid "Base URL" +msgstr "" + +msgid "Is Mirror" +msgstr "" + +msgid "URL Args" +msgstr "" + +msgid "Enabled" +msgstr "" + +msgid "GPG Check" +msgstr "" + +msgid "GPG Key" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Remove" +msgstr "" + +msgid "Enable" +msgstr "" + +msgid "Disable" +msgstr "" + +msgid "Package Name" +msgstr "" + +msgid "Version" +msgstr "" + +msgid "Architecture" +msgstr "" + +msgid "Repository" +msgstr "" + +msgid "Update All" +msgstr "" + +msgid "Updating..." +msgstr "" + +msgid "Failed to retrieve packages update information." +msgstr "" + +msgid "Failed to update package(s)." +msgstr "" + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" + +msgid "Generated Time" +msgstr "" + +msgid "Generate" +msgstr "" + +msgid "Generating..." +msgstr "" + +msgid "Rename" +msgstr "" + +msgid "Download" +msgstr "" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "" + +msgid "Pending..." +msgstr "" + +msgid "Report name is the same as the original one." +msgstr "" + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "" + +msgid "Power off Confirmation" +msgstr "" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" + +msgid "Reset Confirmation" +msgstr "" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" + +msgid "Shut Down Confirmation" +msgstr "" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "" + +msgid "Virtual Machine delete Confirmation" +msgstr "" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" + +msgid "Attaching..." +msgstr "" + +msgid "Replacing..." +msgstr "" + +msgid "Successfully attached!" +msgstr "" + +msgid "Successfully replaced!" +msgstr "" + +msgid "Successfully detached!" +msgstr "" + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" + +msgid "interface:" +msgstr "" + +msgid "address:" +msgstr "" + +msgid "link_type:" +msgstr "" + +msgid "block:" +msgstr "" + +msgid "drive_type:" +msgstr "" + +msgid "model:" +msgstr "" + +msgid "Affected devices:" +msgstr "" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "" + +msgid "unavailable" +msgstr "" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "" + +msgid "Create a network" +msgstr "" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "" + +msgid "This storage pool is empty." +msgstr "" + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "" + +msgid "SCSI Fibre Channel" +msgstr "" + +msgid "No SCSI adapters found." +msgstr "" + +msgid "Loading iSCSI targets..." +msgstr "" + +msgid "No iSCSI found. Please input one." +msgstr "" + +msgid "Failed to load iSCSI targets." +msgstr "" + +msgid "The storage pool name can not be blank." +msgstr "" + +msgid "The storage pool path can not be blank." +msgstr "" + +msgid "NFS server mount path can not be blank." +msgstr "" + +msgid "Invalid NFS mount path." +msgstr "" + +msgid "No logical device selected." +msgstr "" + +msgid "The iSCSI target can not be blank." +msgstr "" + +msgid "Server name can not be blank." +msgstr "" + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "" + +msgid "Looking for available partitions ..." +msgstr "" + +msgid "No available partitions found." +msgstr "" + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" + +msgid "Unable to retrieve partitions information." +msgstr "" + +msgid "In progress..." +msgstr "" + +msgid "Failed!" +msgstr "" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" + +msgid "Disk pool or volume cannot be blank." +msgstr "" + +msgid "Filter" +msgstr "" + +msgid "Network Name" +msgstr "" + +msgid "State" +msgstr "" + +msgid "Network Type" +msgstr "" + +msgid "Address Space" +msgstr "" + +msgid "Name should not contain '/' and '\"'." +msgstr "" + +msgid "Isolated: no external network connection" +msgstr "" + +msgid "NAT: outbound physical network connection only" +msgstr "" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "" + +msgid "(No interfaces found)" +msgstr "" + +msgid "Destination" +msgstr "" + +msgid "Enable VLAN" +msgstr "" + +msgid "VLAN ID" +msgstr "" + +msgid "Stop" +msgstr "" + +msgid "Generate a New Debug Report" +msgstr "" + +msgid "Report Name" +msgstr "" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" + +msgid "Rename a Debug Report" +msgstr "" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" + +msgid "Submit" +msgstr "" + +msgid "Add a Repository" +msgstr "" + +msgid "Identifier" +msgstr "" + +msgid "Single word, unique identifier for the repository." +msgstr "" + +msgid "Textual name for the repository." +msgstr "" + +msgid "URL" +msgstr "" + +msgid "Required Field" +msgstr "" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "" + +msgid "Repository is a mirror" +msgstr "" + +msgid "Distribution" +msgstr "" + +msgid "Distribution of the DEB repository." +msgstr "" + +msgid "Components" +msgstr "" + +msgid "List of components in DEB repository." +msgstr "" + +msgid "Edit Repository" +msgstr "" + +msgid "Mirror List URL" +msgstr "" + +msgid "Yes" +msgstr "" + +msgid "No" +msgstr "" + +msgid "Capacity" +msgstr "" + +msgid "Allocated" +msgstr "" + +msgid "Location" +msgstr "" + +msgid "Device path" +msgstr "" + +msgid "active" +msgstr "" + +msgid "inactive" +msgstr "" + +msgid "Deactivate" +msgstr "" + +msgid "Activate" +msgstr "" + +msgid "Add Volume" +msgstr "" + +msgid "Extend" +msgstr "" + +msgid "Undefine" +msgstr "" + +msgid "Format" +msgstr "" + +msgid "Allocation" +msgstr "" + +msgid "Define a New Storage Pool" +msgstr "" + +msgid "Storage Pool Name" +msgstr "" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "" + +msgid "Storage Pool Type" +msgstr "" + +msgid "Storage Path" +msgstr "" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "" + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "" + +msgid "NFS Server IP" +msgstr "" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" + +msgid "NFS Path" +msgstr "" + +msgid "The NFS exported path on NFS server." +msgstr "" + +msgid "iSCSI Server" +msgstr "" + +msgid "Server" +msgstr "" + +msgid "Port" +msgstr "" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "" + +msgid "Target" +msgstr "" + +msgid "The iSCSI target on iSCSI server" +msgstr "" + +msgid "Add iSCSI Authentication" +msgstr "" + +msgid "iSCSI Authentication" +msgstr "" + +msgid "User Name" +msgstr "" + +msgid "Password" +msgstr "" + +msgid "SCSI Adapter" +msgstr "" + +msgid "Please, wait..." +msgstr "" + +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + +msgid "Add Template" +msgstr "" + +msgid "Where is the source media for this template? " +msgstr "" + +msgid "Local ISO Image" +msgstr "" + +msgid "Local Image File" +msgstr "" + +msgid "Remote ISO Image" +msgstr "" + +msgid "Search ISOs" +msgstr "" + +msgid "The following ISOs are available:" +msgstr "" + +msgid "OS: " +msgstr "" + +msgid "Version: " +msgstr "" + +msgid "Size: " +msgstr "" + +msgid "Search more ISOs" +msgstr "" + +msgid "Create Templates from Selected ISO" +msgstr "" + +msgid "I want to use a specific ISO file" +msgstr "" + +msgid "Loading default remote ISOs ..." +msgstr "" + +msgid "Arch: " +msgstr "" + +msgid "I want to use a custom URL" +msgstr "" + +msgid "Edit Template" +msgstr "" + +msgid "CDROM" +msgstr "" + +msgid "Image File" +msgstr "" + +msgid "Graphics" +msgstr "" + +msgid "Disk(GB)" +msgstr "" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "" + +msgid "Manually set CPU topology" +msgstr "" + +msgid "Cores" +msgstr "" + +msgid "Threads" +msgstr "" + +msgid "No templates found." +msgstr "" diff --git a/src/wok/plugins/kimchi/po/ko_KR.po b/src/wok/plugins/kimchi/po/ko_KR.po new file mode 100644 index 0000000..08bf222 --- /dev/null +++ b/src/wok/plugins/kimchi/po/ko_KR.po @@ -0,0 +1,2197 @@ +# English translations for kimchi package. +# Copyright (C) 2013 ORGANIZATION +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2013-07-11 17:32-0400\n" +"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" +"Language-Team: English\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ko_KR\n" +"Generated-By: pygettext.py 1.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "" + +msgid "Unknown \"_cap\" specified" +msgstr "" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "������ ��������� ������������ ������ ��������� ������������������. ������������: %(err)s" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "%(device)s��� ������ ������ ������ ��������� ������������ ������ ��������� ������������������." + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "distro ��������� ������ ��� ������: %(filename)s" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "" +"distro ������(%(filename)s)��� ������ ��������� ��� ������������. JSON ������������ ���������������" +"���." + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "iSCSI ��������� ������ %(portal)s��� ������������ ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "iSCSI host %(host)s ������ %(target)s��� ������������ ��� ������������." + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "ISO ������ %(filename)s���(���) ������ ������������ ������������." + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "ISO ������ %(filename)s��� ��������� El Torito ������ ������������ ������������." + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "" +"ISO %(filename)s��� ������������ ������ El Torito ��������� ������ ��������� ������������." + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "ISO %(filename)s��� ������������ ������ El Torito ������ ������������ ������������." + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "ISO %(filename)s������ ������ ��������� ��������� ������ ������ ���������������." + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" +"ISO %(filename)s������ ������ ������������������ ������ ������ ��������� ��������� ������������������" +"���." + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" +"��������������������� ��� ISO %(filename)s���(���) ��������� ��������� ������������. ������ /var/" +"lib/libvirt ��������� ������������������, (��������� ������) ������ ��������� '%(user)s' ���������" +"��� ������ ��������� ������ ��������� ���������������, '%(user)s'���(���) ISO ������ ��������� ������" +"���������, 'chmod -R o+x 'path_to_iso'(������������ ������)��� ������������������. ������������: " +"%(err)s" + +msgid "An error occurred when probing image OS information." +msgstr "" + +msgid "No OS information found in given image." +msgstr "" + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "������ ������ %(name)s���(���) ������ ���������������." + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "������ ������ %(name)s���(���) ������������." + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "��������� ������ ������ %(name)s��� ������ ��������������� ��������� ��� ������������." + +msgid "Remote ISO image is not supported by this server." +msgstr "������ ISO ������������ ��� ������������ ������������ ������������." + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "������ ������ ��������� ��������� IPv4 ������ IPv6������ ���������." + +msgid "Specify a template to create a virtual machine from" +msgstr "������ ��������� ������������ ������ ��������������� ������������������." + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "������ ������ %(name)s��� ��������� ������ ��� ������������. ������������: %(err)s" + +msgid "User name list must be an array" +msgstr "" + +msgid "User name must be a string" +msgstr "������������ ��������� ������������������ ���������." + +msgid "Group name list must be an array" +msgstr "" + +msgid "Group name must be a string" +msgstr "������������ ��������� ������������������ ���������." + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "'%(users)s' ������������ ������������." + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "'%(groups)s' ������������ ������������." + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +msgid "The guest console password must be a string." +msgstr "" + +msgid "The life time for the guest console password must be a number." +msgstr "" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" + +msgid "\"name\" should be a device name string" +msgstr "" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "������ ������ %(name)s��� %(iface)s ������������������ ������������." + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "������ ������ %(name)s��� ������ ��������� %(network)s ��������������� ������������." + +msgid "Supported virtual machine interfaces type is only network" +msgstr "������������ ������ ������ ��������������� ��������� ������������������������." + +msgid "Network name for virtual machine interface must be a string" +msgstr "������ ������ ������������������ ������������ ��������� ������������������ ���������." + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" +"������ ������ ������������������ ������ ������������ ������ ������������ ������ ��������� ������������������" +"���." + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "��� ������ ������ ������������������ ��������� ������ ��� ��������������� ������������������." + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "������������ %(name)s���(���) ������ ���������������." + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "������������ %(template)s��� ������ ��������� '%(network)s' ��������������� ������������." + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "" +"������������ %(template)s��� ������ ��������� ������������ ��� %(pool)s���(���) ������������." + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "" +"������������ %(template)s��� ������ ��������� ������������ ��� %(pool)s���(���) ��������� ���������" +"���." + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "CDROM��� ������ ������������ ������ ������������ '%(param)s'���(���) ���������������������." + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" +"������������ %(template)s��� ������ ��������� %(network)s ��������������� ��������� ������������." + +msgid "Template name must be a string" +msgstr "������������ ��������� ������������������ ���������." + +msgid "Template icon must be a path to the image" +msgstr "������������ ������������ ������������ ������������ ���������." + +msgid "Template distribution must be a string" +msgstr "������������ ��������� ������������������ ���������." + +msgid "Template distribution version must be a string" +msgstr "������������ ������ ��������� ������������������ ���������." + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "CPU ������ ������������ ���������." + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "��������� ������(MB)��� 512������ ��� ������������ ���������." + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "������������ CDROM��� ������ ������ ������ ISO ��������������� ���������." + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "" +"��������������� ������ ������������ ������ ������������ ��� URI %(value)s���(���) ���������������������." + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "��������������� ��������������� ISO ������������ CDROM������ ������������������." + +msgid "All networks for the template must be specified in a list." +msgstr "��������������� ������ ��������������� ��������� ��������������� ���������." + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "������ ��������� ��������������� ��������� ��� ������: %(err)s" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "������ ��������� ��������������� ��������� ��� ������: %(err)s" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "" + +msgid "Template base image must be a valid local image file" +msgstr "������������ CDROM��� ������ ������ ������ ISO ��������������� ���������." + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "������������ ��� %(name)s���(���) ������ ���������������." + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "������������ ��� %(name)s���(���) ������������." + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "������������ ��� %(name)s���(���) ��������������� %(item)s���(���) ������������������." + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "������ ������������ ��� %(name)s���(���) ��������� ��� ������������." + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "������������ ������ ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "������������ ��� %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "" +"������������ ��� %(name)s��� ������ ������������ ��������� ������ ��������� ��� ������������. ���������" +"���: %(err)s" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "������������ ��� %(name)s���(���) ������������ ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "������������ ��� %(name)s���(���) ��������������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "������������ ��� %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" +"������������ ������ %(path)s���(���) ��������� ������ ��������� ��� ������������ NFS ������ ��������� " +"��� ������������." + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" +"������������ ������ %(path)s ������������ ������������������ NFS ������ ��������� ��� ������������." + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "������������ ������ ������������ ��� ������: %(type)s" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" + +msgid "Storage pool path must be a string" +msgstr "������������ ��� ��������� ������������������ ���������." + +msgid "Storage pool host must be a IP or hostname" +msgstr "������������ ��� ������������ IP ������ ��������� ��������������� ���������." + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" + +msgid "Storage pool devices parameter must be a list" +msgstr "������������ ��� ��������� ��������������� ���������." + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "iSCSI ������ ������ IQN��� ������������������ ���������." + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "������ ������������ ��������� ��������� 1��� 65535 ��������� ������������ ���������." + +msgid "iSCSI target username must be a string" +msgstr "" + +msgid "iSCSI target password must be a string" +msgstr "" + +msgid "Specify name and type to create a storage pool" +msgstr "������������ ������ ��������������� ������ ��� ��������� ������������������." + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "" +"%(disk)s���(���) ��������� ���������/������������ ������������. ������ %(pool)s ������ ��������� ��� " +"������������." + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "������ ������������ ������ ������������ ������������ ��������������� ��� ������������." + +msgid "The SCSI host adapter name must be a string." +msgstr "SCSI ��������� ��������� ��������� ������������������ ���������." + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "������������ ��� kimchi_isos��� ������ ��������� ���������������������." + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"NFS ������������ ��� %(name)s���(���) ������������ ��� ������������. NFS ������ %(server)s��� ���" +"������ ��� ������������." + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"NFS ������������ ��� %(name)s���(���) ��������������� ��� ������������. NFS ������ %(server)s��� " +"��������� ��� ������������." + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "" +"������ ��������������� ������������ ������������ %(name)s ������ ��������������� ��� ������������." + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "������ ��������������� ������������ ������������ %(name)s ������ ��������� ��� ������������." + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "" +"��������� '%(name)s'��� ������ ��������� ������ ���������������. ������ ������ ��������������� ������ ���" +"������ ������������������." + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "" +"������ ��������� ��������� ������ ��������� ��������������������� ��������������� ��� ������: %(err)s" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "������������ ������ %(name)s���(���) ������ ���������������." + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "������������ ������ %(name)s���(���) ������������ ��� %(pool)s��� ������������." + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "������������ ������ %(volume)s���(���) ��������������� %(item)s���(���) ������������������." + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "" +"������������ ��� %(pool)s���(���) ��������� ������������ ������������ ��������� ��������� ��� ���������" +"���." + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "" +"������������ ������ %(name)s���(���) ������������ ��� %(pool)s��� ��������� ��� ������������. ������" +"������: %(err)s" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "" +"������������ ��� %(pool)s��� ������������ ��������� ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "������������ ��� %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "������������ ������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "������������ ������ %(name)s��� ��������� ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "������������ ������ %(type)s���(���) ������ ������ ��� ��������� ������������ ������������." + +msgid "Storage volume name must be a string" +msgstr "������������ ������ ��������� ������������������ ���������." + +msgid "Storage volume allocation must be an integer number" +msgstr "������������ ������ ��������� ������������ ���������." + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" + +msgid "Storage volume requires a volume name" +msgstr "������������ ��������� ������ ��������� ���������������." + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "" +"������ ��������� ������������ ������ ��������� ��������������������� ��������������� ��� ������: %(err)s" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "" + +msgid "Storage volume capacity must be an integer number." +msgstr "" + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "" + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "��������������� %(name)s���(���) ������������." + +#, python-format +msgid "Network %(name)s already exists" +msgstr "������������ %(name)s���(���) ������ ���������������." + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "������������ %(name)s���(���) ������������." + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" +"������������ %(network)s��� ������ ��������� ��������� %(subnet)s���(���) ������������ ������������." + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" +"������������ ������������ %(name)s���(���) ��������� ������������ ������������������ ������������������." + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "������ ������������ %(name)s���(���) ��������� ��� ������������." + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" +"������������ %(network)s��� ������ ��������� ��������������� %(iface)s���(���) ������ ������ ������" +"������." + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "������������������ ������ NIC, ������ ������ ��������� ������������ ���������." + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "������������ %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "������������ '%(name)s'��� ������ ������ IP ��������� ������ ��� ������������." + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "������������ ������������ ��������� ������, NAT ��� ������������������." + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "" +"������������ ������������ IP ������ ��� ��������� ������ ��������������� ������ ������������������ ���������." + +msgid "Network interface must be a string" +msgstr "������������ ������������������ ������������������ ���������." + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "������������ VLAN ID��� 1��� 4094 ��������� ������������ ���������." + +msgid "Specify name and type to create a Network" +msgstr "��������������� ��������������� ������ ��� ��������� ������������������." + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "��������� ������ %(name)s���(���) VLAN��� ��������� ��������� ��� ��� ������������." + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "%(iface)s ������������������ ��������������� ������: %(err)s." + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "" +"%(iface)s ������������������ ��������������� ���������������. ��������� ������ ��������� ���������������" +"���." + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "��������� ��������� %(name)s���(���) ������������." + +msgid "Debug report tool not found in system" +msgstr "��������� ��������� ��������� ������������ ������������." + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "��������� ��������� %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "��������� ��������� %(name)s���(���) ��������� ��� ������������. ������������: %(err)s" + +msgid "You should give a name for the debug report file." +msgstr "" + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "" +"��������� '%(name)s'��� ������ ��������� ������ ���������������. ������ ������ ��������������� ������ ���" +"������ ������������������." + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "������������ ������ %(server)s���(���) Kimchi������ ������������ ���������������." + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "Distro '%(name)s'���(���) ������������." + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "��������� %(name)s���(���) ������������ ������������." + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "������ ��������� ������ ������ ��������� ��������� ��������� ��� ������������." + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "������ ��������� ������ ������ ��������� ��������� ������ ��������� ��� ������������." + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "������ ������ '%(name)s'���(���) ������������." + +msgid "Conflicting flag filters specified." +msgstr "" + +msgid "No packages marked for update" +msgstr "������������ ��������� ������������ ������������." + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "��������� %(name)s���(���) ��������������������� ������������ ���������������." + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "" +"��������������������� ��������� ������������ ������������ ������ ��������� ������������������. ������������: %" +"(err)s" + +msgid "There is no compatible package manager for this system." +msgstr "��� ������������ ������ ������ ��������� ��������� ������������ ������������." + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "������������ ������ URI %(uri)s" + +msgid "Unable to choose a virtual machine name" +msgstr "" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "������������ ������ ������������ ���������������. ������������ ������: 'cdrom'" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" + +msgid "Only CDROM path can be update." +msgstr "" + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "��� ������������ ��������� ������������ ������ ������ ������: %(error)s" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "������������ ��������� ������������������ ������ ������ ������: %(error)s" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "������������ ��������� ������������ ������ ������ ������: %(error)s" + +msgid "Do not support IDE device hot plug" +msgstr "" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "��� ������ ������ ������������ ��������� ������ ��� ��������� ������������������." + +msgid "Specify path to update virtual machine disk" +msgstr "������ ������ ������������ ��������������� ��������� ������������������." + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" + +msgid "Volume already in use by other virtual machine." +msgstr "" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "��� ������ ������ ������������ ��������� ������ ��� ��������� ������������������." + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" + +msgid "YUM Repository ID must be one word only string." +msgstr "YUM ��������� ID��� ������ ��������� ������������������ ���������." + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "��������� URL��� http://, ftp:// ������ file:// URL��������� ���������." + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "��������� ��������� ��������� ��������� ������ ������ ������ ������ ���������������." + +msgid "Distribution to DEB repository must be a string" +msgstr "DEB ������������ ������ ��������� ������������������ ���������." + +msgid "Components to DEB repository must be listed in a array" +msgstr "DEB ������������ ������ ��������������� ��������� ��������������� ���������." + +msgid "Components to DEB repository must be a string" +msgstr "DEB ������������ ������ ��������������� ������������������ ���������." + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "YUM ��������� ��������� ������������������ ���������." + +msgid "GPG check must be a boolean value." +msgstr "GPG ��������� ������ ������������ ���������." + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "GPG ������ ASCII ������ ��������� ������������ URL��������� ���������." + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "%(repo_id)s ������������ ��������������� ��� ������������." + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "%(repo_id)s ������������ ������������." + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "������ ������������ ������ ��������� ������ ��������� ������������ ���������������." + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "%(repo_id)s ������������ ������ ������������ ������������ ������������." + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "%(repo_id)s ������������ ������ ������ ������������ ������������ ������������." + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "%(repo_id)s ������������ ��������� ��� ������������." + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "��������� ������ ������ %(repo_file)s���(���) ��������� ��� ������������." + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "DEB ������������ ��������������� ��������� ��������� ������������������." + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "%(repo_id)s ������������ ������������ ��������� ��� ������������." + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "%(repo_id)s ������������ ������ ������������ ��������� ��� ������������." + +msgid "YUM Repository ID already exists" +msgstr "YUM ��������� ID��� ������ ���������������." + +msgid "YUM Repository name must be a string" +msgstr "YUM ��������� ��������� ������������������ ���������." + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "������������ ��������� ��� ������������. ������������: '%(err)s'" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "��������� ��������� ��������� ��� ������������. ������������: '%(err)s'" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "������������ ��������� ��� ������������. ������������: '%(err)s'" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "������������ ��������� ��� ������������. ������������: '%(err)s'" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" + +msgid "The number of vCPUs is too large for this system." +msgstr "" + +msgid "Invalid vCPU/topology combination." +msgstr "" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "" + +msgid "ERROR CODE" +msgstr "������ ������" + +msgid "REASON" +msgstr "������" + +msgid "STACK" +msgstr "������" + +msgid "Go to Homepage" +msgstr "��� ������������ ������" + +msgid "Create a New Virtual Machine" +msgstr "��� ������ ������ ������" + +msgid "Virtual Machine Name" +msgstr "������ ������ ������" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" +"������ ��������� ������������ ��� ������������ ���������������. ������������ ��������� ��������� ������������" +"��� ������������ ���������������." + +msgid "Template" +msgstr "������������" + +msgid "Please create a template first." +msgstr "��������������� ������ ������������������." + +msgid "Create a Template" +msgstr "������������ ������" + +msgid "Please choose a template." +msgstr "��������������� ������������������." + +msgid "OS" +msgstr "OS" + +msgid "OS Version" +msgstr "OS ������" + +msgid "CPUS" +msgstr "CPUS" + +msgid "Memory" +msgstr "���������" + +msgid "Create" +msgstr "������" + +msgid "Creating..." +msgstr "" + +msgid "Cancel" +msgstr "������" + +msgid "Edit Guest" +msgstr "��������� ������" + +msgid "General" +msgstr "������" + +msgid "Storage" +msgstr "������������" + +msgid "Interface" +msgstr "���������������" + +msgid "Permission" +msgstr "������" + +msgid "Host PCI Device" +msgstr "" + +msgid "Snapshot" +msgstr "" + +msgid "Name" +msgstr "������" + +msgid "CPUs" +msgstr "CPU" + +msgid "Memory (MB)" +msgstr "���������" + +msgid "Icon" +msgstr "���������" + +msgid "Device" +msgstr "������ ������" + +msgid "Path" +msgstr "NFS ������" + +msgid "Network" +msgstr "������������" + +msgid "Type" +msgstr "������" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "" + +msgid "Selected system users and groups" +msgstr "" + +msgid "User" +msgstr "" + +msgid "All" +msgstr "������" + +msgid "To Add" +msgstr "" + +msgid "Added" +msgstr "" + +msgid "filter" +msgstr "" + +msgid "Product" +msgstr "" + +msgid "Vendor" +msgstr "������������" + +msgid "Created" +msgstr "" + +msgid "Save" +msgstr "������" + +msgid "Replace" +msgstr "������" + +msgid "Detach" +msgstr "������" + +msgid "revert" +msgstr "" + +msgid "Start" +msgstr "������" + +msgid "Reset" +msgstr "������ ������" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "" + +msgid "Actions" +msgstr "������" + +msgid "Connect" +msgstr "������" + +msgid "Clone" +msgstr "" + +msgid "Edit" +msgstr "������" + +msgid "Shut Down" +msgstr "��������� ������" + +msgid "Delete" +msgstr "������" + +msgid "CPU" +msgstr "CPU" + +msgid "Disk I/O" +msgstr "��������� I/O" + +msgid "Network I/O" +msgstr "������������ I/O" + +msgid "Livetile" +msgstr "���������������" + +msgid "No guests found." +msgstr "������������ ������������." + +msgid "Add a Storage Device to VM" +msgstr "������������ ��������� VM��� ������" + +msgid "Device Type" +msgstr "������ ������" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "������ ���������������. ������ \"cdrom\"��� ���������������." + +msgid "Storage Pool" +msgstr "������������ ���" + +msgid "Storage pool which volume located in" +msgstr "������������ ��� ��������� ������������������ ���������." + +msgid "Storage Volume" +msgstr "������������ ��� ������" + +msgid "Storage volume to be attached" +msgstr "������������ ������ ��������� ������������������ ���������." + +msgid "File Path" +msgstr "������ ������" + +msgid "The ISO file path in the server for CDROM." +msgstr "CDROM��� ������ ��������� ISO ������ ���������������." + +msgid "Attach" +msgstr "������" + +msgid "Shut down" +msgstr "��������� ������" + +msgid "Restart" +msgstr "������ ������" + +msgid "Basic Information" +msgstr "������ ������" + +msgid "OS Distro" +msgstr "OS Distro" + +msgid "OS Code Name" +msgstr "OS ������ ������" + +msgid "Processor" +msgstr "������������" + +msgid "CPU(s)" +msgstr "" + +msgid "System Statistics" +msgstr "��������� ������" + +msgid "Software Updates" +msgstr "��������������� ������������" + +msgid "Update Progress" +msgstr "������������ ������������" + +msgid "Repositories" +msgstr "���������" + +msgid "Debug Reports" +msgstr "��������� ���������" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "" +"��������� ��������� ������ ������ ��������������� ������������ ������������. ������ ������������������." + +msgid "This field is required." +msgstr "��� ��������� ���������������." + +msgid "Log in" +msgstr "���������" + +msgid "Logging in..." +msgstr "��������� ���..." + +msgid "Host" +msgstr "���������" + +msgid "Guests" +msgstr "���������" + +msgid "Templates" +msgstr "������������" + +msgid "Failed to get application configuration" +msgstr "������������������ ��������� ������������ ���������������." + +msgid "This is not a valid Linux path" +msgstr "��������� Linux ��������� ������������." + +msgid "This is not a valid URL." +msgstr "��������� URL��� ������������." + +msgid "No such data available." +msgstr "������ ������������ ������������." + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" +"��������� ������������ ��������� ��� ������������. ��������� ������������ ��������������� ������ ������ ������" +"������ ��������� ��������� ������������������. HTTP ������ ������ %1. " + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "������ ������" + +msgid "OK" +msgstr "������" + +msgid "Confirm" +msgstr "������" + +msgid "Warning" +msgstr "������" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "������ ���..." + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "���������" + +msgid "Detailed message:" +msgstr "������ ���������:" + +msgid "No ISO found" +msgstr "" + +msgid "This is not a valid ISO file." +msgstr "��������� ISO ��������� ������������." + +msgid "This may take a long time. Do you want to continue?" +msgstr "��������� ������ ������������. ������������������������?" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "��������������� ��������������� ���������������. ������������������������?" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "������ ������ ��������� ������ ������������ ������������ ��������� ��� ������������." + +msgid "Max:" +msgstr "������:" + +msgid "Utilization" +msgstr "���������" + +msgid "Available" +msgstr "������ ������" + +msgid "Read Rate" +msgstr "������ ������" + +msgid "Write Rate" +msgstr "������ ������" + +msgid "Received" +msgstr "������" + +msgid "Sent" +msgstr "������" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"������������ ��������������� ������ ������������ ������������ ������ ��������� ���������������. ��������� ���" +"���/������ ��������� ������������������������?" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "������������ ��������������� ������������ ��������� ��� ������������. ������������������������?" + +msgid "ID" +msgstr "ID" + +msgid "Base URL" +msgstr "������ URL" + +msgid "Is Mirror" +msgstr "���������" + +msgid "URL Args" +msgstr "URL ������" + +msgid "Enabled" +msgstr "���������" + +msgid "GPG Check" +msgstr "GPG ������" + +msgid "GPG Key" +msgstr "GPG ���" + +msgid "Add" +msgstr "������" + +msgid "Remove" +msgstr "������" + +msgid "Enable" +msgstr "������" + +msgid "Disable" +msgstr "������ ������" + +msgid "Package Name" +msgstr "��������� ������" + +msgid "Version" +msgstr "������" + +msgid "Architecture" +msgstr "������������" + +msgid "Repository" +msgstr "���������" + +msgid "Update All" +msgstr "������ ������������" + +msgid "Updating..." +msgstr "������������ ���..." + +msgid "Failed to retrieve packages update information." +msgstr "" + +msgid "Failed to update package(s)." +msgstr "������������ ������������������ ���������������." + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"��������� ������������ ��������������� ������������ ��������� ��� ������������. ������������������������?" + +msgid "Generated Time" +msgstr "������ ������" + +msgid "Generate" +msgstr "������" + +msgid "Generating..." +msgstr "������ ���..." + +msgid "Rename" +msgstr "������ ���������" + +msgid "Download" +msgstr "������������" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "��������� ������������ ������, ������ ���/������ ���������('-')��� ��������������� ���������." + +msgid "Pending..." +msgstr "������ ���..." + +msgid "Report name is the same as the original one." +msgstr "" + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "" +"������ ������ ��� ������ ������ ������������ ���������������. ��� ��������� ������ ��������� ��� ���������" +"���. ������������������������?" + +msgid "Power off Confirmation" +msgstr "������ ������" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" + +msgid "Reset Confirmation" +msgstr "������ ������" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" + +msgid "Shut Down Confirmation" +msgstr "������ ������" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "��������������� ��������������� ���������������. ������������������������?" + +msgid "Virtual Machine delete Confirmation" +msgstr "" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" +"��� CDROM��� ��������������� ������������ ������ ��������� ��� ������������. ��������� ���������������������" +"���?" + +msgid "Attaching..." +msgstr "������ ���..." + +msgid "Replacing..." +msgstr "������ ���..." + +msgid "Successfully attached!" +msgstr "���������������������." + +msgid "Successfully replaced!" +msgstr "���������������������." + +msgid "Successfully detached!" +msgstr "���������������������." + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" + +msgid "interface:" +msgstr "" + +msgid "address:" +msgstr "" + +msgid "link_type:" +msgstr "" + +msgid "block:" +msgstr "" + +msgid "drive_type:" +msgstr "" + +msgid "model:" +msgstr "" + +msgid "Affected devices:" +msgstr "" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "VLAN ID��� 1��� 4094 ������������ ���������." + +msgid "unavailable" +msgstr "������ ���������" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "" +"��� ��������� ��� ��������������� ������������ ������ ��������� ������������ ��������� ���������������������." + +msgid "Create a network" +msgstr "������������ ������" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"��� ������������ ������ ��������������� ������������. ��� ��������� ������ ������������������ ������ ���������" +"������ ���������������. ������������������������?" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "������������ ������ ��������������� ���������������. ������������������������?" + +msgid "This storage pool is empty." +msgstr "��� ������������ ������ ������ ������������." + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "������������ ������������ ������������ ���������������. ������������������������? " + +msgid "SCSI Fibre Channel" +msgstr "SCSI ��������� ������" + +msgid "No SCSI adapters found." +msgstr "SCSI ������������ ������������." + +msgid "Loading iSCSI targets..." +msgstr "" + +msgid "No iSCSI found. Please input one." +msgstr "" + +msgid "Failed to load iSCSI targets." +msgstr "" + +msgid "The storage pool name can not be blank." +msgstr "������������ ��� ��������� ��������� ��� ������������." + +msgid "The storage pool path can not be blank." +msgstr "������������ ��� ��������� ��������� ��� ������������." + +msgid "NFS server mount path can not be blank." +msgstr "NFS ������ ��������� ��������� ��������� ��� ������������." + +msgid "Invalid NFS mount path." +msgstr "������������ ������ NFS ��������� ���������������." + +msgid "No logical device selected." +msgstr "������ ��������� ������������ ���������������." + +msgid "The iSCSI target can not be blank." +msgstr "iSCSI ��������� ��������� ��� ������������." + +msgid "Server name can not be blank." +msgstr "������ ��������� ��������� ��� ������������." + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "" + +msgid "Looking for available partitions ..." +msgstr "������ ��������� ������������ ������ ���..." + +msgid "No available partitions found." +msgstr "������ ��������� ������������ ������������." + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"��� ������������ ������ ��������������� ������������. ��� ��������� ������ ������������������ ������ ���������" +"������ ���������������. ������������������������?" + +msgid "Unable to retrieve partitions information." +msgstr "��������� ��������� ��������� ��� ������������. ������������: '%(err)s'" + +msgid "In progress..." +msgstr "" + +msgid "Failed!" +msgstr "" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" + +msgid "Disk pool or volume cannot be blank." +msgstr "������������ ��� ��������� ��������� ��� ������������." + +msgid "Filter" +msgstr "" + +msgid "Network Name" +msgstr "������������ ������" + +msgid "State" +msgstr "������" + +msgid "Network Type" +msgstr "������������ ������" + +msgid "Address Space" +msgstr "������ ������" + +msgid "Name should not contain '/' and '\"'." +msgstr "������������ ������ ������������ ��� ���������������. '/'��� ������������ ��������� ���������." + +msgid "Isolated: no external network connection" +msgstr "���������: ��������� ������������ ������ ������" + +msgid "NAT: outbound physical network connection only" +msgstr "NAT: ��������������� ��������� ������������ ���������" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "������������: ������ ��������� ��������� ��������������� ������ ���������" + +msgid "(No interfaces found)" +msgstr "" + +msgid "Destination" +msgstr "������:" + +msgid "Enable VLAN" +msgstr "VLAN ������:" + +msgid "VLAN ID" +msgstr "VLAN ID:" + +msgid "Stop" +msgstr "������" + +msgid "Generate a New Debug Report" +msgstr "��� ��������� ��������� ������" + +msgid "Report Name" +msgstr "��������� ������" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" +"������������ ������������ ��� ������������ ���������������. ������������ ��������� ������ ��������� ���������" +"��� ���������������. ��������� ������, ������ ��� ���������(\"-\")��� ��������� ��� ������������." + +msgid "Rename a Debug Report" +msgstr "��� ��������� ��������� ������" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" +"������������ ������������ ��� ������������ ���������������. ������������ ��������� ������ ��������� ���������" +"��� ���������������. ��������� ������, ������ ��� ���������(\"-\")��� ��������� ��� ������������." + +msgid "Submit" +msgstr "" + +msgid "Add a Repository" +msgstr "��������� ������" + +msgid "Identifier" +msgstr "ID" + +msgid "Single word, unique identifier for the repository." +msgstr "������������ ������ ������ ��������� ������ ID���������." + +msgid "Textual name for the repository." +msgstr "������������ ������ ��������� ���������������." + +msgid "URL" +msgstr "URL" + +msgid "Required Field" +msgstr "������ ������" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "������������ ������ URL���������. ������������ ��������������� http, ftp ��� file���������." + +msgid "Repository is a mirror" +msgstr "������������ ���������������." + +msgid "Distribution" +msgstr "������" + +msgid "Distribution of the DEB repository." +msgstr "DEB ������������ ���������������." + +msgid "Components" +msgstr "������������" + +msgid "List of components in DEB repository." +msgstr "DEB ������������ ������������ ���������������." + +msgid "Edit Repository" +msgstr "��������� ������" + +msgid "Mirror List URL" +msgstr "������ ������ URL" + +msgid "Yes" +msgstr "���" + +msgid "No" +msgstr "���������" + +msgid "Capacity" +msgstr "������" + +msgid "Allocated" +msgstr "���������" + +msgid "Location" +msgstr "������" + +msgid "Device path" +msgstr "������ ������" + +msgid "active" +msgstr "������" + +msgid "inactive" +msgstr "���������" + +msgid "Deactivate" +msgstr "������������" + +msgid "Activate" +msgstr "���������" + +msgid "Add Volume" +msgstr "" + +msgid "Extend" +msgstr "" + +msgid "Undefine" +msgstr "������ ������" + +msgid "Format" +msgstr "������:" + +msgid "Allocation" +msgstr "������:" + +msgid "Define a New Storage Pool" +msgstr "��� ������������ ��� ������" + +msgid "Storage Pool Name" +msgstr "������������ ��� ������" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "������������ ������ ������������ ��� ������������ ������������ ������ ������ ��������� ���������." + +msgid "Storage Pool Type" +msgstr "������������ ��� ������" + +msgid "Storage Path" +msgstr "������������ ������" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "������������ ������ ���������������. ��� ������������ ������ ������ ��������� ��������� ���������." + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "" +"��������������� ������������ ������ ������������ ��������� Kimchi��� ������������ ��������� ���������������." + +msgid "NFS Server IP" +msgstr "NFS ������ IP" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" +"NFS ������ IP ������ ��������� ���������������. ��������� ��������������� ������������������ ��������� ��� " +"������������." + +msgid "NFS Path" +msgstr "NFS ������" + +msgid "The NFS exported path on NFS server." +msgstr "NFS ������������ NFS��� ��������� ���������������." + +msgid "iSCSI Server" +msgstr "iSCSI ������" + +msgid "Server" +msgstr "������" + +msgid "Port" +msgstr "������" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "iSCSI ������ IP ������ ��������� ���������������. ������ ������ ��������� ���������." + +msgid "Target" +msgstr "������" + +msgid "The iSCSI target on iSCSI server" +msgstr "iSCSI ��������� iSCSI ������" + +msgid "Add iSCSI Authentication" +msgstr "iSCSI ������ ������" + +msgid "iSCSI Authentication" +msgstr "iSCSI ������" + +msgid "User Name" +msgstr "��������� ������" + +msgid "Password" +msgstr "������������" + +msgid "SCSI Adapter" +msgstr "SCSI ���������" + +msgid "Please, wait..." +msgstr "������ ��������� ������������." + +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + +msgid "Add Template" +msgstr "������������ ������" + +msgid "Where is the source media for this template? " +msgstr "��� ��������������� ������ ��������� ��������� ������������?" + +msgid "Local ISO Image" +msgstr "������ ISO ���������" + +msgid "Local Image File" +msgstr "" + +msgid "Remote ISO Image" +msgstr "������ ISO ���������" + +msgid "Search ISOs" +msgstr "ISO ������" + +msgid "The following ISOs are available:" +msgstr "������ ISO��� ������ ���������������." + +msgid "OS: " +msgstr "OS: " + +msgid "Version: " +msgstr "������: " + +msgid "Size: " +msgstr "������: " + +msgid "Search more ISOs" +msgstr "������ ISO ������" + +msgid "Create Templates from Selected ISO" +msgstr "��������� ISO��������� ������������ ������" + +msgid "I want to use a specific ISO file" +msgstr "������ ISO ��������� ��������������� ���������." + +msgid "Loading default remote ISOs ..." +msgstr "������ ������ ISO ������ ���..." + +msgid "Arch: " +msgstr "Arch: " + +msgid "I want to use a custom URL" +msgstr "��������� ������ URL��� ��������������� ���������." + +msgid "Edit Template" +msgstr "������������ ������" + +msgid "CDROM" +msgstr "CDROM" + +msgid "Image File" +msgstr "" + +msgid "Graphics" +msgstr "���������" + +msgid "Disk(GB)" +msgstr "" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "CPU ������" + +msgid "Manually set CPU topology" +msgstr "" + +msgid "Cores" +msgstr "" + +msgid "Threads" +msgstr "" + +msgid "No templates found." +msgstr "��������������� ������������." + +#~ msgid "Delete is not allowed for %(resource)s" +#~ msgstr "%(resource)s��� ��������� ������������ ������" + +#~ msgid "%(resource)s does not implement update method" +#~ msgstr "%(resource)s��������� ������������ ������������ ������������ ������" + +#~ msgid "Create is not allowed for %(resource)s" +#~ msgstr "%(resource)s��� ��������� ������������ ������" + +#~ msgid "Unable to parse JSON request" +#~ msgstr "JSON ��������� ������ ��������� ��� ������������." + +#~ msgid "This API only supports JSON" +#~ msgstr "��� API��� JSON��� ���������������." + +#~ msgid "Datastore is not initiated in the model object." +#~ msgstr "��������� ������������ ������ ������������������ ������������ ���������������." + +#~ msgid "Unable to start task due error: %(err)s" +#~ msgstr "������ ��������� ��������� ��������� ��� ������: %(err)s" + +#~ msgid "" +#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" +#~ msgstr "��������� '%(username)s'��� ��������� ������������������. [������ ������: %(code)s]" + +#~ msgid "You are not authorized to access Kimchi" +#~ msgstr "Kimchi��� ������������ ��������� ������������." + +#~ msgid "Specify %(item)s to login into Kimchi" +#~ msgstr "Kimchi��� ������������������ %(item)s���(���) ������������������." + +#~ msgid "Unable to find %(item)s in datastore" +#~ msgstr "��������� ��������������� %(item)s���(���) ������ ��� ������������." + +#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +#~ msgstr "" +#~ "%(seconds)s��� ������ '%(cmd)s' ������ ������ ��� ��������������� ���������������������." + +#~ msgid "Help" +#~ msgstr "���������" + +#~ msgid "About" +#~ msgstr "������" + +#~ msgid "Log out" +#~ msgstr "������������" + +#~ msgid "Version:" +#~ msgstr "������: " diff --git a/src/wok/plugins/kimchi/po/pt_BR.po b/src/wok/plugins/kimchi/po/pt_BR.po new file mode 100644 index 0000000..c2cb4e9 --- /dev/null +++ b/src/wok/plugins/kimchi/po/pt_BR.po @@ -0,0 +1,2369 @@ +# i18n portable object for kimchi. +# Copyright (C) IBM, Corp. 2013-2014 +# ShaoHe Feng <shaohef@linux.vnet.ibm.com>, 2013-04-18. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 1.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2015-03-23 12:57+0000\n" +"Last-Translator: Cr��stian Deives dos Santos Viana <cristiandeives@gmail." +"com>\n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/" +"kimchi/language/pt_BR/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pt_BR\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "Par��metro desconhecido: %(value)s" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" +"Limite de tempo de %(seconds)s segundos expirado ao executar a tarefa '%" +"(task)s'." + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "Usu��rio %(user_id)s n��o encontrado com as configura����es LDAP dadas." + +msgid "Unknown \"_cap\" specified" +msgstr "\"_cap\" desconhecido especificado" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "\"_passthrough\" deve ser \"true\" ou \"false\"" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "\"_passthrough_affected_by\" deve ser um texto do nome do dispositivo" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "Erro ao consultar block devices. Detalhes %(err)s" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "Erro ao consultar informa����es de block devices para %(device)s." + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "N��o foi poss��vel encontrar o arquivo da distribui����o: %(filename)s" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "" +"N��o foi poss��vel ler o arquivo da distribui����o: %(filename)s. Confirme se �� " +"um arquivo JSON." + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" +"N��o foi poss��vel logar na m��quina alvo do iSCSI %(portal)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "N��o foi poss��vel logar na m��quina %(host)s alvo %(target)s do iSCSI" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "N��o foi poss��vel encontrar a ISO %(filename)s" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "A ISO %(filename)s n��o �� boot��vel" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "A ISO %(filename)s n��o possui uma grava����o v��lida de boot El Torito" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "Valida����o El Torito inv��lida na ISO %(filename)s" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "Indicador de boot El Torito inv��lido na ISO %(filename)s" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" +"Tipo de volume n��o esperado para um volume prim��rio na ISO %(filename)s" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "Formato errado na leitura do descritor de volume na ISO %(filename)s" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" +"O servidor n��o tem permiss��o para acessar a ISO %(filename)s. Considere mud��-" +"la para o diret��rio /var/lib/libvirt, ou mude as permiss��es para que o " +"usu��rio '%(user)s' tenha acesso, ou, adicione o usu��rio '%(user)s' no grupo " +"do caminho da ISO, ou (n��o recomendado) 'chmod -R o+x 'caminho_para_iso'. " +"Detalhes: %(err)s" + +msgid "An error occurred when probing image OS information." +msgstr "Ocorreu um erro ao identificar o sistema operacional da imagem." + +msgid "No OS information found in given image." +msgstr "" +"Nenhuma informa����o de sistema operacional encontrada na imagem fornecida." + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "N��o foi poss��vel ler o arquivo de imagem %(filename)s." + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" +"Arquivo de imagem deve ser um arquivo existente no sistema. %(filename)s n��o " +"�� uma entrada v��lida." + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "M��quina virtual %(name)s j�� existe" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "M��quina virtual %(name)s n��o existe" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" +"N��o foi poss��vel renomear a m��quina virtual %(name)s. O nome %(new_name)s j�� " +"est�� em uso ou a m��quina virtual n��o est�� ligada." + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" +"N��o foi poss��vel tirar uma foto da tela para a m��quina virtual %(name)s que " +"est�� desligada" + +msgid "Remote ISO image is not supported by this server." +msgstr "Imagem de ISO remota n��o �� suportada por esse servidor." + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "Foto da tela n��o �� suportado na m��quina virtual %(name)s" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "N��o foi poss��vel criar a m��quina virtual %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "" +"N��o foi poss��vel atualizar a m��quina virtual %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "" +"N��o foi poss��vel encontrar a m��quina virtual %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "N��o foi poss��vel conectar �� m��quina virtual desligada %(name)s." + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "URI do Modelo inv��lida %(value)s especificada para m��quina virtual" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" +"URI do Storage pool URI inv��lida %(value)s especificada para m��quina virtual" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "Gr��ficos suportados para a m��quina virtual s��o Spice ou VNC" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "Endere��o para receber eventos gr��ficos deve ser IPv4 ou IPv6" + +msgid "Specify a template to create a virtual machine from" +msgstr "Especifique um modelo para ser base da cria����o da m��quina virtual" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "N��o foi poss��vel iniciar a m��quina virtual %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "" +"N��o foi poss��vel for��ar o desligamento da m��quina virtual %(name)s. " +"Detalhes: %(err)s" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "N��o foi poss��vel remover a m��quina virtual %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "" +"N��o foi poss��vel reiniciar a m��quina virtual %(name)s. Detalhes: %(err)s" + +msgid "User name list must be an array" +msgstr "Lista de nomes de usu��rio deve ser um array" + +msgid "User name must be a string" +msgstr "Nome de usu��rio deve ser um texto" + +msgid "Group name list must be an array" +msgstr "Lista de nomes de grupo deve ser um array" + +msgid "Group name must be a string" +msgstr "Nome de grupo deve ser um texto" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "Usu��rio(s) '%(users)s' n��o existe(m)" + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "Grupo(s) '%(groups)s' n��o existe(m)" + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "" +"N��o foi poss��vel desligar a m��quina virtual %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "" +"N��o foi poss��vel acessar os metadados da m��quina virtual %(name)s. Detalhes: " +"%(err)s" + +msgid "The guest console password must be a string." +msgstr "A senha para o console do guest deve ser um texto." + +msgid "The life time for the guest console password must be a number." +msgstr "O tempo de vida da senha do console do guest deve ser um n��mero." + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "A m��quina virtual '%(name)s' deve estar parada antes de clon��-la." + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "Espa��o em disco insuficiente para clonar a m��quina virtual '%(name)s'" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "N��o foi poss��vel clonar a VM '%(name)s'. Detalhes: %(err)s" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "Opera����o inv��lida para m��quina virtual n��o-persistente %(name)s" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" +"A VM %(vmid)s n��o cont��m o dispositivo de host atribu��do diretamente %" +"(dev_name)s." + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" +"N��o �� permitido atribuir diretamente o dispositivo de host %(dev_name)s." + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" +"Nenhum grupo IOMMU encontrado. Passthrough de host PCI necessita do grupo " +"IOMMU para funcionar corretamente. Por favor, habilite o suporte ao Intel VT-" +"d ou AMD IOMMU. Para uma CPU Intel, adicione \"intel_iommu=on\" nos seus " +"par��metros de kernel em \"/boot/grub2/grub.conf\". Para uma CPU AMD, " +"adicione \"iommu=pt iommu=1\"." + +msgid "\"name\" should be a device name string" +msgstr "\"nome\" deve ser um texto do nome do dispositivo." + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "Interface %(iface)s n��o existe na m��quina virtual %(name)s" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" +"Rede %(network)s especificada para a m��quina virtual %(name)s n��o existe" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "Tipo de interface suportado das m��quinas virtuais �� somente rede" + +msgid "Network name for virtual machine interface must be a string" +msgstr "Nome da rede para a interface da m��quina virtual deve ser texto" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "Modelo de placa de rede inv��lido para a interface da m��quina virtual" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" +"Especifique o tipo e a rede para adicionar uma nova interface da m��quina " +"virtual" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "Modelo %(name)s j�� existe" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "Rede '%(network)s' especificada para o modelo %(template)s n��o existe" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "" +"Storage pool %(pool)s especificado para o modelo %(template)s n��o existe" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "" +"Storage pool %(pool)s especificado para o modelo %(template)s n��o est�� ativo" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "Par��metro inv��lido '%(param)s' especificado para CDROM" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "Rede %(network)s especificada para modelo %(template)s n��o est�� ativa" + +msgid "Template name must be a string" +msgstr "Nome do modelo deve ser um texto" + +msgid "Template icon must be a path to the image" +msgstr "��cone do modelo deve ser um caminho para uma imagem" + +msgid "Template distribution must be a string" +msgstr "Distribui����o do modelo deve ser um texto" + +msgid "Template distribution version must be a string" +msgstr "Vers��o da distribui����o do modelo deve ser um texto" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "O n��mero de CPUs deve ser um inteiro maior do que 0" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "Quantidade de mem��ria (MB) deve ser um inteiro maior que 512" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "Modelo do CDROM deve ser um arquivo ISO local ou remoto" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "URI de storage pool inv��lido %(value)s especificado para modelo" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "" +"Especifique uma imagem ISO como CD-ROM ou uma imagem base para criar um " +"modelo" + +msgid "All networks for the template must be specified in a list." +msgstr "Todas redes para o modelo devem ser especificadas em uma lista" + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" +"Especifique um volume para o template quando o storage pool for iSCSI or SCSI" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "O volume %(volume)s n��o est�� no storage pool %(pool)s" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "N��o foi poss��vel criar o modelo devido a um erro: %(err)s" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "N��o foi poss��vel remover o modelo devido a um erro: %(err)s" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "O tamanho do disco deve ser um n��mero inteiro maior que 1GB." + +msgid "Template base image must be a valid local image file" +msgstr "Imagem base do modelo deve ser um arquivo de imagem local v��lido" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "N��o foi poss��vel identificar o formato da imagem base %(path)s" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" +"Ao especificar a topologia de CPU, VCPUs deve ser um produto de sockets, " +"cores e threads." + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" +"Ao especificar a topologia de CPU, cada elemento deve ser um n��mero inteiro " +"maior do que zero." + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" +"Formato de imagem de disco inv��lido. Formatos v��lidos: bochs, cloop, cow, " +"dmg, qcow, qcow2, qed, raw, vmdk, vpc." + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "Storage pool %(name)s j�� existe" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "Storage pool %(name)s n��o existe" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "Especifique %(item)s para criar o storage pool %(name)s" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "N��o foi poss��vel remover o storage pool ativo %(name)s" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "N��o foi poss��vel listar os storage pools. Detalhes: %(err)s" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "N��o foi poss��vel criar o storage pool %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "" +"N��o foi poss��vel saber o n��mero de volumes no storage pool %(name)s. " +"Detalhes: %(err)s" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "N��o foi possivel ativar o storage pool %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "N��o foi possivel desativar o storage pool %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "N��o foi possivel remover o storage pool %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" +"N��o foi poss��vel criar Pool NFS uma vez que o caminho de exporta����o %(path)s " +"pode bloquear durante a montagem" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" +"N��o foi poss��vel criar NFS Pool uma vez que a montagem do caminho de " +"exporta����o %(path)s falhou" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "Tipo de storage pool n��o suportado: %(type)s" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "Erro durante a leitura do XML do storage pool %(pool)s" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" +"Tipos de storage pool supportados s��o dir, netfs, logical, iscsi, scsi e " +"kimchi-iso" + +msgid "Storage pool path must be a string" +msgstr "Caminho para storage pool deve ser um texto" + +msgid "Storage pool host must be a IP or hostname" +msgstr "Host do storage pool deve ser um IP ou um hostname" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" +"Dispositivo do storage pool deve ser o caminho absoluto para o block device" + +msgid "Storage pool devices parameter must be a list" +msgstr "Par��metro dos dispositivos do storage pool devem ser uma lista" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "Alvo IQN de um pool iSCSI deve ser um texto" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" +"Porta de um servidor remoto de storage deve ser um inteiro entre 1 e 65535" + +msgid "iSCSI target username must be a string" +msgstr "Usu��rio do iSCSI target deve ser um texto" + +msgid "iSCSI target password must be a string" +msgstr "Senha do iSCSI target deve ser um texto" + +msgid "Specify name and type to create a storage pool" +msgstr "Especifique o nome e o tipo para criar um storage pool" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "" +"%(disk)s n��o �� um disco/parti����o v��lido. N��o foi poss��vel adicion��-lo ao " +"pool %(pool)s." + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "N��o foi poss��vel extender o pool l��gico %(pool)s. Detalhes: %(err)s" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "" +"O par��metro discos somente pode ser atualizado para storage pool l��gicos." + +msgid "The SCSI host adapter name must be a string." +msgstr "O nome do adaptador SCSI host deve ser um texto" + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "O storage pool kimchi_isos �� reservado para uso interno" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"N��o foi poss��vel ativar o storage pool NFS %(name)s. Servidor NFS %(server)s " +"est�� inacess��vel." + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"N��o foi poss��vel desativar o storage pool NFS %(name)s. Servidor NFS %" +"(server)s est�� inacess��vel." + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "" +"N��o foi poss��vel desativar o pool %(name)s uma vez que ele est�� associado " +"com algum dos modelos" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "" +"N��o foi poss��vel remover o pool %(name)s uma vez que ele est�� associado com " +"algum dos modelos" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "" +"Um grupo de volume chamado '%(name)s' j�� existe. Por favor, escolha outro " +"nome para criar o pool l��gico." + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "" +"N��o foi poss��vel atualizar a base de dados com informa����es de mais ISOs " +"devido a um erro: %(err)s" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "Volume de storage %(name)s j�� existe" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "Volume de storage %(name)s n��o existe no storage pool %(pool)s" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" +"N��o foi poss��vel criar o storaget volume %(volume)s pois o storage pool %" +"(pool)s n��o est�� ativo" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "Especifique %(item)s para poder criar o volume %(volume)s" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "" +"N��o foi poss��vel listar volumes pois o storage pool %(pool)s n��o est�� ativo" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "" +"N��o foi poss��vel criar o volume %(name)s no storage pool %(pool)s. Detalhes: " +"%(err)s" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "" +"N��o foi poss��vel listar os volumes do storage pool %(pool)s. Detalhes: %(err)" +"s" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "N��o foi poss��vel limpar o volume %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "N��o foi poss��vel remover o volume %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "N��o foi poss��vel redimensionar o volume %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "Storage do tipo %(type)s n��o suporta cria����o ou remo����o de volume" + +msgid "Storage volume name must be a string" +msgstr "Nome do volume deve ser um texto" + +msgid "Storage volume allocation must be an integer number" +msgstr "Aloca����o do volume de storage deve ser um n��mero inteiro" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" +"Formato de volume de storage inv��lido. Formatos v��lidos: bochs, cloop, cow, " +"dmg, qcow, qcow2, qed, raw, vmdk, vpc." + +msgid "Storage volume requires a volume name" +msgstr "Volume de storage requer um nome" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "" +"N��o foi poss��vel atualizar a base de dados com informa����es de volume de " +"storage devido a um erro: %(err)s" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "Somente um par��metro %(param)s pode ser especificado" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "Criar um volume a partir de %(param)s n��o �� suportado" + +msgid "Storage volume capacity must be an integer number." +msgstr "A capacidade do storage volume deve ser um n��mero inteiro." + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" +"URL para o storage volume deve ser http://, https://, ftp:// ou ftps://." + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "Erro ao acessar arquivo %(url)s. Por favor, verifique isso." + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" +"N��o foi poss��vel clonar o volume de storage '%(name)s' no pool '%(pool)s'. " +"Detalhes: %(err)s" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "Interface %(name)s n��o existe" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "Rede %(name)s j�� existe" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "Rede %(name)s n��o existe" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" +"A subrede %(subnet)s especificada para a rede %(network)s n��o �� v��lida." + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "Especifique uma interface de rede para criar a rede de bridge %(name)s" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "N��o foi poss��vel remover a rede ativa %(name)s" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" +"A interface %(iface)s especificada para a rede %(network)s j�� est�� em uso" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "Interface deve ser 'bare NIC', 'bonding' ou 'dispositivo de bridge'." + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "N��o foi poss��vel criar a rede %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "N��o foi poss��vel encontrar um endere��o IP livre para a rede '%(name)s'" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "A interface %(iface)s j�� existe" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "Tipos de rede suportados s��o isolada, NAT e bridge" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "" +"Subrede deve ser um texto com endere��o IP e prefixo, ou m��scara de rede" + +msgid "Network interface must be a string" +msgstr "Interface de rede deve ser um texto" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "ID da rede VLAN deve ser um inteiro entre 1 e 4094" + +msgid "Specify name and type to create a Network" +msgstr "Especifique o nome e o tipo para criar uma rede" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" +"N��o foi poss��vel desativar a rede %(name)s. H�� alguma m��quina virtual %(vms)" +"s e/ou modelo associados a esta rede." + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" +"N��o foi poss��vel desativar a rede %(name)s. H�� alguma m��quina virtual %(vms)" +"s e/ou modelo associados a esta rede." + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "" +"Dispositivo da bridge %(name)s n��o pode ser um dispositivo vinculado a uma " +"VLAN." + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "N��o foi poss��vel ativar a interface %(iface)s: %(err)s." + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "" +"N��o foi poss��vel ativar a interface %(iface)s. Por favor, verifique o status " +"da conex��o f��sica." + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "N��o foi poss��vel iniciar a rede %(name)s. Detalhes: %(err)s" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "Relat��rio de debug %(name)s n��o existe" + +msgid "Debug report tool not found in system" +msgstr "Ferramenta de relat��rio de debug n��o encontrada no sistema" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "" +"N��o foi poss��vel criar o relat��rio de debug %(name)s. Detalhes: %(err)s." + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "N��o foi poss��vel encontrar nenhum relat��rio com o nome %(name)s" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "" +"N��o foi poss��vel gerar o relat��rio de debug %(name)s. Detalhes: %(err)s" + +msgid "You should give a name for the debug report file." +msgstr "Voc�� deve dar um nome para o arquivo do relat��rio de debug." + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" +"Nome do relat��rio deve ser um texto. Somente letras, digitos, underscore " +"('_') e h��fem ('-') s��o permitidos." + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "" +"O relat��rio de debug com o nome especificado \"%(name)s\" j�� existe. Por " +"favor, use outro nome." + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "Servidor de storage %(server)s n��o foi usado pelo Kimchi" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "Distribui����o '%(name)s' n��o existe" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "Parti����o %(name)s n��o existe no host" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" +"N��o foi poss��vel desligar o host uma vez que h�� m��quinas virtuais ligadas" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" +"N��o foi poss��vel resetar o host uma vez que h�� m��quinas virtuais ligadas" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "Dispositivo de n�� '%(name)s' n��o encontrado" + +msgid "Conflicting flag filters specified." +msgstr "Foram especificados filtros de flag com conflito." + +msgid "No packages marked for update" +msgstr "Nenhum pacote marcado para atualiza����o" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "Pacote %(name)s n��o est�� marcado para atualiza����o." + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "Erro ao buscar pacotes marcados para atualiza����o. Detalhes: %(err)s" + +msgid "There is no compatible package manager for this system." +msgstr "N��o h�� gerenciador de pacotes compat��vel para este sistema." + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "URI %(uri)s inv��lida" + +msgid "Unable to choose a virtual machine name" +msgstr "N��o foi poss��vel escolher um nome para a m��quina virtual" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "Tipo de storage inv��lido. Tipos suportados: 'cdrom', 'disco'" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" +"O caminho '%(value)s' n��o �� um caminho local/remoto v��lido para este " +"dispositivo" + +msgid "Only CDROM path can be update." +msgstr "Apenas o caminho do CD-ROM pode ser atualizado." + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "O disco %(dev_name)s n��o existe na m��quina virtual %(vm_name)s" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "Erro ao criar novo dispositivo de storage: %(error)s" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "Erro ao atualizar dispositivo de storage: %(error)s" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "Erro ao remover dispositivo de storage: %(error)s" + +msgid "Do not support IDE device hot plug" +msgstr "Dispositivo IDE hot plug n��o �� suportado" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "" +"Especifique o tipo e o caminho, ou o tipo e o pool/volume, para adicionar um " +"novo disco da m��quina virtual" + +msgid "Specify path to update virtual machine disk" +msgstr "Especifique o caminho para atualizar o disco da m��quina virtual" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" +"Limita����o do tipo do controlador %(type)s de %(limit)s dispositivos foi " +"alcan��ada" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" +"N��o foi poss��vel buscar informa����es do caminho do disco para o pool/volume " +"dado: %(error)s" + +msgid "Volume already in use by other virtual machine." +msgstr "Volume j�� em uso por outra m��quina virtual." + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "" +"Somente um caminho ou pool/volume pode ser especificado para adicionar um " +"novo disco da m��quina virtual." + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" +"Volume escolhido com formato %(format)s n��o se enquadra no tipo de storage %" +"(type)s" + +msgid "YUM Repository ID must be one word only string." +msgstr "ID do reposit��rio YUM deve ser apenas uma palavra." + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "URL do reposit��rio deve ser uma URL http://, ftp:// ou file://." + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "" +"Configura����o do reposit��rio �� um dicion��rio com valores espec��ficos de " +"acordo com o tipo do reposit��rio." + +msgid "Distribution to DEB repository must be a string" +msgstr "Distribui����o para o reposit��rio DEB deve ser um texto" + +msgid "Components to DEB repository must be listed in a array" +msgstr "Componentes para o reposit��rio DEB deve ser um array" + +msgid "Components to DEB repository must be a string" +msgstr "Componentes para o reposit��rio DEB deve ser um texto" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "Nome do reposit��rio YUM deve ser um texto." + +msgid "GPG check must be a boolean value." +msgstr "Verifica����o de GPG deve ser um valor booleano." + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "" +"Chave GPG deve ser uma URL apontando para o arquivo no formato ASCII-armor." + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "N��o foi poss��vel atualizar o reposit��rio %(repo_id)s." + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "Reposit��rio %(repo_id)s n��o existe." + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "" +"Ferramenta de gerenciamento de reposit��rio n��o foi reconhecida no seu " +"sistema." + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "Reposit��rio %(repo_id)s j�� est�� habilitado." + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "Reposit��rio %(repo_id)s j�� est�� desabilitado." + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "N��o foi poss��vel remover o reposit��rio %(repo_id)s." + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "" +"N��o foi poss��vel gravar o arquivo de configura����o do reposit��rio %(repo_file)" +"s" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "" +"Especificar o reposit��rio de distribui����o para poder criar o reposit��rio DEB." + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "N��o foi poss��vel habilitar o reposit��rio %(repo_id)s." + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "N��o foi poss��vel desabilitar o reposit��rio %(repo_id)s." + +msgid "YUM Repository ID already exists" +msgstr "ID do reposit��rio YUM j�� existe" + +msgid "YUM Repository name must be a string" +msgstr "Nome do reposit��rio YUM deve ser um texto" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "N��o �� poss��vel listar os reposit��rios. Detalhes: '%(err)s'" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "" +"N��o foi poss��vel carregar as informa����es do reposit��rio. Detalhes: '%(err)s'" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "N��o foi poss��vel adicionar o reposit��rio. Detalhes: '%(err)s'" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "N��o foi poss��vel remover o reposit��rio. Detalhes: '%(err)s'" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" +"Itens de configura����o '%(items)s' n��o s��o suportados pelo gerenciador de " +"reposit��rios." + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" +"A m��quina virtual '%(vm)s' deve estar parada antes de criar um snapshot dela" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" +"N��o foi poss��vel criar o snapshot '%(name)s' na m��quina virtual '%(vm)s'. " +"Detalhes: %(err)s" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "O snapshot '%(name)s' n��o existe na m��quina virtual '%(vm)s'." + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" +"N��o foi poss��vel recuperar o snapshot '%(name)s' da m��quina virtual '%(vm)" +"s'. Detalhes: %(err)s" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" +"N��o foi poss��vel listar os snapshots da m��quina virtual '%(vm)s'. Detalhes: %" +"(err)s" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" +"N��o foi poss��vel remover o snapshot '%(name)s' da m��quina virtual '%(vm)s'. " +"Detalhes: %(err)s" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" +"N��o foi poss��vel recuperar o snapshot atual da m��quina virtual '%(vm)s'. " +"Detalhes: %(err)s." + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" +"N��o foi poss��vel reverter a m��quina virtual '%(vm)s' para o snapshot '%(name)" +"s'. Detalhes: %(err)s" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" +"N��o foi poss��vel criar o snapshot para a m��quina virtual '%(vm)s' porque ela " +"cont��m discos no formato '%(format)s'; somente 'qcow2' �� suportado." + +msgid "The number of vCPUs is too large for this system." +msgstr "O n��mero de VCPUs �� grande demais para esse sistema." + +msgid "Invalid vCPU/topology combination." +msgstr "Combina����o inv��lida de VCPU/topologia." + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "Este host (ou configura����o atual) n��o permite topologia de CPU." + +msgid "ERROR CODE" +msgstr "C��DIGO DE ERRO" + +msgid "REASON" +msgstr "MOTIVO" + +msgid "STACK" +msgstr "PILHA" + +msgid "Go to Homepage" +msgstr "Ir para a P��gina Inicial" + +msgid "Create a New Virtual Machine" +msgstr "Criar nova M��quina Virtual" + +msgid "Virtual Machine Name" +msgstr "Nome da M��quina Virtual" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" +"O nome usado para identificar a m��quina virtual. Se ele for omitido, a " +"escolha ser�� baseada no modelo selecionado." + +msgid "Template" +msgstr "Modelo" + +msgid "Please create a template first." +msgstr "Por favor, crie um modelo primeiro." + +msgid "Create a Template" +msgstr "Criar um Modelo" + +msgid "Please choose a template." +msgstr "Por favor, escolha um modelo." + +msgid "OS" +msgstr "Sistema Operacional" + +msgid "OS Version" +msgstr "Vers��o do Sistema Speracional" + +msgid "CPUS" +msgstr "CPUS" + +msgid "Memory" +msgstr "Mem��ria" + +msgid "Create" +msgstr "Criar" + +msgid "Creating..." +msgstr "Criando..." + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Edit Guest" +msgstr "Editar Guest" + +msgid "General" +msgstr "Geral" + +msgid "Storage" +msgstr "Storage" + +msgid "Interface" +msgstr "Interface" + +msgid "Permission" +msgstr "Permiss��o" + +msgid "Host PCI Device" +msgstr "Dispositivo de host PCI" + +msgid "Snapshot" +msgstr "Snapshot" + +msgid "Name" +msgstr "Nome" + +msgid "CPUs" +msgstr "CPUs" + +msgid "Memory (MB)" +msgstr "Mem��ria (MB)" + +msgid "Icon" +msgstr "��cone" + +msgid "Device" +msgstr "Dispositivo" + +msgid "Path" +msgstr "Caminho" + +msgid "Network" +msgstr "Rede" + +msgid "Type" +msgstr "Tipo" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "Usu��rios e grupos de sistema dispon��veis" + +msgid "Selected system users and groups" +msgstr "Usu��rios e grupos de sistema selecionados" + +msgid "User" +msgstr "Usu��rio" + +msgid "All" +msgstr "Todos" + +msgid "To Add" +msgstr "Para adicionar" + +msgid "Added" +msgstr "Adicionado" + +msgid "filter" +msgstr "filtro" + +msgid "Product" +msgstr "Produto" + +msgid "Vendor" +msgstr "Vendor" + +msgid "Created" +msgstr "Criado" + +msgid "Save" +msgstr "Salvar" + +msgid "Replace" +msgstr "Substituir" + +msgid "Detach" +msgstr "Remover" + +msgid "revert" +msgstr "Reverter" + +msgid "Start" +msgstr "Iniciar" + +msgid "Reset" +msgstr "Reiniciar" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "For��ar desligamento" + +msgid "Actions" +msgstr "A����es" + +msgid "Connect" +msgstr "Conectar" + +msgid "Clone" +msgstr "Clonar" + +msgid "Edit" +msgstr "Editar" + +msgid "Shut Down" +msgstr "Desligar" + +msgid "Delete" +msgstr "Remover" + +msgid "CPU" +msgstr "CPU" + +msgid "Disk I/O" +msgstr "Disco E/S" + +msgid "Network I/O" +msgstr "Rede E/S" + +msgid "Livetile" +msgstr "Tela ao vivo" + +msgid "No guests found." +msgstr "Nenhum guest encontrado." + +msgid "Add a Storage Device to VM" +msgstr "Adicionar um dispositivo de storage �� VM" + +msgid "Device Type" +msgstr "Tipo do Dispositivo" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "" +"O tipo do dispositivo. Atualmente, \"cdrom\" e \"disco\" s��o suportados." + +msgid "Storage Pool" +msgstr "Storage Pool" + +msgid "Storage pool which volume located in" +msgstr "Storage pool no qual o volume est�� localizado" + +msgid "Storage Volume" +msgstr "Volume de storage" + +msgid "Storage volume to be attached" +msgstr "Volume de storage a ser adicionado" + +msgid "File Path" +msgstr "Caminho do Arquivo" + +msgid "The ISO file path in the server for CDROM." +msgstr "O caminho do arquivo ISO para o CDROM no servidor." + +msgid "Attach" +msgstr "Adicionar" + +msgid "Shut down" +msgstr "Desligar" + +msgid "Restart" +msgstr "Reiniciar" + +msgid "Basic Information" +msgstr "Informa����es b��sicas" + +msgid "OS Distro" +msgstr "Distribui����o" + +msgid "OS Code Name" +msgstr "Nome-c��digo do sistema operacional" + +msgid "Processor" +msgstr "Processador" + +msgid "CPU(s)" +msgstr "CPU(s)" + +msgid "System Statistics" +msgstr "Estat��sticas do sistema" + +msgid "Software Updates" +msgstr "Atualiza����es de software" + +msgid "Update Progress" +msgstr "Progresso da atualiza����o" + +msgid "Repositories" +msgstr "Reposit��rios" + +msgid "Debug Reports" +msgstr "Relat��rios de Debug" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "" +"O usu��rio ou senha inseridos est��o incorretos. Por favor, tente novamente." + +msgid "This field is required." +msgstr "Esse campo �� obrigat��rio." + +msgid "Log in" +msgstr "Entrar" + +msgid "Logging in..." +msgstr "Entrando..." + +msgid "Host" +msgstr "Host" + +msgid "Guests" +msgstr "Guests" + +msgid "Templates" +msgstr "Modelos" + +msgid "Failed to get application configuration" +msgstr "N��o foi poss��vel carregar as configura����es da aplica����o" + +msgid "This is not a valid Linux path" +msgstr "Este n��o �� um caminho v��lido no Linux" + +msgid "This is not a valid URL." +msgstr "Essa n��o �� uma URL v��lida." + +msgid "No such data available." +msgstr "N��o h�� dados dispon��veis." + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" +"N��o foi poss��vel contactar o sistema host. Verique se o sistema do host est�� " +"ligado e se voc�� possui conectividade de rede com ele. Resposta da " +"requisi����o HTTP %1. " + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "Confirma����o de remo����o" + +msgid "OK" +msgstr "OK" + +msgid "Confirm" +msgstr "Confirmar" + +msgid "Warning" +msgstr "Aviso" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "Carregando..." + +msgid "An error occurred while retrieving system information." +msgstr "Ocorreu um erro ao recuperar informa����es do sistema." + +msgid "Retry" +msgstr "Tentar novamente" + +msgid "Detailed message:" +msgstr "Mensagem detalhada:" + +msgid "No ISO found" +msgstr "Nenhuma ISO encontrada" + +msgid "This is not a valid ISO file." +msgstr "Esse n��o �� um arquivo ISO v��lido." + +msgid "This may take a long time. Do you want to continue?" +msgstr "Isso vai levar um longo tempo. Deseja continuar?" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "O modelo vai ser permanentemente removido. Deseja continuar?" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" +"N��o foi poss��vel desligar o sistema porque algumas m��quinas virtuais est��o " +"ligadas!" + +msgid "Max:" +msgstr "M��ximo:" + +msgid "Utilization" +msgstr "Utiliza����o" + +msgid "Available" +msgstr "Dispon��vel" + +msgid "Read Rate" +msgstr "Taxa de leitura" + +msgid "Write Rate" +msgstr "Taxa de escrita" + +msgid "Received" +msgstr "Recebido" + +msgid "Sent" +msgstr "Enviado" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"Desligar ou reiniciar o host causar�� perda de trabalho que n��o foi salvo. " +"Continuar o processo de desligar/reiniciar?" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"Reposit��rio ser�� removido permanentemente e n��o poder�� ser recuperado. " +"Deseja continuar?" + +msgid "ID" +msgstr "ID" + +msgid "Base URL" +msgstr "URL Base" + +msgid "Is Mirror" +msgstr "�� mirror" + +msgid "URL Args" +msgstr "Argumentos da URL" + +msgid "Enabled" +msgstr "Ativado" + +msgid "GPG Check" +msgstr "Verifica����o GPG" + +msgid "GPG Key" +msgstr "Chave GPG" + +msgid "Add" +msgstr "Adicionar" + +msgid "Remove" +msgstr "Remover" + +msgid "Enable" +msgstr "Ativar" + +msgid "Disable" +msgstr "Desativar" + +msgid "Package Name" +msgstr "Nome do pacote" + +msgid "Version" +msgstr "Vers��o" + +msgid "Architecture" +msgstr "Arquitetura" + +msgid "Repository" +msgstr "Reposit��rio" + +msgid "Update All" +msgstr "Atualizar todos" + +msgid "Updating..." +msgstr "Atualizando..." + +msgid "Failed to retrieve packages update information." +msgstr "N��o foi poss��vel recuperar as informa����es de atualiza����o de pacoates." + +msgid "Failed to update package(s)." +msgstr "Erro ao atualizar pacote(s)." + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"Relat��rio de debug ser�� permanentemente removido e n��o poder�� ser " +"recuperado. Deseja continuar?" + +msgid "Generated Time" +msgstr "Tempo gerado" + +msgid "Generate" +msgstr "Gerar" + +msgid "Generating..." +msgstr "Gerando..." + +msgid "Rename" +msgstr "Renomear" + +msgid "Download" +msgstr "Baixar" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "" +"Nome do relat��rio deve apenas conter letras, n��meros, underscore ('_') e/ou " +"h��fen ('-')." + +msgid "Pending..." +msgstr "Pendente..." + +msgid "Report name is the same as the original one." +msgstr "Nome do relat��rio �� o mesmo que o original." + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "" +"A m��quina virtual vai ser removida com todos seus discos. Essa opera����o �� " +"irrevers��vel. Deseja continuar?" + +msgid "Power off Confirmation" +msgstr "Confirma����o de desligamento for��ado" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" +"Essa a����o pode produzir resultados n��o desej��veis, como por exemplo cache de " +"disco n��o-atualizado no guest. Deseja continuar?" + +msgid "Reset Confirmation" +msgstr "Confirma����o de reinicializa����o" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" +"Existe um risco de perda de dados causado pela reinicializa����o sem o " +"desligamento do sistema operacional do guest. Deseja continuar?" + +msgid "Shut Down Confirmation" +msgstr "Confirma����o de desligamento" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "" +"O sistema operacional do guest pode ignorar essa requisi����o. Deseja " +"continuar?" + +msgid "Virtual Machine delete Confirmation" +msgstr "Confirma����o de Remo����o da M��quina Virtual" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" +"Essa m��quina virtual n��o �� persistente. O desligamento ir�� remov��-la. Deseja " +"continuar?" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" +"Quando o guest de destino tiver volumes SCSI ou iSCSI, eles ser��o clonados " +"no storage pool padr��o. O mesmo vai acontecer quando o pool de destino n��o " +"tiver espa��o suficiente para clonar os volumes. Voc�� deseja continuar?" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" +"Esse CDROM ser�� desconectado permanentemente e voc�� pode reconect��-lo. " +"Deseja continuar a remo����o? " + +msgid "Attaching..." +msgstr "Adicionando..." + +msgid "Replacing..." +msgstr "Substituindo..." + +msgid "Successfully attached!" +msgstr "Adicionado com sucesso!" + +msgid "Successfully replaced!" +msgstr "Substitu��do com sucesso!" + +msgid "Successfully detached!" +msgstr "Removido com sucesso!" + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" +"Esse disco ser�� desconectado permanentemente e voc�� pode reconect��-lo. " +"Deseja continuar a remo����o? " + +msgid "interface:" +msgstr "interface:" + +msgid "address:" +msgstr "endere��o:" + +msgid "link_type:" +msgstr "tipo do link:" + +msgid "block:" +msgstr "bloco:" + +msgid "drive_type:" +msgstr "tipo do drive:" + +msgid "model:" +msgstr "modelo:" + +msgid "Affected devices:" +msgstr "Dispositivos afetados:" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "ID da VLAN deve ser um n��mero entre 1 e 4094." + +msgid "unavailable" +msgstr "indispon��vel" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "" +"Esta a����o ir�� interromper a conectividade da rede para qualquer m��quina " +"virtual que depende dessa rede." + +msgid "Create a network" +msgstr "Criar uma rede" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"Essa rede n��o �� persistente. Ao inv��s de parar, essa a����o ir�� remov��-la " +"permantemente. Deseja continuar?" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "O storage pool vai ser permanentemente removido. Deseja continuar?" + +msgid "This storage pool is empty." +msgstr "Esse storage pool est�� vazio." + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "" +"Isso formatar�� seu disco e voc�� perder�� toda informa����o, voc�� tem certeza " +"que quer continuar?" + +msgid "SCSI Fibre Channel" +msgstr "SCSI Fibre Channel" + +msgid "No SCSI adapters found." +msgstr "Nenhum adaptador SCSI encontrado." + +msgid "Loading iSCSI targets..." +msgstr "Carregando iSCSI targets..." + +msgid "No iSCSI found. Please input one." +msgstr "Nenhum iSCSI encontrado. Por favor, forne��a um." + +msgid "Failed to load iSCSI targets." +msgstr "Erro ao carregar iSCSI targets." + +msgid "The storage pool name can not be blank." +msgstr "O nome do storage pool n��o pode ser vazio." + +msgid "The storage pool path can not be blank." +msgstr "O caminho do storage pool n��o pode ser vazio." + +msgid "NFS server mount path can not be blank." +msgstr "Caminho de montagem do servidor de NFS n��o pode ser vazio." + +msgid "Invalid NFS mount path." +msgstr "Caminho de montagem do NFS inv��lido." + +msgid "No logical device selected." +msgstr "Nenhum dispositivo l��gico selecionado." + +msgid "The iSCSI target can not be blank." +msgstr "O alvo iSCSI n��o pode ser vazio." + +msgid "Server name can not be blank." +msgstr "Nome do servidor n��o pode ser vazio." + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "Este n��o �� um nome ou IP de servidor v��lido. Por favor, modifique-o." + +msgid "Looking for available partitions ..." +msgstr "Procurando por parti����es dispon��veis ..." + +msgid "No available partitions found." +msgstr "Nenhuma parti����o dispon��vel encontrada." + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"O storage pool n��o �� persistente. Ao inv��s de desativar, essa a����o vai " +"remov��-lo permanentemente. Deseja continuar?" + +msgid "Unable to retrieve partitions information." +msgstr "N��o foi poss��vel recuperar as informa����es das parti����es." + +msgid "In progress..." +msgstr "Em progresso..." + +msgid "Failed!" +msgstr "Falhou!" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" +"Caminho do CDROM precisa ser um caminho local v��lido e n��o pode ser vazio." + +msgid "Disk pool or volume cannot be blank." +msgstr "Pool ou volume do disco n��o pode ser vazio." + +#, fuzzy +msgid "Filter" +msgstr "filtro" + +msgid "Network Name" +msgstr "Nome da rede" + +msgid "State" +msgstr "Estado" + +msgid "Network Type" +msgstr "Tipo da rede" + +msgid "Address Space" +msgstr "Espa��o de endere��o" + +msgid "Name should not contain '/' and '\"'." +msgstr "O nome n��o deve conter '/' and '\"'." + +msgid "Isolated: no external network connection" +msgstr "Isolada: nenhuma conex��o externa" + +msgid "NAT: outbound physical network connection only" +msgstr "NAT: somente conex��o de rede f��sica de sa��da" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "" +"Bridged: M��quinas virtuais est��o conectadas diretamente com a rede f��sica" + +msgid "(No interfaces found)" +msgstr "(Nenhuma interface encontrada)" + +msgid "Destination" +msgstr "Destino" + +msgid "Enable VLAN" +msgstr "Habilitar VLAN" + +msgid "VLAN ID" +msgstr "ID da VLAN" + +msgid "Stop" +msgstr "Parar" + +msgid "Generate a New Debug Report" +msgstr "Gerar um novo Relat��rio de Debug" + +msgid "Report Name" +msgstr "Nome do Relat��rio" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" +"O nome usado para identificar o relat��rio. Se omitido, um nome ser�� " +"escolhido baseado no hor��rio atual. O nome pode conter: letras, n��meros, " +"underscore ('_') e h��fen ('-')." + +msgid "Rename a Debug Report" +msgstr "Renomear um Relat��rio de Debug" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" +"O nome usado para identificar o relat��rio. O nome pode conter: letras, " +"d��gitos e h��fen (\"-\")." + +msgid "Submit" +msgstr "Enviar" + +msgid "Add a Repository" +msgstr "Adicionar um Reposit��rio" + +msgid "Identifier" +msgstr "Identificador" + +msgid "Single word, unique identifier for the repository." +msgstr "Uma ��nica palavra, identificador ��nico para o reposit��rio." + +msgid "Textual name for the repository." +msgstr "Nome textual para o reposit��rio." + +msgid "URL" +msgstr "URL" + +msgid "Required Field" +msgstr "Campo Obrigat��rio" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "URL para o reposit��rio. Protocolos suportados s��o http, ftp e file." + +msgid "Repository is a mirror" +msgstr "Reposit��rio �� um mirror" + +msgid "Distribution" +msgstr "Distribui����o" + +msgid "Distribution of the DEB repository." +msgstr "Distribui����o para o reposit��rio DEB." + +msgid "Components" +msgstr "Componentes" + +msgid "List of components in DEB repository." +msgstr "Lista de componentes para o reposit��rio DEB." + +msgid "Edit Repository" +msgstr "Editar Reposit��rio" + +msgid "Mirror List URL" +msgstr "URL para a lista de mirror" + +msgid "Yes" +msgstr "Sim" + +msgid "No" +msgstr "N��o" + +msgid "Capacity" +msgstr "Capacidade" + +msgid "Allocated" +msgstr "Alocado" + +msgid "Location" +msgstr "Localiza����o" + +msgid "Device path" +msgstr "Caminho do dispositivo" + +msgid "active" +msgstr "ativo" + +msgid "inactive" +msgstr "inativo" + +msgid "Deactivate" +msgstr "Desativar" + +msgid "Activate" +msgstr "Ativar" + +msgid "Add Volume" +msgstr "Adicionar volume" + +msgid "Extend" +msgstr "Aumentar" + +msgid "Undefine" +msgstr "Indefinir" + +msgid "Format" +msgstr "Formato" + +msgid "Allocation" +msgstr "Aloca����o" + +msgid "Define a New Storage Pool" +msgstr "Definir novo Storage Pool" + +msgid "Storage Pool Name" +msgstr "Nome do Storage Pool" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "O nome usado para identificar o storage pool e n��o deve ser vazio." + +msgid "Storage Pool Type" +msgstr "Tipo do Storage Pool" + +msgid "Storage Path" +msgstr "Caminho do storage" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "" +"O caminho do Storage Pool. Cada Storage Pool deve ter um caminho ��nico." + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "" +"O Kimchi vai tentar criar o diret��rio se ainda n��o existir no seu sistema." + +msgid "NFS Server IP" +msgstr "IP do servidor NFS" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" +"IP ou hostname do servidor NFS. Pode ser inserido ou escolhido do hist��rico." + +msgid "NFS Path" +msgstr "Caminho do NFS" + +msgid "The NFS exported path on NFS server." +msgstr "O caminho exportado do servidor NFS." + +msgid "iSCSI Server" +msgstr "Servidor iSCSI" + +msgid "Server" +msgstr "Servidor" + +msgid "Port" +msgstr "Porta" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "IP ou hostname do servidor iSCSI. N��o deve ser vazio." + +msgid "Target" +msgstr "Alvo" + +msgid "The iSCSI target on iSCSI server" +msgstr "O alvo iSCSI no servidor iSCSI" + +msgid "Add iSCSI Authentication" +msgstr "Adicionar as credenciais do iSCSI" + +msgid "iSCSI Authentication" +msgstr "Credenciais do iSCSI" + +msgid "User Name" +msgstr "Usu��rio" + +msgid "Password" +msgstr "Senha" + +msgid "SCSI Adapter" +msgstr "Adaptador SCSI" + +msgid "Please, wait..." +msgstr "Por favor, aguarde..." + +msgid "Add a Volume to Storage Pool" +msgstr "Adicionar um volume ao Storage Pool" + +msgid "Fetch from remote URL" +msgstr "Fazer download de uma URL remota" + +msgid "Enter the remote URL here." +msgstr "Digite a URL remota aqui." + +msgid "Upload a file" +msgstr "Fazer upload de um arquivo" + +msgid "Choose the file you want to upload." +msgstr "Escolha o arquivo que voc�� quer fazer upload." + +msgid "Add Template" +msgstr "Adicionar Modelo" + +msgid "Where is the source media for this template? " +msgstr "Onde est�� a m��dia de origem desse modelo? " + +msgid "Local ISO Image" +msgstr "Imagem ISO Local" + +msgid "Local Image File" +msgstr "Arquivo de Imagem Local" + +msgid "Remote ISO Image" +msgstr "Imagem ISO Remota" + +msgid "Search ISOs" +msgstr "Procurar ISOs" + +msgid "The following ISOs are available:" +msgstr "As seguintes ISOs est��o dispon��veis:" + +msgid "OS: " +msgstr "Sistema Operacional: " + +msgid "Version: " +msgstr "Vers��o: " + +msgid "Size: " +msgstr "Tamanho: " + +msgid "Search more ISOs" +msgstr "Procurar por mais ISOs" + +msgid "Create Templates from Selected ISO" +msgstr "Criar Modelos a partir das ISOs selecionadas" + +msgid "I want to use a specific ISO file" +msgstr "Eu quero usar um arquivo ISO espec��fico" + +msgid "Loading default remote ISOs ..." +msgstr "Carregando ISOs remotas ..." + +msgid "Arch: " +msgstr "Arquitetura: " + +msgid "I want to use a custom URL" +msgstr "Eu quero usar uma URL personalizada" + +msgid "Edit Template" +msgstr "Editar Modelo" + +msgid "CDROM" +msgstr "CD-ROM" + +msgid "Image File" +msgstr "Arquivo de imagem" + +msgid "Graphics" +msgstr "Gr��ficos" + +msgid "Disk(GB)" +msgstr "Disco (GB)" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "Quantidade de CPUs" + +msgid "Manually set CPU topology" +msgstr "Configurar manualmente a topologia de CPU" + +msgid "Cores" +msgstr "Cores" + +msgid "Threads" +msgstr "Threads" + +msgid "No templates found." +msgstr "Nenhum modelo encontrado." + +#~ msgid "Delete is not allowed for %(resource)s" +#~ msgstr "M��todo de remo����o n��o �� permitido em %(resource)s" + +#~ msgid "%(resource)s does not implement update method" +#~ msgstr "%(resource)s n��o implementa m��todo de atualiza����o" + +#~ msgid "Create is not allowed for %(resource)s" +#~ msgstr "M��todo de cria����o n��o �� permitido em %(resource)s" + +#~ msgid "Unable to parse JSON request" +#~ msgstr "N��o �� poss��vel realizar a leitura da requisi����o do JSON" + +#~ msgid "This API only supports JSON" +#~ msgstr "Essa API suporta apenas JSON" + +#~ msgid "Parameters does not match requirement in schema: %(err)s" +#~ msgstr "Par��metros n��o correspondem �� especifica����o do esquema: %(err)s" + +#~ msgid "You don't have permission to perform this operation." +#~ msgstr "Voc�� n��o tem permiss��o para executar esta opera����o." + +#~ msgid "Datastore is not initiated in the model object." +#~ msgstr "Datastore n��o est�� inicializado no objeto modelo." + +#~ msgid "Unable to start task due error: %(err)s" +#~ msgstr "N��o foi poss��vel iniciar a tarefa devido a um erro: %(err)s" + +#~ msgid "" +#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" +#~ msgstr "" +#~ "Autentica����o falhou para o usu��rio '%(username)s'. [C��digo de erro: %" +#~ "(code)s]" + +#~ msgid "You are not authorized to access Kimchi" +#~ msgstr "Voc�� n��o est�� autorizado para acessar o Kimchi" + +#~ msgid "Specify %(item)s to login into Kimchi" +#~ msgstr "Especifique %(item)s para autenticar no Kimchi" + +#~ msgid "Invalid LDAP configuration: %(item)s : %(value)s" +#~ msgstr "Configura����es LDAP inv��lidas: %(item)s : %(value)s" + +#~ msgid "Unable to find %(item)s in datastore" +#~ msgstr "N��o foi poss��vel encontrar %(item)s no datastore" + +#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +#~ msgstr "" +#~ "Fim do limite de tempo ao rodar comando '%(cmd)s' ap��s %(seconds)s " +#~ "segundos" + +#~ msgid "Invalid data value '%(value)s'" +#~ msgstr "Valor inv��lido '%(value)s'" + +#~ msgid "Invalid data unit '%(unit)s'" +#~ msgstr "Unidade inv��lida '%(unit)s'" + +#~ msgid "Peers" +#~ msgstr "Peers" + +#~ msgid "Searching" +#~ msgstr "Procurando" + +#~ msgid "No peers found." +#~ msgstr "Nenhum peer encontrado." + +#~ msgid "Help" +#~ msgstr "Ajuda" + +#~ msgid "About" +#~ msgstr "Sobre" + +#~ msgid "Log out" +#~ msgstr "Sair" + +#~ msgid "Version:" +#~ msgstr "Vers��o:" + +#~ msgid "Session timeout, please re-login." +#~ msgstr "" +#~ "Fim do limite do tempo da sess��o, por favor se autentique novamente." diff --git a/src/wok/plugins/kimchi/po/ru_RU.po b/src/wok/plugins/kimchi/po/ru_RU.po new file mode 100644 index 0000000..a5dec2e --- /dev/null +++ b/src/wok/plugins/kimchi/po/ru_RU.po @@ -0,0 +1,2198 @@ +# English translations for kimchi package. +# Copyright (C) 2013 ORGANIZATION +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2014-08-28 17:32+0000\n" +"Last-Translator: Aline Manera <aline.manera@gmail.com>\n" +"Language-Team: Russian (http://www.transifex.com/projects/p/kimchi/language/" +"ru/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ru_RU\n" +"Generated-By: pygettext.py 1.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "" + +msgid "Unknown \"_cap\" specified" +msgstr "" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "������������ ������������������ �������������� ������������������. ����������������: %(err)s" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "������������ ������������������ �������������������� �� �������������� ���������������������� ������ %(device)s." + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "���� ������������ �������� ���������������� ����: %(filename)s" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "" +"������������ �������������� ���������� ���������������� ���� %(filename)s. ������������������, ������ ������ �������� JSON." + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "���� �������������� ���������� �� �������������� %(portal)s ���������� iSCSI. ����������������: %(err)s" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "���� �������������� ���������� �� �������������� %(target)s ���������� iSCSI %(host)s" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "�������� ISO %(filename)s ���� ����������������������" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" +"�������� ISO %(filename)s ���� ���������������� �������������������� ���������������������� ������������ El Torito" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "������������������������ ������������ ���������������� El Torito �� ������������ ISO %(filename)s" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "������������������������ ������������������ ���������������� El Torito �� ������������ ISO %(filename)s" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "���������������������� ������ �������� ������ ���������������� �������� �� ������������ ISO %(filename)s" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "���������������� ������������ ���������������������� �������� �� ������������ ISO %(filename)s" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" +"�� ���������������������� ������ �������� �������������� ������ �������������������������� ���������� ������������ ISO %(filename)" +"s. ���������������������� ������ �� �������������� /var/lib/libvirt, ���������������� �������������������� ���� ���������� " +"�� ������������ ���������������� �������������� ������ ������������������������ %(user)s, �������� ������ ����������������, " +"���������������� %(user)s �� ������������ �������� �� ������������ ISO ������ (���� ��������������������������) " +"������������������ �������������� 'chmod -R o+x 'path_to_iso'. ����������������: %(err)s" + +msgid "An error occurred when probing image OS information." +msgstr "" + +msgid "No OS information found in given image." +msgstr "" + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "���������������������� ������������ %(name)s ������ ��������������������" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "���������������������� ������������ %(name)s ���� ��������������������" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" +"���� �������������� ���������������� ������������ ������������ ������ �������������������������� ���������������������� ������������ %" +"(name)s" + +msgid "Remote ISO image is not supported by this server." +msgstr "������������������ ���������� ISO ���� ���������������������������� �������� ����������������." + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "���� �������������� ���������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" +"���������� ������������ ���������������� ������ ���������������������� �������������������� ������������ �������� IPv4 ������ IPv6" + +msgid "Specify a template to create a virtual machine from" +msgstr "�������������� ������������ ������ ���������������� ���������������������� ������������" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "���� �������������� ������������������ ���������������������� ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "" +"���� �������������� �������������������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" + +msgid "User name list must be an array" +msgstr "" + +msgid "User name must be a string" +msgstr "������ �������� ������������ �������� ��������������" + +msgid "Group name list must be an array" +msgstr "" + +msgid "Group name must be a string" +msgstr "������ �������� ������������ �������� ��������������" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "������������������������ %(users)s ���� ��������������������." + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "������������������������ %(groups)s ���� ��������������������." + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������������� ���������������������� ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "���� �������������� ������������������ ���������������������� ������������ %(name)s. ����������������: %(err)s" + +msgid "The guest console password must be a string." +msgstr "" + +msgid "The life time for the guest console password must be a number." +msgstr "" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" + +msgid "\"name\" should be a device name string" +msgstr "" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "������������������ %(iface)s ���� �������������������� �� ���������������������� ������������ %(name)s" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" +"�������� %(network)s, ������������������ ������ ���������������������� ������������ %(name)s, ���� ��������������������" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "���������������������������� ������������ �������� ������ ���������������������� ���������������������� ������������ - ��������" + +msgid "Network name for virtual machine interface must be a string" +msgstr "������ �������� ������ �������������������� ���������������������� ������������ ������������ �������� ��������������" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" +"�������������� ������������������������ ���������� ������������ �������� ������ �������������������� ���������������������� ������������" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "�������������� ������ �� �������� ������ �������������������� ������������ �������������������� ���������������������� ������������" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "������������ %(name)s ������ ��������������������" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "�������� %(network)s, ������������������ ������ �������������� %(template)s, ���� ��������������������" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "������ ������������ %(pool)s, ������������������ ������ �������������� %(template)s, ���� ��������������������" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "������ ������������ %(pool)s, ������������������ ������ �������������� %(template)s, ���� ��������������" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "������������ ������������������������ ���������������� %(param)s ������ CDROM." + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "�������� %(network)s, ������������������ ������ �������������� %(template)s, ���� ��������������" + +msgid "Template name must be a string" +msgstr "������ �������������� ������������ �������� ��������������" + +msgid "Template icon must be a path to the image" +msgstr "������������ �������������� ������������ �������� ���������� �� ������������" + +msgid "Template distribution must be a string" +msgstr "�������������� �������������� ������������ �������� ��������������" + +msgid "Template distribution version must be a string" +msgstr "������������ ���������������� �������������� ������������ �������� ��������������" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "���������� ���������������������� ������������ �������� ���������� ������������" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "���������� ������������ (����) ������������ �������� ���������� ������������ ������������ 512" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "CDROM �������������� ������������ �������� ������������������ ������ ������������������ ������������ ISO" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "������ �������������� ������������ ������������������������ URI �������� ������������ %(value)s" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "�������������� ���������� ISO �� ���������������� CDROM ������ ���������������� ��������������" + +msgid "All networks for the template must be specified in a list." +msgstr "������ �������� ������ �������������� ������������ �������� �������������� �� ������������." + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "���� �������������� �������������� ������������ ����-���� ������������ %(err)s" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "���� �������������� �������������� ������������ ����-���� ������������ %(err)s" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "" + +msgid "Template base image must be a valid local image file" +msgstr "CDROM �������������� ������������ �������� ������������������ ������ ������������������ ������������ ISO" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "������ ������������ %(name)s ������ ��������������������" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "������ ������������ %(name)s ���� ��������������������" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "�������������� %(item)s ������ ���������������� �������� ������������ %(name)s" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "���� �������������� �������������� ���������������� ������ ������������ %(name)s" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "���� �������������� �������������� ������������ ���������� ������������. ����������������: %(err)s" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������� ������ ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "" +"���� �������������� ���������������� ���������� ���������� �� �������� ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "���� �������������� ������������������������ ������ ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "���� �������������� ���������������������������� ������ ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������� ������ ������������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" +"���� �������������� �������������� ������ NFS: �������������������������������� �������� %(path)s ������ �������� " +"������������������������ ���� ���������� ������������������������" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" +"���� �������������� �������������� ������ NFS: ���� �������������� ������������������������ �������������������������������� �������� %" +"(path)s" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "�������������������������������� ������ �������� ������������: %(type)s" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" + +msgid "Storage pool path must be a string" +msgstr "�������� �� �������� ������������ ������������ �������� ��������������" + +msgid "Storage pool host must be a IP or hostname" +msgstr "�������� �������� ������������ ������������ �������� IP-�������������� ������ ������������ ����������" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" + +msgid "Storage pool devices parameter must be a list" +msgstr "���������������� ������������������ �������� ������������ ������������ �������� ��������������" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "�������������� IQN �������� iSCSI ������������ �������� ��������������" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "�������� �������������������� �������������� ������������ ������������ �������� ���������� ������������ ���� 1 ���� 65535" + +msgid "iSCSI target username must be a string" +msgstr "" + +msgid "iSCSI target password must be a string" +msgstr "" + +msgid "Specify name and type to create a storage pool" +msgstr "�������������� ������ �� ������ ������ ���������������� �������� ������������" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "" +"%(disk)s ���� ���������������� �������������������� ������������/����������������. ���� �������������� ���������������� ������ �� " +"������ %(pool)s." + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "���������� �������������������� ���������� ������������������ ������������ ������ ���������������������� �������� ������������." + +msgid "The SCSI host adapter name must be a string." +msgstr "������ ���������������� ���������� SCSI ������������ �������� ��������������." + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "kimchi_isos �������� ������������ ���������������������������� ������ ���������������������� ��������������������������" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"���� �������������� ������������������������ ������ ������������ NFS %(name)s. ������������ NFS %(server)s " +"��������������������." + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "" +"���� �������������� ���������������������������� ������ ������������ NFS %(name)s. ������������ NFS %(server)s " +"��������������������." + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "" +"���� �������������� ���������������������������� ������ %(name)s: ������ ������������ �� �������������������� ������������������" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "���� �������������� �������������� ������ %(name)s: ������ ������������ �� �������������������� ������������������" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "" +"������������ ���������� �� ������������ %(name)s ������ ��������������������. ���������������� ������������ ������ ������ " +"���������������� ���������������������� ��������." + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "" +"���� �������������� ���������������� �������� ������������ �� ���������������������� ������������������ ������������������������ ����-���� " +"������������ %(err)s" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "������ %(name)s ������ ��������������������" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "������ %(name)s ���� �������������������� �� �������� ������������ %(pool)s" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "�������������� %(item)s ������ ���������������� �������� %(volume)s" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "���� �������������� �������������� ������������ ����������: ������ ������������ %(pool)s ���� ��������������" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "" +"���� �������������� �������������� ������ %(name)s �� �������� ������������ %(pool)s. ����������������: %(err)s" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "" +"���� �������������� �������������� ������������ ���������� �� �������� ������������ %(pool)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������� �������� %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������� ������ %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "���� �������������� ���������������� ������������ �������� %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "������ ������������ %(type)s ���� ������������������������ ���������������� �� ���������������� ����������" + +msgid "Storage volume name must be a string" +msgstr "������ �������� ������������ �������� ��������������" + +msgid "Storage volume allocation must be an integer number" +msgstr "������������������ �������� ������������ �������� ���������� ������������" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" + +msgid "Storage volume requires a volume name" +msgstr "�������� ������������������ ������" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "" +"���� �������������� ���������������� �������� ������������ �� ���������������������� �� ���������� ����-���� ������������ %(err)s" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "" + +msgid "Storage volume capacity must be an integer number." +msgstr "" + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "" + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "������������������ %(name)s ���� ��������������������" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "�������� %(name)s ������ ��������������������" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "�������� %(name)s ���� ��������������������" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "�������������� %(subnet)s, ������������������ ������ �������� %(network)s, ����������������������." + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" +"�������������� �������������� ������������������ ������ ���������������� �������� %(name)s �� ���������������� ���������� ��������" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "���� �������������� �������������� ���������������� �������� %(name)s" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "������������������ %(iface)s, ������������������ ������ �������� %(network)s, ������ ������������������������" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "" +"������������������ ������������ �������� �������������� ������������, ���������������������� ���������� ������ ������������������ " +"����������������������." + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������� �������� %(name)s. ����������������: %(err)s" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "���� ������������ ������������������ IP-���������� ������ �������� %(name)s" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "���������������������������� �������� ����������: isolated, NAT �� bridge" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "" +"�������������� �������� ������������ �������� ��������������, �������������������� IP-����������, �������������� ������ ���������� ��������" + +msgid "Network interface must be a string" +msgstr "�������������� ������������������ ������������ �������� ��������������" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "�������������� ���� VLAN ������������ �������� ���������� ������������ ���� 1 ���� 4094" + +msgid "Specify name and type to create a Network" +msgstr "�������������� ������ �� ������ ������ ���������������� ��������" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "" +"�������������������� ���������� %(name)s ���� ���������� �������� �������������������������� ���������������������� VLAN." + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "���� �������������� ������������������������ ������������������ %(iface)s: %(err)s." + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "" +"���� ������������ ������������������������ ������������������ %(iface)s. ������������������ ������������������ �������������������� " +"���������� ����������. " + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "�������������������� ���������� %(name)s ���� ��������������������" + +msgid "Debug report tool not found in system" +msgstr "�������������������� ���������������������� ������������ ���� ������������ �� ��������������" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "���� �������������� �������������� �������������������� ���������� %(name)s. ����������������: %(err)s." + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "���� �������������� �������������� �������������������� ���������� %(name)s. ����������������: %(err)s" + +msgid "You should give a name for the debug report file." +msgstr "" + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "" +"������������ ���������� �� ������������ %(name)s ������ ��������������������. ���������������� ������������ ������ ������ " +"���������������� ���������������������� ��������." + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "������������ ������������ %(server)s ���� �������������������������� Kimchi" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "�������������� ���� %(name)s ���� ��������������������" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "������������ %(name)s ���� �������������������� ���� ����������" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" +"���� �������������� ������������������ ������������ �������������� ����������: ���������������������� ���������������������� ������������" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "���� �������������� �������������������������� �������������� ����������: ���������������������� ���������������������� ������������" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "�������������������� %(name)s �������� ���� ��������������" + +msgid "Conflicting flag filters specified." +msgstr "" + +msgid "No packages marked for update" +msgstr "������ ��������������, �������������������� ������ ��������������������" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "���������� %(name)s ���� �������������� ������ ��������������������." + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "������������ ������������������ ��������������, �������������������� ������ ��������������������. ����������������: %(err)s" + +msgid "There is no compatible package manager for this system." +msgstr "������ ������������������������ ���������������������������� �������������� ������ �������� ��������������." + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "������������������������ URI %(uri)s" + +msgid "Unable to choose a virtual machine name" +msgstr "" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "������������������������ ������ ������������. ���������������������������� ��������: cdrom" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" + +msgid "Only CDROM path can be update." +msgstr "" + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "������������ ���������������� �������������������� ����������������: %(error)s" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "������������ �������������������� �������������������� ����������������: %(error)s" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "������������ ���������������� �������������������� ����������������: %(error)s" + +msgid "Do not support IDE device hot plug" +msgstr "" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "�������������� ������ �� �������� ������ �������������������� ������������ ���������� ���������������������� ������������" + +msgid "Specify path to update virtual machine disk" +msgstr "�������������� �������� ������ �������������������� ���������� ���������������������� ������������" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" + +msgid "Volume already in use by other virtual machine." +msgstr "" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "�������������� ������ �� �������� ������ �������������������� ������������ ���������� ���������������������� ������������" + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" + +msgid "YUM Repository ID must be one word only string." +msgstr "" +"���� ������������������ YUM ������������ �������� ��������������, ������������������ ������������ ���� ������������ ����������." + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "URL ������������������ ������������ �������� http://, ftp:// ������ file:// ." + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "" +"������������������������ ������������������ ������������������������ ���������� �������������� ����������������, ������������������������ " +"���������� ������������������." + +msgid "Distribution to DEB repository must be a string" +msgstr "�������������� ������ ������������������ DEB ������������ �������� ��������������" + +msgid "Components to DEB repository must be listed in a array" +msgstr "�������������������� ������ ������������������ DEB ������������ �������� ���������������������� �� ��������������" + +msgid "Components to DEB repository must be a string" +msgstr "�������������������� ������ ������������������ DEB ������������ �������� ��������������" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "������ ������������������ YUM ������������ �������� ��������������." + +msgid "GPG check must be a boolean value." +msgstr "���������������� GPG ������������ �������� ������������������ ������������������." + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "" +"�������� GPG ������������ �������� URL, ���������������������� ���� �������������������� �������� �� ������������������������ " +"ASCII." + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "���� �������������� ���������������� ������������������ %(repo_id)s." + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "������������������ %(repo_id)s ���� ��������������������." + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "���� ������������������ �������������������� �������������������� �������������������� ������ ��������������." + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "������������������ %(repo_id)s ������ ����������������." + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "������������������ %(repo_id)s ������ ������������������." + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "���� �������������� �������������� ������������������ %(repo_id)s." + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "���� �������������� ���������������� �� �������� ������������������������ ������������������ %(repo_file)s" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "�������������� �������������� ������������������ ������ ���������������� ������������������ DEB." + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "���� �������������� ���������������� ������������������ %(repo_id)s." + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "���� �������������� ������������������ ������������������ %(repo_id)s." + +msgid "YUM Repository ID already exists" +msgstr "���� ������������������ YUM ������ ��������������������" + +msgid "YUM Repository name must be a string" +msgstr "������ ������������������ YUM ������������ �������� ��������������" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "���� �������������� �������������� ������������ ����������������. ����������������: %(err)s" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "���� �������������� ���������������� �������������������� �� ������������������. ����������������: %(err)s" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "���� �������������� ���������������� ������������������. ����������������: %(err)s" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "���� �������������� �������������� ������������������. ����������������: %(err)s" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" + +msgid "The number of vCPUs is too large for this system." +msgstr "" + +msgid "Invalid vCPU/topology combination." +msgstr "" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "" + +msgid "ERROR CODE" +msgstr "������ ������������" + +msgid "REASON" +msgstr "��������������" + +msgid "STACK" +msgstr "��������" + +msgid "Go to Homepage" +msgstr "�������������� ���� �������������� ����������������" + +msgid "Create a New Virtual Machine" +msgstr "�������������� ���������� ���������������������� ������������" + +msgid "Virtual Machine Name" +msgstr "������ ���������������������� ������������" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" +"������ ������ �������������������������� ���������������������� ������������. �������� ���� ��������������, ������ ���������� �������������� " +"�� ���������������������� ���� �������������������������� ��������������." + +msgid "Template" +msgstr "������������" + +msgid "Please create a template first." +msgstr "��������������������, ���������������� ������������ �� ������������ ��������������." + +msgid "Create a Template" +msgstr "�������������� ������������" + +msgid "Please choose a template." +msgstr "��������������������, ���������������� ������������." + +msgid "OS" +msgstr "����" + +msgid "OS Version" +msgstr "������������ ����" + +msgid "CPUS" +msgstr "��������������������" + +msgid "Memory" +msgstr "������������" + +msgid "Create" +msgstr "��������������" + +msgid "Creating..." +msgstr "" + +msgid "Cancel" +msgstr "������������" + +msgid "Edit Guest" +msgstr "���������������� ���������������� ��������������" + +msgid "General" +msgstr "����������" + +msgid "Storage" +msgstr "������������������" + +msgid "Interface" +msgstr "������������������" + +msgid "Permission" +msgstr "������������" + +msgid "Host PCI Device" +msgstr "" + +msgid "Snapshot" +msgstr "" + +msgid "Name" +msgstr "������" + +msgid "CPUs" +msgstr "��������������������" + +msgid "Memory (MB)" +msgstr "������������ (����)" + +msgid "Icon" +msgstr "������������" + +msgid "Device" +msgstr "������ ��������������������" + +msgid "Path" +msgstr "�������� NFS" + +msgid "Network" +msgstr "��������" + +msgid "Type" +msgstr "������" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "" + +msgid "Selected system users and groups" +msgstr "" + +msgid "User" +msgstr "" + +msgid "All" +msgstr "������" + +msgid "To Add" +msgstr "" + +msgid "Added" +msgstr "" + +msgid "filter" +msgstr "" + +msgid "Product" +msgstr "" + +msgid "Vendor" +msgstr "������������" + +msgid "Created" +msgstr "" + +msgid "Save" +msgstr "������������������" + +msgid "Replace" +msgstr "����������������" + +msgid "Detach" +msgstr "������������������" + +msgid "revert" +msgstr "" + +msgid "Start" +msgstr "������������������" + +msgid "Reset" +msgstr "����������������" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "������������������" + +msgid "Actions" +msgstr "����������������" + +msgid "Connect" +msgstr "��������������������" + +msgid "Clone" +msgstr "����������������������" + +msgid "Edit" +msgstr "��������������������������" + +msgid "Shut Down" +msgstr "������������������ ������������" + +msgid "Delete" +msgstr "��������������" + +msgid "CPU" +msgstr "������������������" + +msgid "Disk I/O" +msgstr "���������������� ��������-����������" + +msgid "Network I/O" +msgstr "�������������� ��������-����������" + +msgid "Livetile" +msgstr "Livetile" + +msgid "No guests found." +msgstr "���� �������������� ���������������� ��������������." + +msgid "Add a Storage Device to VM" +msgstr "���������������� �������������������� ���������������� �� VM" + +msgid "Device Type" +msgstr "������ ��������������������" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "������ ��������������������. �� ������������ ������������ ���������������������������� ������������ \"cdrom\"." + +msgid "Storage Pool" +msgstr "������ ������������" + +msgid "Storage pool which volume located in" +msgstr "�������� �� �������� ������������ ������������ �������� ��������������" + +msgid "Storage Volume" +msgstr "������ �������� ������������" + +msgid "Storage volume to be attached" +msgstr "������ �������� ������������ �������� ��������������" + +msgid "File Path" +msgstr "�������� �� ����������" + +msgid "The ISO file path in the server for CDROM." +msgstr "�������� �� ���������� ISO ������ CDROM ���� ��������������." + +msgid "Attach" +msgstr "��������������������" + +msgid "Shut down" +msgstr "����������������" + +msgid "Restart" +msgstr "��������������������" + +msgid "Basic Information" +msgstr "�������������� ��������������������" + +msgid "OS Distro" +msgstr "�������������� ����" + +msgid "OS Code Name" +msgstr "�������������� ������ ����" + +msgid "Processor" +msgstr "������������������" + +msgid "CPU(s)" +msgstr "" + +msgid "System Statistics" +msgstr "������������������ ��������������������" + +msgid "Software Updates" +msgstr "�������������������� ������������������������ ����������������������" + +msgid "Update Progress" +msgstr "������ ��������������������" + +msgid "Repositories" +msgstr "������������������" + +msgid "Debug Reports" +msgstr "�������������������� ������������" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "�������������� ���������������� ������ ������������������������ ������ ������������. �������������� ������ ������." + +msgid "This field is required." +msgstr "������ ������������������������ ��������." + +msgid "Log in" +msgstr "����������" + +msgid "Logging in..." +msgstr "��������..." + +msgid "Host" +msgstr "��������" + +msgid "Guests" +msgstr "���������������� ��������������" + +msgid "Templates" +msgstr "��������������" + +msgid "Failed to get application configuration" +msgstr "���� �������������� ���������������� ������������������������ ��������������������" + +msgid "This is not a valid Linux path" +msgstr "�������� ������������������������ �������� �� Linux" + +msgid "This is not a valid URL." +msgstr "������ ������������������������ URL." + +msgid "No such data available." +msgstr "������ ���������� ������������." + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" +"������ ���������� �� ���������������� ����������. ������������������, ������ �������������� ���������� ���������������� �� ���������������� " +"������ ����������������������. ���������� ���� ������������ HTTP: %1. " + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "�������������������������� ����������������" + +msgid "OK" +msgstr "OK" + +msgid "Confirm" +msgstr "����������������������" + +msgid "Warning" +msgstr "����������������������������" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "����������������������..." + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "������������������" + +msgid "Detailed message:" +msgstr "������������������ ������������������:" + +msgid "No ISO found" +msgstr "" + +msgid "This is not a valid ISO file." +msgstr "�������� �������� ���� ���������������� �������������������� �������������� ISO." + +msgid "This may take a long time. Do you want to continue?" +msgstr "������ ������������ ���������� ��������������. ��������������������?" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "������������ ���������� ������������������������ ������������. ��������������������?" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" +"�������������������� ������������������ ������������ ��������������, ������������������ �� ������ ���������������� ���������������������� " +"������������!" + +msgid "Max:" +msgstr "��������.:" + +msgid "Utilization" +msgstr "��������������������������" + +msgid "Available" +msgstr "����������������" + +msgid "Read Rate" +msgstr "���������������� ������������" + +msgid "Write Rate" +msgstr "���������������� ������������" + +msgid "Received" +msgstr "����������������" + +msgid "Sent" +msgstr "��������������������" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"�������������������� ������������ �� �������������������� ���������� ���������������� �� ������������ �������������������������� ������������. " +"�������������������� �������������������� ������������/��������������������?" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "������������������ ���������� �������������� ������ ���������������������� ����������������������������. ��������������������?" + +msgid "ID" +msgstr "����" + +msgid "Base URL" +msgstr "�������������� URL" + +msgid "Is Mirror" +msgstr "�������������������� ����������" + +msgid "URL Args" +msgstr "������������������ URL" + +msgid "Enabled" +msgstr "����������������" + +msgid "GPG Check" +msgstr "���������������� GPG" + +msgid "GPG Key" +msgstr "�������� GPG" + +msgid "Add" +msgstr "����������������" + +msgid "Remove" +msgstr "��������������" + +msgid "Enable" +msgstr "����������������" + +msgid "Disable" +msgstr "������������������" + +msgid "Package Name" +msgstr "������ ������������" + +msgid "Version" +msgstr "������������" + +msgid "Architecture" +msgstr "����������������������" + +msgid "Repository" +msgstr "������������������" + +msgid "Update All" +msgstr "���������������� ������" + +msgid "Updating..." +msgstr "��������������������..." + +msgid "Failed to retrieve packages update information." +msgstr "" + +msgid "Failed to update package(s)." +msgstr "���� �������������� ���������������� ������������." + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "" +"�������������������� ���������� ���������� ������������ ������ ���������������������� ����������������������������. ��������������������?" + +msgid "Generated Time" +msgstr "���������� ����������������" + +msgid "Generate" +msgstr "��������������" + +msgid "Generating..." +msgstr "����������������..." + +msgid "Rename" +msgstr "��������������������������" + +msgid "Download" +msgstr "������������������" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "������ ������������ ������������ ������������������ ������������ ����������, ���������� �� ������������ ('-')." + +msgid "Pending..." +msgstr "����������������������..." + +msgid "Report name is the same as the original one." +msgstr "" + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "" +"���������� �������������� ���������������������� ������������ ������������ ���� ������������ ������������������������ ��������������. ������ " +"���������������������� ����������������. ��������������������?" + +msgid "Power off Confirmation" +msgstr "�������������������������� ����������������" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" + +msgid "Reset Confirmation" +msgstr "�������������������������� ����������������" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" + +msgid "Shut Down Confirmation" +msgstr "�������������������������� ����������������" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "������������ ���������� ������������������������ ������������. ��������������������?" + +msgid "Virtual Machine delete Confirmation" +msgstr "" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" +"�������� CDROM ���������� ����������������. ������ ���������� ���������� ���������� ��������������������. ������������������?" + +msgid "Attaching..." +msgstr "����������������������..." + +msgid "Replacing..." +msgstr "������������..." + +msgid "Successfully attached!" +msgstr "�������������� ������������������!" + +msgid "Successfully replaced!" +msgstr "�������������� ��������������!" + +msgid "Successfully detached!" +msgstr "�������������� ����������������!" + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" + +msgid "interface:" +msgstr "" + +msgid "address:" +msgstr "" + +msgid "link_type:" +msgstr "" + +msgid "block:" +msgstr "" + +msgid "drive_type:" +msgstr "" + +msgid "model:" +msgstr "" + +msgid "Affected devices:" +msgstr "" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "���� VLAN ������������ �������� ���� 1 ���� 4094." + +msgid "unavailable" +msgstr "��������������������" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "" +"������ ���������������� �������������� �������������� �������������������� �� �������� ���������������������� ����������, �������������� " +"�������������� ���� �������� ��������." + +msgid "Create a network" +msgstr "�������������� ��������" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"�������� ������ ������������ ���� ��������������������. ������������ ����������������������, ������ ���������������� ������������������������ " +"������ ������������. ��������������������?" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "������ ������������ ���������� ������������������������ ������������. ��������������������?" + +msgid "This storage pool is empty." +msgstr "�������� ������ ������������ ������������." + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "" +"�������� ���������� ����������������������������, �� ������ ������������ ���� ������ ���������� ����������������. ���� " +"�������������������������� ������������ ��������������������? " + +msgid "SCSI Fibre Channel" +msgstr "SCSI Fibre Channel" + +msgid "No SCSI adapters found." +msgstr "���� �������������� ���������������� SCSI." + +msgid "Loading iSCSI targets..." +msgstr "" + +msgid "No iSCSI found. Please input one." +msgstr "" + +msgid "Failed to load iSCSI targets." +msgstr "" + +msgid "The storage pool name can not be blank." +msgstr "���� �������������� ������ �������� ������������." + +msgid "The storage pool path can not be blank." +msgstr "���� ������������ �������� �� �������� ������������." + +msgid "NFS server mount path can not be blank." +msgstr "���� ������������ �������� ������������������������ �������������� NFS." + +msgid "Invalid NFS mount path." +msgstr "������������������������ �������� ������������������������ NFS." + +msgid "No logical device selected." +msgstr "���� �������������� �������������������� ��������������������." + +msgid "The iSCSI target can not be blank." +msgstr "���� ������������ �������������� ������������ iSCSI." + +msgid "Server name can not be blank." +msgstr "���� �������������� ������ ��������������." + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "" + +msgid "Looking for available partitions ..." +msgstr "���������� ������������������ ����������������..." + +msgid "No available partitions found." +msgstr "���� �������������� ������������������ ��������������." + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"�������� ������ ������������ ���� ��������������������. ������������ ����������������������, ������ ���������������� ������������������������ " +"������ ������������. ��������������������?" + +msgid "Unable to retrieve partitions information." +msgstr "���� �������������� ���������������� �������������������� �� ������������������. ����������������: %(err)s" + +msgid "In progress..." +msgstr "" + +msgid "Failed!" +msgstr "" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" + +msgid "Disk pool or volume cannot be blank." +msgstr "���� �������������� ������ �������� ������������." + +msgid "Filter" +msgstr "" + +msgid "Network Name" +msgstr "������ ��������" + +msgid "State" +msgstr "������������������" + +msgid "Network Type" +msgstr "������ ��������" + +msgid "Address Space" +msgstr "���������������� ������������������������" + +msgid "Name should not contain '/' and '\"'." +msgstr "������������������������ ������ �������� ������������. �� ���������� ���� ������������ �������� ���������������� '/'." + +msgid "Isolated: no external network connection" +msgstr "�������������������������� (������ �������������������� �������������� ��������������������)" + +msgid "NAT: outbound physical network connection only" +msgstr "NAT (������������ ������������������ �������������������� �������������� ��������������������)" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "���������� �������� (������������ ���������������������� ���������������������� ���������� �� �������������������� ��������)" + +msgid "(No interfaces found)" +msgstr "" + +msgid "Destination" +msgstr "�������������� ������������������������:" + +msgid "Enable VLAN" +msgstr "���������������� VLAN:" + +msgid "VLAN ID" +msgstr "" + +msgid "Stop" +msgstr "������������������" + +msgid "Generate a New Debug Report" +msgstr "�������������� ���������� �������������������� ����������" + +msgid "Report Name" +msgstr "������ ������������" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" +"������ ������ �������������������������� ������������. �������� ���� ��������������, ������ ���������� ������������������������ ���� " +"������������ ���������������� ��������������. ������ ���������� ������������������: ����������, ���������� �� ������������ (\"-\")." + +msgid "Rename a Debug Report" +msgstr "�������������� ���������� �������������������� ����������" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" +"������ ������ �������������������������� ������������. �������� ���� ��������������, ������ ���������� ������������������������ ���� " +"������������ ���������������� ��������������. ������ ���������� ������������������: ����������, ���������� �� ������������ (\"-\")." + +msgid "Submit" +msgstr "����������������������" + +msgid "Add a Repository" +msgstr "���������������� ������������������" + +msgid "Identifier" +msgstr "��������������������������" + +msgid "Single word, unique identifier for the repository." +msgstr "������������������ ���������� - �������������������� �������������������������� ������������������." + +msgid "Textual name for the repository." +msgstr "������������������ ������ ������������������." + +msgid "URL" +msgstr "URL" + +msgid "Required Field" +msgstr "������������������������ ��������" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "URL ������������������. ���������������������������� ������������������: http, ftp, file." + +msgid "Repository is a mirror" +msgstr "������������������ ���������������� �������������������� ������������." + +msgid "Distribution" +msgstr "��������������" + +msgid "Distribution of the DEB repository." +msgstr "�������������� ������������������ DEB." + +msgid "Components" +msgstr "��������������������" + +msgid "List of components in DEB repository." +msgstr "������������ ���������������������� �� ������������������ DEB." + +msgid "Edit Repository" +msgstr "���������������� ������������������" + +msgid "Mirror List URL" +msgstr "URL ������������ �������������������� ����������" + +msgid "Yes" +msgstr "����" + +msgid "No" +msgstr "������" + +msgid "Capacity" +msgstr "��������������" + +msgid "Allocated" +msgstr "����������������" + +msgid "Location" +msgstr "������������������������" + +msgid "Device path" +msgstr "�������� �� ��������������������" + +msgid "active" +msgstr "��������������" + +msgid "inactive" +msgstr "������������������" + +msgid "Deactivate" +msgstr "������������������" + +msgid "Activate" +msgstr "������������������������" + +msgid "Add Volume" +msgstr "" + +msgid "Extend" +msgstr "" + +msgid "Undefine" +msgstr "��������������" + +msgid "Format" +msgstr "������������:" + +msgid "Allocation" +msgstr "������������������ ����������������:" + +msgid "Define a New Storage Pool" +msgstr "�������������� ������ ������������" + +msgid "Storage Pool Name" +msgstr "������ �������� ������������" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "������ ������ �������������������������� ���������� ������������. ���� ���������� �������� ������������." + +msgid "Storage Pool Type" +msgstr "������ �������� ������������" + +msgid "Storage Path" +msgstr "�������� �� ����������" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "�������� �� �������� ������������. ������������ ������ ������������ ������������ ���������� �������������������� ��������." + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "Kimchi �������������������� �������������� ��������������, �������� ���� ���� �������������������� �� ��������������." + +msgid "NFS Server IP" +msgstr "IP-���������� �������������� NFS" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" +"IP-���������� ������ ������ ���������� �������������� NFS. ������ ���������� ������������ ������ �������������� �� " +"��������������������." + +msgid "NFS Path" +msgstr "�������� NFS" + +msgid "The NFS exported path on NFS server." +msgstr "�������������������������������� �������� NFS ���� �������������� NFS." + +msgid "iSCSI Server" +msgstr "������������ iSCSI" + +msgid "Server" +msgstr "������������" + +msgid "Port" +msgstr "��������" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "IP-���������� ������ ������ ���������� �������������� iSCSI. ���� ���������� �������� ������������." + +msgid "Target" +msgstr "�������������� ������������" + +msgid "The iSCSI target on iSCSI server" +msgstr "�������������� ������������ iSCSI ���� �������������� iSCSI" + +msgid "Add iSCSI Authentication" +msgstr "���������������� �������������������������� iSCSI" + +msgid "iSCSI Authentication" +msgstr "�������������������������� iSCSI" + +msgid "User Name" +msgstr "������ ������������������������" + +msgid "Password" +msgstr "������������" + +msgid "SCSI Adapter" +msgstr "�������������� SCSI" + +msgid "Please, wait..." +msgstr "������������������..." + +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + +msgid "Add Template" +msgstr "���������������� ������������" + +msgid "Where is the source media for this template? " +msgstr "������ ������������������ ���������������� ���������������� ������ ���������� ��������������?" + +msgid "Local ISO Image" +msgstr "������������������ ���������� ISO" + +msgid "Local Image File" +msgstr "" + +msgid "Remote ISO Image" +msgstr "������������������ ���������� ISO" + +msgid "Search ISOs" +msgstr "���������� �������������� ISO" + +msgid "The following ISOs are available:" +msgstr "������������������ ������������ ISO:" + +msgid "OS: " +msgstr "����: " + +msgid "Version: " +msgstr "������������: " + +msgid "Size: " +msgstr "������������: " + +msgid "Search more ISOs" +msgstr "���������� ���������������������������� �������������� ISO" + +msgid "Create Templates from Selected ISO" +msgstr "�������������� �������������� ���� ������������������ �������������� ISO" + +msgid "I want to use a specific ISO file" +msgstr "������������������������ �������������������� �������� ISO" + +msgid "Loading default remote ISOs ..." +msgstr "���������������� ������������������ ISO ���� ������������������..." + +msgid "Arch: " +msgstr "����������������������: " + +msgid "I want to use a custom URL" +msgstr "������������������������ ������������ URL" + +msgid "Edit Template" +msgstr "���������������� ������������" + +msgid "CDROM" +msgstr "CDROM" + +msgid "Image File" +msgstr "" + +msgid "Graphics" +msgstr "��������������" + +msgid "Disk(GB)" +msgstr "" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "�������������������� ����������������������" + +msgid "Manually set CPU topology" +msgstr "" + +msgid "Cores" +msgstr "" + +msgid "Threads" +msgstr "" + +msgid "No templates found." +msgstr "���� �������������� ��������������." + +#~ msgid "Delete is not allowed for %(resource)s" +#~ msgstr "���������������� ������������������ ������ %(resource)s" + +#~ msgid "%(resource)s does not implement update method" +#~ msgstr "%(resource)s ���� ������������������ ���������� ��������������������" + +#~ msgid "Create is not allowed for %(resource)s" +#~ msgstr "���������������� ������������������ ������ %(resource)s" + +#~ msgid "Unable to parse JSON request" +#~ msgstr "������������ �������������� �������������� JSON" + +#~ msgid "This API only supports JSON" +#~ msgstr "������ �������������� API ������������������������ ������������ JSON" + +#~ msgid "Datastore is not initiated in the model object." +#~ msgstr "������������������ ������������ �� �������������� ������������ ���� ��������������������������������." + +#~ msgid "Unable to start task due error: %(err)s" +#~ msgstr "���� �������������� ������������������ ������������ ����-���� ������������ %(err)s" + +#~ msgid "" +#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" +#~ msgstr "" +#~ "�������� �������������������������� ������������������������ %(username)s. [������ ������������: %(code)s]" + +#~ msgid "You are not authorized to access Kimchi" +#~ msgstr "������ �������� �������������� �� Kimchi" + +#~ msgid "Specify %(item)s to login into Kimchi" +#~ msgstr "�������������� %(item)s ������ ���������� �� Kimchi" + +#~ msgid "Unable to find %(item)s in datastore" +#~ msgstr "���� ������������ %(item)s �� ������������������ ������������" + +#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +#~ msgstr "���������� ��������-������ �������������������� �������������� %(cmd)s (%(seconds)s ��)" + +#~ msgid "Help" +#~ msgstr "������������" + +#~ msgid "About" +#~ msgstr "�� ������������������" + +#~ msgid "Log out" +#~ msgstr "����������" + +#~ msgid "Version:" +#~ msgstr "������������:" diff --git a/src/wok/plugins/kimchi/po/zh_CN.po b/src/wok/plugins/kimchi/po/zh_CN.po new file mode 100644 index 0000000..fc6dd84 --- /dev/null +++ b/src/wok/plugins/kimchi/po/zh_CN.po @@ -0,0 +1,2186 @@ +# i18n portable object for kimchi. +# Copyright (C) IBM, Corp. 2013-2014 +# ShaoHe Feng <shaohef@linux.vnet.ibm.com>, 2013-04-18. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2013-06-27 10:48+0000\n" +"Last-Translator: ShaoHe Feng <shaohef@linux.vnet.ibm.com>\n" +"Language-Team: ShaoHe Feng <shaohef@linux.vnet.ibm.com>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: zh_CN\n" +"Generated-By: pygettext.py 1.5\n" +"X-Poedit-Country: CHINA\n" +"X-Poedit-Language: Chinese\n" +"X-Poedit-SourceCharset: utf-8\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "������������ %(value)s" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "������'%(task)s������%(seconds)s������" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "���������������LDAP���������������%(user_id)s������" + +msgid "Unknown \"_cap\" specified" +msgstr "������������\"_cap\"" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "\"_passthrough\"���������\"true\"������\"false\"" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "\"_passthrough_affected_by\"���������������������������������" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "������������������������������������%(err)s" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "��������������� %(device)s ������������������" + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "���������������������������%(filename)s" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "������������������������������%(filename)s������������������������JSON������������������" + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "������������ %(portal)s ������iSCSI���������������������������%(err)s" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "������������iSCSI������%(host)s������������%(target)s���" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "������������ISO������ %(filename)s" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "ISO������%(filename)s���������������" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "ISO������%(filename)s���������������El Torito���������������" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "���ISO������%(filename)s������������������El Torito������������������" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "ISO������%(filename)s���El Torito������������������������" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "������������ISO������%(filename)s���������������" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "ISO������%(filename)s���������������������������" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" +"hypervisor������������ISO������%(filename)s���������������������ISO������/var/lib/libvirt���" +"���������������'%(user)s'���������������������������������'%(user)s'���������������ISO������������������" +"������������������������������������������ 'chmod -R o+x '���������������������������%(err)s" + +msgid "An error occurred when probing image OS information." +msgstr "������������������������������������������������" + +msgid "No OS information found in given image." +msgstr "���������������������������������������������������������" + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "������������������������ %(filename)s" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "���������������������������������������%(filename)s���������������������" + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "���������%(name)s������������" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "���������%(name)s���������" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" +"��������������������� %(name)s ������������������ %(new_name)s ������������������������������������" +"������" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "������������������������������������%(name)s���������" + +msgid "Remote ISO image is not supported by this server." +msgstr "���������������������������ISO���������" + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "��������� %(name)s ���������������" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������%(err)s" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������%(err)s" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������%(err)s" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "���������%(name)s���������������������������" + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "������������������������URI %(value)s" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "���������������������������URI %(value)s" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "������������������������������Spice������VNC" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "������������������������������������������IPv4���IPv6���������" + +msgid "Specify a template to create a virtual machine from" +msgstr "������������������������������������" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "��������������������� %(name)s. ���������%(err)s" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������%(err)s" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "��������������������� %(name)s������������%(err)s" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������%(err)s" + +msgid "User name list must be an array" +msgstr "������������������������������������" + +msgid "User name must be a string" +msgstr "���������������������������������" + +msgid "Group name list must be an array" +msgstr "������������������������������������" + +msgid "Group name must be a string" +msgstr "���������������������������������������" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "������'%(users)s'���������" + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "���������'%(groups)s'���������" + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������%(err)s" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "��������������������� %(name)s������������������������%(err)s" + +msgid "The guest console password must be a string." +msgstr "���������������������������������������������������" + +msgid "The life time for the guest console password must be a number." +msgstr "������������������������������������������������������������" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "���������'%(name)s'���������������������������������" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "���������������'%(name)s'���������������������������������" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "���������������������������'%(name)s'������������������%(err)s" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "���������%(vmid)s���������������������������������%(dev_name)s���" + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "������������%(dev_name)s������������������������������������" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" +"���������IOMMU groups���������PCI pass through������IOMMU group������������������������������" +"BIOS������������Intel VT-d ������ AMD IOMMU ���������������������������������������IOMMU���������" +"Intel CPU������������/boot/grub2/grub.conf���������������������intel_iommu=on���������AMD " +"CPU������������iommu=pt iommu=1���" + +msgid "\"name\" should be a device name string" +msgstr "\"name\"���������������������������������������" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "��������� %(name)s ��������������� %(iface)s" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "������������%(name)s���������������%(network)s���������" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "���������������������������������������" + +msgid "Network name for virtual machine interface must be a string" +msgstr "������������������������������������������������" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "���������������������������������������������" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "���������������������������������������������" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "������ %(name)s ������������" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "��������� %(template)s ��������������� '%(network)s' ���������" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "��������� %(template)s ������������������ '%(pool)s' ���������" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "��������� %(template)s ������������������ '%(pool)s' ������������" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "���CDROM��������������� '%(param)s' ������" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "��������� %(template)s ��������������� '%(network)s' ������������" + +msgid "Template name must be a string" +msgstr "���������������������������������������" + +msgid "Template icon must be a path to the image" +msgstr "���������������������������������������������������" + +msgid "Template distribution must be a string" +msgstr "������������������������������������������" + +msgid "Template distribution version must be a string" +msgstr "���������������������������������������������������" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "CPU���������������������������0���������" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "���������������MB���������������������������������512���������" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "���������CDROM������������������������������������ISO������" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "������������������������������������URI %(value)s" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "������������ISO���������������������������CDROM������������������" + +msgid "All networks for the template must be specified in a list." +msgstr "������������������������������������������������" + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "���������������������iSCSI������SCSI������������������������������������" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "���%(volume)s���������������%(pool)s���" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "������������������������������%(err)s" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "���������������%(err)s���������������������" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "������������������������1GB���" + +msgid "Template base image must be a valid local image file" +msgstr "������������������������������������������������������������" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "������������������������%(path)s������" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "CPU������������VCPUs������������sockets, cores ������threads���" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "CPU���������������������������������������������������������" + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" +"���������������������������������������������������bochs, cloop, cow, dmg, qcow, qcow2, qed, " +"raw, vmdk, vpc���" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "���������%(name)s������������" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "���������%(name)s���������" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "���������������%(name)s������%(item)s" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "������������������������������ %(name)s" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "������������������������ ��������� %(err)s" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "��������������������� %(name)s������������ %(err)s" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "���������������������%(name)s��������������������������� %(err)s" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������ %(err)s" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������ %(err)s" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������ %(err)s" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "������������NFS������������������������������%(path)s������������������������" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "������������NFS������������������������������%(path)s������" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "������������������������������%(type)s" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "���������������XML���%(pool)s���������������" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "������������������������dir���netfs���logical���iscsi���isci������kimchi-iso" + +msgid "Storage pool path must be a string" +msgstr "���������������������������������" + +msgid "Storage pool host must be a IP or hostname" +msgstr "������������������������������IP���������������" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "������������������������������������������������������" + +msgid "Storage pool devices parameter must be a list" +msgstr "������������������������������������������" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "iSCSI������������������IQN������������������" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "���������������������������������������1���65535���������������" + +msgid "iSCSI target username must be a string" +msgstr "iSCSI���������������������������������������" + +msgid "iSCSI target password must be a string" +msgstr "iSCSI������������������������������������" + +msgid "Specify name and type to create a storage pool" +msgstr "������������������������������������" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "%(disk)s ���������������������/������������������������������������%(pool)s���" + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "���������������������%(pool)s���������������������%(err)s" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "������������������������������������������������" + +msgid "The SCSI host adapter name must be a string." +msgstr "SCSI���������������������������������������" + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "���������kimchi_isos������������������" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "������������NFS���������%(name)s���NFS���������%(server)s���������������" + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "������������NFS���������%(name)s���NFS���������%(server)s���������������" + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "���������������������%(name)s������������������������������������" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "���������������������%(name)s������������������������������������" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "������'%(name)s'������������������������������������������������������������������" + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "������������������������������������������%(err)s���" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "���������%(name)s������������" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "���������%(pool)s������������������%(name)s" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "���������������������%(volume)s������������������%(pool)s ������������" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "���������������%(volume)s������������%(item)s" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "���������������������������������������%(pool)s������������" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "������������������%(pool)s������������������%(name)s������������%(err)s" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "������������������%(pool)s������������������������������%(err)s" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������%(err)s" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s������������%(err)s" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "���������������������%(name)s���������������������%(err)s" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "������������%(type)s������������������������������" + +msgid "Storage volume name must be a string" +msgstr "������������������������������������" + +msgid "Storage volume allocation must be an integer number" +msgstr "���������������������������������" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" +"������������������������������������������������bochs, cloop, cow, dmg, qcow, qcow2, qed, " +"raw, vmdk, vpc���" + +msgid "Storage volume requires a volume name" +msgstr "���������������������" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "���������������������������������������%(err)s" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "���������������%(param)s������������������������" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "������������%(param)s���������������" + +msgid "Storage volume capacity must be an integer number." +msgstr "������������������������������������" + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "���������URL���������http://���https://���ftp://���ftps://" + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "������������������%(url)s������������������������������������" + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "������������������'%(pool)s'���������������'%(name)s'���������������������%(err)s" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "������%(name)s���������" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "������%(name)s������������" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "������%(name)s���������" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "���������%(network)s���������������%(subnet)s������" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "������������������������������������������������������%(name)s" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "���������������������������%(name)s" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "���������%(network)s���������������%(iface)s������������" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "���������������������������������������������bonding���������������������" + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "������������������%(name)s������������%(err)s" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "���������������'%(name)s'������������������������IP���������������" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "���������������������������������NAT���������" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "���������������������������IP������������������������������������������������" + +msgid "Network interface must be a string" +msgstr "������������������������������������" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "������VLAN������������1���4094���������������" + +msgid "Specify name and type to create a Network" +msgstr "���������������������������������" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "������������������%(name)s������VLAN���trunk���������" + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "������������������������ %(iface)s���%(err)s���" + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "������������%(iface)s���������������������������������������������" + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "������������%(name)s������������������%(err)s" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "������������%(name)s���������" + +msgid "Debug report tool not found in system" +msgstr "���������������������������������" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "������������������������%(name)s������������%(err)s" + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "������������������������%(name)s���������������" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "������������������������%(name)s������������%(err)s" + +msgid "You should give a name for the debug report file." +msgstr "������������������������%(name)s������������%(err)s" + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" +"������������������������������������������������������������������������������������('_')���������������('-')" +"������������������" + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "���������\"'%(name)s\"���������������������������������������������������������" + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "���������������%(server)s������Kimchi������" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "������������'%(name)s'���������" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "������������������������%(name)s" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "������������������������������������������" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "������������������������������������������" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "������������������������'%(name)s'" + +msgid "Conflicting flag filters specified." +msgstr "flag filters���������" + +msgid "No packages marked for update" +msgstr "������������������������������" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "���������%(name)s������������������������" + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "���������������������������������������������������������%(err)s" + +msgid "There is no compatible package manager for this system." +msgstr "������������������������������������������" + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "���������URI %(uri)s" + +msgid "Unable to choose a virtual machine name" +msgstr "���������������������������������" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "������������������������������������������'cdrom'���'disk'" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "������'%(value)s'���������������������������/������������" + +msgid "Only CDROM path can be update." +msgstr "���������CDROM���������������" + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "������������%(dev_name)s������������%(vm_name)s������������" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "������������������������������������%(error)s" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "������������������������������%(error)s" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "������������������������������%(error)s" + +msgid "Do not support IDE device hot plug" +msgstr "���������IDE������������������" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "���������������������������������������������������������������������������/���������" + +msgid "Specify path to update virtual machine disk" +msgstr "������������������������������������" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "������������������%(type)s���������������������%(limit)s" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "���������������������������/������������������������������������������%(error)s" + +msgid "Volume already in use by other virtual machine." +msgstr "���������������������������������������" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "���������������������������������������������������������/���������������������" + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "���������%(format)s���������������������������%(type)s" + +msgid "YUM Repository ID must be one word only string." +msgstr "YUM������������ID������������������������������������������" + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "������������URL���������http://��� ftp:// ��� file://" + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "������������������������������������������������������������������" + +msgid "Distribution to DEB repository must be a string" +msgstr "DEB���������������������������������������������" + +msgid "Components to DEB repository must be listed in a array" +msgstr "DEB������������������������������������������" + +msgid "Components to DEB repository must be a string" +msgstr "DEB���������������������������������������" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "YUM���������������������������������������" + +msgid "GPG check must be a boolean value." +msgstr "GPG������������������������������" + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "GPG������������������������ASCII���������������.asc������������URL" + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "������������������������%(repo_id)s" + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "������������%(repo_id)s������������" + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "������������������������������������������" + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "������������%(repo_id)s���������������" + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "������������%(repo_id)s���������������" + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "������������������������%(repo_id)s" + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "������������������������������������%(repo_file)s" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "���������������������������������������������DEB���������" + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "������������������������%(repo_id)s" + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "������������������������%(repo_id)s" + +msgid "YUM Repository ID already exists" +msgstr "YUM������ID������������" + +msgid "YUM Repository name must be a string" +msgstr "YUM������������������������������������" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "������������������������������������'%(err)s'" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "���������������������������������������������'%(err)s'" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "������������������������������������'%(err)s'" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "������������������������������������'%(err)s'" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "���������������������������������: %(items)s" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "���������'%(vm)s'���������������������������������" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "������������������'%(vm)s'������������'%(name)s'������������%(err)s" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "������'%(name)s'������������������'%(vm)s'������" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "������������������'%(vm)s'������������'%(name)s'������������%(err)s" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "���������������������'%(vm)s'���������������������%(err)s" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "���������������������'%(vm)s'������'%(name)s'������������%(err)s" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "���������������������'%(vm)s'������������������������%(err)s" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "���������������������'%(vm)s'���������'%(name)s'������������%(err)s" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" +"������������������'%(vm)s'���������������������������������������'%(format)s'������������������������" +"���'qcow2'���������" + +msgid "The number of vCPUs is too large for this system." +msgstr "vCPUs������������������������������������" + +msgid "Invalid vCPU/topology combination." +msgstr "���������vCPU/topology���������" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "������������������������������������������CPU���������" + +msgid "ERROR CODE" +msgstr "���������" + +msgid "REASON" +msgstr "������" + +msgid "STACK" +msgstr "���������" + +msgid "Go to Homepage" +msgstr "������������" + +msgid "Create a New Virtual Machine" +msgstr "���������������������������" + +msgid "Virtual Machine Name" +msgstr "���������������" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "���������������������������������������������������������������������������������������������" + +msgid "Template" +msgstr "������" + +msgid "Please create a template first." +msgstr "������������������������" + +msgid "Create a Template" +msgstr "������������������" + +msgid "Please choose a template." +msgstr "������������������" + +msgid "OS" +msgstr "������������" + +msgid "OS Version" +msgstr "������������������" + +msgid "CPUS" +msgstr "���������������" + +msgid "Memory" +msgstr "������" + +msgid "Create" +msgstr "������" + +msgid "Creating..." +msgstr "������������..." + +msgid "Cancel" +msgstr "������" + +msgid "Edit Guest" +msgstr "���������������" + +msgid "General" +msgstr "������" + +msgid "Storage" +msgstr "������" + +msgid "Interface" +msgstr "������������" + +msgid "Permission" +msgstr "������" + +msgid "Host PCI Device" +msgstr "������PCI������" + +msgid "Snapshot" +msgstr "������" + +msgid "Name" +msgstr "������" + +msgid "CPUs" +msgstr "���������������" + +msgid "Memory (MB)" +msgstr "������(MB)" + +msgid "Icon" +msgstr "������" + +msgid "Device" +msgstr "������������" + +msgid "Path" +msgstr "������" + +msgid "Network" +msgstr "������" + +msgid "Type" +msgstr "������" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "���������������������������������" + +msgid "Selected system users and groups" +msgstr "���������������������������������" + +msgid "User" +msgstr "������" + +msgid "All" +msgstr "������" + +msgid "To Add" +msgstr "���������" + +msgid "Added" +msgstr "���������" + +msgid "filter" +msgstr "���������" + +msgid "Product" +msgstr "������" + +msgid "Vendor" +msgstr "������" + +msgid "Created" +msgstr "���������" + +msgid "Save" +msgstr "������" + +msgid "Replace" +msgstr "������" + +msgid "Detach" +msgstr "������" + +msgid "revert" +msgstr "������" + +msgid "Start" +msgstr "������" + +msgid "Reset" +msgstr "������" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "������������" + +msgid "Actions" +msgstr "������" + +msgid "Connect" +msgstr "���������" + +msgid "Clone" +msgstr "������������" + +msgid "Edit" +msgstr "������" + +msgid "Shut Down" +msgstr "������" + +msgid "Delete" +msgstr "������" + +msgid "CPU" +msgstr "���������" + +msgid "Disk I/O" +msgstr "������I/O" + +msgid "Network I/O" +msgstr "������I/O" + +msgid "Livetile" +msgstr "������" + +msgid "No guests found." +msgstr "���������������������" + +msgid "Add a Storage Device to VM" +msgstr "������������������������������������" + +msgid "Device Type" +msgstr "������������" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "������������������������������������������\"cdrom\"���\"disk\"��� " + +msgid "Storage Pool" +msgstr "���������" + +msgid "Storage pool which volume located in" +msgstr "���������������������������" + +msgid "Storage Volume" +msgstr "���������" + +msgid "Storage volume to be attached" +msgstr "���������������������" + +msgid "File Path" +msgstr "������������" + +msgid "The ISO file path in the server for CDROM." +msgstr "������������CDROM������������ISO������������" + +msgid "Attach" +msgstr "������" + +msgid "Shut down" +msgstr "������" + +msgid "Restart" +msgstr "������" + +msgid "Basic Information" +msgstr "������������" + +msgid "OS Distro" +msgstr "���������������������" + +msgid "OS Code Name" +msgstr "������������������" + +msgid "Processor" +msgstr "���������" + +msgid "CPU(s)" +msgstr "CPU(s)" + +msgid "System Statistics" +msgstr "������������������" + +msgid "Software Updates" +msgstr "������������" + +msgid "Update Progress" +msgstr "������������" + +msgid "Repositories" +msgstr "������������" + +msgid "Debug Reports" +msgstr "������������������" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "���������������������������������������������" + +msgid "This field is required." +msgstr "������������������" + +msgid "Log in" +msgstr "������" + +msgid "Logging in..." +msgstr "���������..." + +msgid "Host" +msgstr "������" + +msgid "Guests" +msgstr "���������" + +msgid "Templates" +msgstr "������" + +msgid "Failed to get application configuration" +msgstr "������������������������" + +msgid "This is not a valid Linux path" +msgstr "������������������������Linux������" + +msgid "This is not a valid URL." +msgstr "������������������������URL" + +msgid "No such data available." +msgstr "���������������������" + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" +"������������������������������������������������������������������������������������������HTTP���������������%1" + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "������������" + +msgid "OK" +msgstr "������" + +msgid "Confirm" +msgstr "������" + +msgid "Warning" +msgstr "������" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "������������..." + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "������" + +msgid "Detailed message:" +msgstr "���������������" + +msgid "No ISO found" +msgstr "������������ISO������" + +msgid "This is not a valid ISO file." +msgstr "������������������������ISO������" + +msgid "This may take a long time. Do you want to continue?" +msgstr "���������������������������������������" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "������������������������������������������" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "���������������������������������������������" + +msgid "Max:" +msgstr "���������" + +msgid "Utilization" +msgstr "���������" + +msgid "Available" +msgstr "������������" + +msgid "Read Rate" +msgstr "���������" + +msgid "Write Rate" +msgstr "���������" + +msgid "Received" +msgstr "������" + +msgid "Sent" +msgstr "������" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "���������������������������������������������������������������������������/���������" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "���������������������������������������������������������������" + +msgid "ID" +msgstr "���������" + +msgid "Base URL" +msgstr "������URL" + +msgid "Is Mirror" +msgstr "���������������" + +msgid "URL Args" +msgstr "URL������" + +msgid "Enabled" +msgstr "���������" + +msgid "GPG Check" +msgstr "GPG������" + +msgid "GPG Key" +msgstr "GPG���" + +msgid "Add" +msgstr "������" + +msgid "Remove" +msgstr "������" + +msgid "Enable" +msgstr "������" + +msgid "Disable" +msgstr "������" + +msgid "Package Name" +msgstr "���������������" + +msgid "Version" +msgstr "������" + +msgid "Architecture" +msgstr "������������" + +msgid "Repository" +msgstr "������������" + +msgid "Update All" +msgstr "������������" + +msgid "Updating..." +msgstr "������������..." + +msgid "Failed to retrieve packages update information." +msgstr "������������������������������������" + +msgid "Failed to update package(s)." +msgstr "���������������������" + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "���������������������������������������������������������������������" + +msgid "Generated Time" +msgstr "������������" + +msgid "Generate" +msgstr "������" + +msgid "Generating..." +msgstr "������������..." + +msgid "Rename" +msgstr "���������" + +msgid "Download" +msgstr "������" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "������������������������������������������������������('_')������������('-')" + +msgid "Pending..." +msgstr "������������..." + +msgid "Report name is the same as the original one." +msgstr "������������������������������������" + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "���������������������������������������������������������������������������������" + +msgid "Power off Confirmation" +msgstr "������������������" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "������������������������������������������������������������������������������������������������" + +msgid "Reset Confirmation" +msgstr "������������" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "������������������������������������������������������������������������������������������������������" + +msgid "Shut Down Confirmation" +msgstr "������������" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "���������������������������������������������������������������������������������" + +msgid "Virtual Machine delete Confirmation" +msgstr "���������������������" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "������������������������������������������������������������������������������������" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" +"������������������������SCSI������iSCSI���������������������������������������������������������������������" +"������������������������������������������������������������������������������������������������������" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "CDROM���������������������������������������������������������������" + +msgid "Attaching..." +msgstr "������������" + +msgid "Replacing..." +msgstr "������������..." + +msgid "Successfully attached!" +msgstr "������������" + +msgid "Successfully replaced!" +msgstr "������������" + +msgid "Successfully detached!" +msgstr "������������" + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "���������������������������������������������������������������������������������������?" + +msgid "interface:" +msgstr "���������" + +msgid "address:" +msgstr "���������" + +msgid "link_type:" +msgstr "���������������" + +msgid "block:" +msgstr "������" + +msgid "drive_type:" +msgstr "���������������" + +msgid "model:" +msgstr "���������" + +msgid "Affected devices:" +msgstr "���������������������" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "VLAN ������������������1���4094������" + +msgid "unavailable" +msgstr "������������" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "������������������������������������������������������������������" + +msgid "Create a network" +msgstr "������������������" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"���������" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "���������������������������������������������" + +msgid "This storage pool is empty." +msgstr "���������������������" + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "������������������������������������������������������������������������������������" + +msgid "SCSI Fibre Channel" +msgstr "SCSI������������" + +msgid "No SCSI adapters found." +msgstr "������������SCSI���������" + +msgid "Loading iSCSI targets..." +msgstr "������iSCSI������..." + +msgid "No iSCSI found. Please input one." +msgstr "������������iSCSI,������������������" + +msgid "Failed to load iSCSI targets." +msgstr "������iSCSI���������������" + +msgid "The storage pool name can not be blank." +msgstr "���������������������������������" + +msgid "The storage pool path can not be blank." +msgstr "���������������������������������" + +msgid "NFS server mount path can not be blank." +msgstr "NFS������������������������������������" + +msgid "Invalid NFS mount path." +msgstr "���������NFS���������������" + +msgid "No logical device selected." +msgstr "���������������������������" + +msgid "The iSCSI target can not be blank." +msgstr "iSCSI���������������������" + +msgid "Server name can not be blank." +msgstr "������������������������" + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "������������������������������������������IP���������������������������������" + +msgid "Looking for available partitions ..." +msgstr "��������������������� ..." + +msgid "No available partitions found." +msgstr "���������������������" + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "���������������������������������������������������������������������������������������������������" + +msgid "Unable to retrieve partitions information." +msgstr "���������������������������" + +msgid "In progress..." +msgstr "������������..." + +msgid "Failed!" +msgstr "���������" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "CDROM���������������������������������/������������������������������" + +msgid "Disk pool or volume cannot be blank." +msgstr "���������������������������" + +#, fuzzy +msgid "Filter" +msgstr "���������" + +msgid "Network Name" +msgstr "������������" + +msgid "State" +msgstr "������" + +msgid "Network Type" +msgstr "������������" + +msgid "Address Space" +msgstr "������������" + +msgid "Name should not contain '/' and '\"'." +msgstr "������������������������/������'\"'���" + +msgid "Isolated: no external network connection" +msgstr "������: ������������������������" + +msgid "NAT: outbound physical network connection only" +msgstr "NAT: ���������������������������������������" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "���������������������������������������������������������" + +msgid "(No interfaces found)" +msgstr "(������������������������)" + +msgid "Destination" +msgstr "������������" + +msgid "Enable VLAN" +msgstr "������VLAN" + +msgid "VLAN ID" +msgstr "VLAN���" + +msgid "Stop" +msgstr "������" + +msgid "Generate a New Debug Report" +msgstr "������������������������������" + +msgid "Report Name" +msgstr "���������������" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������������������������������ ('_') ���������������'-'���" + +msgid "Rename a Debug Report" +msgstr "���������������������������" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "������������������������������������������������������������������������������������(\"-\")���" + +msgid "Submit" +msgstr "������" + +msgid "Add a Repository" +msgstr "������������������������" + +msgid "Identifier" +msgstr "���������" + +msgid "Single word, unique identifier for the repository." +msgstr "���������������������������������������" + +msgid "Textual name for the repository." +msgstr "���������������������������" + +msgid "URL" +msgstr "URL" + +msgid "Required Field" +msgstr "���������������" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "���������������URL���������������������http���ftp������file" + +msgid "Repository is a mirror" +msgstr "���������������������������" + +msgid "Distribution" +msgstr "���������" + +msgid "Distribution of the DEB repository." +msgstr "DEB������������������" + +msgid "Components" +msgstr "������" + +msgid "List of components in DEB repository." +msgstr "DEB������������������������" + +msgid "Edit Repository" +msgstr "������������������" + +msgid "Mirror List URL" +msgstr "������������URL" + +msgid "Yes" +msgstr "���" + +msgid "No" +msgstr "���" + +msgid "Capacity" +msgstr "������" + +msgid "Allocated" +msgstr "���������" + +msgid "Location" +msgstr "������" + +msgid "Device path" +msgstr "������������" + +msgid "active" +msgstr "���������" + +msgid "inactive" +msgstr "���������" + +msgid "Deactivate" +msgstr "������" + +msgid "Activate" +msgstr "������" + +msgid "Add Volume" +msgstr "���������" + +msgid "Extend" +msgstr "������" + +msgid "Undefine" +msgstr "������������" + +msgid "Format" +msgstr "������" + +msgid "Allocation" +msgstr "������" + +msgid "Define a New Storage Pool" +msgstr "���������������������������" + +msgid "Storage Pool Name" +msgstr "���������������" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "���������������������������������������������������������������" + +msgid "Storage Pool Type" +msgstr "���������������" + +msgid "Storage Path" +msgstr "������������" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "������������������.���������������������������������������" + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "������������������������KIMCHI���������������������������������������������" + +msgid "NFS Server IP" +msgstr "NFS���������IP" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "NFS���������IP���������������������������������������������������������������������" + +msgid "NFS Path" +msgstr "NFS ������" + +msgid "The NFS exported path on NFS server." +msgstr "NFS���������������������NFS������" + +msgid "iSCSI Server" +msgstr "iSCSI���������" + +msgid "Server" +msgstr "���������" + +msgid "Port" +msgstr "������" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "iSCSI���������IP������������������ ���������������" + +msgid "Target" +msgstr "������" + +msgid "The iSCSI target on iSCSI server" +msgstr "iSCSI������" + +msgid "Add iSCSI Authentication" +msgstr "������ISCSI������" + +msgid "iSCSI Authentication" +msgstr "iSCSI������" + +msgid "User Name" +msgstr "���������" + +msgid "Password" +msgstr "������" + +msgid "SCSI Adapter" +msgstr "SCSI���������" + +msgid "Please, wait..." +msgstr "���������..." + +msgid "Add a Volume to Storage Pool" +msgstr "���������������������������" + +msgid "Fetch from remote URL" +msgstr "���������URL������" + +msgid "Enter the remote URL here." +msgstr "���������������������URL���" + +msgid "Upload a file" +msgstr "������������������" + +msgid "Choose the file you want to upload." +msgstr "������������������������������" + +msgid "Add Template" +msgstr "������������" + +msgid "Where is the source media for this template? " +msgstr "������������������������������" + +msgid "Local ISO Image" +msgstr "������ISO������" + +msgid "Local Image File" +msgstr "������������������" + +msgid "Remote ISO Image" +msgstr "������ISO������" + +msgid "Search ISOs" +msgstr "������ISO" + +msgid "The following ISOs are available:" +msgstr "������ISO������������" + +msgid "OS: " +msgstr "��������������� " + +msgid "Version: " +msgstr "��������� " + +msgid "Size: " +msgstr "���������" + +msgid "Search more ISOs" +msgstr "������������ISO" + +msgid "Create Templates from Selected ISO" +msgstr "������������ISO���������������" + +msgid "I want to use a specific ISO file" +msgstr "������������ISO������" + +msgid "Loading default remote ISOs ..." +msgstr "���������������������ISOs ..." + +msgid "Arch: " +msgstr "���������������" + +msgid "I want to use a custom URL" +msgstr "���������������������������URL" + +msgid "Edit Template" +msgstr "������������" + +msgid "CDROM" +msgstr "������" + +msgid "Image File" +msgstr "������������" + +msgid "Graphics" +msgstr "������" + +msgid "Disk(GB)" +msgstr "������(GB)" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "CPU������" + +msgid "Manually set CPU topology" +msgstr "������������CPU������" + +msgid "Cores" +msgstr "���������" + +msgid "Threads" +msgstr "������" + +msgid "No templates found." +msgstr "������������������" + +#~ msgid "Delete is not allowed for %(resource)s" +#~ msgstr "���������������%(resource)s" + +#~ msgid "%(resource)s does not implement update method" +#~ msgstr "���������������%(resource)s" + +#~ msgid "Create is not allowed for %(resource)s" +#~ msgstr "���������������%(resource)s" + +#~ msgid "Unable to parse JSON request" +#~ msgstr "������������JSON������" + +#~ msgid "This API only supports JSON" +#~ msgstr "������API���������JSON" + +#~ msgid "Parameters does not match requirement in schema: %(err)s" +#~ msgstr "���������������������������������%(err)s" + +#~ msgid "You don't have permission to perform this operation." +#~ msgstr "������������������������������������" + +#~ msgid "Datastore is not initiated in the model object." +#~ msgstr "���������model������������������������������" + +#~ msgid "Unable to start task due error: %(err)s" +#~ msgstr "������������%(err)s������������������" + +#~ msgid "" +#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" +#~ msgstr "������'%(username)s'������������������.[���������������%(code)s]" + +#~ msgid "You are not authorized to access Kimchi" +#~ msgstr "������������������������Kimchi" + +#~ msgid "Specify %(item)s to login into Kimchi" +#~ msgstr "������������Kimchi���%(item)s" + +#~ msgid "Invalid LDAP configuration: %(item)s : %(value)s" +#~ msgstr "���������LDAP���������%(item)s : %(value)s" + +#~ msgid "Unable to find %(item)s in datastore" +#~ msgstr "���������������������������%(item)s" + +#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +#~ msgstr "������'%(cmd)s'������%(seconds)s���������������" + +#~ msgid "Peers" +#~ msgstr "���������" + +#~ msgid "Searching" +#~ msgstr "������������" + +#~ msgid "No peers found." +#~ msgstr "������������������������" + +#~ msgid "Help" +#~ msgstr "������" + +#~ msgid "About" +#~ msgstr "������" + +#~ msgid "Log out" +#~ msgstr "������" + +#~ msgid "Version:" +#~ msgstr "���������" + +#~ msgid "Session timeout, please re-login." +#~ msgstr "���������������������������������" diff --git a/src/wok/plugins/kimchi/po/zh_TW.po b/src/wok/plugins/kimchi/po/zh_TW.po new file mode 100644 index 0000000..90045b5 --- /dev/null +++ b/src/wok/plugins/kimchi/po/zh_TW.po @@ -0,0 +1,2138 @@ +# English translations for kimchi package. +# Copyright (C) 2013 ORGANIZATION +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-01 16:11-0300\n" +"PO-Revision-Date: 2013-07-11 17:32-0400\n" +"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" +"Language-Team: English\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: zh_TW\n" +"Generated-By: pygettext.py 1.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, python-format +msgid "Unknown parameter %(value)s" +msgstr "" + +#, python-format +msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s." +msgstr "" + +#, python-format +msgid "User %(user_id)s not found with given LDAP settings." +msgstr "" + +msgid "Unknown \"_cap\" specified" +msgstr "" + +msgid "\"_passthrough\" should be \"true\" or \"false\"" +msgstr "" + +msgid "\"_passthrough_affected_by\" should be a device name string" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "���������������������������������������������������%(err)s" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "������ %(device)s ���������������������������������������" + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "��������� distro ���������%(filename)s" + +#, python-format +msgid "" +"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file." +msgstr "������������ distro ���������%(filename)s������������������ JSON ���������" + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "������������ iSCSI ������������ %(portal)s������������������%(err)s" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "������������ iSCSI ������ %(host)s ������ %(target)s" + +#, python-format +msgid "Unable to find ISO file %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "ISO ������ %(filename)s ������������" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "ISO ������ %(filename)s ��������������� El Torito ������������" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "ISO %(filename)s ��������������� El Torito ������������" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "ISO %(filename)s ��������������� El Torito ���������������" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "ISO %(filename)s ���������������������������������������������" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "������ ISO %(filename)s ���������������������������������������������" + +#, python-format +msgid "" +"The hypervisor doesn't have permission to use this ISO %(filename)s. " +"Consider moving it under /var/lib/libvirt, or set the search permission to " +"file access control lists for '%(user)s' user if possible, or add the '%" +"(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x " +"'path_to_iso'.Details: %(err)s" +msgstr "" +"Hypervisor ��������������� ISO %(filename)s ��������������������������������������� /var/lib/" +"libvirt ������������������������������'%(user)s' ���������������������������������������������������������" +"��� '%(user)s' ��������� ISO ������������������������������������������������������ 'chmod -R o+x " +"'path_to_iso'������������������%(err)s" + +msgid "An error occurred when probing image OS information." +msgstr "" + +msgid "No OS information found in given image." +msgstr "" + +#, python-format +msgid "Unable to read image file %(filename)s" +msgstr "" + +#, python-format +msgid "" +"Image file must be an existing file on system. %(filename)s is not a valid " +"input." +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s already exists" +msgstr "������������ %(name)s ���������" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "������������ %(name)s ���������" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s is already " +"in use or the virtual machine is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "��������������������������������� %(name)s ���������" + +msgid "Remote ISO image is not supported by this server." +msgstr "��������������������������� ISO ������������" + +#, python-format +msgid "Screenshot is not supported on virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to update virtual machine %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to connect to powered off virtual machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string without slashes (/)" +msgstr "" + +#, python-format +msgid "Invalid template URI %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are Spice or VNC" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "������������������������������������ IPv4 ��� IPv6" + +msgid "Specify a template to create a virtual machine from" +msgstr "���������������������������������������" + +#, python-format +msgid "Unable to start virtual machine %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to power off virtual machine %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to delete virtual machine %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to reset virtual machine %(name)s. Details: %(err)s" +msgstr "������������������������������ %(name)s������������������%(err)s" + +msgid "User name list must be an array" +msgstr "" + +msgid "User name must be a string" +msgstr "���������������������������" + +msgid "Group name list must be an array" +msgstr "" + +msgid "Group name must be a string" +msgstr "���������������������������" + +#, python-format +msgid "User(s) '%(users)s' do not exist" +msgstr "��������� '%(users)s' ������������" + +#, python-format +msgid "Group(s) '%(groups)s' do not exist" +msgstr "��������� '%(groups)s' ������������" + +#, python-format +msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +#, python-format +msgid "" +"Unable to get access metadata of virtual machine %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +msgid "The guest console password must be a string." +msgstr "" + +msgid "The life time for the guest console password must be a number." +msgstr "" + +#, python-format +msgid "Virtual machine '%(name)s' must be stopped before cloning it." +msgstr "" + +#, python-format +msgid "Insufficient disk space to clone virtual machine '%(name)s'" +msgstr "" + +#, python-format +msgid "Unable to clone VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Invalid operation for non-persistent virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Cannot suspend VM '%(name)s' because it is not running." +msgstr "" + +#, python-format +msgid "Unable to suspend VM '%(name)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Cannot resume VM '%(name)s' because it is not paused." +msgstr "" + +#, python-format +msgid "Unable to resume VM '%(name)s'. Details: %(err)s" +msgstr "" + +msgid "Memory assigned is higher then the maximum allowed in the host." +msgstr "" + +#, python-format +msgid "" +"VM '%(name)s' does not support live memory update. Update the memory with " +"the machine offline to enable this feature." +msgstr "" + +msgid "Only increase memory is allowed in active VMs" +msgstr "" + +msgid "" +"For live memory update, new memory value must be equal old memory value plus " +"multiples of 1024 Mib" +msgstr "" + +msgid "There are not enough free slots of 1024 Mib in the guest." +msgstr "" + +msgid "" +"Host's libvirt version does not support memory devices. Libvirt must be >= " +"1.2.14" +msgstr "" + +#, python-format +msgid "Error attaching memory device. Details: %(error)s" +msgstr "" + +#, python-format +msgid "" +"VM %(vmid)s does not contain directly assigned host device %(dev_name)s." +msgstr "" + +#, python-format +msgid "The host device %(dev_name)s is not allowed to directly assign to VM." +msgstr "" + +msgid "" +"No IOMMU groups found. Host PCI pass through needs IOMMU group to function " +"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify " +"the Kernel is compiled with IOMMU support. For Intel CPU, add intel_iommu=on " +"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt " +"iommu=1." +msgstr "" + +msgid "\"name\" should be a device name string" +msgstr "" + +#, python-format +msgid "" +"The device %(name)s is probably in use by the host. Unable to attach it to " +"the guest." +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "������ %(iface)s ������������������������ %(name)s ���" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "��������������� %(name)s ��������������� %(network)s ���������" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "���������������������������������������������������" + +msgid "Network name for virtual machine interface must be a string" +msgstr "������������������������������������������������" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "���������������������������������������������������" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "������������������������������������������������" + +msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF" +msgstr "" + +#, python-format +msgid "MAC Address %(mac)s already exists in virtual machine %(name)s" +msgstr "" + +msgid "Invalid MAC Address" +msgstr "" + +msgid "Cannot change MAC address of a running virtual machine" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "������ %(name)s ���������" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "��������� %(template)s ��������������� '%(network)s' ���������" + +#, python-format +msgid "" +"Storage pool %(pool)s specified for template %(template)s does not exist" +msgstr "��������� %(template)s ������������������ '%(pool)s' ���������" + +#, python-format +msgid "Storage pool %(pool)s specified for template %(template)s is not active" +msgstr "��������� %(template)s ������������������ '%(pool)s' ������������������������" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for CDROM." +msgstr "��� CDROM ��������������� '%(param)s' ���������" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "��������� %(template)s ��������������� %(network)s ������������������������" + +msgid "Template name must be a string" +msgstr "���������������������������" + +msgid "Template icon must be a path to the image" +msgstr "������������������������������������" + +msgid "Template distribution must be a string" +msgstr "���������������������������������" + +msgid "Template distribution version must be a string" +msgstr "���������������������������������" + +msgid "The number of CPUs must be an integer greater than 0" +msgstr "CPU ���������������������" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "��������������� (MB) ��������������� 512 ���������" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "������ CDROM ������������������������ ISO ������" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for template" +msgstr "��������������������������� URI %(value)s ������" + +msgid "Specify an ISO image as CDROM or a base image to create a template" +msgstr "������ ISO ��������������� CDROM ���������������" + +msgid "All networks for the template must be specified in a list." +msgstr "���������������������������������������������������" + +msgid "Specify a volume to a template when storage pool is iSCSI or SCSI" +msgstr "" + +#, python-format +msgid "The volume %(volume)s is not in storage pool %(pool)s" +msgstr "" + +#, python-format +msgid "Unable to create template due error: %(err)s" +msgstr "������������������������������������������%(err)s" + +#, python-format +msgid "Unable to delete template due error: %(err)s" +msgstr "������������������������������������������%(err)s" + +msgid "Disk size must be an integer greater than 1GB." +msgstr "" + +msgid "Template base image must be a valid local image file" +msgstr "������ CDROM ������������������������ ISO ������" + +#, python-format +msgid "Cannot identify base image %(path)s format" +msgstr "" + +msgid "" +"When specifying CPU topology, VCPUs must be a product of sockets, cores, and " +"threads." +msgstr "" + +msgid "" +"When specifying CPU topology, each element must be an integer greater than " +"zero." +msgstr "" + +msgid "" +"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, " +"qcow2, qed, raw, vmdk, vpc." +msgstr "" + +#, python-format +msgid "Storage pool %(name)s already exists" +msgstr "��������� %(name)s ���������" + +#, python-format +msgid "Storage pool %(name)s does not exist" +msgstr "��������� %(name)s ���������" + +#, python-format +msgid "Specify %(item)s in order to create the storage pool %(name)s" +msgstr "������ %(item)s ������������������ %(name)s" + +#, python-format +msgid "Unable to delete active storage pool %(name)s" +msgstr "��������������������������������� %(name)s" + +#, python-format +msgid "Unable to list storage pools. Details: %(err)s" +msgstr "���������������������������������������%(err)s" + +#, python-format +msgid "Unable to create storage pool %(name)s. Details: %(err)s" +msgstr "��������������������� %(name)s������������������%(err)s" + +#, python-format +msgid "" +"Unable to get number of storage volumes in storage pool %(name)s. Details: %" +"(err)s" +msgstr "��������������������� %(name)s ������������������������������������������%(err)s" + +#, python-format +msgid "Unable to activate storage pool %(name)s. Details: %(err)s" +msgstr "��������������������� %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s" +msgstr "��������������������������� %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to delete storage pool %(name)s. Details: %(err)s" +msgstr "��������������������� %(name)s������������������%(err)s" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "������������ NFS ������������������������������������������������ %(path)s ���������������" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "������������ NFS ������������������������������ %(path)s ������������" + +#, python-format +msgid "Unsupported storage pool type: %(type)s" +msgstr "���������������������������������%(type)s" + +#, python-format +msgid "Error while retrieving storage pool XML to %(pool)s" +msgstr "" + +msgid "Storage pool name must be a string without slashes (/)" +msgstr "" + +msgid "" +"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-" +"iso" +msgstr "" + +msgid "Storage pool path must be a string" +msgstr "������������������������������" + +msgid "Storage pool host must be a IP or hostname" +msgstr "������������������������ IP ���������������" + +msgid "Storage pool device must be the absolute path to the block device" +msgstr "" + +msgid "Storage pool devices parameter must be a list" +msgstr "������������������������������������" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "iSCSI ������������������ IQN ���������������" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "��������������������������������������������� 1 ��� 65535 ���������������" + +msgid "iSCSI target username must be a string" +msgstr "" + +msgid "iSCSI target password must be a string" +msgstr "" + +msgid "Specify name and type to create a storage pool" +msgstr "���������������������������������������" + +#, python-format +msgid "" +"%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)" +"s." +msgstr "%(disk)s ���������������������/������������������������������������������%(pool)s���" + +#, python-format +msgid "Unable to extend logical pool %(pool)s. Details: %(err)s" +msgstr "" + +msgid "The parameter disks only can be updated for logical storage pool." +msgstr "������������������������������������������������������������" + +msgid "The SCSI host adapter name must be a string." +msgstr "SCSI ���������������������������������������" + +msgid "The storage pool kimchi_isos is reserved for internal use" +msgstr "��������� kimchi_isos ���������������������" + +#, python-format +msgid "" +"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "������������ NFS ��������� %(name)s���NFS ��������� %(server)s���������������" + +#, python-format +msgid "" +"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is " +"unreachable." +msgstr "������������������ NFS ��������� %(name)s���NFS ��������� %(server)s���������������" + +#, python-format +msgid "" +"Unable to deactivate pool %(name)s as it is associated with some templates" +msgstr "��������������������������� %(name)s������������������������������������" + +#, python-format +msgid "Unable to delete pool %(name)s as it is associated with some templates" +msgstr "��������������������� %(name)s������������������������������������" + +#, python-format +msgid "" +"A volume group named '%(name)s' already exists. Please, choose another name " +"to create the logical pool." +msgstr "������ '%(name)s' ������������������������������������������������������������������������������" + +#, python-format +msgid "Unable to update database with deep scan information due error: %(err)s" +msgstr "������������������������������������������������������������������������%(err)s" + +#, python-format +msgid "Storage volume %(name)s already exists" +msgstr "������������ %(name)s ���������" + +#, python-format +msgid "Storage volume %(name)s does not exist in storage pool %(pool)s" +msgstr "������������ %(name)s ��������������������� %(pool)s ���" + +#, python-format +msgid "" +"Unable to create storage volume %(volume)s because storage pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create storage volume %(volume)s" +msgstr "������ %(item)s ��������������������� %(volume)s" + +#, python-format +msgid "" +"Unable to list storage volumes because storage pool %(pool)s is not active" +msgstr "������������������������������������������ %(pool)s ������������������������" + +#, python-format +msgid "" +"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %" +"(err)s" +msgstr "������������������ %(pool)s ��������������������� %(name)s������������������%(err)s" + +#, python-format +msgid "" +"Unable to list storage volumes in storage pool %(pool)s. Details: %(err)s" +msgstr "��������������������� %(pool)s ������������������������������������%(err)s" + +#, python-format +msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to delete storage volume %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to resize storage volume %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s ���������������������������%(err)s" + +#, python-format +msgid "Storage type %(type)s does not support volume create and delete" +msgstr "��������������� %(type)s ������������������������������" + +msgid "Storage volume name must be a string" +msgstr "���������������������������������" + +msgid "Storage volume allocation must be an integer number" +msgstr "���������������������������������" + +msgid "" +"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, " +"qcow, qcow2, qed, raw, vmdk, vpc." +msgstr "" + +msgid "Storage volume requires a volume name" +msgstr "������������������������������" + +#, python-format +msgid "" +"Unable to update database with storage volume information due error: %(err)s" +msgstr "������������������������������������������������������������������������%(err)s" + +#, python-format +msgid "Only one of parameter %(param)s can be specified" +msgstr "" + +#, python-format +msgid "Create volume from %(param)s is not supported" +msgstr "" + +msgid "Storage volume capacity must be an integer number." +msgstr "" + +msgid "Storage volume URL must be http://, https://, ftp:// or ftps://." +msgstr "" + +#, python-format +msgid "Unable to access file %(url)s. Please, check it." +msgstr "" + +#, python-format +msgid "" +"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)" +"s" +msgstr "" + +msgid "Specify chunk data and its size to upload a file." +msgstr "" + +msgid "In order to upload a storage volume, specify the 'upload' parameter." +msgstr "" + +msgid "" +"Unable to upload chunk data as it does not match with requested chunk size." +msgstr "" + +#, python-format +msgid "The storage volume %(vol)s is not under an upload process." +msgstr "" + +msgid "The upload chunk data will exceed the storage volume size." +msgstr "" + +#, python-format +msgid "Unable to upload chunk data to storage volume. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "������ %(name)s ���������" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "������ %(name)s ���������" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "������ %(name)s ���������" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "��������� %(network)s ������������������ %(subnet)s ���������" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "������������������������������������������ %(name)s" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "������������������������������ %(name)s" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "��������� %(network)s ��������������� %(iface)s ���������������" + +msgid "Interface should be bare NIC, bonding or bridge device." +msgstr "��������������������� NIC������������������������������������" + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "������������������ %(name)s������������������%(err)s" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "��������������� '%(name)s' ��������� IP ������" + +#, python-format +msgid "The interface %(iface)s already exists." +msgstr "" + +msgid "Network name must be a string without slashes (/) or quotes (\")" +msgstr "" + +msgid "Supported network types are isolated, NAT and bridge" +msgstr "���������������������������������������NAT ������������" + +msgid "Network subnet must be a string with IP address and prefix or netmask" +msgstr "��������������������������������� IP ���������������������������������������" + +msgid "Network interface must be a string" +msgstr "���������������������������" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "������ VLAN ID ��������������� 1 ��� 4094 ���������������" + +msgid "Specify name and type to create a Network" +msgstr "������������������������������������" + +#, python-format +msgid "" +"Unable to delete network %(name)s. There are some virtual machines %(vms)s " +"and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "" +"Unable to deactivate network %(name)s. There are some virtual machines %(vms)" +"s and/or templates linked to this network." +msgstr "" + +#, python-format +msgid "Bridge device %(name)s can not be the trunk device of a VLAN." +msgstr "��������������� %(name)s ��������� VLAN ������������������" + +#, python-format +msgid "Failed to activate interface %(iface)s: %(err)s." +msgstr "������������������ %(iface)s���%(err)s���" + +#, python-format +msgid "" +"Failed to activate interface %(iface)s. Please check the physical link " +"status." +msgstr "������������������ %(iface)s���������������������������������" + +#, python-format +msgid "Failed to start network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "������������ %(name)s ���������" + +msgid "Debug report tool not found in system" +msgstr "���������������������������������������" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "������������������������ %(name)s������������������%(err)s���" + +#, python-format +msgid "Can not find any debug report with the given name %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "������������������������ %(name)s������������������%(err)s" + +msgid "You should give a name for the debug report file." +msgstr "" + +msgid "" +"Debug report name must be a string. Only letters, digits, underscore ('_') " +"and hyphen ('-') are allowed." +msgstr "" + +#, python-format +msgid "" +"The debug report with specified name \"%(name)s\" already exists. Please use " +"another one." +msgstr "������ '%(name)s' ������������������������������������������������������������������������������" + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "Kimchi ��������������������������� %(server)s" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "Distro '%(name)s' ���������" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "��������� %(name)s ���������������������" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "���������������������������������������������������������������" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "������������������������������������������������������������������������" + +#, python-format +msgid "Node device '%(name)s' not found" +msgstr "��������������������� '%(name)s'" + +msgid "Conflicting flag filters specified." +msgstr "" + +msgid "No packages marked for update" +msgstr "������������������������������������" + +#, python-format +msgid "Package %(name)s is not marked to be updated." +msgstr "������ %(name)s ������������������������������" + +#, python-format +msgid "Error while getting packages marked to be updated. Details: %(err)s" +msgstr "������������������������������������������������������������������������%(err)s" + +msgid "There is no compatible package manager for this system." +msgstr "���������������������������������������������" + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "URI %(uri)s ������" + +msgid "Unable to choose a virtual machine name" +msgstr "" + +msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" +msgstr "���������������������������������������������'cdrom'" + +#, python-format +msgid "The path '%(value)s' is not a valid local/remote path for the device" +msgstr "" + +msgid "Only CDROM path can be update." +msgstr "" + +#, python-format +msgid "" +"The storage device %(dev_name)s does not exist in the virtual machine %" +"(vm_name)s" +msgstr "" + +#, python-format +msgid "Error while creating new storage device: %(error)s" +msgstr "������������������������������������������%(error)s" + +#, python-format +msgid "Error while updating storage device: %(error)s" +msgstr "������������������������������������%(error)s" + +#, python-format +msgid "Error while removing storage device: %(error)s" +msgstr "������������������������������������%(error)s" + +msgid "Do not support IDE device hot plug" +msgstr "" + +msgid "" +"Specify type and path or type and pool/volume to add a new virtual machine " +"disk" +msgstr "������������������������������������������������" + +msgid "Specify path to update virtual machine disk" +msgstr "���������������������������������������" + +#, python-format +msgid "Controller type %(type)s limitation of %(limit)s devices reached" +msgstr "" + +#, python-format +msgid "Cannot retrieve disk path information for given pool/volume: %(error)s" +msgstr "" + +msgid "Volume already in use by other virtual machine." +msgstr "" + +msgid "" +"Only one of path or pool/volume can be specified to add a new virtual " +"machine disk" +msgstr "������������������������������������������������" + +#, python-format +msgid "" +"Volume chosen with format %(format)s does not fit in the storage type %(type)" +"s" +msgstr "" + +msgid "YUM Repository ID must be one word only string." +msgstr "YUM ��������� ID ���������������������������������������" + +msgid "Repository URL must be an http://, ftp:// or file:// URL." +msgstr "��������� URL ��������� http://���ftp:// ��� file:// URL���" + +msgid "" +"Repository configuration is a dictionary with specific values according to " +"repository type." +msgstr "������������������������������������������������������������������������������" + +msgid "Distribution to DEB repository must be a string" +msgstr "DEB ���������������������������������������" + +msgid "Components to DEB repository must be listed in a array" +msgstr "DEB ������������������������������������������������" + +msgid "Components to DEB repository must be a string" +msgstr "DEB ���������������������������������" + +msgid "Mirror list to repository must be a string" +msgstr "" + +msgid "YUM Repository name must be string." +msgstr "YUM ���������������������������������" + +msgid "GPG check must be a boolean value." +msgstr "GPG ���������������������������" + +msgid "GPG key must be a URL pointing to the ASCII-armored file." +msgstr "GPG ��������������������� ASCII ��������������� URL���" + +#, python-format +msgid "Could not update repository %(repo_id)s." +msgstr "��������������������� %(repo_id)s���" + +#, python-format +msgid "Repository %(repo_id)s does not exist." +msgstr "��������� %(repo_id)s ������������" + +msgid "" +"Specify repository base URL, mirror list or metalink in order to create or " +"update a YUM repository." +msgstr "" + +msgid "Repository management tool was not recognized for your system." +msgstr "���������������������������������������������" + +#, python-format +msgid "Repository %(repo_id)s is already enabled." +msgstr "������������������ %(repo_id)s���" + +#, python-format +msgid "Repository %(repo_id)s is already disabled." +msgstr "������������������ %(repo_id)s���" + +#, python-format +msgid "Could not remove repository %(repo_id)s." +msgstr "��������������������� %(repo_id)s���" + +#, python-format +msgid "Could not write repository configuration file %(repo_file)s" +msgstr "������������������������������ %(repo_file)s" + +msgid "Specify repository distribution in order to create a DEB repository." +msgstr "������������������������������������ DEB ������������" + +#, python-format +msgid "Could not enable repository %(repo_id)s." +msgstr "��������������������� %(repo_id)s���" + +#, python-format +msgid "Could not disable repository %(repo_id)s." +msgstr "��������������������� %(repo_id)s���" + +msgid "YUM Repository ID already exists" +msgstr "YUM ��������� ID ���������" + +msgid "YUM Repository name must be a string" +msgstr "YUM ������������������������������" + +#, python-format +msgid "Unable to list repositories. Details: '%(err)s'" +msgstr "���������������������������������������'%(err)s'" + +#, python-format +msgid "Unable to retrieve repository information. Details: '%(err)s'" +msgstr "���������������������������������������������'%(err)s'" + +#, python-format +msgid "Unable to add repository. Details: '%(err)s'" +msgstr "���������������������������������������'%(err)s'" + +#, python-format +msgid "Unable to remove repository. Details: '%(err)s'" +msgstr "���������������������������������������'%(err)s'" + +#, python-format +msgid "" +"Configuration items: '%(items)s' are not supported by repository manager" +msgstr "" + +msgid "Repository metalink must be an http://, ftp:// or file:// URL." +msgstr "" + +msgid "Cannot specify mirrorlist and metalink at the same time." +msgstr "" + +#, python-format +msgid "" +"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it." +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'." +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %" +"(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create snapshot of virtual machine '%(vm)s' because it contains a " +"disk with format '%(format)s'; only 'qcow2' is supported." +msgstr "" + +msgid "The number of vCPUs is too large for this system." +msgstr "" + +msgid "Invalid vCPU/topology combination." +msgstr "" + +msgid "This host (or current configuration) does not allow CPU topology." +msgstr "" + +msgid "ERROR CODE" +msgstr "���������" + +msgid "REASON" +msgstr "������" + +msgid "STACK" +msgstr "������" + +msgid "Go to Homepage" +msgstr "������������" + +msgid "Create a New Virtual Machine" +msgstr "������������������������" + +msgid "Virtual Machine Name" +msgstr "������������������" + +msgid "" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "���������������������������������������������������������������������������������������������" + +msgid "Template" +msgstr "������" + +msgid "Please create a template first." +msgstr "���������������������" + +msgid "Create a Template" +msgstr "������������" + +msgid "Please choose a template." +msgstr "������������������" + +msgid "OS" +msgstr "OS" + +msgid "OS Version" +msgstr "OS ������" + +msgid "CPUS" +msgstr "CPUS" + +msgid "Memory" +msgstr "���������" + +msgid "Create" +msgstr "������" + +msgid "Creating..." +msgstr "" + +msgid "Cancel" +msgstr "������ " + +msgid "Edit Guest" +msgstr "������������" + +msgid "General" +msgstr "������" + +msgid "Storage" +msgstr "���������" + +msgid "Interface" +msgstr "������" + +msgid "Permission" +msgstr "������" + +msgid "Host PCI Device" +msgstr "" + +msgid "Snapshot" +msgstr "" + +msgid "Name" +msgstr "������" + +msgid "CPUs" +msgstr "CPU" + +msgid "Memory (MB)" +msgstr "���������" + +msgid "Icon" +msgstr "������" + +msgid "Device" +msgstr "������������" + +msgid "Path" +msgstr "NFS ������" + +msgid "Network" +msgstr "������" + +msgid "Type" +msgstr "������" + +msgid "MAC Address" +msgstr "" + +msgid "Available system users and groups" +msgstr "" + +msgid "Selected system users and groups" +msgstr "" + +msgid "User" +msgstr "" + +msgid "All" +msgstr "������" + +msgid "To Add" +msgstr "" + +msgid "Added" +msgstr "" + +msgid "filter" +msgstr "" + +msgid "Product" +msgstr "" + +msgid "Vendor" +msgstr "���������" + +msgid "Created" +msgstr "" + +msgid "Save" +msgstr "������" + +msgid "Replace" +msgstr "������" + +msgid "Detach" +msgstr "������" + +msgid "revert" +msgstr "" + +msgid "Start" +msgstr "������" + +msgid "Reset" +msgstr "������" + +msgid "Pause" +msgstr "" + +msgid "Resume" +msgstr "" + +msgid "Power Off" +msgstr "" + +msgid "Actions" +msgstr "������" + +msgid "Connect" +msgstr "������" + +msgid "Clone" +msgstr "" + +msgid "Edit" +msgstr "������" + +msgid "Shut Down" +msgstr "������" + +msgid "Delete" +msgstr "������" + +msgid "CPU" +msgstr "CPU" + +msgid "Disk I/O" +msgstr "������ I/O" + +msgid "Network I/O" +msgstr "������ I/O" + +msgid "Livetile" +msgstr "Livetile" + +msgid "No guests found." +msgstr "������������������" + +msgid "Add a Storage Device to VM" +msgstr "������������������������ VM" + +msgid "Device Type" +msgstr "������������" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "������������������������������ \"cdrom\"���" + +msgid "Storage Pool" +msgstr "���������" + +msgid "Storage pool which volume located in" +msgstr "������������������������������" + +msgid "Storage Volume" +msgstr "���������������" + +msgid "Storage volume to be attached" +msgstr "���������������������������������" + +msgid "File Path" +msgstr "������������" + +msgid "The ISO file path in the server for CDROM." +msgstr "CDROM ��� ISO ������������������������������" + +msgid "Attach" +msgstr "������" + +msgid "Shut down" +msgstr "������" + +msgid "Restart" +msgstr "������������" + +msgid "Basic Information" +msgstr "������������" + +msgid "OS Distro" +msgstr "OS Distro" + +msgid "OS Code Name" +msgstr "OS ���������������" + +msgid "Processor" +msgstr "���������" + +msgid "CPU(s)" +msgstr "" + +msgid "System Statistics" +msgstr "������������������" + +msgid "Software Updates" +msgstr "������������" + +msgid "Update Progress" +msgstr "������������" + +msgid "Repositories" +msgstr "���������" + +msgid "Debug Reports" +msgstr "������������" + +msgid "The username or password you entered is incorrect. Please try again." +msgstr "������������������������������������������������������������" + +msgid "This field is required." +msgstr "������������������������" + +msgid "Log in" +msgstr "������" + +msgid "Logging in..." +msgstr "������������..." + +msgid "Host" +msgstr "������" + +msgid "Guests" +msgstr "������" + +msgid "Templates" +msgstr "������" + +msgid "Failed to get application configuration" +msgstr "������������������������������" + +msgid "This is not a valid Linux path" +msgstr "��������������� Linux ������" + +msgid "This is not a valid URL." +msgstr "��������������� URL���" + +msgid "No such data available." +msgstr "���������������������������" + +msgid "" +"Can not contact the host system. Verify the host system is up and that you " +"have network connectivity to it. HTTP request response %1. " +msgstr "" +"������������������������������������������������������������������������������������������������������������HTTP " +"��������������� %1���" + +msgid "Unable to read file." +msgstr "" + +msgid "Error while uploading file." +msgstr "" + +msgid "Delete Confirmation" +msgstr "������������" + +msgid "OK" +msgstr "������" + +msgid "Confirm" +msgstr "������" + +msgid "Warning" +msgstr "������" + +msgid "Cloning..." +msgstr "" + +msgid "Loading..." +msgstr "������������..." + +msgid "An error occurred while retrieving system information." +msgstr "" + +msgid "Retry" +msgstr "������" + +msgid "Detailed message:" +msgstr "������������������" + +msgid "No ISO found" +msgstr "" + +msgid "This is not a valid ISO file." +msgstr "��������������� ISO ���������" + +msgid "This may take a long time. Do you want to continue?" +msgstr "������������������������������������������" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "���������������������������������������������������" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "������������������������������������������������������������������" + +msgid "Max:" +msgstr "���������" + +msgid "Utilization" +msgstr "���������" + +msgid "Available" +msgstr "������" + +msgid "Read Rate" +msgstr "������������" + +msgid "Write Rate" +msgstr "������������" + +msgid "Received" +msgstr "���������" + +msgid "Sent" +msgstr "���������" + +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "������������������������������������������������������������������������������/������������������" + +msgid "" +"Repository will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "������������������������������������������������������������������" + +msgid "ID" +msgstr "ID" + +msgid "Base URL" +msgstr "������ URL" + +msgid "Is Mirror" +msgstr "���������" + +msgid "URL Args" +msgstr "URL ������" + +msgid "Enabled" +msgstr "���������" + +msgid "GPG Check" +msgstr "GPG ������" + +msgid "GPG Key" +msgstr "GPG ������" + +msgid "Add" +msgstr "������" + +msgid "Remove" +msgstr "������" + +msgid "Enable" +msgstr "������" + +msgid "Disable" +msgstr "������" + +msgid "Package Name" +msgstr "������������" + +msgid "Version" +msgstr "������" + +msgid "Architecture" +msgstr "������" + +msgid "Repository" +msgstr "���������" + +msgid "Update All" +msgstr "������������" + +msgid "Updating..." +msgstr "������������..." + +msgid "Failed to retrieve packages update information." +msgstr "" + +msgid "Failed to update package(s)." +msgstr "���������������������" + +msgid "" +"Debug report will be removed permanently and can't be recovered. Do you want " +"to continue?" +msgstr "���������������������������������������������������������������������" + +msgid "Generated Time" +msgstr "������������" + +msgid "Generate" +msgstr "������" + +msgid "Generating..." +msgstr "������������..." + +msgid "Rename" +msgstr "������������" + +msgid "Download" +msgstr "������" + +msgid "" +"Report name should contain only letters, digits, underscore ('_') and/or " +"hyphen ('-')." +msgstr "���������������������������������������������/������������ ('-')���" + +msgid "Pending..." +msgstr "������������..." + +msgid "Report name is the same as the original one." +msgstr "" + +msgid "" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" +msgstr "���������������������������������������������������������������������������������������������" + +msgid "Power off Confirmation" +msgstr "������������" + +msgid "" +"This action may produce undesirable results, for example unflushed disk " +"cache in the guest. Would you like to continue?" +msgstr "" + +msgid "Reset Confirmation" +msgstr "������������" + +msgid "" +"There is a risk of data loss caused by reset without the guest OS shutdown. " +"Would you like to continue?" +msgstr "" + +msgid "Shut Down Confirmation" +msgstr "������������" + +msgid "Note the guest OS may ignore this request. Would you like to continue?" +msgstr "���������������������������������������������������" + +msgid "Virtual Machine delete Confirmation" +msgstr "" + +msgid "" +"This virtual machine is not persistent. Power Off will delete it. Continue?" +msgstr "" + +msgid "" +"When the target guest has SCSI or iSCSI volumes, they will be cloned on " +"default storage pool. The same will happen when the target pool does not " +"have enough space to clone the volumes. Do you want to continue?" +msgstr "" + +msgid "" +"This CDROM will be detached permanently and you can re-attach it. Continue " +"to detach it?" +msgstr "" +"������������������������ CDROM��������������������������������������������������������� CDROM ������" + +msgid "Attaching..." +msgstr "������������..." + +msgid "Replacing..." +msgstr "������������..." + +msgid "Successfully attached!" +msgstr "������������������" + +msgid "Successfully replaced!" +msgstr "������������������" + +msgid "Successfully detached!" +msgstr "������������������" + +msgid "" +"This disk will be detached permanently and you can re-attach it. Continue to " +"detach it?" +msgstr "" + +msgid "interface:" +msgstr "" + +msgid "address:" +msgstr "" + +msgid "link_type:" +msgstr "" + +msgid "block:" +msgstr "" + +msgid "drive_type:" +msgstr "" + +msgid "model:" +msgstr "" + +msgid "Affected devices:" +msgstr "" + +msgid "The VLAN id must be between 1 and 4094." +msgstr "VLAN ID ������������ 1 ��� 4094 ���������" + +msgid "unavailable" +msgstr "������������" + +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "������������������������������������������������������������������������������������" + +msgid "Create a network" +msgstr "������������" + +msgid "" +"This network is not persistent. Instead of stop, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������" + +msgid "" +"The bridged VLAN tag may not work well with NetworkManager enabled. You " +"should consider disabling it." +msgstr "" + +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" +msgstr "������������������������������������������������������" + +msgid "This storage pool is empty." +msgstr "������������������������" + +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " +msgstr "������������������������������������������������������������������������������������������������������" + +msgid "SCSI Fibre Channel" +msgstr "SCSI ������������" + +msgid "No SCSI adapters found." +msgstr "��������� SCSI ������������" + +msgid "Loading iSCSI targets..." +msgstr "" + +msgid "No iSCSI found. Please input one." +msgstr "" + +msgid "Failed to load iSCSI targets." +msgstr "" + +msgid "The storage pool name can not be blank." +msgstr "������������������������������" + +msgid "The storage pool path can not be blank." +msgstr "������������������������������" + +msgid "NFS server mount path can not be blank." +msgstr "NFS ������������������������������������" + +msgid "Invalid NFS mount path." +msgstr "NFS ���������������������" + +msgid "No logical device selected." +msgstr "������������������������" + +msgid "The iSCSI target can not be blank." +msgstr "iSCSI ���������������������" + +msgid "Server name can not be blank." +msgstr "������������������������������" + +msgid "This is not a valid Server Name or IP. Please, modify it." +msgstr "" + +msgid "Looking for available partitions ..." +msgstr "������������������������������ ..." + +msgid "No available partitions found." +msgstr "������������������������������" + +msgid "" +"This storage pool is not persistent. Instead of deactivate, this action will " +"permanently delete it. Would you like to continue?" +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������" + +msgid "Unable to retrieve partitions information." +msgstr "���������������������������������������������'%(err)s'" + +msgid "In progress..." +msgstr "" + +msgid "Failed!" +msgstr "" + +msgid "CDROM path needs to be a valid local/remote path and cannot be blank." +msgstr "" + +msgid "Disk pool or volume cannot be blank." +msgstr "������������������������������" + +msgid "Filter" +msgstr "" + +msgid "Network Name" +msgstr "������������" + +msgid "State" +msgstr "������" + +msgid "Network Type" +msgstr "������������" + +msgid "Address Space" +msgstr "������������" + +msgid "Name should not contain '/' and '\"'." +msgstr "������������������������������������������ '/'���" + +msgid "Isolated: no external network connection" +msgstr "������������������������������������" + +msgid "NAT: outbound physical network connection only" +msgstr "NAT���������������������������������" + +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "������������������������������������������������������" + +msgid "(No interfaces found)" +msgstr "" + +msgid "Destination" +msgstr "������������" + +msgid "Enable VLAN" +msgstr "������ VLAN���" + +msgid "VLAN ID" +msgstr "VLAN ID���" + +msgid "Stop" +msgstr "������" + +msgid "Generate a New Debug Report" +msgstr "������������������������" + +msgid "Report Name" +msgstr "������������" + +msgid "" +"The name used to identify the report. If omitted, a name will be chosen " +"based on current time. Name can contain: letters, digits, underscore (\"_\") " +"and hyphen (\"-\")." +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������������������ (\"-\")���" + +msgid "Rename a Debug Report" +msgstr "������������������������" + +msgid "" +"The name used to identify the report. Name can contain: letters, digits and " +"hyphen (\"-\")." +msgstr "" +"������������������������������������������������������������������������������������������������������������������" +"������������������ (\"-\")���" + +msgid "Submit" +msgstr "" + +msgid "Add a Repository" +msgstr "���������������" + +msgid "Identifier" +msgstr "ID" + +msgid "Single word, unique identifier for the repository." +msgstr "��������������������������� ID���" + +msgid "Textual name for the repository." +msgstr "���������������������������" + +msgid "URL" +msgstr "URL" + +msgid "Required Field" +msgstr "������������" + +msgid "URL to the repository. Supported protocols are http, ftp, and file." +msgstr "������������ URL��������������������������������� http���ftp ��� file���" + +msgid "Repository is a mirror" +msgstr "���������������������" + +msgid "Distribution" +msgstr "������������" + +msgid "Distribution of the DEB repository." +msgstr "DEB ���������������������������" + +msgid "Components" +msgstr "������" + +msgid "List of components in DEB repository." +msgstr "DEB ������������������������������" + +msgid "Edit Repository" +msgstr "���������������" + +msgid "Mirror List URL" +msgstr "������������ URL" + +msgid "Yes" +msgstr "���" + +msgid "No" +msgstr "���" + +msgid "Capacity" +msgstr "������" + +msgid "Allocated" +msgstr "���������" + +msgid "Location" +msgstr "������" + +msgid "Device path" +msgstr "������������" + +msgid "active" +msgstr "���������" + +msgid "inactive" +msgstr "������������" + +msgid "Deactivate" +msgstr "������������" + +msgid "Activate" +msgstr "������" + +msgid "Add Volume" +msgstr "" + +msgid "Extend" +msgstr "" + +msgid "Undefine" +msgstr "������������" + +msgid "Format" +msgstr "���������" + +msgid "Allocation" +msgstr "���������" + +msgid "Define a New Storage Pool" +msgstr "���������������������" + +msgid "Storage Pool Name" +msgstr "���������������" + +msgid "" +"The name used to identify the storage pools, and it should not be empty." +msgstr "������������������������������������������������������" + +msgid "Storage Pool Type" +msgstr "���������������" + +msgid "Storage Path" +msgstr "���������������" + +msgid "" +"The path of the Storage Pool. Each Storage Pool must have a unique path." +msgstr "���������������������������������������������������������������������������" + +msgid "" +"Kimchi will try to create the directory when it does not already exist in " +"your system." +msgstr "Kimchi ������������������������������������������������������������������������" + +msgid "NFS Server IP" +msgstr "NFS ��������� IP" + +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "NFS ��������� IP ���������������������������������������������������������������������" + +msgid "NFS Path" +msgstr "NFS ������" + +msgid "The NFS exported path on NFS server." +msgstr "NFS ������������ NFS ������������������" + +msgid "iSCSI Server" +msgstr "iSCSI ���������" + +msgid "Server" +msgstr "���������" + +msgid "Port" +msgstr "���" + +msgid "iSCSI server IP or hostname. It should not be empty." +msgstr "iSCSI ��������� IP ������������������������������������������" + +msgid "Target" +msgstr "������" + +msgid "The iSCSI target on iSCSI server" +msgstr "iSCSI ��������������� iSCSI ������" + +msgid "Add iSCSI Authentication" +msgstr "������ iSCSI ������" + +msgid "iSCSI Authentication" +msgstr "iSCSI ������" + +msgid "User Name" +msgstr "���������������" + +msgid "Password" +msgstr "������" + +msgid "SCSI Adapter" +msgstr "SCSI ���������" + +msgid "Please, wait..." +msgstr "���������..." + +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + +msgid "Add Template" +msgstr "������������" + +msgid "Where is the source media for this template? " +msgstr "���������������������������������������" + +msgid "Local ISO Image" +msgstr "������ ISO ���������" + +msgid "Local Image File" +msgstr "" + +msgid "Remote ISO Image" +msgstr "������ ISO ���������" + +msgid "Search ISOs" +msgstr "������ ISO" + +msgid "The following ISOs are available:" +msgstr "������ ISO ���������" + +msgid "OS: " +msgstr "OS���" + +msgid "Version: " +msgstr "���������" + +msgid "Size: " +msgstr "���������" + +msgid "Search more ISOs" +msgstr "������������ ISO" + +msgid "Create Templates from Selected ISO" +msgstr "��������� ISO ������������" + +msgid "I want to use a specific ISO file" +msgstr "��������������������� ISO ������" + +msgid "Loading default remote ISOs ..." +msgstr "������������������������ ISO ..." + +msgid "Arch: " +msgstr "���������" + +msgid "I want to use a custom URL" +msgstr "������������������ URL" + +msgid "Edit Template" +msgstr "������������" + +msgid "CDROM" +msgstr "CDROM" + +msgid "Image File" +msgstr "" + +msgid "Graphics" +msgstr "���������" + +msgid "Disk(GB)" +msgstr "" + +msgid "Disk Format" +msgstr "" + +msgid "CPU Number" +msgstr "CPU ������" + +msgid "Manually set CPU topology" +msgstr "" + +msgid "Cores" +msgstr "" + +msgid "Threads" +msgstr "" + +msgid "No templates found." +msgstr "������������������" + +#~ msgid "Delete is not allowed for %(resource)s" +#~ msgstr "��������������� %(resource)s ������������" + +#~ msgid "%(resource)s does not implement update method" +#~ msgstr "%(resource)s ���������������������" + +#~ msgid "Create is not allowed for %(resource)s" +#~ msgstr "��������������� %(resource)s ������������" + +#~ msgid "Unable to parse JSON request" +#~ msgstr "������������ JSON ������" + +#~ msgid "This API only supports JSON" +#~ msgstr "��� API ��������� JSON" + +#~ msgid "Datastore is not initiated in the model object." +#~ msgstr "���������������������������������������������" + +#~ msgid "Unable to start task due error: %(err)s" +#~ msgstr "������������������������������������������%(err)s" + +#~ msgid "" +#~ "Authentication failed for user '%(username)s'. [Error code: %(code)s]" +#~ msgstr "��������� '%(username)s' ������������������[������������%(code)s]" + +#~ msgid "You are not authorized to access Kimchi" +#~ msgstr "������������������������ Kimchi" + +#~ msgid "Specify %(item)s to login into Kimchi" +#~ msgstr "������ %(item)s ��������� Kimchi" + +#~ msgid "Unable to find %(item)s in datastore" +#~ msgstr "������������������������������ %(item)s" + +#~ msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +#~ msgstr "������������ '%(cmd)s' %(seconds)s ���������������" + +#~ msgid "Help" +#~ msgstr "������" + +#~ msgid "About" +#~ msgstr "������" + +#~ msgid "Log out" +#~ msgstr "������" + +#~ msgid "Version:" +#~ msgstr "���������" diff --git a/src/wok/plugins/kimchi/repositories.py b/src/wok/plugins/kimchi/repositories.py new file mode 100644 index 0000000..9caabc4 --- /dev/null +++ b/src/wok/plugins/kimchi/repositories.py @@ -0,0 +1,529 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import copy +import os +import time +import urlparse +from ConfigParser import ConfigParser + +from wok.basemodel import Singleton +from wok.exception import InvalidOperation, InvalidParameter +from wok.exception import OperationFailed, NotFoundError, MissingParameter +from wok.utils import validate_repo_url + +from config import kimchiLock +from yumparser import get_yum_repositories, write_repo_to_file + + +class Repositories(object): + __metaclass__ = Singleton + + """ + Class to represent and operate with repositories information. + """ + def __init__(self): + try: + __import__('yum') + self._pkg_mnger = YumRepo() + except ImportError: + try: + __import__('apt_pkg') + self._pkg_mnger = AptRepo() + except ImportError: + raise InvalidOperation('KCHREPOS0014E') + + def addRepository(self, params): + """ + Add and enable a new repository + """ + config = params.get('config', {}) + extra_keys = list( + set(config.keys()).difference(set(self._pkg_mnger.CONFIG_ENTRY))) + if len(extra_keys) > 0: + raise InvalidParameter("KCHREPOS0028E", + {'items': ",".join(extra_keys)}) + + return self._pkg_mnger.addRepo(params) + + def getRepositories(self): + """ + Return a dictionary with all Kimchi's repositories. Each element uses + the format {<repo_id>: {repo}}, where repo is a dictionary in the + repositories.Repositories() format. + """ + return self._pkg_mnger.getRepositoriesList() + + def getRepository(self, repo_id): + """ + Return a dictionary with all info from a given repository ID. + """ + info = self._pkg_mnger.getRepo(repo_id) + info['repo_id'] = repo_id + return info + + def enableRepository(self, repo_id): + """ + Enable a repository. + """ + return self._pkg_mnger.toggleRepo(repo_id, True) + + def disableRepository(self, repo_id): + """ + Disable a given repository. + """ + return self._pkg_mnger.toggleRepo(repo_id, False) + + def updateRepository(self, repo_id, params): + """ + Update the information of a given repository. + The input is the repo_id of the repository to be updated and a dict + with the information to be updated. + """ + return self._pkg_mnger.updateRepo(repo_id, params) + + def removeRepository(self, repo_id): + """ + Remove a given repository + """ + return self._pkg_mnger.removeRepo(repo_id) + + +class YumRepo(object): + """ + Class to represent and operate with YUM repositories. + It's loaded only on those systems listed at YUM_DISTROS and loads necessary + modules in runtime. + """ + TYPE = 'yum' + DEFAULT_CONF_DIR = "/etc/yum.repos.d" + CONFIG_ENTRY = ('repo_name', 'mirrorlist', 'metalink') + + def __init__(self): + self._confdir = self.DEFAULT_CONF_DIR + + def _get_repos(self, errcode): + try: + kimchiLock.acquire() + repos = get_yum_repositories() + except Exception, e: + kimchiLock.release() + raise OperationFailed(errcode, {'err': str(e)}) + finally: + kimchiLock.release() + + return repos + + def getRepositoriesList(self): + """ + Return a list of repositories IDs + """ + repos = self._get_repos('KCHREPOS0024E') + return repos.keys() + + def getRepo(self, repo_id): + """ + Return a dictionary in the repositories.Repositories() of the given + repository ID format with the information of a YumRepository object. + """ + repos = self._get_repos('KCHREPOS0025E') + + if repo_id not in repos.keys(): + raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) + + entry = repos.get(repo_id) + + info = {} + info['enabled'] = entry.enabled + info['baseurl'] = entry.baseurl or '' + info['config'] = {} + info['config']['repo_name'] = entry.name or '' + info['config']['gpgcheck'] = entry.gpgcheck + info['config']['gpgkey'] = entry.gpgkey or '' + info['config']['mirrorlist'] = entry.mirrorlist or '' + info['config']['metalink'] = entry.metalink or '' + return info + + def addRepo(self, params): + """ + Add a given repository to YumBase + """ + # At least one base url, or one mirror, must be given. + baseurl = params.get('baseurl', '') + + config = params.get('config', {}) + mirrorlist = config.get('mirrorlist', '') + metalink = config.get('metalink', '') + if not baseurl and not mirrorlist and not metalink: + raise MissingParameter("KCHREPOS0013E") + + if baseurl: + validate_repo_url(baseurl) + + if mirrorlist: + validate_repo_url(mirrorlist) + + if metalink: + validate_repo_url(metalink) + + if mirrorlist and metalink: + raise InvalidOperation('KCHREPOS0030E') + + repo_id = params.get('repo_id', None) + if repo_id is None: + repo_id = "kimchi_repo_%s" % str(int(time.time() * 1000)) + + repos = self._get_repos('KCHREPOS0026E') + if repo_id in repos.keys(): + raise InvalidOperation("KCHREPOS0022E", {'repo_id': repo_id}) + + repo_name = config.get('repo_name', repo_id) + repo = {'baseurl': baseurl, 'mirrorlist': mirrorlist, + 'name': repo_name, 'gpgcheck': 1, + 'gpgkey': [], 'enabled': 1, 'metalink': metalink} + + # write a repo file in the system with repo{} information. + parser = ConfigParser() + parser.add_section(repo_id) + + for key, value in repo.iteritems(): + if value: + parser.set(repo_id, key, value) + + repofile = os.path.join(self._confdir, repo_id + '.repo') + try: + with open(repofile, 'w') as fd: + parser.write(fd) + except: + raise OperationFailed("KCHREPOS0018E", + {'repo_file': repofile}) + + return repo_id + + def toggleRepo(self, repo_id, enable): + repos = self._get_repos('KCHREPOS0011E') + if repo_id not in repos.keys(): + raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) + + entry = repos.get(repo_id) + if enable and entry.enabled: + raise InvalidOperation("KCHREPOS0015E", {'repo_id': repo_id}) + + if not enable and not entry.enabled: + raise InvalidOperation("KCHREPOS0016E", {'repo_id': repo_id}) + + kimchiLock.acquire() + try: + if enable: + entry.enable() + else: + entry.disable() + + write_repo_to_file(entry) + except: + if enable: + raise OperationFailed("KCHREPOS0020E", {'repo_id': repo_id}) + + raise OperationFailed("KCHREPOS0021E", {'repo_id': repo_id}) + finally: + kimchiLock.release() + + return repo_id + + def updateRepo(self, repo_id, params): + """ + Update a given repository in repositories.Repositories() format + """ + repos = self._get_repos('KCHREPOS0011E') + if repo_id not in repos.keys(): + raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) + + entry = repos.get(repo_id) + + baseurl = params.get('baseurl', None) + config = params.get('config', {}) + mirrorlist = config.get('mirrorlist', None) + metalink = config.get('metalink', None) + + if baseurl is not None and len(baseurl.strip()) == 0: + baseurl = None + + if mirrorlist is not None and len(mirrorlist.strip()) == 0: + mirrorlist = None + + if metalink is not None and len(metalink.strip()) == 0: + metalink = None + + if baseurl is None and mirrorlist is None and metalink is None: + raise MissingParameter("KCHREPOS0013E") + + if baseurl is not None: + validate_repo_url(baseurl) + entry.baseurl = baseurl + + if mirrorlist is not None: + validate_repo_url(mirrorlist) + entry.mirrorlist = mirrorlist + + if metalink is not None: + validate_repo_url(metalink) + entry.metalink = metalink + + if mirrorlist and metalink: + raise InvalidOperation('KCHREPOS0030E') + + entry.id = params.get('repo_id', repo_id) + entry.name = config.get('repo_name', entry.name) + entry.gpgcheck = config.get('gpgcheck', entry.gpgcheck) + entry.gpgkey = config.get('gpgkey', entry.gpgkey) + kimchiLock.acquire() + write_repo_to_file(entry) + kimchiLock.release() + return repo_id + + def removeRepo(self, repo_id): + """ + Remove a given repository + """ + repos = self._get_repos('KCHREPOS0027E') + if repo_id not in repos.keys(): + raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) + + entry = repos.get(repo_id) + parser = ConfigParser() + with open(entry.repofile) as fd: + parser.readfp(fd) + + if len(parser.sections()) == 1: + os.remove(entry.repofile) + return + + parser.remove_section(repo_id) + with open(entry.repofile, "w") as fd: + parser.write(fd) + + +class AptRepo(object): + """ + Class to represent and operate with YUM repositories. + It's loaded only on those systems listed at YUM_DISTROS and loads necessary + modules in runtime. + """ + TYPE = 'deb' + KIMCHI_LIST = "kimchi-source.list" + CONFIG_ENTRY = ('dist', 'comps') + + def __init__(self): + getattr(__import__('apt_pkg'), 'init_config')() + getattr(__import__('apt_pkg'), 'init_system')() + config = getattr(__import__('apt_pkg'), 'config') + self.pkg_lock = getattr(__import__('apt_pkg'), 'SystemLock') + module = __import__('aptsources.sourceslist', globals(), locals(), + ['SourcesList'], -1) + + self._sourceparts_path = '/%s%s' % ( + config.get('Dir::Etc'), config.get('Dir::Etc::sourceparts')) + self._sourceslist = getattr(module, 'SourcesList') + self.filename = os.path.join(self._sourceparts_path, self.KIMCHI_LIST) + if not os.path.exists(self.filename): + with open(self.filename, 'w') as fd: + fd.write("# This file is managed by Kimchi and it must not " + "be modified manually\n") + + def _get_repos(self): + try: + with self.pkg_lock(): + repos = self._sourceslist() + repos.refresh() + except Exception, e: + kimchiLock.release() + raise OperationFailed('KCHREPOS0025E', {'err': e.message}) + + return repos + + def _get_repo_id(self, repo): + data = urlparse.urlparse(repo.uri) + name = data.hostname or data.path + return '%s-%s-%s' % (name, repo.dist, "-".join(repo.comps)) + + def _get_source_entry(self, repo_id): + kimchiLock.acquire() + repos = self._get_repos() + kimchiLock.release() + + for r in repos: + # Ignore deb-src repositories + if r.type != 'deb': + continue + + if self._get_repo_id(r) != repo_id: + continue + + return r + + return None + + def getRepositoriesList(self): + """ + Return a list of repositories IDs + + APT repositories there aren't the concept about repository ID, so for + internal control, the repository ID will be built as described in + _get_repo_id() + """ + kimchiLock.acquire() + repos = self._get_repos() + kimchiLock.release() + + res = [] + for r in repos: + # Ignore deb-src repositories + if r.type != 'deb': + continue + + res.append(self._get_repo_id(r)) + + return res + + def getRepo(self, repo_id): + """ + Return a dictionary in the repositories.Repositories() format of the + given repository ID with the information of a SourceEntry object. + """ + r = self._get_source_entry(repo_id) + if r is None: + raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) + + info = {'enabled': not r.disabled, + 'baseurl': r.uri, + 'config': {'dist': r.dist, + 'comps': r.comps}} + return info + + def addRepo(self, params): + """ + Add a new APT repository based on <params> + """ + # To create a APT repository the dist is a required parameter + # (in addition to baseurl, verified on controller through API.json) + config = params.get('config', None) + if config is None: + raise MissingParameter("KCHREPOS0019E") + + if 'dist' not in config.keys(): + raise MissingParameter("KCHREPOS0019E") + + uri = params['baseurl'] + dist = config['dist'] + comps = config.get('comps', []) + + validate_repo_url(uri) + + kimchiLock.acquire() + try: + repos = self._get_repos() + source_entry = repos.add('deb', uri, dist, comps, + file=self.filename) + with self.pkg_lock(): + repos.save() + except Exception as e: + kimchiLock.release() + raise OperationFailed("KCHREPOS0026E", {'err': e.message}) + kimchiLock.release() + return self._get_repo_id(source_entry) + + def toggleRepo(self, repo_id, enable): + """ + Enable a given repository + """ + r = self._get_source_entry(repo_id) + if r is None: + raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) + + if enable and not r.disabled: + raise InvalidOperation("KCHREPOS0015E", {'repo_id': repo_id}) + + if not enable and r.disabled: + raise InvalidOperation("KCHREPOS0016E", {'repo_id': repo_id}) + + if enable: + line = 'deb' + else: + line = '#deb' + + kimchiLock.acquire() + try: + repos = self._get_repos() + with self.pkg_lock(): + repos.remove(r) + repos.add(line, r.uri, r.dist, r.comps, file=self.filename) + repos.save() + except: + kimchiLock.release() + if enable: + raise OperationFailed("KCHREPOS0020E", {'repo_id': repo_id}) + + raise OperationFailed("KCHREPOS0021E", {'repo_id': repo_id}) + finally: + kimchiLock.release() + + return repo_id + + def updateRepo(self, repo_id, params): + """ + Update a given repository in repositories.Repositories() format + """ + old_info = self.getRepo(repo_id) + updated_info = copy.deepcopy(old_info) + updated_info['baseurl'] = params.get( + 'baseurl', updated_info['baseurl']) + + if 'config' in params.keys(): + config = params['config'] + updated_info['config']['dist'] = config.get( + 'dist', old_info['config']['dist']) + updated_info['config']['comps'] = config.get( + 'comps', old_info['config']['comps']) + + self.removeRepo(repo_id) + try: + return self.addRepo(updated_info) + except: + self.addRepo(old_info) + raise + + def removeRepo(self, repo_id): + """ + Remove a given repository + """ + r = self._get_source_entry(repo_id) + if r is None: + raise NotFoundError("KCHREPOS0012E", {'repo_id': repo_id}) + + kimchiLock.acquire() + try: + repos = self._get_repos() + with self.pkg_lock(): + repos.remove(r) + repos.save() + except: + kimchiLock.release() + raise OperationFailed("KCHREPOS0017E", {'repo_id': repo_id}) + finally: + kimchiLock.release() diff --git a/src/wok/plugins/kimchi/root.py b/src/wok/plugins/kimchi/root.py new file mode 100644 index 0000000..1e2bfc7 --- /dev/null +++ b/src/wok/plugins/kimchi/root.py @@ -0,0 +1,69 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import cherrypy + +from wok.i18n import messages +from wok.root import WokRoot + +import config +import mockmodel +import vnc +from control import sub_nodes +from model import model as kimchiModel + + +class KimchiRoot(WokRoot): + def __init__(self, wok_options): + if hasattr(wok_options, "model"): + self.model = wok_options.model + elif wok_options.test: + self.model = mockmodel.MockModel() + else: + self.model = kimchiModel.Model() + + dev_env = wok_options.environment != 'production' + super(KimchiRoot, self).__init__(self.model, dev_env) + + for ident, node in sub_nodes.items(): + setattr(self, ident, node(self.model)) + + if isinstance(self.model, kimchiModel.Model): + vnc_ws_proxy = vnc.new_ws_proxy() + cherrypy.engine.subscribe('exit', vnc_ws_proxy.terminate) + + self.api_schema = json.load(open(os.path.join(os.path.dirname( + os.path.abspath(__file__)), 'API.json'))) + self.paths = config.kimchiPaths + self.domain = 'kimchi' + self.messages = messages + + make_dirs = [ + os.path.abspath(config.get_distros_store()), + os.path.abspath(config.get_debugreports_path()), + os.path.abspath(config.get_screenshot_path()) + ] + for directory in make_dirs: + if not os.path.isdir(directory): + os.makedirs(directory) + + def get_custom_conf(self): + return config.KimchiConfig() diff --git a/src/wok/plugins/kimchi/scan.py b/src/wok/plugins/kimchi/scan.py new file mode 100644 index 0000000..b475c46 --- /dev/null +++ b/src/wok/plugins/kimchi/scan.py @@ -0,0 +1,89 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import glob +import hashlib +import os.path +import shutil +import tempfile +import time + +from wok.utils import wok_log + +from isoinfo import IsoImage, probe_iso + + +SCAN_IGNORE = ['/tmp/kimchi-scan-*'] + + +class Scanner(object): + SCAN_TTL = 300 + + def __init__(self, record_clean_cb): + self.clean_cb = record_clean_cb + + def delete(self): + self.clean_stale(-1) + + def clean_stale(self, window=SCAN_TTL): + """ + Clear scan pools generated before time window, + Clear all scan pools if window is -1. + """ + try: + now = time.time() + clean_list = glob.glob("/tmp/kimchi-scan-*") + for d in clean_list: + transient_pool = \ + os.path.basename(d).replace('kimchi-scan-', '')[0: -6] + if now - os.path.getmtime(d) > window: + shutil.rmtree(d) + self.clean_cb(transient_pool) + except OSError as e: + msg = "Exception %s occured when cleaning stale pool, ignore" + wok_log.debug(msg % e.message) + + def scan_dir_prepare(self, name): + # clean stale scan storage pools + self.clean_stale() + return tempfile.mkdtemp(prefix='kimchi-scan-' + name, dir='/tmp') + + def start_scan(self, cb, params): + def updater(iso_info): + iso_name = os.path.basename(iso_info['path'])[:-3] + + duplicates = "%s/%s*" % (params['pool_path'], iso_name) + for f in glob.glob(duplicates): + iso_img = IsoImage(f) + if (iso_info['distro'], iso_info['version']) == \ + iso_img.probe(): + return + + iso_path = iso_name + hashlib.md5(iso_info['path']).hexdigest() + \ + '.iso' + link_name = os.path.join(params['pool_path'], + os.path.basename(iso_path)) + os.symlink(iso_info['path'], link_name) + + ignore_paths = params.get('ignore_list', []) + scan_params = dict(path=params['scan_path'], updater=updater, + ignore_list=ignore_paths + SCAN_IGNORE) + probe_iso(None, scan_params) + cb('', True) diff --git a/src/wok/plugins/kimchi/screenshot.py b/src/wok/plugins/kimchi/screenshot.py new file mode 100644 index 0000000..ffe5a1a --- /dev/null +++ b/src/wok/plugins/kimchi/screenshot.py @@ -0,0 +1,184 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import glob +import os +import signal +import tempfile +import time +import uuid + +try: + from PIL import Image +except ImportError: + import Image + + +from wok.utils import wok_log + +import config + + +(fd, pipe) = tempfile.mkstemp() +stream_test_result = None + + +class VMScreenshot(object): + OUTDATED_SECS = 5 + THUMBNAIL_SIZE = (256, 256) + LIVE_WINDOW = 60 + MAX_STREAM_ATTEMPTS = 10 + + def __init__(self, args): + self.vm_uuid = args['uuid'] + args.setdefault('thumbnail', + os.path.join(config.get_screenshot_path(), + '%s-%s.png' % + (self.vm_uuid, str(uuid.uuid4())))) + self.info = args + + @staticmethod + def get_stream_test_result(): + return stream_test_result + + def lookup(self): + now = time.time() + try: + last_update = os.path.getmtime(self.info['thumbnail']) + except OSError: + last_update = 0 + + if now - last_update > self.OUTDATED_SECS: + self._clean_extra(self.LIVE_WINDOW) + self._generate_thumbnail() + return 'plugins/kimchi/data/screenshots/%s' %\ + os.path.basename(self.info['thumbnail']) + + def _clean_extra(self, window=-1): + """ + Clear screenshots before time specified by window, + Clear all screenshots if window is -1. + """ + try: + now = time.time() + clear_list = glob.glob("%s/%s-*.png" % + (config.get_screenshot_path(), + self.vm_uuid)) + for f in clear_list: + if now - os.path.getmtime(f) > window: + os.unlink(f) + except OSError: + pass + + def delete(self): + return self._clean_extra() + + def _generate_scratch(self, thumbnail): + """ + Generate screenshot of given vm. + Override me in child class. + """ + pass + + def _create_black_image(self, thumbnail): + image = Image.new("RGB", self.THUMBNAIL_SIZE, 'black') + image.save(thumbnail) + + def _watch_stream_creation(self, thumbnail): + """ + This is a verification test for libvirt stream functionality. + + It is necessary to avoid the server hangs while creating the screenshot + image using libvirt stream API. + + This problem was found in libvirt 0.9.6 for SLES11 SP2. + + This test consists in running the screeshot creation with a timeout. + If timeout occurs, the libvirt is taking too much time to create the + screenshot image and the stream must be disabled it if happens + successively (to avoid blocking server requests). + """ + pid = os.fork() + if pid == 0: + try: + self._generate_scratch(thumbnail) + os._exit(0) + except: + os._exit(1) + else: + counter = 0 + ret = os.waitpid(pid, os.WNOHANG) + while ret == (0, 0) and counter < 3: + counter += 1 + time.sleep(1) + ret = os.waitpid(pid, os.WNOHANG) + + fd = open(pipe, "a") + if ret != (pid, 0): + fd.write("-") + if ret[0] != pid: + os.kill(int(pid), signal.SIGKILL) + os.waitpid(pid, 0) + else: + fd.write("+") + fd.close() + + def _get_test_result(self): + if not os.path.exists(pipe): + return + + fd = open(pipe, "r") + data = fd.read() + fd.close() + + if len(data) >= self.MAX_STREAM_ATTEMPTS or bool('+' in data): + global stream_test_result + stream_test_result = bool('+' in data) + os.remove(pipe) + + def _generate_thumbnail(self): + thumbnail = os.path.join(config.get_screenshot_path(), '%s-%s.png' % + (self.vm_uuid, str(uuid.uuid4()))) + + self._get_test_result() + if stream_test_result is None: + self._watch_stream_creation(thumbnail) + elif stream_test_result: + try: + self._generate_scratch(thumbnail) + except: + wok_log.error("screenshot_creation: Unable to create " + "screenshot image %s." % thumbnail) + else: + self._create_black_image(thumbnail) + + if os.path.getsize(thumbnail) == 0: + self._create_black_image(thumbnail) + else: + im = Image.open(thumbnail) + try: + # Prevent Image lib from lazy load, + # work around pic truncate validation in thumbnail generation + im.thumbnail(self.THUMBNAIL_SIZE) + except Exception as e: + wok_log.warning("Image load with warning: %s." % e) + im.save(thumbnail, "PNG") + + self.info['thumbnail'] = thumbnail diff --git a/src/wok/plugins/kimchi/swupdate.py b/src/wok/plugins/kimchi/swupdate.py new file mode 100644 index 0000000..84b927f --- /dev/null +++ b/src/wok/plugins/kimchi/swupdate.py @@ -0,0 +1,263 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import subprocess +import time + +from wok.basemodel import Singleton +from wok.exception import NotFoundError, OperationFailed +from wok.utils import run_command, wok_log + +from config import kimchiLock +from yumparser import get_yum_packages_list_update + + +class SoftwareUpdate(object): + __metaclass__ = Singleton + + """ + Class to represent and operate with OS software update. + """ + def __init__(self): + # This stores all packages to be updated for Kimchi perspective. It's a + # dictionary of dictionaries, in the format {'package_name': package}, + # where: + # package = {'package_name': <string>, 'version': <string>, + # 'arch': <string>, 'repository': <string> + # } + self._packages = {} + + # This stores the number of packages to update + self._num2update = 0 + + # Get the distro of host machine and creates an object related to + # correct package management system + try: + __import__('yum') + wok_log.info("Loading YumUpdate features.") + self._pkg_mnger = YumUpdate() + except ImportError: + try: + __import__('apt') + wok_log.info("Loading AptUpdate features.") + self._pkg_mnger = AptUpdate() + except ImportError: + zypper_help = ["zypper", "--help"] + (stdout, stderr, returncode) = run_command(zypper_help) + if returncode == 0: + wok_log.info("Loading ZypperUpdate features.") + self._pkg_mnger = ZypperUpdate() + else: + raise Exception("There is no compatible package manager " + "for this system.") + + def _scanUpdates(self): + """ + Update self._packages with packages to be updated. + """ + self._packages = {} + self._num2update = 0 + + # Call system pkg_mnger to get the packages as list of dictionaries. + for pkg in self._pkg_mnger.getPackagesList(): + + # Check if already exist a package in self._packages + pkg_id = pkg.get('package_name') + if pkg_id in self._packages.keys(): + # package already listed to update. do nothing + continue + + # Update the self._packages and self._num2update + self._packages[pkg_id] = pkg + self._num2update = self._num2update + 1 + + def getUpdates(self): + """ + Return the self._packages. + """ + self._scanUpdates() + return self._packages + + def getUpdate(self, name): + """ + Return a dictionary with all info from a given package name. + """ + if name not in self._packages.keys(): + raise NotFoundError('KCHPKGUPD0002E', {'name': name}) + + return self._packages[name] + + def getNumOfUpdates(self): + """ + Return the number of packages to be updated. + """ + self._scanUpdates() + return self._num2update + + def doUpdate(self, cb, params): + """ + Execute the update + """ + # reset messages + cb('') + + cmd = self._pkg_mnger.update_cmd + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + msgs = [] + while proc.poll() is None: + msgs.append(proc.stdout.readline()) + cb(''.join(msgs)) + time.sleep(0.5) + + # read the final output lines + msgs.extend(proc.stdout.readlines()) + + retcode = proc.poll() + if retcode == 0: + return cb(''.join(msgs), True) + + msgs.extend(proc.stderr.readlines()) + return cb(''.join(msgs), False) + + +class YumUpdate(object): + """ + Class to represent and operate with YUM software update system. + It's loaded only on those systems listed at YUM_DISTROS and loads necessary + modules in runtime. + """ + def __init__(self): + self._pkgs = {} + self.update_cmd = ["yum", "-y", "update"] + + def _refreshUpdateList(self): + """ + Update the list of packages to be updated in the system. + """ + try: + kimchiLock.acquire() + self._pkgs = get_yum_packages_list_update() + except Exception, e: + raise OperationFailed('KCHPKGUPD0003E', {'err': str(e)}) + finally: + kimchiLock.release() + + def getPackagesList(self): + """ + Return a list of package's dictionaries. Each dictionary contains the + information about a package, in the format: + package = {'package_name': <string>, 'version': <string>, + 'arch': <string>, 'repository': <string>} + """ + self._refreshUpdateList() + pkg_list = [] + for pkg in self._pkgs: + package = {'package_name': pkg.name, 'version': pkg.version, + 'arch': pkg.arch, 'repository': pkg.ui_from_repo} + pkg_list.append(package) + return pkg_list + + +class AptUpdate(object): + """ + Class to represent and operate with APT software update system. + It's loaded only on those systems listed at APT_DISTROS and loads necessary + modules in runtime. + """ + def __init__(self): + self._pkgs = {} + self.pkg_lock = getattr(__import__('apt_pkg'), 'SystemLock') + self.update_cmd = ['apt-get', 'upgrade', '-y'] + + def _refreshUpdateList(self): + """ + Update the list of packages to be updated in the system. + """ + apt_cache = getattr(__import__('apt'), 'Cache')() + try: + with self.pkg_lock(): + apt_cache.update() + apt_cache.upgrade() + self._pkgs = apt_cache.get_changes() + except Exception, e: + kimchiLock.release() + raise OperationFailed('KCHPKGUPD0003E', {'err': e.message}) + + def getPackagesList(self): + """ + Return a list of package's dictionaries. Each dictionary contains the + information about a package, in the format + package = {'package_name': <string>, 'version': <string>, + 'arch': <string>, 'repository': <string>} + """ + kimchiLock.acquire() + self._refreshUpdateList() + kimchiLock.release() + pkg_list = [] + for pkg in self._pkgs: + package = {'package_name': pkg.shortname, + 'version': pkg.candidate.version, + 'arch': pkg._pkg.architecture, + 'repository': pkg.candidate.origins[0].label} + pkg_list.append(package) + + return pkg_list + + +class ZypperUpdate(object): + """ + Class to represent and operate with Zypper software update system. + It's loaded only on those systems listed at ZYPPER_DISTROS and loads + necessary modules in runtime. + """ + def __init__(self): + self._pkgs = {} + self.update_cmd = ["zypper", "--non-interactive", "update", + "--auto-agree-with-licenses"] + + def _refreshUpdateList(self): + """ + Update the list of packages to be updated in the system. + """ + self._pkgs = [] + cmd = ["zypper", "list-updates"] + (stdout, stderr, returncode) = run_command(cmd) + + if len(stderr) > 0: + raise OperationFailed('KCHPKGUPD0003E', {'err': stderr}) + + for line in stdout.split('\n'): + if line.find('v |') >= 0: + info = line.split(' | ') + package = {'package_name': info[2], 'version': info[4], + 'arch': info[5], 'repository': info[1]} + self._pkgs.append(package) + + def getPackagesList(self): + """ + Return a list of package's dictionaries. Each dictionary contains the + information about a package, in the format + package = {'package_name': <string>, 'version': <string>, + 'arch': <string>, 'repository': <string>} + """ + kimchiLock.acquire() + self._refreshUpdateList() + kimchiLock.release() + return self._pkgs diff --git a/src/wok/plugins/kimchi/template.conf b/src/wok/plugins/kimchi/template.conf new file mode 100644 index 0000000..f3615e6 --- /dev/null +++ b/src/wok/plugins/kimchi/template.conf @@ -0,0 +1,47 @@ +# +# Configuration file for Kimchi Templates +# + +[main] +# Memory in MB +#memory = 1024 + +# List of networks separated by comma +# Represents the virtual network interfaces to be assigned to guest +#networks = default, + +[storage] +# Storage pool used to handle the guest disk +#pool = default + +# Specify multiple [[disk.X]] sub-sections to add multiples disks to guest +# All the disk files will be created in the same storage pool as set above +[[disk.0]] +# Disk size in GB +#size = 10 + +# Disk format +#format = qcow2 + +[graphics] +# Graphics type +# Valid options: vnc | spice +#type = vnc + +# The network which the vnc/spice server listens on +#listen = 127.0.0.1 + +[processor] +# Number of vcpus +# When specifying CPU topology, make sure cpus value is equal to the product +# of sockets, cores, and threads. +#cpus = 1 + +# Number of sockets (not set by default) +#sockets = + +# Number of cores per socket (not set by default) +#cores = + +# Number of threads per core (not set by default) +#threads = diff --git a/src/wok/plugins/kimchi/tests/Makefile.am b/src/wok/plugins/kimchi/tests/Makefile.am new file mode 100644 index 0000000..c1f6784 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/Makefile.am @@ -0,0 +1,50 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +EXTRA_DIST = \ + Makefile.am \ + run_tests.sh.in \ + test_config.py.in \ + $(filter-out test_config.py, $(wildcard *.py)) \ + $(NULL) + +noinst_SCRIPTS = run_tests.sh + +do_substitution = \ + sed -e 's,[@]HAVE_PYMOD_UNITTEST[@],$(HAVE_PYMOD_UNITTEST),g' \ + -e 's,[@]prefix[@],$(prefix),g' \ + -e 's,[@]datadir[@],$(datadir),g' \ + -e 's,[@]PYTHON_VERSION[@],$(PYTHON_VERSION),g' \ + -e 's,[@]wokdir[@],$(pythondir)/wok,g' \ + -e 's,[@]pkgdatadir[@],$(pkgdatadir),g' + + +run_tests.sh: run_tests.sh.in Makefile + $(do_substitution) < $(srcdir)/run_tests.sh.in > run_tests.sh + chmod +x run_tests.sh + +test_config.py: test_config.py.in Makefile + $(do_substitution) < $(srcdir)/test_config.py.in > test_config.py + +check-local: + $(MKDIR_P) $(top_srcdir)/data/screenshots + ./run_tests.sh + +BUILT_SOURCES = test_config.py +CLEANFILES = run_tests.sh test_config.py diff --git a/src/wok/plugins/kimchi/tests/iso_gen.py b/src/wok/plugins/kimchi/tests/iso_gen.py new file mode 100644 index 0000000..736c660 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/iso_gen.py @@ -0,0 +1,212 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import platform +import struct + +from wok.plugins.kimchi.isoinfo import IsoImage + + +iso_des = [ + ('openbsd', lambda v: True, + lambda v: 'OpenBSD/i386 %s Install CD' % v), + ('centos', lambda v: True, lambda v: 'CentOS_%s_Final' % v), + ('windows', '2000', 'W2AFPP'), + ('windows', 'xp', 'WXPFPP'), + ('windows', '2003', 'ARMECHK'), + ('windows', '2003r2', 'CRMEFPP'), + ('windows', '2008', 'KRTMSVOL'), + ('windows', '2008r2', 'GRMSXVOL'), + ('windows', 'vista', 'FB1EVOL'), + ('windows', '7', 'GRMCULFRER'), + ('windows', '8', 'HB1_CCPA_X86FRE'), + ('sles', '10', 'SLES10'), + ('sles', '11', 'SUSE_SLES-11-0-0'), + ('opensuse', '11.1', 'SU1110.001'), + ('opensuse', '11.3', 'openSUSE-DVD-x86_64.0702..001'), + ('opensuse', '11.4', 'openSUSE-DVD-x86_640024'), + ('opensuse', '12.1', 'openSUSE-DVD-x86_640039'), + ('opensuse', '12.2', 'openSUSE-DVD-x86_640167'), + ('opensuse', lambda v: True, lambda v: 'openSUSE-%s' % v), + ('rhel', '4.8', 'RHEL/4-U8'), + ('rhel', lambda v: v.startswith('6.'), lambda v: 'RHEL_%s' % v), + ('debian', lambda v: True, lambda v: 'Debian %s' % v), + ('ubuntu', + lambda v: v in ('7.10', '8.04', '8.10', '9.04', '9.10', '10.04', '10.10', + '11.04', '11.10', '12.04', '12.10', '13.04', '13.10', + '14.04'), + lambda v: 'Ubuntu %s' % v), + ('fedora', + lambda v: v in ('16', '17', '18', '19'), + lambda v: 'Fedora %s' % v) +] + + +class FakeIsoImage(object): + def _build_iso(self, fd, iso_volid, bootable): + if platform.machine().startswith('ppc'): + self._build_powerpc_bootable_iso(fd, iso_volid) + return + self._build_intel_iso(fd, iso_volid, bootable) + + def _build_powerpc_bootable_iso(self, fd, iso_volid): + self._build_prim_vol(fd, iso_volid) + self._build_bootable_ppc_path_table(fd) + + def _build_intel_iso(self, fd, iso_volid, bootable): + # Do not change the order of the method calls + self._build_el_boot(fd, bootable) + self._build_prim_vol(fd, iso_volid) + self._build_el_torito(fd) + + def _build_prim_vol(self, fd, iso_volid): + fd.seek(16 * IsoImage.SECTOR_SIZE) + fmt = IsoImage.VOL_DESC + vd_type = 1 + vd_ident = 'CD001' + vd_ver = 1 + pad0 = 1 + sys_id = 'fake os' + vol_id = iso_volid + data = (vd_type, vd_ident, vd_ver, pad0, sys_id, vol_id) + s = fmt.pack(*data) + fd.write(s) + self._add_sector_padding(fd, s) + + def _add_sector_padding(self, fd, s): + padding_len = IsoImage.SECTOR_SIZE - len(s) + fmt = struct.Struct('=%ss' % padding_len) + s = fmt.pack('a' * padding_len) + fd.write(s) + + def _build_el_torito(self, fd): + fmt = IsoImage.EL_TORITO_BOOT_RECORD + vd_type = 0 + vd_ident = 'CD001' + vd_ver = 1 + et_ident = "EL TORITO SPECIFICATION:" + pad0 = 'a' * 32 + boot_cat = 0 + data = (vd_type, vd_ident, vd_ver, et_ident, pad0, boot_cat) + s = fmt.pack(*data) + fd.write(s) + self._add_sector_padding(fd, s) + + def _build_el_boot(self, fd, bootable): + fmt = IsoImage.EL_TORITO_VALIDATION_ENTRY + hdr_id = 0 + platform_id = 0 + pad0 = 1 + ident = 'c' * 24 + csum = 1 + key55 = 0x55 + keyAA = 0xaa + data = (hdr_id, platform_id, pad0, ident, csum, key55, keyAA) + s = fmt.pack(*data) + fd.write(s) + + fmt = IsoImage.EL_TORITO_BOOT_ENTRY + if bootable: + boot = 0x88 + else: + boot = 0 + media_type = 1 + load_seg = 1 + sys_type = 1 + pad0 = 1 + sectors = 1 + load_rba = 1 + data = (boot, media_type, load_seg, sys_type, pad0, sectors, load_rba) + s = fmt.pack(*data) + fd.write(s) + + s = 'a' * IsoImage.SECTOR_SIZE + fd.write(s) + + def _build_bootable_ppc_path_table(self, fd): + # write path table locator + PATH_TABLE_LOC_OFFSET = 16 * IsoImage.SECTOR_SIZE + 132 + PATH_TABLE_SIZE_LOC = struct.Struct("<I 4s I") + path_table_size = 64 + path_table_loc = 18 + fd.seek(PATH_TABLE_LOC_OFFSET) + fmt = PATH_TABLE_SIZE_LOC + data = (path_table_size, 4*'0', path_table_loc) + s = fmt.pack(*data) + fd.write(s) + # write path table entry + fd.seek(path_table_loc * IsoImage.SECTOR_SIZE) + DIR_NAMELEN_LOCATION_PARENT = struct.Struct("<B B I H 3s") + dir_namelen = 3 + dir_loc = 19 + dir_parent = 1 + dir_name = 'ppc' + data = (dir_namelen, 0, dir_loc, dir_parent, dir_name) + fmt = DIR_NAMELEN_LOCATION_PARENT + s = fmt.pack(*data) + fd.write(s) + # write 'ppc' dir record + ppc_dir_offset = dir_loc * IsoImage.SECTOR_SIZE + fd.seek(ppc_dir_offset) + STATIC_DIR_RECORD_FMT = struct.Struct("<B 9s I 11s B 6s B 12s") + dir_rec_len = 1 + unused1 = 9 * '0' + dir_size = 100 + unused2 = 11 * '0' + file_flags = 0 + unused3 = 6 * '0' + file_name_len = 12 + boot_file_name = "bootinfo.txt" + data = (dir_rec_len, unused1, dir_size, unused2, file_flags, + unused3, file_name_len, boot_file_name) + fmt = STATIC_DIR_RECORD_FMT + s = fmt.pack(*data) + fd.write(s) + + +def construct_fake_iso(path, bootable, version, distro): + iso = FakeIsoImage() + + for d, v, gen_id in iso_des: + if d != distro: + continue + if hasattr(v, '__call__'): + supported = v(version) + else: + supported = version == v + + if not supported: + continue + + if hasattr(gen_id, '__call__'): + vol_id = gen_id(version) + else: + vol_id = gen_id + with open(path, 'w') as fd: + return iso._build_iso(fd, vol_id, bootable) + + raise Exception("%s: %s not supported generation" % (distro, version)) + + +if __name__ == '__main__': + construct_fake_iso('centos.iso', True, '6.1', 'centos') + construct_fake_iso('ubuntu12.04.iso', True, '12.04', 'ubuntu') + construct_fake_iso('fedora17.iso', True, '17', 'fedora') + construct_fake_iso('sles10.iso', True, '10', 'sles') + construct_fake_iso('openbsd.iso', True, '5.0', 'openbsd') diff --git a/src/wok/plugins/kimchi/tests/run_tests.sh.in b/src/wok/plugins/kimchi/tests/run_tests.sh.in new file mode 100644 index 0000000..beef75e --- /dev/null +++ b/src/wok/plugins/kimchi/tests/run_tests.sh.in @@ -0,0 +1,55 @@ +#!/bin/bash +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +HAVE_UNITTEST=@HAVE_PYMOD_UNITTEST@ +PYTHON_VER=@PYTHON_VERSION@ + +if [ "$1" = "-v" ]; then + OPTS="-v" + shift +else + OPTS="" +fi + +if [ $# -ne 0 ]; then + ARGS="$@" +else + ARGS=`find -name "test_*.py" | xargs -I @ basename @ .py` +fi + +if [ "$HAVE_UNITTEST" != "yes" -o "$PYTHON_VER" == "2.6" ]; then + CMD="unit2" +else + CMD="python -m unittest" +fi + +LIST=($ARGS) +MODEL_LIST=() +MOCK_LIST=() +for ((i=0;i<${#LIST[@]};i++)); do + + if [[ ${LIST[$i]} == test_model* ]]; then + MODEL_LIST+=(${LIST[$i]}) + else + MOCK_LIST+=(${LIST[$i]}) + fi +done + +PYTHONPATH=../plugins:../src:../ $CMD $OPTS ${MODEL_LIST[@]} ${MOCK_LIST[@]} diff --git a/src/wok/plugins/kimchi/tests/test_authorization.py b/src/wok/plugins/kimchi/tests/test_authorization.py new file mode 100644 index 0000000..87d68ab --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_authorization.py @@ -0,0 +1,178 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import unittest +from functools import partial + +from wok.plugins.kimchi import mockmodel + +from iso_gen import construct_fake_iso +from utils import get_free_port, patch_auth, request +from utils import run_server, wait_task + + +test_server = None +model = None +host = None +port = None +ssl_port = None +fake_iso = '/tmp/fake.iso' + + +def setUpModule(): + global test_server, model, host, port, ssl_port + + patch_auth(sudo=False) + model = mockmodel.MockModel('/tmp/obj-store-test') + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + test_server = run_server(host, port, ssl_port, test_mode=True, model=model) + + # Create fake ISO to do the tests + construct_fake_iso(fake_iso, True, '12.04', 'ubuntu') + + +def tearDownModule(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + os.unlink(fake_iso) + + +class AuthorizationTests(unittest.TestCase): + def setUp(self): + self.request = partial(request, host, ssl_port) + model.reset() + + def test_nonroot_access(self): + # Non-root users can access static host information + resp = self.request('/plugins/kimchi/host', '{}', 'GET') + self.assertEquals(403, resp.status) + + # Non-root users can access host stats + resp = self.request('/plugins/kimchi/host/stats', '{}', 'GET') + self.assertEquals(403, resp.status) + + # Non-root users can not reboot/shutdown host system + resp = self.request('/plugins/kimchi/host/reboot', '{}', 'POST') + self.assertEquals(403, resp.status) + resp = self.request('/plugins/kimchi/host/shutdown', '{}', 'POST') + self.assertEquals(403, resp.status) + + # Non-root users can not get or debug reports + resp = self.request('/plugins/kimchi/debugreports', '{}', 'GET') + self.assertEquals(403, resp.status) + resp = self.request('/plugins/kimchi/debugreports', '{}', 'POST') + self.assertEquals(403, resp.status) + + # Non-root users can not create or delete network (only get) + resp = self.request('/plugins/kimchi/networks', '{}', 'GET') + self.assertEquals(200, resp.status) + resp = self.request('/plugins/kimchi/networks', '{}', 'POST') + self.assertEquals(403, resp.status) + resp = self.request('/plugins/kimchi/networks/default/activate', '{}', + 'POST') + self.assertEquals(403, resp.status) + resp = self.request('/plugins/kimchi/networks/default', '{}', 'DELETE') + self.assertEquals(403, resp.status) + + # Non-root users can not create or delete storage pool (only get) + resp = self.request('/plugins/kimchi/storagepools', '{}', 'GET') + self.assertEquals(200, resp.status) + resp = self.request('/plugins/kimchi/storagepools', '{}', 'POST') + self.assertEquals(403, resp.status) + resp = self.request('/plugins/kimchi/storagepools/default/activate', + '{}', 'POST') + self.assertEquals(403, resp.status) + resp = self.request('/plugins/kimchi/storagepools/default', '{}', + 'DELETE') + self.assertEquals(403, resp.status) + + # Non-root users can not update or delete a template + # but he can get and create a new one + resp = self.request('/plugins/kimchi/templates', '{}', 'GET') + self.assertEquals(403, resp.status) + req = json.dumps({'name': 'test', 'cdrom': fake_iso}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(403, resp.status) + resp = self.request('/plugins/kimchi/templates/test', '{}', 'PUT') + self.assertEquals(403, resp.status) + resp = self.request('/plugins/kimchi/templates/test', '{}', 'DELETE') + self.assertEquals(403, resp.status) + + # Non-root users can only get vms authorized to them + model.templates_create({'name': u'test', 'cdrom': fake_iso}) + + task_info = model.vms_create({ + 'name': u'test-me', + 'template': '/plugins/kimchi/templates/test' + }) + wait_task(model.task_lookup, task_info['id']) + + model.vm_update(u'test-me', + {'users': [mockmodel.fake_user.keys()[0]], + 'groups': []}) + + task_info = model.vms_create({ + 'name': u'test-usera', + 'template': '/plugins/kimchi/templates/test' + }) + wait_task(model.task_lookup, task_info['id']) + + non_root = list(set(model.users_get_list()) - set(['root']))[0] + model.vm_update(u'test-usera', {'users': [non_root], 'groups': []}) + + task_info = model.vms_create({ + 'name': u'test-groupa', + 'template': '/plugins/kimchi/templates/test' + }) + wait_task(model.task_lookup, task_info['id']) + a_group = model.groups_get_list()[0] + model.vm_update(u'test-groupa', {'groups': [a_group]}) + + resp = self.request('/plugins/kimchi/vms', '{}', 'GET') + self.assertEquals(200, resp.status) + vms_data = json.loads(resp.read()) + self.assertEquals([u'test-groupa', u'test-me'], + sorted([v['name'] for v in vms_data])) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(403, resp.status) + + # Create a vm using mockmodel directly to test Resource access + task_info = model.vms_create({ + 'name': 'kimchi-test', + 'template': '/plugins/kimchi/templates/test' + }) + wait_task(model.task_lookup, task_info['id']) + resp = self.request('/plugins/kimchi/vms/kimchi-test', '{}', 'PUT') + self.assertEquals(403, resp.status) + resp = self.request('/plugins/kimchi/vms/kimchi-test', '{}', 'DELETE') + self.assertEquals(403, resp.status) + + # Non-root users can only update VMs authorized by them + resp = self.request('/plugins/kimchi/vms/test-me/start', '{}', 'POST') + self.assertEquals(200, resp.status) + resp = self.request('/plugins/kimchi/vms/test-usera/start', '{}', + 'POST') + self.assertEquals(403, resp.status) + + model.template_delete('test') + model.vm_delete('test-me') diff --git a/src/wok/plugins/kimchi/tests/test_config.py.in b/src/wok/plugins/kimchi/tests/test_config.py.in new file mode 100644 index 0000000..4604eb1 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_config.py.in @@ -0,0 +1,267 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import unittest +from cherrypy.lib.reprconf import Parser + +from wok.config import Paths, PluginPaths, WokConfig + +from wok.plugins.kimchi.config import get_debugreports_path +from wok.plugins.kimchi.config import get_screenshot_path +from wok.plugins.kimchi.config import KimchiConfig, KimchiPaths + + +get_prefix = None + + +def setUpModule(): + global get_prefix + get_prefix = Paths.get_prefix + + +def tearDownModule(): + Paths.get_prefix = KimchiPaths.get_prefix = get_prefix + + +class ConfigTests(unittest.TestCase): + def assertInstalledPath(self, actual, expected): + if '@pkgdatadir@' != '/usr/share/kimchi': + usr_local = '/usr/local' + if not expected.startswith('/usr'): + expected = usr_local + expected + self.assertEquals(actual, expected) + + def test_installed_paths(self): + Paths.get_prefix = lambda self: '@datadir@/wok' + paths = Paths() + self.assertInstalledPath(paths.state_dir, '/var/lib/wok') + self.assertInstalledPath(paths.log_dir, '/var/log/wok') + self.assertInstalledPath(paths.conf_dir, '/etc/wok') + self.assertInstalledPath(paths.src_dir, '@wokdir@') + self.assertInstalledPath(paths.plugins_dir, '@wokdir@/plugins') + self.assertInstalledPath(paths.ui_dir, '@datadir@/wok/ui') + self.assertInstalledPath(paths.mo_dir, '@prefix@/share/locale') + + def test_uninstalled_paths(self): + Paths.get_prefix = lambda self: '/home/user/wok' + paths = Paths() + self.assertEquals(paths.state_dir, '/home/user/wok/data') + self.assertEquals(paths.log_dir, '/home/user/wok/log') + self.assertEquals(paths.conf_dir, '/home/user/wok/src') + self.assertEquals(paths.src_dir, '/home/user/wok/src/wok') + self.assertEquals(paths.plugins_dir, '/home/user/wok/plugins') + self.assertEquals(paths.ui_dir, '/home/user/wok/ui') + self.assertEquals(paths.mo_dir, '/home/user/wok/mo') + + def test_installed_plugin_paths(self): + KimchiPaths.get_prefix = lambda self: '@datadir@/wok' + paths = KimchiPaths() + self.assertInstalledPath(paths.conf_dir, '/etc/wok/plugins.d') + self.assertInstalledPath(paths.conf_file, + '/etc/wok/plugins.d/kimchi.conf') + self.assertInstalledPath(paths.src_dir, '@wokdir@/plugins/kimchi') + self.assertInstalledPath(paths.ui_dir, + '@datadir@/wok/plugins/kimchi/ui') + self.assertInstalledPath(paths.mo_dir, '@prefix@/share/locale') + + def test_uninstalled_plugin_paths(self): + KimchiPaths.get_prefix = lambda self: '/home/user/wok' + paths = KimchiPaths() + self.assertEquals(paths.conf_dir, '/home/user/wok/plugins/kimchi') + self.assertEquals( + paths.conf_file, '/home/user/wok/plugins/kimchi/kimchi.conf') + self.assertEquals(paths.src_dir, '/home/user/wok/plugins/kimchi') + self.assertEquals(paths.ui_dir, '/home/user/wok/plugins/kimchi/ui') + self.assertEquals(paths.mo_dir, '/home/user/wok/plugins/kimchi/mo') + + def test_wok_config(self): + Paths.get_prefix = PluginPaths.get_prefix = get_prefix + paths = Paths() + CACHEEXPIRES = 31536000 + SESSIONSTIMEOUT = 10 + configObj = { + '/': { + 'tools.trailing_slash.on': False, + 'request.methods_with_bodies': ('POST', 'PUT'), + 'tools.nocache.on': True, + 'tools.proxy.on': True, + 'tools.sessions.on': True, + 'tools.sessions.name': 'wok', + 'tools.sessions.secure': True, + 'tools.sessions.httponly': True, + 'tools.sessions.locking': 'explicit', + 'tools.sessions.storage_type': 'ram', + 'tools.sessions.timeout': SESSIONSTIMEOUT, + 'tools.wokauth.on': False + }, + '/wok-ui.html': { + 'tools.wokauth.on': True + }, + '/css': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': '%s/ui/css' % paths.prefix, + 'tools.expires.on': True, + 'tools.expires.secs': CACHEEXPIRES, + 'tools.nocache.on': False, + 'tools.wokauth.on': False + }, + '/js': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': '%s/ui/js' % paths.prefix, + 'tools.expires.on': True, + 'tools.expires.secs': CACHEEXPIRES, + 'tools.nocache.on': False, + 'tools.wokauth.on': False + }, + '/libs': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': '%s/ui/libs' % paths.prefix, + 'tools.expires.on': True, + 'tools.expires.secs': CACHEEXPIRES, + 'tools.nocache.on': False, + 'tools.wokauth.on': False + }, + '/images': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': '%s/ui/images' % paths.prefix, + 'tools.nocache.on': False, + 'tools.wokauth.on': False + }, + '/favicon.ico': { + 'tools.staticfile.on': True, + 'tools.staticfile.filename': + '%s/images/logo.ico' % paths.ui_dir + }, + '/robots.txt': { + 'tools.staticfile.on': True, + 'tools.staticfile.filename': '%s/robots.txt' % paths.ui_dir + }, + } + + wok_config = WokConfig() + self.assertEquals(wok_config, configObj) + + + def test_kimchi_config(self): + KimchiPaths.get_prefix = PluginPaths.get_prefix = get_prefix + paths = KimchiPaths() + pluginPrefix = paths.add_prefix(paths.plugin_dir) + CACHEEXPIRES = 31536000 + SESSIONSTIMEOUT = 10 + configObj = { + 'wok': { + 'enable': True, + 'plugin_class': "KimchiRoot", + 'uri': '/%s' % paths.plugin_dir, + 'extra_auth_api_class': "control.sub_nodes" + }, + '/': { + 'tools.trailing_slash.on': False, + 'request.methods_with_bodies': ('POST', 'PUT'), + 'tools.nocache.on': True, + 'tools.proxy.on': True, + 'tools.sessions.on': True, + 'tools.sessions.name': 'wok', + 'tools.sessions.secure': True, + 'tools.sessions.httponly': True, + 'tools.sessions.locking': 'explicit', + 'tools.sessions.storage_type': 'ram', + 'tools.sessions.timeout': SESSIONSTIMEOUT, + 'tools.wokauth.on': True + }, + '/novnc': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': paths.novnc_dir, + 'tools.nocache.on': True, + 'tools.wokauth.on': True + }, + '/spice_auto.html': { + 'tools.staticfile.on': True, + 'tools.staticfile.filename': paths.spice_file, + 'tools.nocache.on': True, + 'tools.wokauth.on': True + }, + '/spice-html5': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': paths.spice_dir, + 'tools.nocache.on': True + }, + '/spice-html5/spice.css': { + 'tools.staticfile.on': True, + 'tools.staticfile.filename': paths.spice_css_file, + 'tools.nocache.on': True, + }, + '/ui/config/tab-ext.xml': { + 'tools.staticfile.on': True, + 'tools.staticfile.filename': '%s/ui/config/tab-ext.xml' % + pluginPrefix, + 'tools.nocache.on': True + }, + '/css': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': '%s/ui/css' % pluginPrefix, + 'tools.expires.on': True, + 'tools.expires.secs': CACHEEXPIRES, + 'tools.nocache.on': False, + 'tools.wokauth.on': False + }, + '/js': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': '%s/ui/js' % pluginPrefix, + 'tools.expires.on': True, + 'tools.expires.secs': CACHEEXPIRES, + 'tools.nocache.on': False, + 'tools.wokauth.on': False + }, + '/libs': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': '%s/ui/libs' % pluginPrefix, + 'tools.expires.on': True, + 'tools.expires.secs': CACHEEXPIRES, + 'tools.nocache.on': False, + 'tools.wokauth.on': False, + }, + '/images': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': '%s/ui/images' % pluginPrefix, + 'tools.nocache.on': False, + 'tools.wokauth.on': False + }, + '/data/screenshots': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': get_screenshot_path(), + 'tools.nocache.on': False + }, + '/data/debugreports': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': get_debugreports_path(), + 'tools.nocache.on': False, + 'tools.wokauth.on': True, + 'tools.staticdir.content_types': {'xz': 'application/x-xz'} + }, + '/help': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': '%s/ui/pages/help' % pluginPrefix, + 'tools.nocache.on': True + } + } + + kimchi_config = Parser().dict_from_file(KimchiPaths().conf_file) + kimchi_config.update(KimchiConfig()) + self.assertEquals(kimchi_config, configObj) diff --git a/src/wok/plugins/kimchi/tests/test_exception.py b/src/wok/plugins/kimchi/tests/test_exception.py new file mode 100644 index 0000000..4459aa6 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_exception.py @@ -0,0 +1,123 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import unittest + +from wok.plugins.kimchi import mockmodel + +from utils import get_free_port, patch_auth, request, run_server + + +test_server = None +model = None +host = None +port = None +ssl_port = None + + +def setup_server(environment='development'): + global test_server, model, host, port, ssl_port + + patch_auth() + model = mockmodel.MockModel('/tmp/obj-store-test') + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + test_server = run_server(host, port, ssl_port, test_mode=True, model=model, + environment=environment) + + +class ExceptionTests(unittest.TestCase): + def tearDown(self): + test_server.stop() + os.unlink('/tmp/obj-store-test') + + def test_production_env(self): + """ + Test reasons sanitized in production env + """ + setup_server('production') + # test 404 + resp = json.loads( + request(host, ssl_port, '/plugins/kimchi/vms/blah').read() + ) + self.assertEquals('404 Not Found', resp.get('code')) + + # test 405 wrong method + resp = json.loads(request(host, ssl_port, '/', None, 'DELETE').read()) + msg = u'WOKAPI0002E: Delete is not allowed for wokroot' + self.assertEquals('405 Method Not Allowed', resp.get('code')) + self.assertEquals(msg, resp.get('reason')) + + # test 400 parse error + resp = json.loads( + request(host, ssl_port, '/plugins/kimchi/vms', '{', 'POST').read() + ) + msg = u'WOKAPI0006E: Unable to parse JSON request' + self.assertEquals('400 Bad Request', resp.get('code')) + self.assertEquals(msg, resp.get('reason')) + self.assertNotIn('call_stack', resp) + + # test 400 missing required parameter + req = json.dumps({}) + resp = json.loads( + request(host, ssl_port, '/plugins/kimchi/vms', req, 'POST').read() + ) + self.assertEquals('400 Bad Request', resp.get('code')) + m = u"KCHVM0016E: Specify a template to create a virtual machine from" + self.assertEquals(m, resp.get('reason')) + self.assertNotIn('call_stack', resp) + + def test_development_env(self): + """ + Test traceback thrown in development env + """ + setup_server() + # test 404 + resp = json.loads( + request(host, ssl_port, '/plugins/kimchi/vms/blah').read() + ) + self.assertEquals('404 Not Found', resp.get('code')) + + # test 405 wrong method + resp = json.loads(request(host, ssl_port, '/', None, 'DELETE').read()) + msg = u'WOKAPI0002E: Delete is not allowed for wokroot' + self.assertEquals('405 Method Not Allowed', resp.get('code')) + self.assertEquals(msg, resp.get('reason')) + + # test 400 parse error + resp = json.loads( + request(host, ssl_port, '/plugins/kimchi/vms', '{', 'POST').read() + ) + msg = u'WOKAPI0006E: Unable to parse JSON request' + self.assertEquals('400 Bad Request', resp.get('code')) + self.assertEquals(msg, resp.get('reason')) + self.assertIn('call_stack', resp) + + # test 400 missing required parameter + req = json.dumps({}) + resp = json.loads( + request(host, ssl_port, '/plugins/kimchi/vms', req, 'POST').read() + ) + m = u"KCHVM0016E: Specify a template to create a virtual machine from" + self.assertEquals('400 Bad Request', resp.get('code')) + self.assertEquals(m, resp.get('reason')) + self.assertIn('call_stack', resp) diff --git a/src/wok/plugins/kimchi/tests/test_host.py b/src/wok/plugins/kimchi/tests/test_host.py new file mode 100644 index 0000000..6cd0833 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_host.py @@ -0,0 +1,206 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import platform +import psutil +import tempfile +import time +import unittest +from functools import partial + +from wok.plugins.kimchi.mockmodel import MockModel + +from utils import get_free_port, patch_auth, request, run_server, wait_task + + +test_server = None +model = None +host = None +ssl_port = None +tmpfile = None + + +def setUpModule(): + global test_server, model, host, ssl_port, tmpfile + + patch_auth() + tmpfile = tempfile.mktemp() + model = MockModel(tmpfile) + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + cherrypy_port = get_free_port('cherrypy_port') + test_server = run_server(host, port, ssl_port, test_mode=True, + cherrypy_port=cherrypy_port, model=model) + + +def tearDownModule(): + test_server.stop() + os.unlink(tmpfile) + + +class HostTests(unittest.TestCase): + def setUp(self): + self.request = partial(request, host, ssl_port) + + def test_hostinfo(self): + resp = self.request('/plugins/kimchi/host').read() + info = json.loads(resp) + keys = ['os_distro', 'os_version', 'os_codename', 'cpu_model', + 'memory', 'cpus'] + self.assertEquals(sorted(keys), sorted(info.keys())) + + distro, version, codename = platform.linux_distribution() + self.assertEquals(distro, info['os_distro']) + self.assertEquals(version, info['os_version']) + self.assertEquals(unicode(codename, "utf-8"), info['os_codename']) + self.assertEquals(psutil.TOTAL_PHYMEM, info['memory']) + + def test_hoststats(self): + time.sleep(1) + stats_keys = ['cpu_utilization', 'memory', 'disk_read_rate', + 'disk_write_rate', 'net_recv_rate', 'net_sent_rate'] + resp = self.request('/plugins/kimchi/host/stats').read() + stats = json.loads(resp) + self.assertEquals(sorted(stats_keys), sorted(stats.keys())) + + cpu_utilization = stats['cpu_utilization'] + self.assertIsInstance(cpu_utilization, float) + self.assertGreaterEqual(cpu_utilization, 0.0) + self.assertTrue(cpu_utilization <= 100.0) + + memory_stats = stats['memory'] + self.assertIn('total', memory_stats) + self.assertIn('free', memory_stats) + self.assertIn('cached', memory_stats) + self.assertIn('buffers', memory_stats) + self.assertIn('avail', memory_stats) + + resp = self.request('/plugins/kimchi/host/stats/history').read() + history = json.loads(resp) + self.assertEquals(sorted(stats_keys), sorted(history.keys())) + + def test_host_actions(self): + def _task_lookup(taskid): + return json.loads( + self.request('/plugins/kimchi/tasks/%s' % taskid).read() + ) + + resp = self.request('/plugins/kimchi/host/shutdown', '{}', 'POST') + self.assertEquals(200, resp.status) + resp = self.request('/plugins/kimchi/host/reboot', '{}', 'POST') + self.assertEquals(200, resp.status) + + # Test system update + resp = self.request('/plugins/kimchi/host/packagesupdate', None, 'GET') + pkgs = json.loads(resp.read()) + self.assertEquals(3, len(pkgs)) + + pkg_keys = ['package_name', 'repository', 'arch', 'version'] + for p in pkgs: + name = p['package_name'] + resp = self.request('/plugins/kimchi/host/packagesupdate/' + name, + None, 'GET') + info = json.loads(resp.read()) + self.assertEquals(sorted(pkg_keys), sorted(info.keys())) + + resp = self.request('/plugins/kimchi/host/swupdate', '{}', 'POST') + task = json.loads(resp.read()) + task_params = [u'id', u'message', u'status', u'target_uri'] + self.assertEquals(sorted(task_params), sorted(task.keys())) + + resp = self.request('/tasks/' + task[u'id'], None, + 'GET') + task_info = json.loads(resp.read()) + self.assertEquals(task_info['status'], 'running') + wait_task(_task_lookup, task_info['id']) + resp = self.request('/tasks/' + task[u'id'], None, + 'GET') + task_info = json.loads(resp.read()) + self.assertEquals(task_info['status'], 'finished') + self.assertIn(u'All packages updated', task_info['message']) + pkgs = model.packagesupdate_get_list() + self.assertEquals(0, len(pkgs)) + + def test_host_partitions(self): + resp = self.request('/plugins/kimchi/host/partitions') + self.assertEquals(200, resp.status) + partitions = json.loads(resp.read()) + + keys = ['name', 'path', 'type', 'fstype', 'size', 'mountpoint', + 'available'] + for item in partitions: + resp = self.request('/plugins/kimchi/host/partitions/%s' % + item['name']) + info = json.loads(resp.read()) + self.assertEquals(sorted(info.keys()), sorted(keys)) + + def test_host_devices(self): + def asset_devices_type(devices, dev_type): + for dev in devices: + self.assertEquals(dev['device_type'], dev_type) + + resp = self.request('/plugins/kimchi/host/devices?_cap=scsi_host') + nodedevs = json.loads(resp.read()) + # Mockmodel brings 3 preconfigured scsi fc_host + self.assertEquals(3, len(nodedevs)) + + nodedev = json.loads( + self.request('/plugins/kimchi/host/devices/scsi_host2').read() + ) + # Mockmodel generates random wwpn and wwnn + self.assertEquals('scsi_host2', nodedev['name']) + self.assertEquals('fc_host', nodedev['adapter']['type']) + self.assertEquals(16, len(nodedev['adapter']['wwpn'])) + self.assertEquals(16, len(nodedev['adapter']['wwnn'])) + + devs = json.loads(self.request('/plugins/kimchi/host/devices').read()) + dev_names = [dev['name'] for dev in devs] + for dev_type in ('pci', 'usb_device', 'scsi'): + resp = self.request('/plugins/kimchi/host/devices?_cap=%s' % + dev_type) + devsByType = json.loads(resp.read()) + names = [dev['name'] for dev in devsByType] + self.assertTrue(set(names) <= set(dev_names)) + asset_devices_type(devsByType, dev_type) + + resp = self.request('/plugins/kimchi/host/devices?_passthrough=true') + passthru_devs = [dev['name'] for dev in json.loads(resp.read())] + self.assertTrue(set(passthru_devs) <= set(dev_names)) + + for dev_type in ('pci', 'usb_device', 'scsi'): + resp = self.request( + '/plugins/kimchi/host/devices?_cap=%s&_passthrough=true' % + dev_type + ) + filteredDevs = json.loads(resp.read()) + filteredNames = [dev['name'] for dev in filteredDevs] + self.assertTrue(set(filteredNames) <= set(dev_names)) + asset_devices_type(filteredDevs, dev_type) + + for dev in passthru_devs: + resp = self.request( + '/plugins/kimchi/host/devices?_passthrough_affected_by=%s' % + dev + ) + affected_devs = [dev['name'] for dev in json.loads(resp.read())] + self.assertTrue(set(affected_devs) <= set(dev_names)) diff --git a/src/wok/plugins/kimchi/tests/test_mock_network.py b/src/wok/plugins/kimchi/tests/test_mock_network.py new file mode 100644 index 0000000..4e2a939 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_mock_network.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import unittest +from functools import partial + +from wok.plugins.kimchi.mockmodel import MockModel + +from test_model_network import _do_network_test +from utils import get_free_port, patch_auth, request, run_server + + +model = None +test_server = None +host = None +port = None +ssl_port = None +cherrypy_port = None + + +def setUpModule(): + global test_server, model, host, port, ssl_port, cherrypy_port + + patch_auth() + model = MockModel('/tmp/obj-store-test') + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + cherrypy_port = get_free_port('cherrypy_port') + test_server = run_server(host, port, ssl_port, test_mode=True, + cherrypy_port=cherrypy_port, model=model) + + +def tearDownModule(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + + +class MockNetworkTests(unittest.TestCase): + def setUp(self): + self.request = partial(request, host, ssl_port) + model.reset() + + def test_vlan_tag_bridge(self): + # Verify the current system has at least one interface to create a + # bridged network + interfaces = json.loads( + self.request('/plugins/kimchi/interfaces?type=nic').read() + ) + if len(interfaces) > 0: + iface = interfaces[0]['name'] + _do_network_test(self, model, {'name': u'bridge-network', + 'connection': 'bridge', + 'interface': iface, 'vlan_id': 987}) diff --git a/src/wok/plugins/kimchi/tests/test_mock_storagepool.py b/src/wok/plugins/kimchi/tests/test_mock_storagepool.py new file mode 100644 index 0000000..5cf5b3e --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_mock_storagepool.py @@ -0,0 +1,147 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import unittest +from functools import partial + +from wok.plugins.kimchi.mockmodel import MockModel + +from utils import get_free_port, patch_auth, request, run_server + + +model = None +test_server = None +host = None +port = None +ssl_port = None +cherrypy_port = None + + +def setUpModule(): + global test_server, model, host, port, ssl_port, cherrypy_port + + patch_auth() + model = MockModel('/tmp/obj-store-test') + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + cherrypy_port = get_free_port('cherrypy_port') + test_server = run_server(host, port, ssl_port, test_mode=True, + cherrypy_port=cherrypy_port, model=model) + + +def tearDownModule(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + + +class MockStoragepoolTests(unittest.TestCase): + def setUp(self): + self.request = partial(request, host, ssl_port) + model.reset() + + def _task_lookup(self, taskid): + return json.loads( + self.request('/tasks/%s' % taskid).read() + ) + + def test_storagepool(self): + # MockModel always returns 2 partitions (vdx, vdz) + partitions = json.loads( + self.request('/plugins/kimchi/host/partitions').read() + ) + devs = [dev['path'] for dev in partitions] + + # MockModel always returns 3 FC devices + fc_devs = json.loads( + self.request('/plugins/kimchi/host/devices?_cap=fc_host').read() + ) + fc_devs = [dev['name'] for dev in fc_devs] + + poolDefs = [ + {'type': 'dir', 'name': u'k������h��UnitTestDirPool', + 'path': '/tmp/kimchi-images'}, + {'type': 'netfs', 'name': u'k������h��UnitTestNSFPool', + 'source': {'host': 'localhost', + 'path': '/var/lib/kimchi/nfs-pool'}}, + {'type': 'scsi', 'name': u'k������h��UnitTestSCSIFCPool', + 'source': {'adapter_name': fc_devs[0]}}, + {'type': 'iscsi', 'name': u'k������h��UnitTestISCSIPool', + 'source': {'host': '127.0.0.1', + 'target': 'iqn.2015-01.localhost.kimchiUnitTest'}}, + {'type': 'logical', 'name': u'k������h��UnitTestLogicalPool', + 'source': {'devices': [devs[0]]}}] + + def _do_test(params): + name = params['name'] + uri = '/plugins/kimchi/storagepools/%s' % name.encode('utf-8') + + req = json.dumps(params) + resp = self.request('/plugins/kimchi/storagepools', req, 'POST') + self.assertEquals(201, resp.status) + + # activate the storage pool + resp = self.request(uri + '/activate', '{}', 'POST') + storagepool = json.loads(self.request(uri).read()) + self.assertEquals('active', storagepool['state']) + + # Set autostart flag of an active storage pool + for autostart in [True, False]: + t = {'autostart': autostart} + req = json.dumps(t) + resp = self.request(uri, req, 'PUT') + storagepool = json.loads(self.request(uri).read()) + self.assertEquals(autostart, storagepool['autostart']) + + # Extend an active logical pool + if params['type'] == 'logical': + t = {'disks': [devs[1]]} + req = json.dumps(t) + resp = self.request(uri, req, 'PUT') + self.assertEquals(200, resp.status) + + # Deactivate the storage pool + resp = self.request(uri + '/deactivate', '{}', 'POST') + storagepool = json.loads(self.request(uri).read()) + self.assertEquals('inactive', storagepool['state']) + + # Set autostart flag of an inactive storage pool + for autostart in [True, False]: + t = {'autostart': autostart} + req = json.dumps(t) + resp = self.request(uri, req, 'PUT') + storagepool = json.loads(self.request(uri).read()) + self.assertEquals(autostart, storagepool['autostart']) + + # Extend an inactive logical pool + if params['type'] == 'logical': + t = {'disks': [devs[1]]} + req = json.dumps(t) + resp = self.request(uri, req, 'PUT') + self.assertEquals(200, resp.status) + + # Delete the storage pool + resp = self.request(uri, '{}', 'DELETE') + self.assertEquals(204, resp.status) + + for pool in poolDefs: + _do_test(pool) diff --git a/src/wok/plugins/kimchi/tests/test_mock_storagevolume.py b/src/wok/plugins/kimchi/tests/test_mock_storagevolume.py new file mode 100644 index 0000000..9d0a5ad --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_mock_storagevolume.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import unittest +from functools import partial + +from wok.plugins.kimchi.mockmodel import MockModel + +from test_model_storagevolume import _do_volume_test +from utils import get_free_port, patch_auth, request, run_server + + +model = None +test_server = None +host = None +port = None +ssl_port = None +cherrypy_port = None + + +def setUpModule(): + global test_server, model, host, port, ssl_port, cherrypy_port + + patch_auth() + model = MockModel('/tmp/obj-store-test') + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + cherrypy_port = get_free_port('cherrypy_port') + test_server = run_server(host, port, ssl_port, test_mode=True, + cherrypy_port=cherrypy_port, model=model) + + +def tearDownModule(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + + +class MockStorageVolumeTests(unittest.TestCase): + def setUp(self): + self.request = partial(request, host, ssl_port) + + def test_storagevolume(self): + # MockModel always returns 2 partitions (vdx, vdz) + partitions = json.loads( + self.request('/plugins/kimchi/host/partitions').read() + ) + devs = [dev['path'] for dev in partitions] + + # MockModel always returns 3 FC devices + fc_devs = json.loads( + self.request('/plugins/kimchi/host/devices?_cap=fc_host').read() + ) + fc_devs = [dev['name'] for dev in fc_devs] + + poolDefs = [ + {'type': 'dir', 'name': u'k������h��UnitTestDirPool', + 'path': '/tmp/kimchi-images'}, + {'type': 'netfs', 'name': u'k������h��UnitTestNSFPool', + 'source': {'host': 'localhost', + 'path': '/var/lib/kimchi/nfs-pool'}}, + {'type': 'scsi', 'name': u'k������h��UnitTestSCSIFCPool', + 'source': {'adapter_name': fc_devs[0]}}, + {'type': 'iscsi', 'name': u'k������h��UnitTestISCSIPool', + 'source': {'host': '127.0.0.1', + 'target': 'iqn.2015-01.localhost.kimchiUnitTest'}}, + {'type': 'logical', 'name': u'k������h��UnitTestLogicalPool', + 'source': {'devices': [devs[0]]}}] + + for pool in poolDefs: + pool_name = pool['name'] + uri = '/plugins/kimchi/storagepools/%s' % pool_name.encode('utf-8') + req = json.dumps(pool) + resp = self.request('/plugins/kimchi/storagepools', req, 'POST') + self.assertEquals(201, resp.status) + # activate the storage pool + resp = self.request(uri + '/activate', '{}', 'POST') + self.assertEquals(200, resp.status) + _do_volume_test(self, model, host, ssl_port, pool_name) diff --git a/src/wok/plugins/kimchi/tests/test_mockmodel.py b/src/wok/plugins/kimchi/tests/test_mockmodel.py new file mode 100644 index 0000000..ffbf8d5 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_mockmodel.py @@ -0,0 +1,141 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import cherrypy +import json +import os +import time +import unittest + +from wok.plugins.kimchi import mockmodel +from wok.plugins.kimchi.osinfo import get_template_default + +from utils import get_free_port, patch_auth, request, run_server, wait_task + + +test_server = None +model = None +host = None +port = None +ssl_port = None +fake_iso = None + + +def setUpModule(): + global host, port, ssl_port, model, test_server, fake_iso + cherrypy.request.headers = {'Accept': 'application/json'} + model = mockmodel.MockModel('/tmp/obj-store-test') + patch_auth() + port = get_free_port('http') + ssl_port = get_free_port('https') + host = '127.0.0.1' + test_server = run_server(host, port, ssl_port, test_mode=True, + model=model) + fake_iso = '/tmp/fake.iso' + open(fake_iso, 'w').close() + + +def tearDown(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + os.unlink(fake_iso) + + +class MockModelTests(unittest.TestCase): + def setUp(self): + model.reset() + + def test_screenshot_refresh(self): + # Create a VM + req = json.dumps({'name': 'test', 'cdrom': fake_iso}) + request(host, ssl_port, '/plugins/kimchi/templates', req, 'POST') + req = json.dumps({'name': 'test-vm', 'template': '/templates/test'}) + resp = request(host, ssl_port, '/plugins/kimchi/vms', req, 'POST') + task = json.loads(resp.read()) + wait_task(model.task_lookup, task['id']) + + # Test screenshot refresh for running vm + request(host, ssl_port, '/plugins/kimchi/vms/test-vm/start', '{}', + 'POST') + resp = request(host, ssl_port, + '/plugins/kimchi/vms/test-vm/screenshot') + self.assertEquals(200, resp.status) + self.assertEquals('image/png', resp.getheader('content-type')) + resp1 = request(host, ssl_port, '/plugins/kimchi/vms/test-vm') + rspBody = resp1.read() + testvm_Data = json.loads(rspBody) + screenshotURL = testvm_Data['screenshot'] + time.sleep(5) + resp2 = request(host, ssl_port, screenshotURL) + self.assertEquals(200, resp2.status) + self.assertEquals(resp2.getheader('content-type'), + resp.getheader('content-type')) + self.assertEquals(resp2.getheader('content-length'), + resp.getheader('content-length')) + self.assertEquals(resp2.getheader('last-modified'), + resp.getheader('last-modified')) + + def test_vm_list_sorted(self): + req = json.dumps({'name': 'test', 'cdrom': fake_iso}) + request(host, ssl_port, '/plugins/kimchi/templates', req, 'POST') + + def add_vm(name): + # Create a VM + req = json.dumps({'name': name, + 'template': '/plugins/kimchi/templates/test'}) + task = json.loads(request(host, ssl_port, '/plugins/kimchi/vms', + req, 'POST').read()) + wait_task(model.task_lookup, task['id']) + + vms = [u'abc', u'bca', u'cab', u'xba'] + for vm in vms: + add_vm(vm) + + vms.append(u'test') + self.assertEqual(model.vms_get_list(), sorted(vms)) + + def test_vm_info(self): + model.templates_create({'name': u'test', + 'cdrom': fake_iso}) + task = model.vms_create({'name': u'test-vm', + 'template': '/plugins/kimchi/templates/test'}) + wait_task(model.task_lookup, task['id']) + vms = model.vms_get_list() + self.assertEquals(2, len(vms)) + self.assertIn(u'test-vm', vms) + + keys = set(('name', 'state', 'stats', 'uuid', 'memory', 'cpus', + 'screenshot', 'icon', 'graphics', 'users', 'groups', + 'access', 'persistent')) + + stats_keys = set(('cpu_utilization', + 'net_throughput', 'net_throughput_peak', + 'io_throughput', 'io_throughput_peak')) + + info = model.vm_lookup(u'test-vm') + self.assertEquals(keys, set(info.keys())) + self.assertEquals('shutoff', info['state']) + self.assertEquals('test-vm', info['name']) + self.assertEquals(get_template_default('old', 'memory'), + info['memory']) + self.assertEquals(1, info['cpus']) + self.assertEquals('images/icon-vm.png', info['icon']) + self.assertEquals(stats_keys, set(info['stats'].keys())) + self.assertEquals('vnc', info['graphics']['type']) + self.assertEquals('127.0.0.1', info['graphics']['listen']) diff --git a/src/wok/plugins/kimchi/tests/test_model.py b/src/wok/plugins/kimchi/tests/test_model.py new file mode 100644 index 0000000..7c89048 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_model.py @@ -0,0 +1,1248 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import grp +import os +import pwd +import re +import shutil +import time +import unittest +import uuid + +import wok.objectstore +from wok.basemodel import Singleton +from wok.config import config +from wok.exception import InvalidOperation +from wok.exception import InvalidParameter, NotFoundError, OperationFailed +from wok.rollbackcontext import RollbackContext +from wok.utils import add_task + +from wok.plugins.kimchi import netinfo +from wok.plugins.kimchi.osinfo import get_template_default +from wok.plugins.kimchi.model import model +from wok.plugins.kimchi.model.libvirtconnection import LibvirtConnection + +import iso_gen +import utils + + +invalid_repository_urls = ['www.fedora.org', # missing protocol + '://www.fedora.org', # missing protocol + 'http://www.fedora', # invalid domain name + 'file:///home/foobar'] # invalid path + +TMP_DIR = '/var/lib/kimchi/tests/' +UBUNTU_ISO = TMP_DIR + 'ubuntu14.04.iso' + + +def setUpModule(): + if not os.path.exists(TMP_DIR): + os.makedirs(TMP_DIR) + + iso_gen.construct_fake_iso(UBUNTU_ISO, True, '14.04', 'ubuntu') + + # Some FeatureTests functions depend on server to validate their result. + # As CapabilitiesModel is a Singleton class it will get the first result + # from FeatureTests which may be wrong when using the Model instance + # directly - the case of this test_model.py + # So clean Singleton instances to make sure to get the right result when + # running the following tests. + Singleton._instances = {} + + +def tearDownModule(): + shutil.rmtree(TMP_DIR) + + +class ModelTests(unittest.TestCase): + def setUp(self): + self.tmp_store = '/tmp/kimchi-store-test' + + def tearDown(self): + # FIXME: Tests using 'test:///default' URI should be moved to + # test_rest or test_mockmodel to avoid overriding problems + LibvirtConnection._connections['test:///default'] = {} + + os.unlink(self.tmp_store) + + def test_vm_info(self): + inst = model.Model('test:///default', self.tmp_store) + vms = inst.vms_get_list() + self.assertEquals(1, len(vms)) + self.assertEquals('test', vms[0]) + + keys = set(('name', 'state', 'stats', 'uuid', 'memory', 'cpus', + 'screenshot', 'icon', 'graphics', 'users', 'groups', + 'access', 'persistent')) + + stats_keys = set(('cpu_utilization', + 'net_throughput', 'net_throughput_peak', + 'io_throughput', 'io_throughput_peak')) + info = inst.vm_lookup('test') + self.assertEquals(keys, set(info.keys())) + self.assertEquals('running', info['state']) + self.assertEquals('test', info['name']) + self.assertEquals(2048, info['memory']) + self.assertEquals(2, info['cpus']) + self.assertEquals(None, info['icon']) + self.assertEquals(stats_keys, set(info['stats'].keys())) + self.assertRaises(NotFoundError, inst.vm_lookup, 'nosuchvm') + self.assertEquals([], info['users']) + self.assertEquals([], info['groups']) + self.assertTrue(info['persistent']) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_vm_lifecycle(self): + inst = model.Model(objstore_loc=self.tmp_store) + + with RollbackContext() as rollback: + vol_params = {'name': u'test-vol', 'capacity': 1024} + task = inst.storagevolumes_create(u'default', vol_params) + rollback.prependDefer(inst.storagevolume_delete, u'default', + vol_params['name']) + inst.task_wait(task['id']) + task = inst.task_lookup(task['id']) + self.assertEquals('finished', task['status']) + vol = inst.storagevolume_lookup(u'default', vol_params['name']) + + params = {'name': 'test', 'disks': [{'base': vol['path'], + 'size': 1}], + 'cdrom': UBUNTU_ISO} + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'test') + + params = {'name': 'kimchi-vm', + 'template': '/plugins/kimchi/templates/test'} + task = inst.vms_create(params) + rollback.prependDefer(inst.vm_delete, 'kimchi-vm') + inst.task_wait(task['id'], 10) + task = inst.task_lookup(task['id']) + self.assertEquals('finished', task['status']) + + vms = inst.vms_get_list() + self.assertTrue('kimchi-vm' in vms) + + inst.vm_start('kimchi-vm') + + info = inst.vm_lookup('kimchi-vm') + self.assertEquals('running', info['state']) + + self.assertRaises(InvalidOperation, inst.vmsnapshots_create, + u'kimchi-vm') + + inst.vm_poweroff(u'kimchi-vm') + vm = inst.vm_lookup(u'kimchi-vm') + + empty_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm') + self.assertEquals({}, empty_snap) + + # this snapshot should be deleted when its VM is deleted + params = {'name': u'mysnap'} + task = inst.vmsnapshots_create(u'kimchi-vm', params) + inst.task_wait(task['id']) + task = inst.task_lookup(task['id']) + self.assertEquals('finished', task['status']) + + self.assertRaises(NotFoundError, inst.vmsnapshot_lookup, + u'kimchi-vm', u'foobar') + + snap = inst.vmsnapshot_lookup(u'kimchi-vm', params['name']) + self.assertTrue(int(time.time()) >= int(snap['created'])) + self.assertEquals(vm['state'], snap['state']) + self.assertEquals(params['name'], snap['name']) + self.assertEquals(u'', snap['parent']) + + snaps = inst.vmsnapshots_get_list(u'kimchi-vm') + self.assertEquals([params['name']], snaps) + + current_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm') + self.assertEquals(snap, current_snap) + + task = inst.vmsnapshots_create(u'kimchi-vm') + snap_name = task['target_uri'].split('/')[-1] + rollback.prependDefer(inst.vmsnapshot_delete, + u'kimchi-vm', snap_name) + inst.task_wait(task['id']) + task = inst.task_lookup(task['id']) + self.assertEquals('finished', task['status']) + + snaps = inst.vmsnapshots_get_list(u'kimchi-vm') + self.assertEquals(sorted([params['name'], snap_name], + key=unicode.lower), snaps) + + snap = inst.vmsnapshot_lookup(u'kimchi-vm', snap_name) + current_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm') + self.assertEquals(snap, current_snap) + + # update vm name + inst.vm_update('kimchi-vm', {'name': u'kimchi-vm-new'}) + + # Look up the first created snapshot from the renamed vm + snap = inst.vmsnapshot_lookup(u'kimchi-vm-new', params['name']) + + # snapshot revert to the first created vm + result = inst.vmsnapshot_revert(u'kimchi-vm-new', params['name']) + self.assertEquals(result, [u'kimchi-vm', snap['name']]) + + vm = inst.vm_lookup(u'kimchi-vm') + self.assertEquals(vm['state'], snap['state']) + + current_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm') + self.assertEquals(params['name'], current_snap['name']) + + self.assertRaises(NotFoundError, inst.vmsnapshot_delete, + u'kimchi-vm', u'foobar') + + # suspend and resume the VM + info = inst.vm_lookup(u'kimchi-vm') + self.assertEquals(info['state'], 'shutoff') + self.assertRaises(InvalidOperation, inst.vm_suspend, u'kimchi-vm') + inst.vm_start(u'kimchi-vm') + info = inst.vm_lookup(u'kimchi-vm') + self.assertEquals(info['state'], 'running') + inst.vm_suspend(u'kimchi-vm') + info = inst.vm_lookup(u'kimchi-vm') + self.assertEquals(info['state'], 'paused') + self.assertRaises(InvalidParameter, inst.vm_update, u'kimchi-vm', + {'name': 'foo'}) + inst.vm_resume(u'kimchi-vm') + info = inst.vm_lookup(u'kimchi-vm') + self.assertEquals(info['state'], 'running') + self.assertRaises(InvalidOperation, inst.vm_resume, u'kimchi-vm') + # leave the VM suspended to make sure a paused VM can be + # deleted correctly + inst.vm_suspend(u'kimchi-vm') + + vms = inst.vms_get_list() + self.assertFalse('kimchi-vm' in vms) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_image_based_template(self): + inst = model.Model(objstore_loc=self.tmp_store) + + with RollbackContext() as rollback: + vol = 'base-vol.img' + params = {'name': vol, + 'capacity': 1073741824, # 1 GiB + 'allocation': 1048576, # 1 MiB + 'format': 'qcow2'} + task_id = inst.storagevolumes_create('default', params)['id'] + rollback.prependDefer(inst.storagevolume_delete, 'default', vol) + inst.task_wait(task_id) + self.assertEquals('finished', inst.task_lookup(task_id)['status']) + vol_path = inst.storagevolume_lookup('default', vol)['path'] + + params = {'name': 'test', 'disks': [{'base': vol_path}]} + self.assertRaises(OperationFailed, inst.templates_create, params) + + # Hack the model objstore to add a new template + # It is needed as the image file must be a bootable image when + # using model + # As it is difficult to create one on test runtime, inject a + # template with an empty image file to the objstore to test the + # feature + tmpl_name = "img-tmpl" + tmpl_info = {"cpus": 1, "cdrom": "", + "graphics": {"type": "vnc", "listen": "127.0.0.1"}, + "networks": ["default"], "memory": 1024, "folder": [], + "icon": "images/icon-vm.png", + "os_distro": "unknown", "os_version": "unknown", + "disks": [{"base": vol_path, "size": 10}], + "storagepool": "/plugins/kimchi/storagepools/default"} + + with inst.objstore as session: + session.store('template', tmpl_name, tmpl_info) + + params = {'name': 'kimchi-vm', + 'template': '/plugins/kimchi/templates/img-tmpl'} + task = inst.vms_create(params) + inst.task_wait(task['id']) + rollback.prependDefer(inst.vm_delete, 'kimchi-vm') + + vms = inst.vms_get_list() + self.assertTrue('kimchi-vm' in vms) + + inst.vm_start('kimchi-vm') + rollback.prependDefer(inst.vm_poweroff, 'kimchi-vm') + + info = inst.vm_lookup('kimchi-vm') + self.assertEquals('running', info['state']) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_vm_graphics(self): + inst = model.Model(objstore_loc=self.tmp_store) + params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO} + inst.templates_create(params) + with RollbackContext() as rollback: + params = {'name': 'kimchi-vnc', + 'template': '/plugins/kimchi/templates/test'} + task1 = inst.vms_create(params) + inst.task_wait(task1['id']) + rollback.prependDefer(inst.vm_delete, 'kimchi-vnc') + + info = inst.vm_lookup('kimchi-vnc') + self.assertEquals('vnc', info['graphics']['type']) + self.assertEquals('127.0.0.1', info['graphics']['listen']) + + graphics = {'type': 'spice', 'listen': '127.0.0.1'} + params = {'name': 'kimchi-spice', + 'template': '/plugins/kimchi/templates/test', + 'graphics': graphics} + task2 = inst.vms_create(params) + inst.task_wait(task2['id']) + rollback.prependDefer(inst.vm_delete, 'kimchi-spice') + + info = inst.vm_lookup('kimchi-spice') + self.assertEquals('spice', info['graphics']['type']) + self.assertEquals('127.0.0.1', info['graphics']['listen']) + + inst.template_delete('test') + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_vm_ifaces(self): + inst = model.Model(objstore_loc=self.tmp_store) + with RollbackContext() as rollback: + params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO} + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'test') + + # Create a network + net_name = 'test-network' + net_args = {'name': net_name, + 'connection': 'nat', + 'subnet': '127.0.100.0/24'} + inst.networks_create(net_args) + rollback.prependDefer(inst.network_delete, net_name) + inst.network_activate(net_name) + rollback.prependDefer(inst.network_deactivate, net_name) + + for vm_name in ['kimchi-ifaces', 'kimchi-ifaces-running']: + params = {'name': vm_name, + 'template': '/plugins/kimchi/templates/test'} + task = inst.vms_create(params) + inst.task_wait(task['id']) + rollback.prependDefer(inst.vm_delete, vm_name) + + ifaces = inst.vmifaces_get_list(vm_name) + self.assertEquals(1, len(ifaces)) + + iface = inst.vmiface_lookup(vm_name, ifaces[0]) + self.assertEquals(17, len(iface['mac'])) + self.assertEquals("default", iface['network']) + self.assertIn("model", iface) + + # attach network interface to vm + iface_args = {"type": "network", + "network": "test-network", + "model": "virtio"} + mac = inst.vmifaces_create(vm_name, iface_args) + # detach network interface from vm + rollback.prependDefer(inst.vmiface_delete, vm_name, mac) + self.assertEquals(17, len(mac)) + + iface = inst.vmiface_lookup(vm_name, mac) + self.assertEquals("network", iface["type"]) + self.assertEquals("test-network", iface['network']) + self.assertEquals("virtio", iface["model"]) + + # attach network interface to vm without providing model + iface_args = {"type": "network", + "network": "test-network"} + mac = inst.vmifaces_create(vm_name, iface_args) + rollback.prependDefer(inst.vmiface_delete, vm_name, mac) + + iface = inst.vmiface_lookup(vm_name, mac) + self.assertEquals("network", iface["type"]) + self.assertEquals("test-network", iface['network']) + + # update vm interface + newMacAddr = '54:50:e3:44:8a:af' + iface_args = {"mac": newMacAddr} + inst.vmiface_update(vm_name, mac, iface_args) + iface = inst.vmiface_lookup(vm_name, newMacAddr) + self.assertEquals(newMacAddr, iface['mac']) + + # undo mac address change + iface_args = {"mac": mac} + inst.vmiface_update(vm_name, newMacAddr, iface_args) + iface = inst.vmiface_lookup(vm_name, mac) + self.assertEquals(mac, iface['mac']) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_vm_disk(self): + disk_path = os.path.join(TMP_DIR, 'existent2.iso') + open(disk_path, 'w').close() + modern_disk_bus = get_template_default('modern', 'disk_bus') + + def _attach_disk(expect_bus=modern_disk_bus): + disk_args = {"type": "disk", + "pool": pool, + "vol": vol} + disk = inst.vmstorages_create(vm_name, disk_args) + storage_list = inst.vmstorages_get_list(vm_name) + self.assertEquals(prev_count + 1, len(storage_list)) + + # Check the bus type to be 'virtio' + disk_info = inst.vmstorage_lookup(vm_name, disk) + self.assertEquals(u'disk', disk_info['type']) + self.assertEquals(vol_path, disk_info['path']) + self.assertEquals(expect_bus, disk_info['bus']) + return disk + + inst = model.Model(objstore_loc=self.tmp_store) + with RollbackContext() as rollback: + path = os.path.join(TMP_DIR, 'kimchi-images') + pool = 'test-pool' + vol = 'test-volume.img' + vol_path = "%s/%s" % (path, vol) + if not os.path.exists(path): + os.mkdir(path) + rollback.prependDefer(shutil.rmtree, path) + + args = {'name': pool, + 'path': path, + 'type': 'dir'} + inst.storagepools_create(args) + rollback.prependDefer(inst.storagepool_delete, pool) + + # Activate the pool before adding any volume + inst.storagepool_activate(pool) + rollback.prependDefer(inst.storagepool_deactivate, pool) + + params = {'name': vol, + 'capacity': 1073741824, # 1 GiB + 'allocation': 536870912, # 512 MiB + 'format': 'qcow2'} + task_id = inst.storagevolumes_create(pool, params)['id'] + rollback.prependDefer(inst.storagevolume_delete, pool, vol) + inst.task_wait(task_id) + + vm_name = 'kimchi-cdrom' + params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO} + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'test') + params = {'name': vm_name, + 'template': '/plugins/kimchi/templates/test'} + task1 = inst.vms_create(params) + inst.task_wait(task1['id']) + rollback.prependDefer(inst.vm_delete, vm_name) + + prev_count = len(inst.vmstorages_get_list(vm_name)) + self.assertEquals(1, prev_count) + + # Volume format with mismatched type raise error + cdrom_args = {"type": "cdrom", "pool": pool, "vol": vol} + self.assertRaises(InvalidParameter, inst.vmstorages_create, + vm_name, cdrom_args) + + # Cold plug and unplug a disk + disk = _attach_disk() + inst.vmstorage_delete(vm_name, disk) + + # Hot plug a disk + inst.vm_start(vm_name) + disk = _attach_disk() + + # VM disk still there after powered off + inst.vm_poweroff(vm_name) + disk_info = inst.vmstorage_lookup(vm_name, disk) + self.assertEquals(u'disk', disk_info['type']) + inst.vmstorage_delete(vm_name, disk) + + # Specifying pool and path at same time will fail + disk_args = {"type": "disk", + "pool": pool, + "vol": vol, + "path": disk_path} + self.assertRaises( + InvalidParameter, inst.vmstorages_create, vm_name, disk_args) + + old_distro_iso = TMP_DIR + 'rhel4_8.iso' + iso_gen.construct_fake_iso(old_distro_iso, True, '4.8', 'rhel') + + vm_name = 'kimchi-ide-bus-vm' + params = {'name': 'old_distro_template', 'disks': [], + 'cdrom': old_distro_iso} + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'old_distro_template') + params = { + 'name': vm_name, + 'template': '/plugins/kimchi/templates/old_distro_template' + } + task2 = inst.vms_create(params) + inst.task_wait(task2['id']) + rollback.prependDefer(inst.vm_delete, vm_name) + + # Need to check the right disk_bus for old distro + disk = _attach_disk(get_template_default('old', 'disk_bus')) + inst.vmstorage_delete('kimchi-ide-bus-vm', disk) + + # Hot plug IDE bus disk does not work + inst.vm_start(vm_name) + self.assertRaises(InvalidOperation, _attach_disk) + inst.vm_poweroff(vm_name) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_vm_cdrom(self): + inst = model.Model(objstore_loc=self.tmp_store) + with RollbackContext() as rollback: + vm_name = 'kimchi-cdrom' + params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO} + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'test') + params = {'name': vm_name, + 'template': '/plugins/kimchi/templates/test'} + task = inst.vms_create(params) + inst.task_wait(task['id']) + rollback.prependDefer(inst.vm_delete, vm_name) + + prev_count = len(inst.vmstorages_get_list(vm_name)) + self.assertEquals(1, prev_count) + + # dummy .iso files + iso_path = os.path.join(TMP_DIR, 'existent.iso') + iso_path2 = os.path.join(TMP_DIR, 'existent2.iso') + open(iso_path, 'w').close() + rollback.prependDefer(os.remove, iso_path) + open(iso_path2, 'w').close() + rollback.prependDefer(os.remove, iso_path2) + wrong_iso_path = '/nonexistent.iso' + + # Create a cdrom + cdrom_args = {"type": "cdrom", + "path": iso_path} + cdrom_dev = inst.vmstorages_create(vm_name, cdrom_args) + storage_list = inst.vmstorages_get_list(vm_name) + self.assertEquals(prev_count + 1, len(storage_list)) + + # Get cdrom info + cd_info = inst.vmstorage_lookup(vm_name, cdrom_dev) + self.assertEquals(u'cdrom', cd_info['type']) + self.assertEquals(iso_path, cd_info['path']) + + # update path of existing cd with + # non existent iso + self.assertRaises(InvalidParameter, inst.vmstorage_update, + vm_name, cdrom_dev, {'path': wrong_iso_path}) + + # Make sure CD ROM still exists after failure + cd_info = inst.vmstorage_lookup(vm_name, cdrom_dev) + self.assertEquals(u'cdrom', cd_info['type']) + self.assertEquals(iso_path, cd_info['path']) + + # update path of existing cd with existent iso of shutoff vm + inst.vmstorage_update(vm_name, cdrom_dev, {'path': iso_path2}) + cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev) + self.assertEquals(iso_path2, cdrom_info['path']) + + # update path of existing cd with existent iso of running vm + inst.vm_start(vm_name) + inst.vmstorage_update(vm_name, cdrom_dev, {'path': iso_path}) + cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev) + self.assertEquals(iso_path, cdrom_info['path']) + + # eject cdrom + cdrom_dev = inst.vmstorage_update(vm_name, cdrom_dev, {'path': ''}) + cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev) + self.assertEquals('', cdrom_info['path']) + inst.vm_poweroff(vm_name) + + # removing non existent cdrom + self.assertRaises(NotFoundError, inst.vmstorage_delete, vm_name, + "fakedev") + + # removing valid cdrom + inst.vmstorage_delete(vm_name, cdrom_dev) + storage_list = inst.vmstorages_get_list(vm_name) + self.assertEquals(prev_count, len(storage_list)) + + # Create a new cdrom using a remote iso + valid_remote_iso_path = utils.get_remote_iso_path() + cdrom_args = {"type": "cdrom", + "path": valid_remote_iso_path} + cdrom_dev = inst.vmstorages_create(vm_name, cdrom_args) + storage_list = inst.vmstorages_get_list(vm_name) + self.assertEquals(prev_count + 1, len(storage_list)) + + # Update remote-backed cdrom with the same ISO + inst.vmstorage_update(vm_name, cdrom_dev, + {'path': valid_remote_iso_path}) + cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev) + cur_cdrom_path = re.sub(":80/", '/', cdrom_info['path']) + self.assertEquals(valid_remote_iso_path, cur_cdrom_path) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_vm_storage_provisioning(self): + inst = model.Model(objstore_loc=self.tmp_store) + + with RollbackContext() as rollback: + params = {'name': 'test', 'disks': [{'size': 1}], + 'cdrom': UBUNTU_ISO} + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'test') + + params = {'name': 'test-vm-1', + 'template': '/plugins/kimchi/templates/test'} + task = inst.vms_create(params) + inst.task_wait(task['id']) + rollback.prependDefer(inst.vm_delete, 'test-vm-1') + + vm_info = inst.vm_lookup(params['name']) + disk_path = '%s/%s-0.img' % ( + inst.storagepool_lookup('default')['path'], vm_info['uuid']) + self.assertTrue(os.access(disk_path, os.F_OK)) + self.assertFalse(os.access(disk_path, os.F_OK)) + + def test_vm_memory_hotplug(self): + config.set("authentication", "method", "pam") + inst = model.Model(None, objstore_loc=self.tmp_store) + orig_params = {'name': 'test', 'memory': 1024, 'cdrom': UBUNTU_ISO} + inst.templates_create(orig_params) + + with RollbackContext() as rollback: + params = {'name': 'kimchi-vm1', + 'template': '/plugins/kimchi/templates/test'} + task1 = inst.vms_create(params) + inst.task_wait(task1['id']) + rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, + 'kimchi-vm1') + # Start vm + inst.vm_start('kimchi-vm1') + rollback.prependDefer(utils.rollback_wrapper, inst.vm_poweroff, + 'kimchi-vm1') + + # Hotplug memory, only available in Libvirt >= 1.2.14 + params = {'memory': 2048} + if inst.capabilities_lookup()['mem_hotplug_support']: + inst.vm_update('kimchi-vm1', params) + rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, + 'kimchi-vm1') + self.assertEquals(params['memory'], + inst.vm_lookup('kimchi-vm1')['memory']) + else: + self.assertRaises(InvalidOperation, inst.vm_update, + 'kimchi-vm1', params) + + def test_vm_edit(self): + config.set("authentication", "method", "pam") + inst = model.Model(None, + objstore_loc=self.tmp_store) + + orig_params = {'name': 'test', 'memory': 1024, 'cpus': 1, + 'cdrom': UBUNTU_ISO} + inst.templates_create(orig_params) + + with RollbackContext() as rollback: + params_1 = {'name': 'kimchi-vm1', + 'template': '/plugins/kimchi/templates/test'} + params_2 = {'name': 'kimchi-vm2', + 'template': '/plugins/kimchi/templates/test'} + task1 = inst.vms_create(params_1) + inst.task_wait(task1['id']) + rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, + 'kimchi-vm1') + task2 = inst.vms_create(params_2) + inst.task_wait(task2['id']) + rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, + 'kimchi-vm2') + + vms = inst.vms_get_list() + self.assertTrue('kimchi-vm1' in vms) + + # make sure "vm_update" works when the domain has a snapshot + inst.vmsnapshots_create(u'kimchi-vm1') + + # update vm graphics when vm is not running + inst.vm_update(u'kimchi-vm1', + {"graphics": {"passwd": "123456"}}) + + inst.vm_start('kimchi-vm1') + rollback.prependDefer(utils.rollback_wrapper, inst.vm_poweroff, + 'kimchi-vm1') + + vm_info = inst.vm_lookup(u'kimchi-vm1') + self.assertEquals('123456', vm_info['graphics']["passwd"]) + self.assertEquals(None, vm_info['graphics']["passwdValidTo"]) + + # update vm graphics when vm is running + inst.vm_update(u'kimchi-vm1', + {"graphics": {"passwd": "abcdef", + "passwdValidTo": 20}}) + vm_info = inst.vm_lookup(u'kimchi-vm1') + self.assertEquals('abcdef', vm_info['graphics']["passwd"]) + self.assertGreaterEqual(20, vm_info['graphics']['passwdValidTo']) + + info = inst.vm_lookup('kimchi-vm1') + self.assertEquals('running', info['state']) + + params = {'name': 'new-vm'} + self.assertRaises(InvalidParameter, inst.vm_update, + 'kimchi-vm1', params) + + # change VM users and groups, when wm is running. + inst.vm_update(u'kimchi-vm1', + {'users': ['root'], 'groups': ['root']}) + vm_info = inst.vm_lookup(u'kimchi-vm1') + self.assertEquals(['root'], vm_info['users']) + self.assertEquals(['root'], vm_info['groups']) + # change VM users and groups by removing all elements, + # when wm is running. + inst.vm_update(u'kimchi-vm1', {'users': [], 'groups': []}) + vm_info = inst.vm_lookup(u'kimchi-vm1') + self.assertEquals([], vm_info['users']) + self.assertEquals([], vm_info['groups']) + + inst.vm_poweroff('kimchi-vm1') + self.assertRaises(OperationFailed, inst.vm_update, + 'kimchi-vm1', {'name': 'kimchi-vm2'}) + + params = {'name': u'��e��-�����', 'cpus': 4, 'memory': 2048} + inst.vm_update('kimchi-vm1', params) + rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, + u'��e��-�����') + self.assertEquals(info['uuid'], inst.vm_lookup(u'��e��-�����')['uuid']) + info = inst.vm_lookup(u'��e��-�����') + for key in params.keys(): + self.assertEquals(params[key], info[key]) + + # change only VM users - groups are not changed (default is empty) + users = inst.users_get_list()[:3] + inst.vm_update(u'��e��-�����', {'users': users}) + self.assertEquals(users, inst.vm_lookup(u'��e��-�����')['users']) + self.assertEquals([], inst.vm_lookup(u'��e��-�����')['groups']) + + # change only VM groups - users are not changed (default is empty) + groups = inst.groups_get_list()[:2] + inst.vm_update(u'��e��-�����', {'groups': groups}) + self.assertEquals(users, inst.vm_lookup(u'��e��-�����')['users']) + self.assertEquals(groups, inst.vm_lookup(u'��e��-�����')['groups']) + + # change VM users and groups by adding a new element to each one + users.append(pwd.getpwuid(os.getuid()).pw_name) + groups.append(grp.getgrgid(os.getgid()).gr_name) + inst.vm_update(u'��e��-�����', {'users': users, 'groups': groups}) + self.assertEquals(users, inst.vm_lookup(u'��e��-�����')['users']) + self.assertEquals(groups, inst.vm_lookup(u'��e��-�����')['groups']) + + # change VM users (wrong value) and groups + # when an error occurs, everything fails and nothing is changed + self.assertRaises(InvalidParameter, inst.vm_update, u'��e��-�����', + {'users': ['userdoesnotexist'], 'groups': []}) + self.assertEquals(users, inst.vm_lookup(u'��e��-�����')['users']) + self.assertEquals(groups, inst.vm_lookup(u'��e��-�����')['groups']) + + # change VM users and groups (wrong value) + # when an error occurs, everything fails and nothing is changed + self.assertRaises(InvalidParameter, inst.vm_update, u'��e��-�����', + {'users': [], 'groups': ['groupdoesnotexist']}) + self.assertEquals(users, inst.vm_lookup(u'��e��-�����')['users']) + self.assertEquals(groups, inst.vm_lookup(u'��e��-�����')['groups']) + + # change VM users and groups by removing all elements + inst.vm_update(u'��e��-�����', {'users': [], 'groups': []}) + self.assertEquals([], inst.vm_lookup(u'��e��-�����')['users']) + self.assertEquals([], inst.vm_lookup(u'��e��-�����')['groups']) + + def test_get_interfaces(self): + inst = model.Model('test:///default', + objstore_loc=self.tmp_store) + expected_ifaces = netinfo.all_favored_interfaces() + ifaces = inst.interfaces_get_list() + self.assertEquals(len(expected_ifaces), len(ifaces)) + for name in expected_ifaces: + iface = inst.interface_lookup(name) + self.assertEquals(iface['name'], name) + self.assertIn('type', iface) + self.assertIn('status', iface) + self.assertIn('ipaddr', iface) + self.assertIn('netmask', iface) + + def test_async_tasks(self): + class task_except(Exception): + pass + + def quick_op(cb, message): + cb(message, True) + + def long_op(cb, params): + time.sleep(params.get('delay', 3)) + cb(params.get('message', ''), params.get('result', False)) + + def abnormal_op(cb, params): + try: + raise task_except + except: + cb("Exception raised", False) + + def continuous_ops(cb, params): + cb("step 1 OK") + time.sleep(2) + cb("step 2 OK") + time.sleep(2) + cb("step 3 OK", params.get('result', True)) + + inst = model.Model('test:///default', + objstore_loc=self.tmp_store) + taskid = add_task('', quick_op, inst.objstore, 'Hello') + inst.task_wait(taskid) + self.assertEquals(1, taskid) + self.assertEquals('finished', inst.task_lookup(taskid)['status']) + self.assertEquals('Hello', inst.task_lookup(taskid)['message']) + + taskid = add_task('', long_op, inst.objstore, + {'delay': 3, 'result': False, + 'message': 'It was not meant to be'}) + self.assertEquals(2, taskid) + self.assertEquals('running', inst.task_lookup(taskid)['status']) + self.assertEquals('OK', inst.task_lookup(taskid)['message']) + inst.task_wait(taskid) + self.assertEquals('failed', inst.task_lookup(taskid)['status']) + self.assertEquals('It was not meant to be', + inst.task_lookup(taskid)['message']) + taskid = add_task('', abnormal_op, inst.objstore, {}) + inst.task_wait(taskid) + self.assertEquals('Exception raised', + inst.task_lookup(taskid)['message']) + self.assertEquals('failed', inst.task_lookup(taskid)['status']) + + taskid = add_task('', continuous_ops, inst.objstore, + {'result': True}) + self.assertEquals('running', inst.task_lookup(taskid)['status']) + inst.task_wait(taskid, timeout=10) + self.assertEquals('finished', inst.task_lookup(taskid)['status']) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_delete_running_vm(self): + inst = model.Model(objstore_loc=self.tmp_store) + + with RollbackContext() as rollback: + params = {'name': u'test', 'disks': [], 'cdrom': UBUNTU_ISO} + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'test') + + params = {'name': u'k������h��-�����', + 'template': u'/plugins/kimchi/templates/test'} + task = inst.vms_create(params) + inst.task_wait(task['id']) + rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, + u'k������h��-�����') + + inst.vm_start(u'k������h��-�����') + self.assertEquals(inst.vm_lookup(u'k������h��-�����')['state'], 'running') + rollback.prependDefer(utils.rollback_wrapper, inst.vm_poweroff, + u'k������h��-�����') + + inst.vm_delete(u'k������h��-�����') + + vms = inst.vms_get_list() + self.assertFalse(u'k������h��-�����' in vms) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_vm_list_sorted(self): + inst = model.Model(objstore_loc=self.tmp_store) + + with RollbackContext() as rollback: + params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO} + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'test') + + params = {'name': 'kimchi-vm', + 'template': '/plugins/kimchi/templates/test'} + task = inst.vms_create(params) + inst.task_wait(task['id']) + rollback.prependDefer(inst.vm_delete, 'kimchi-vm') + + vms = inst.vms_get_list() + + self.assertEquals(vms, sorted(vms, key=unicode.lower)) + + def test_vm_clone(self): + inst = model.Model('test:///default', objstore_loc=self.tmp_store) + + all_vm_names = inst.vms_get_list() + name = all_vm_names[0] + + original_vm = inst.vm_lookup(name) + if original_vm['state'] == u'shutoff': + inst.vm_start(name) + + # the VM 'test' should be running by now, so we can't clone it yet + self.assertRaises(InvalidParameter, inst.vm_clone, name) + + with RollbackContext() as rollback: + inst.vm_poweroff(name) + rollback.prependDefer(inst.vm_start, name) + + # create two simultaneous clones of the same VM + # and make sure both of them complete successfully + task1 = inst.vm_clone(name) + task2 = inst.vm_clone(name) + clone1_name = task1['target_uri'].split('/')[-2] + rollback.prependDefer(inst.vm_delete, clone1_name) + clone2_name = task2['target_uri'].split('/')[-2] + rollback.prependDefer(inst.vm_delete, clone2_name) + inst.task_wait(task1['id']) + task1 = inst.task_lookup(task1['id']) + self.assertEquals('finished', task1['status']) + inst.task_wait(task2['id']) + task2 = inst.task_lookup(task2['id']) + self.assertEquals('finished', task2['status']) + + # update the original VM info because its state has changed + original_vm = inst.vm_lookup(name) + clone_vm = inst.vm_lookup(clone1_name) + + self.assertNotEqual(original_vm['name'], clone_vm['name']) + self.assertTrue(re.match(u'%s-clone-\d+' % original_vm['name'], + clone_vm['name'])) + del original_vm['name'] + del clone_vm['name'] + + self.assertNotEqual(original_vm['uuid'], clone_vm['uuid']) + del original_vm['uuid'] + del clone_vm['uuid'] + + # compare all VM settings except the ones already compared + # (and removed) above (i.e. 'name' and 'uuid') + self.assertEquals(original_vm, clone_vm) + + def test_use_test_host(self): + inst = model.Model('test:///default', + objstore_loc=self.tmp_store) + + with RollbackContext() as rollback: + params = { + 'name': 'test', + 'disks': [], + 'cdrom': UBUNTU_ISO, + 'storagepool': '/plugins/kimchi/storagepools/default-pool', + 'domain': 'test', + 'arch': 'i686' + } + + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'test') + + params = {'name': 'kimchi-vm', + 'template': '/plugins/kimchi/templates/test'} + task = inst.vms_create(params) + inst.task_wait(task['id']) + rollback.prependDefer(inst.vm_delete, 'kimchi-vm') + + vms = inst.vms_get_list() + + self.assertTrue('kimchi-vm' in vms) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_debug_reports(self): + inst = model.Model('test:///default', + objstore_loc=self.tmp_store) + + if not inst.capabilities_lookup()['system_report_tool']: + raise unittest.SkipTest("Without debug report tool") + + try: + timeout = int(os.environ['TEST_REPORT_TIMEOUT']) + except (ValueError, KeyError): + timeout = 120 + + namePrefix = 'unitTestReport' + # sosreport always deletes unsual letters like '-' and '_' in the + # generated report file name. + uuidstr = str(uuid.uuid4()).translate(None, "-_") + reportName = namePrefix + uuidstr + try: + inst.debugreport_delete(namePrefix + '*') + except NotFoundError: + pass + with RollbackContext() as rollback: + report_list = inst.debugreports_get_list() + self.assertFalse(reportName in report_list) + try: + tmp_name = reportName + "_1" + task = inst.debugreports_create({'name': reportName}) + rollback.prependDefer(inst.debugreport_delete, tmp_name) + taskid = task['id'] + inst.task_wait(taskid, timeout) + self.assertEquals('finished', + inst.task_lookup(taskid)['status'], + "It is not necessary an error. " + "You may need to increase the " + "timeout number by " + "TEST_REPORT_TIMEOUT=200 " + "./run_tests.sh test_model") + report_list = inst.debugreports_get_list() + self.assertTrue(reportName in report_list) + name = inst.debugreport_update(reportName, {'name': tmp_name}) + self.assertEquals(name, tmp_name) + report_list = inst.debugreports_get_list() + self.assertTrue(tmp_name in report_list) + except OperationFailed, e: + if 'debugreport tool not found' not in e.message: + raise e + + def test_get_distros(self): + inst = model.Model('test:///default', + objstore_loc=self.tmp_store) + distros = inst.distros_get_list() + for d in distros: + distro = inst.distro_lookup(d) + self.assertIn('name', distro) + self.assertIn('os_distro', distro) + self.assertIn('os_version', distro) + self.assertIn('os_arch', distro) + self.assertIn('path', distro) + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_deep_scan(self): + inst = model.Model(None, + objstore_loc=self.tmp_store) + with RollbackContext() as rollback: + deep_path = os.path.join(TMP_DIR, 'deep-scan') + subdir_path = os.path.join(deep_path, 'isos') + if not os.path.exists(subdir_path): + os.makedirs(subdir_path) + ubuntu_iso = os.path.join(deep_path, 'ubuntu12.04.iso') + sles_iso = os.path.join(subdir_path, 'sles10.iso') + iso_gen.construct_fake_iso(ubuntu_iso, True, '12.04', 'ubuntu') + iso_gen.construct_fake_iso(sles_iso, True, '10', 'sles') + + args = {'name': 'kimchi-scanning-pool', + 'path': deep_path, + 'type': 'kimchi-iso'} + inst.storagepools_create(args) + rollback.prependDefer(shutil.rmtree, deep_path) + rollback.prependDefer(shutil.rmtree, args['path']) + rollback.prependDefer(inst.storagepool_deactivate, args['name']) + + time.sleep(1) + volumes = inst.storagevolumes_get_list(args['name']) + self.assertEquals(len(volumes), 2) + + def test_repository_create(self): + inst = model.Model('test:///default', + objstore_loc=self.tmp_store) + + yum_repos = [{'repo_id': 'fedora-fake', + 'baseurl': 'http://www.fedora.org'}, + {'repo_id': 'fedora-updates-fake', + 'config': + {'mirrorlist': 'http://www.fedoraproject.org'}}] + + deb_repos = [{'baseurl': 'http://archive.ubuntu.com/ubuntu/', + 'config': {'dist': 'quantal'}}, + {'baseurl': 'http://archive.ubuntu.com/ubuntu/', + 'config': {'dist': 'quantal', 'comps': ['main']}}] + + yum_invalid_repos = [] + deb_invalid_repos = [] + + for url in invalid_repository_urls: + wrong_baseurl = {'repo_id': 'wrong-id', 'baseurl': url} + wrong_mirrorlist = {'repo_id': 'wrong-id', + 'baseurl': 'www.example.com', + 'config': {'mirrorlist': url}} + wrong_config_item = { + 'repo_id': 'wrong-id', + 'baseurl': 'www.example.com', + 'config': { + 'gpgkey': 'file:///tmp/KEY-fedora-updates-fake-19'}} + + yum_invalid_repos.append(wrong_baseurl) + yum_invalid_repos.append(wrong_mirrorlist) + yum_invalid_repos.append(wrong_config_item) + + wrong_baseurl['config'] = {'dist': 'tasty'} + wrong_config = {'baseurl': deb_repos[0]['baseurl'], + 'config': { + 'unsupported_item': "a_unsupported_item"}} + deb_invalid_repos.append(wrong_baseurl) + deb_invalid_repos.append(wrong_config) + + repo_type = inst.capabilities_lookup()['repo_mngt_tool'] + if repo_type == 'yum': + test_repos = yum_repos + invalid_repos = yum_invalid_repos + elif repo_type == 'deb': + test_repos = deb_repos + invalid_repos = deb_invalid_repos + else: + # repository management tool was not recognized by Kimchi + # skip test case + return + + # create repositories with invalid data + for repo in invalid_repos: + self.assertRaises(InvalidParameter, inst.repositories_create, repo) + + for repo in test_repos: + system_host_repos = len(inst.repositories_get_list()) + repo_id = inst.repositories_create(repo) + host_repos = inst.repositories_get_list() + self.assertEquals(system_host_repos + 1, len(host_repos)) + + repo_info = inst.repository_lookup(repo_id) + self.assertEquals(repo_id, repo_info['repo_id']) + self.assertEquals(True, repo_info.get('enabled')) + self.assertEquals(repo.get('baseurl', ''), + repo_info.get('baseurl')) + + original_config = repo.get('config', {}) + config_info = repo_info.get('config', {}) + + if repo_type == 'yum': + self.assertEquals(original_config.get('mirrorlist', ''), + config_info.get('mirrorlist', '')) + self.assertEquals(True, config_info['gpgcheck']) + else: + self.assertEquals(original_config['dist'], config_info['dist']) + self.assertEquals(original_config.get('comps', []), + config_info.get('comps', [])) + + inst.repository_delete(repo_id) + self.assertRaises(NotFoundError, inst.repository_lookup, repo_id) + + self.assertRaises(NotFoundError, inst.repository_lookup, 'google') + + def test_repository_update(self): + inst = model.Model('test:///default', + objstore_loc=self.tmp_store) + + yum_repo = {'repo_id': 'fedora-fake', + 'baseurl': 'http://www.fedora.org'} + yum_new_repo = {'baseurl': 'http://www.fedoraproject.org'} + + deb_repo = {'baseurl': 'http://archive.ubuntu.com/ubuntu/', + 'config': {'dist': 'quantal'}} + deb_new_repo = {'baseurl': 'http://br.archive.canonical.com/ubuntu/', + 'config': {'dist': 'utopic'}} + + yum_invalid_repos = [] + deb_invalid_repos = [] + + for url in invalid_repository_urls: + wrong_baseurl = {'baseurl': url} + wrong_mirrorlist = {'baseurl': 'www.example.com', + 'config': {'mirrorlist': url}} + + yum_invalid_repos.append(wrong_baseurl) + yum_invalid_repos.append(wrong_mirrorlist) + + wrong_baseurl['config'] = {'dist': 'tasty'} + deb_invalid_repos.append(wrong_baseurl) + + repo_type = inst.capabilities_lookup()['repo_mngt_tool'] + if repo_type == 'yum': + repo = yum_repo + new_repo = yum_new_repo + invalid_repos = yum_invalid_repos + elif repo_type == 'deb': + repo = deb_repo + new_repo = deb_new_repo + invalid_repos = deb_invalid_repos + else: + # repository management tool was not recognized by Kimchi + # skip test case + return + + system_host_repos = len(inst.repositories_get_list()) + + with RollbackContext() as rollback: + repo_id = inst.repositories_create(repo) + rollback.prependDefer(inst.repository_delete, repo_id) + + host_repos = inst.repositories_get_list() + self.assertEquals(system_host_repos + 1, len(host_repos)) + + # update repositories with invalid data + for tmp_repo in invalid_repos: + self.assertRaises(InvalidParameter, inst.repository_update, + repo_id, tmp_repo) + + new_repo_id = inst.repository_update(repo_id, new_repo) + repo_info = inst.repository_lookup(new_repo_id) + + self.assertEquals(new_repo_id, repo_info['repo_id']) + self.assertEquals(new_repo['baseurl'], repo_info['baseurl']) + self.assertEquals(True, repo_info['enabled']) + inst.repository_update(new_repo_id, repo) + + def test_repository_disable_enable(self): + inst = model.Model('test:///default', + objstore_loc=self.tmp_store) + + yum_repo = {'repo_id': 'fedora-fake', + 'baseurl': 'http://www.fedora.org'} + deb_repo = {'baseurl': 'http://archive.ubuntu.com/ubuntu/', + 'config': {'dist': 'quantal'}} + + repo_type = inst.capabilities_lookup()['repo_mngt_tool'] + if repo_type == 'yum': + repo = yum_repo + elif repo_type == 'deb': + repo = deb_repo + else: + # repository management tool was not recognized by Kimchi + # skip test case + return + + system_host_repos = len(inst.repositories_get_list()) + + repo_id = inst.repositories_create(repo) + + host_repos = inst.repositories_get_list() + self.assertEquals(system_host_repos + 1, len(host_repos)) + + repo_info = inst.repository_lookup(repo_id) + self.assertEquals(True, repo_info['enabled']) + + inst.repository_disable(repo_id) + repo_info = inst.repository_lookup(repo_id) + self.assertEquals(False, repo_info['enabled']) + + inst.repository_enable(repo_id) + repo_info = inst.repository_lookup(repo_id) + self.assertEquals(True, repo_info['enabled']) + + # remove files creates + inst.repository_delete(repo_id) + + +class BaseModelTests(unittest.TestCase): + class FoosModel(object): + def __init__(self): + self.data = {} + + def create(self, params): + self.data.update(params) + + def get_list(self): + return list(self.data) + + class TestModel(wok.basemodel.BaseModel): + def __init__(self): + foo = BaseModelTests.FoosModel() + super(BaseModelTests.TestModel, self).__init__([foo]) + + def test_root_model(self): + t = BaseModelTests.TestModel() + t.foos_create({'item1': 10}) + self.assertEquals(t.foos_get_list(), ['item1']) diff --git a/src/wok/plugins/kimchi/tests/test_model_network.py b/src/wok/plugins/kimchi/tests/test_model_network.py new file mode 100644 index 0000000..e4cf5ef --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_model_network.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import unittest +from functools import partial + +from wok.rollbackcontext import RollbackContext + +from wok.plugins.kimchi.model.model import Model + +from utils import get_free_port, patch_auth, request, rollback_wrapper +from utils import run_server + + +model = None +test_server = None +host = None +port = None +ssl_port = None +cherrypy_port = None + + +def setUpModule(): + global test_server, model, host, port, ssl_port, cherrypy_port + + patch_auth() + model = Model(None, '/tmp/obj-store-test') + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + cherrypy_port = get_free_port('cherrypy_port') + test_server = run_server(host, port, ssl_port, test_mode=True, + cherrypy_port=cherrypy_port, model=model) + + +def tearDownModule(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + + +def _do_network_test(self, model, params): + with RollbackContext() as rollback: + net_name = params['name'] + uri = '/plugins/kimchi/networks/%s' % net_name.encode('utf-8') + + # Create a network + req = json.dumps(params) + resp = self.request('/plugins/kimchi/networks', req, 'POST') + rollback.prependDefer(rollback_wrapper, model.network_delete, + net_name) + self.assertEquals(201, resp.status) + + # Verify the network + resp = self.request(uri) + network = json.loads(resp.read()) + self.assertEquals('inactive', network['state']) + self.assertTrue(network['persistent']) + + # activate the network + resp = self.request(uri + '/activate', '{}', 'POST') + rollback.prependDefer(rollback_wrapper, + model.network_deactivate, net_name) + self.assertEquals(200, resp.status) + resp = self.request(uri) + network = json.loads(resp.read()) + self.assertEquals('active', network['state']) + + # Deactivate the network + resp = self.request(uri + '/deactivate', '{}', 'POST') + self.assertEquals(200, resp.status) + resp = self.request(uri) + network = json.loads(resp.read()) + self.assertEquals('inactive', network['state']) + + # Delete the network + resp = self.request(uri, '{}', 'DELETE') + self.assertEquals(204, resp.status) + + +class NetworkTests(unittest.TestCase): + def setUp(self): + self.request = partial(request, host, ssl_port) + + def test_get_networks(self): + networks = json.loads(self.request('/plugins/kimchi/networks').read()) + self.assertIn('default', [net['name'] for net in networks]) + + with RollbackContext() as rollback: + # Now add a couple of Networks to the mock model + for i in xrange(5): + name = 'network-%i' % i + req = json.dumps({'name': name, + 'connection': 'nat', + 'subnet': '127.0.10%i.0/24' % i}) + + resp = self.request('/plugins/kimchi/networks', req, 'POST') + rollback.prependDefer(model.network_delete, name) + self.assertEquals(201, resp.status) + network = json.loads(resp.read()) + self.assertEquals([], network["vms"]) + + nets = json.loads(self.request('/plugins/kimchi/networks').read()) + self.assertEquals(len(networks) + 5, len(nets)) + + network = json.loads( + self.request('/plugins/kimchi/networks/network-1').read() + ) + keys = [u'name', u'connection', u'interface', u'subnet', u'dhcp', + u'vms', u'in_use', u'autostart', u'state', u'persistent'] + self.assertEquals(sorted(keys), sorted(network.keys())) + + def test_network_lifecycle(self): + # Verify all the supported network type + networks = [{'name': u'k������h��-��et', 'connection': 'isolated'}, + {'name': u'nat-network', 'connection': 'nat'}, + {'name': u'subnet-network', 'connection': 'nat', + 'subnet': '127.0.100.0/24'}] + + # Verify the current system has at least one interface to create a + # bridged network + interfaces = json.loads( + self.request('/plugins/kimchi/interfaces?type=nic').read() + ) + if len(interfaces) > 0: + iface = interfaces[0]['name'] + networks.append({'name': u'bridge-network', 'connection': 'bridge', + 'interface': iface}) + + for net in networks: + _do_network_test(self, model, net) diff --git a/src/wok/plugins/kimchi/tests/test_model_storagepool.py b/src/wok/plugins/kimchi/tests/test_model_storagepool.py new file mode 100644 index 0000000..5f9b966 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_model_storagepool.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import tempfile +import unittest +from functools import partial + +from wok.rollbackcontext import RollbackContext + +from wok.plugins.kimchi.model.model import Model + +from utils import get_free_port, patch_auth, request +from utils import run_server + + +model = None +test_server = None +host = None +port = None +ssl_port = None +cherrypy_port = None + + +def setUpModule(): + global test_server, model, host, port, ssl_port, cherrypy_port + + patch_auth() + model = Model(None, '/tmp/obj-store-test') + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + cherrypy_port = get_free_port('cherrypy_port') + test_server = run_server(host, port, ssl_port, test_mode=True, + cherrypy_port=cherrypy_port, model=model) + + +def tearDownModule(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + + +class StoragepoolTests(unittest.TestCase): + def setUp(self): + self.request = partial(request, host, ssl_port) + + def test_get_storagepools(self): + storagepools = json.loads( + self.request('/plugins/kimchi/storagepools').read() + ) + self.assertIn('default', [pool['name'] for pool in storagepools]) + + with RollbackContext() as rollback: + # Now add a couple of storage pools + for i in xrange(3): + name = u'k������h��-storagepool-%i' % i + req = json.dumps({'name': name, 'type': 'dir', + 'path': '/var/lib/libvirt/images/%i' % i}) + resp = self.request('/plugins/kimchi/storagepools', req, + 'POST') + rollback.prependDefer(model.storagepool_delete, name) + + self.assertEquals(201, resp.status) + + # Pool name must be unique + req = json.dumps({'name': name, 'type': 'dir', + 'path': '/var/lib/libvirt/images/%i' % i}) + resp = self.request('/plugins/kimchi/storagepools', req, + 'POST') + self.assertEquals(400, resp.status) + + # Verify pool information + resp = self.request('/plugins/kimchi/storagepools/%s' % + name.encode("utf-8")) + p = json.loads(resp.read()) + keys = [u'name', u'state', u'capacity', u'allocated', + u'available', u'path', u'source', u'type', + u'nr_volumes', u'autostart', u'persistent'] + self.assertEquals(sorted(keys), sorted(p.keys())) + self.assertEquals(name, p['name']) + self.assertEquals('inactive', p['state']) + self.assertEquals(True, p['persistent']) + self.assertEquals(True, p['autostart']) + self.assertEquals(0, p['nr_volumes']) + + pools = json.loads( + self.request('/plugins/kimchi/storagepools').read() + ) + self.assertEquals(len(storagepools) + 3, len(pools)) + + # Create a pool with an existing path + tmp_path = tempfile.mkdtemp(dir='/var/lib/kimchi') + rollback.prependDefer(os.rmdir, tmp_path) + req = json.dumps({'name': 'existing_path', 'type': 'dir', + 'path': tmp_path}) + resp = self.request('/plugins/kimchi/storagepools', req, 'POST') + rollback.prependDefer(model.storagepool_delete, 'existing_path') + self.assertEquals(201, resp.status) + + # Reserved pool return 400 + req = json.dumps({'name': 'kimchi_isos', 'type': 'dir', + 'path': '/var/lib/libvirt/images/%i' % i}) + resp = request(host, ssl_port, '/plugins/kimchi/storagepools', req, + 'POST') + self.assertEquals(400, resp.status) diff --git a/src/wok/plugins/kimchi/tests/test_model_storagevolume.py b/src/wok/plugins/kimchi/tests/test_model_storagevolume.py new file mode 100644 index 0000000..46c07bd --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_model_storagevolume.py @@ -0,0 +1,280 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import requests +import unittest +from functools import partial + +from wok.config import paths +from wok.rollbackcontext import RollbackContext + +from wok.plugins.kimchi.config import READONLY_POOL_TYPE +from wok.plugins.kimchi.mockmodel import MockModel +from wok.plugins.kimchi.model.model import Model + +from utils import fake_auth_header, get_free_port, patch_auth, request +from utils import rollback_wrapper, run_server, wait_task + + +model = None +test_server = None +host = None +port = None +ssl_port = None +cherrypy_port = None + + +def setUpModule(): + global test_server, model, host, port, ssl_port, cherrypy_port + + patch_auth() + model = Model(None, '/tmp/obj-store-test') + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + cherrypy_port = get_free_port('cherrypy_port') + test_server = run_server(host, port, ssl_port, test_mode=True, + cherrypy_port=cherrypy_port, model=model) + + +def tearDownModule(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + + +def _do_volume_test(self, model, host, ssl_port, pool_name): + def _task_lookup(taskid): + return json.loads( + self.request('/tasks/%s' % taskid).read() + ) + + uri = '/plugins/kimchi/storagepools/%s/storagevolumes' \ + % pool_name.encode('utf-8') + resp = self.request(uri) + self.assertEquals(200, resp.status) + + resp = self.request('/plugins/kimchi/storagepools/%s' % + pool_name.encode('utf-8')) + pool_info = json.loads(resp.read()) + with RollbackContext() as rollback: + # Create storage volume with 'capacity' + vol = 'test-volume' + vol_uri = uri + '/' + vol + req = json.dumps({'name': vol, 'format': 'raw', + 'capacity': 1073741824}) # 1 GiB + resp = self.request(uri, req, 'POST') + if pool_info['type'] in READONLY_POOL_TYPE: + self.assertEquals(400, resp.status) + else: + rollback.prependDefer(rollback_wrapper, model.storagevolume_delete, + pool_name, vol) + self.assertEquals(202, resp.status) + task_id = json.loads(resp.read())['id'] + wait_task(_task_lookup, task_id) + status = json.loads( + self.request('/tasks/%s' % task_id).read() + ) + self.assertEquals('finished', status['status']) + vol_info = json.loads(self.request(vol_uri).read()) + vol_info['name'] = vol + vol_info['format'] = 'raw' + vol_info['capacity'] = 1073741824 + + # Resize the storage volume: increase its capacity to 2 GiB + req = json.dumps({'size': 2147483648}) # 2 GiB + resp = self.request(vol_uri + '/resize', req, 'POST') + self.assertEquals(200, resp.status) + storagevolume = json.loads(self.request(vol_uri).read()) + self.assertEquals(2147483648, storagevolume['capacity']) + + # Resize the storage volume: decrease its capacity to 512 MiB + # FIXME: Due a libvirt bug it is not possible to decrease the + # volume capacity + # For reference: + # - https://bugzilla.redhat.com/show_bug.cgi?id=1021802 + req = json.dumps({'size': 536870912}) # 512 MiB + resp = self.request(vol_uri + '/resize', req, 'POST') + # It is only possible when using MockModel + if isinstance(model, MockModel): + self.assertEquals(200, resp.status) + storagevolume = json.loads(self.request(vol_uri).read()) + self.assertEquals(536870912, storagevolume['capacity']) + else: + self.assertEquals(500, resp.status) + + # Wipe the storage volume + resp = self.request(vol_uri + '/wipe', '{}', 'POST') + self.assertEquals(200, resp.status) + storagevolume = json.loads(self.request(vol_uri).read()) + self.assertEquals(0, storagevolume['allocation']) + + # Clone the storage volume + vol_info = json.loads(self.request(vol_uri).read()) + resp = self.request(vol_uri + '/clone', '{}', 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + cloned_vol_name = task['target_uri'].split('/')[-1] + rollback.prependDefer(model.storagevolume_delete, pool_name, + cloned_vol_name) + wait_task(_task_lookup, task['id']) + task = json.loads( + self.request('/tasks/%s' % task['id']).read() + ) + self.assertEquals('finished', task['status']) + resp = self.request(uri + '/' + cloned_vol_name.encode('utf-8')) + + self.assertEquals(200, resp.status) + cloned_vol = json.loads(resp.read()) + + self.assertNotEquals(vol_info['name'], cloned_vol['name']) + self.assertNotEquals(vol_info['path'], cloned_vol['path']) + for key in ['name', 'path', 'allocation']: + del vol_info[key] + del cloned_vol[key] + + self.assertEquals(vol_info, cloned_vol) + + # Delete the storage volume + resp = self.request(vol_uri, '{}', 'DELETE') + self.assertEquals(204, resp.status) + resp = self.request(vol_uri) + self.assertEquals(404, resp.status) + + # Storage volume upload + # It is done through a sequence of POST and several PUT requests + filename = 'COPYING.LGPL' + filepath = os.path.join(paths.get_prefix(), filename) + filesize = os.stat(filepath).st_size + + # Create storage volume for upload + req = json.dumps({'name': filename, 'format': 'raw', + 'capacity': filesize, 'upload': True}) + resp = self.request(uri, req, 'POST') + if pool_info['type'] in READONLY_POOL_TYPE: + self.assertEquals(400, resp.status) + else: + rollback.prependDefer(rollback_wrapper, model.storagevolume_delete, + pool_name, filename) + self.assertEquals(202, resp.status) + task_id = json.loads(resp.read())['id'] + wait_task(_task_lookup, task_id) + status = json.loads(self.request('/tasks/%s' % + task_id).read()) + self.assertEquals('ready for upload', status['message']) + + # Upload volume content + url = 'https://%s:%s' % (host, ssl_port) + uri + '/' + filename + + # Create a file with 5M to upload + # Max body size is set to 4M so the upload will fail with 413 + newfile = '/tmp/5m-file' + with open(newfile, 'wb') as fd: + fd.seek(5*1024*1024-1) + fd.write("\0") + rollback.prependDefer(os.remove, newfile) + + with open(newfile, 'rb') as fd: + with open(newfile + '.tmp', 'wb') as tmp_fd: + data = fd.read() + tmp_fd.write(data) + + with open(newfile + '.tmp', 'rb') as tmp_fd: + r = requests.put(url, data={'chunk_size': len(data)}, + files={'chunk': tmp_fd}, + verify=False, + headers=fake_auth_header()) + self.assertEquals(r.status_code, 413) + + # Do upload + index = 0 + chunk_size = 2 * 1024 + content = '' + + with open(filepath, 'rb') as fd: + while True: + with open(filepath + '.tmp', 'wb') as tmp_fd: + fd.seek(index*chunk_size) + data = fd.read(chunk_size) + tmp_fd.write(data) + + with open(filepath + '.tmp', 'rb') as tmp_fd: + r = requests.put(url, data={'chunk_size': len(data)}, + files={'chunk': tmp_fd}, + verify=False, + headers=fake_auth_header()) + self.assertEquals(r.status_code, 200) + content += data + index = index + 1 + + if len(data) < chunk_size: + break + + rollback.prependDefer(os.remove, filepath + '.tmp') + resp = self.request(uri + '/' + filename) + self.assertEquals(200, resp.status) + uploaded_path = json.loads(resp.read())['path'] + with open(uploaded_path) as fd: + uploaded_content = fd.read() + + self.assertEquals(content, uploaded_content) + + # Create storage volume with 'url' + url = 'https://github.com/kimchi-project/kimchi/raw/master/COPYING' + req = json.dumps({'url': url}) + resp = self.request(uri, req, 'POST') + + if pool_info['type'] in READONLY_POOL_TYPE: + self.assertEquals(400, resp.status) + else: + rollback.prependDefer(model.storagevolume_delete, pool_name, + 'COPYING') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(_task_lookup, task['id']) + resp = self.request(uri + '/COPYING') + self.assertEquals(200, resp.status) + + +class StorageVolumeTests(unittest.TestCase): + def setUp(self): + self.request = partial(request, host, ssl_port) + + def test_get_storagevolume(self): + uri = '/plugins/kimchi/storagepools/default/storagevolumes' + resp = self.request(uri) + self.assertEquals(200, resp.status) + + keys = [u'name', u'type', u'capacity', u'allocation', u'path', + u'used_by', u'format'] + for vol in json.loads(resp.read()): + resp = self.request(uri + '/' + vol['name']) + self.assertEquals(200, resp.status) + + all_keys = keys[:] + vol_info = json.loads(resp.read()) + if vol_info['format'] == 'iso': + all_keys.extend([u'os_distro', u'os_version', u'bootable']) + + self.assertEquals(sorted(all_keys), sorted(vol_info.keys())) + + def test_storagevolume_action(self): + _do_volume_test(self, model, host, ssl_port, 'default') diff --git a/src/wok/plugins/kimchi/tests/test_networkxml.py b/src/wok/plugins/kimchi/tests/test_networkxml.py new file mode 100644 index 0000000..a64b6c2 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_networkxml.py @@ -0,0 +1,172 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import ipaddr +import lxml.etree as ET +import unittest + +from wok.xmlutils.utils import xpath_get_text + +from wok.plugins.kimchi.xmlutils import network as nxml + +import utils + + +class NetworkXmlTests(unittest.TestCase): + def test_dhcp_xml(self): + """ + Test network dhcp xml + """ + dhcp_range = {"start": "192.168.122.100", "end": "192.168.122.254"} + host1 = {"mac": "00:16:3e:77:e2:ed", + "name": "foo.example.com", + "ip": "192.168.122.10"} + host2 = {"mac": "00:16:3e:3e:a9:1a", + "name": "bar.example.com", + "ip": "192.168.122.11"} + params = {} + + dhcp = nxml._get_dhcp_elem(**params) + self.assertEquals(None, dhcp) + + params["range"] = dhcp_range + xml = ET.tostring(nxml._get_dhcp_elem(**params)) + start = xpath_get_text(xml, "/dhcp/range/@start") + end = xpath_get_text(xml, "/dhcp/range/@end") + self.assertEquals(dhcp_range['start'], start[0]) + self.assertEquals(dhcp_range['end'], end[0]) + + params["hosts"] = [host1, host2] + xml = ET.tostring(nxml._get_dhcp_elem(**params)) + ip = xpath_get_text(xml, "/dhcp/host/@ip") + self.assertEquals(ip, [host1['ip'], host2['ip']]) + + def test_ip_xml(self): + """ + Test network ip xml + """ + dhcp_range = {"start": "192.168.122.100", "end": "192.168.122.254"} + params = {} + + dhcp = nxml._get_dhcp_elem(**params) + self.assertEquals(None, dhcp) + + params["net"] = "192.168.122.0/255.255.255.0" + params["dhcp"] = {'range': dhcp_range} + xml = ET.tostring(nxml._get_ip_elem(**params)) + start = xpath_get_text(xml, "/ip/dhcp/range/@start")[0] + end = xpath_get_text(xml, "/ip/dhcp/range/@end")[0] + self.assertEquals(dhcp_range['start'], start) + self.assertEquals(dhcp_range['end'], end) + + address = xpath_get_text(xml, "/ip/@address")[0] + netmask = xpath_get_text(xml, "/ip/@netmask")[0] + self.assertEquals(address, params["net"].split("/")[0]) + self.assertEquals(netmask, params["net"].split("/")[1]) + + # test _get_ip_xml can accepts strings: '192.168.122.0/24', + # which is same as "192.168.122.0/255.255.255.0" + params["net"] = "192.168.122.0/24" + xml = ET.tostring(nxml._get_ip_elem(**params)) + netmask = xpath_get_text(xml, "/ip/@netmask")[0] + self.assertEquals(netmask, + str(ipaddr.IPNetwork(params["net"]).netmask)) + + def test_forward_xml(self): + """ + Test network forward xml + """ + params = {"mode": None} + + forward = nxml._get_forward_elem(**params) + self.assertEquals(None, forward) + + params["mode"] = 'nat' + params["dev"] = 'eth0' + xml = ET.tostring(nxml._get_forward_elem(**params)) + mode = xpath_get_text(xml, "/forward/@mode")[0] + dev = xpath_get_text(xml, "/forward/@dev")[0] + self.assertEquals(params['mode'], mode) + self.assertEquals(params['dev'], dev) + + def test_network_xml(self): + """ + Test network xml + """ + params = {"name": "test", + "forward": {"mode": "nat", "dev": ""}, + "net": "192.168.0.0/255.255.255.0"} + xml = nxml.to_network_xml(**params) + name = xpath_get_text(xml, "/network/name")[0] + self.assertEquals(name, params['name']) + + forward_mode = xpath_get_text(xml, "/network/forward/@mode")[0] + self.assertEquals(forward_mode, params['forward']['mode']) + forward_dev = xpath_get_text(xml, "/network/forward/@dev")[0] + self.assertEquals(forward_dev, '') + + address = xpath_get_text(xml, "/network/ip/@address")[0] + self.assertEquals(address, params["net"].split("/")[0]) + netmask = xpath_get_text(xml, "/network/ip/@netmask")[0] + self.assertEquals(netmask, params["net"].split("/")[1]) + + dhcp_start = xpath_get_text(xml, "/network/ip/dhcp/range/@start") + self.assertEquals(dhcp_start, []) + dhcp_end = xpath_get_text(xml, "/network/ip/dhcp/range/@end") + self.assertEquals(dhcp_end, []) + + # test optional params + params['forward']['dev'] = "eth0" + params['dhcp'] = {"range": {'start': '192.168.0.1', + 'end': '192.168.0.254'}} + xml = nxml.to_network_xml(**params) + forward_dev = xpath_get_text(xml, "/network/forward/@dev")[0] + self.assertEquals(forward_dev, params['forward']['dev']) + + dhcp_start = xpath_get_text(xml, "/network/ip/dhcp/range/@start")[0] + self.assertEquals(dhcp_start, params['dhcp']['range']['start']) + dhcp_end = xpath_get_text(xml, "/network/ip/dhcp/range/@end")[0] + self.assertEquals(dhcp_end, params['dhcp']['range']['end']) + + # test _get_ip_xml can accepts strings: '192.168.122.0/24', + # which is same as "192.168.122.0/255.255.255.0" + params["net"] = "192.168.0.0/24" + xml = nxml.to_network_xml(**params) + netmask = xpath_get_text(xml, "/network/ip/@netmask")[0] + self.assertEquals(netmask, + str(ipaddr.IPNetwork(params["net"]).netmask)) + + +class InterfaceXmlTests(unittest.TestCase): + + def test_vlan_tagged_bridge_no_ip(self): + expected_xml = """ + <interface type='bridge' name='br10'> + <start mode='onboot'/> + <bridge> + <interface type='vlan' name='em1.10'> + <vlan tag='10'> + <interface name='em1'/> + </vlan> + </interface> + </bridge> + </interface> + """ + actual_xml = nxml.create_vlan_tagged_bridge_xml('br10', 'em1', '10') + self.assertEquals(actual_xml, utils.normalize_xml(expected_xml)) diff --git a/src/wok/plugins/kimchi/tests/test_objectstore.py b/src/wok/plugins/kimchi/tests/test_objectstore.py new file mode 100644 index 0000000..632786f --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_objectstore.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import tempfile +import threading +import unittest + +from wok import objectstore +from wok.exception import NotFoundError + + +tmpfile = None + + +def setUpModule(): + global tmpfile + tmpfile = tempfile.mktemp() + + +def tearDownModule(): + os.unlink(tmpfile) + + +class ObjectStoreTests(unittest.TestCase): + def test_objectstore(self): + store = objectstore.ObjectStore(tmpfile) + + with store as session: + # Test create + session.store('f����', 't��st1', {'��': 1}) + session.store('f����', 't��st2', {'��': 2}) + + # Test list + items = session.get_list('f����') + self.assertTrue(u't��st1' in items) + self.assertTrue(u't��st2' in items) + + # Test get + item = session.get('f����', 't��st1') + self.assertEquals(1, item[u'��']) + + # Test delete + session.delete('f����', 't��st2') + self.assertEquals(1, len(session.get_list('f����'))) + + # Test get non-existent item + + self.assertRaises(NotFoundError, session.get, + '��', '��') + + # Test delete non-existent item + self.assertRaises(NotFoundError, session.delete, + 'f����', 't��st2') + + # Test refresh existing item + session.store('f����', 't��st1', {'��': 2}) + item = session.get('f����', 't��st1') + self.assertEquals(2, item[u'��']) + + def test_object_store_threaded(self): + def worker(ident): + with store as session: + session.store('foo', ident, {}) + + store = objectstore.ObjectStore(tmpfile) + + threads = [] + for i in xrange(50): + t = threading.Thread(target=worker, args=(i,)) + t.setDaemon(True) + t.start() + threads.append(t) + + for t in threads: + t.join() + + with store as session: + self.assertEquals(50, len(session.get_list('foo'))) + self.assertEquals(10, len(store._connections.keys())) diff --git a/src/wok/plugins/kimchi/tests/test_osinfo.py b/src/wok/plugins/kimchi/tests/test_osinfo.py new file mode 100644 index 0000000..bd2af58 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_osinfo.py @@ -0,0 +1,69 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import unittest + +from wok.plugins.kimchi.osinfo import _get_arch, get_template_default, lookup +from wok.plugins.kimchi.osinfo import modern_version_bases + + +class OSInfoTests(unittest.TestCase): + def test_default_lookup(self): + entry = lookup(None, None) + self.assertEquals('unknown', entry['os_distro']) + self.assertEquals('unknown', entry['os_version']) + self.assertEquals(['default'], entry['networks']) + + def test_old_distros(self): + old_versions = {'debian': '5.0', 'ubuntu': '7.04', 'opensuse': '10.1', + 'centos': '5.1', 'rhel': '5.1', 'fedora': '15'} + for distro, version in old_versions.iteritems(): + entry = lookup(distro, version) + self.assertEquals(entry['disk_bus'], + get_template_default('old', 'disk_bus')) + self.assertEquals(entry['nic_model'], + get_template_default('old', 'nic_model')) + + def test_modern_bases(self): + for distro, version in modern_version_bases[_get_arch()].iteritems(): + entry = lookup(distro, version) + self.assertEquals(entry['disk_bus'], + get_template_default('modern', 'disk_bus')) + self.assertEquals(entry['nic_model'], + get_template_default('modern', 'nic_model')) + + def test_modern_distros(self): + # versions based on ppc64 modern distros + modern_versions = {'ubuntu': '14.04', 'opensuse': '13.1', + 'rhel': '6.5', 'fedora': '19', 'sles': '11sp3'} + for distro, version in modern_versions.iteritems(): + entry = lookup(distro, version) + self.assertEquals(entry['disk_bus'], + get_template_default('modern', 'disk_bus')) + self.assertEquals(entry['nic_model'], + get_template_default('modern', 'nic_model')) + + def test_lookup_unknown_distro_version_returns_old_distro(self): + distro = 'unknown_distro' + version = 'unknown_version' + entry = lookup(distro, version) + self.assertEquals(entry['disk_bus'], + get_template_default('old', 'disk_bus')) + self.assertEquals(entry['nic_model'], + get_template_default('old', 'nic_model')) diff --git a/src/wok/plugins/kimchi/tests/test_plugin.py b/src/wok/plugins/kimchi/tests/test_plugin.py new file mode 100644 index 0000000..fc8e277 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_plugin.py @@ -0,0 +1,126 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import unittest +from functools import partial + +from wok.utils import get_enabled_plugins + +from wok.plugins.kimchi import mockmodel + +import utils + + +test_server = None +model = None +host = None +port = None +ssl_port = None + + +def setUpModule(): + global test_server, model, host, port, ssl_port + + utils.patch_auth() + model = mockmodel.MockModel('/tmp/obj-store-test') + host = '127.0.0.1' + port = utils.get_free_port('http') + ssl_port = utils.get_free_port('https') + test_server = utils.run_server(host, port, ssl_port, test_mode=True, + model=model) + + +def tearDownModule(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + + +@unittest.skipUnless( + 'sample' in [plugin for plugin, _config in get_enabled_plugins()], + 'sample plugin is not enabled, skip this test!') +class PluginTests(unittest.TestCase): + + def setUp(self): + self.request = partial(utils.request, host, ssl_port) + + def _create_rectangle(self, name, length, width): + req = json.dumps({'name': name, 'length': length, 'width': width}) + resp = self.request('/plugins/sample/rectangles', req, 'POST') + return resp + + def _get_rectangle(self, name): + resp = self.request('/plugins/sample/rectangles/%s' % name) + return json.loads(resp.read()) + + def _create_rectangle_and_assert(self, name, length, width): + resp = self._create_rectangle(name, length, width) + self.assertEquals(201, resp.status) + + rectangle = self._get_rectangle(name) + self.assertEquals(rectangle['name'], name) + self.assertEquals(rectangle['length'], length) + self.assertEquals(rectangle['width'], width) + + def _get_rectangles_list(self): + resp = self.request('/plugins/sample/rectangles') + rectangles = json.loads(resp.read()) + name_list = [rectangle['name'] for rectangle in rectangles] + return name_list + + def test_rectangles(self): + # Create two new rectangles + self._create_rectangle_and_assert('small', 10, 8) + self._create_rectangle_and_assert('big', 20, 16) + + # Verify they're in the list + name_list = self._get_rectangles_list() + self.assertIn('small', name_list) + self.assertIn('big', name_list) + + # Update the big rectangle. + req = json.dumps({'length': 40, 'width': 30}) + resp = self.request('/plugins/sample/rectangles/big', req, 'PUT') + self.assertEquals(200, resp.status) + big = self._get_rectangle('big') + self.assertEquals(big['length'], 40) + self.assertEquals(big['width'], 30) + + # Delete two rectangles + resp = self.request('/plugins/sample/rectangles/big', '{}', 'DELETE') + self.assertEquals(204, resp.status) + resp = self.request('/plugins/sample/rectangles/small', '{}', 'DELETE') + self.assertEquals(204, resp.status) + name_list = self._get_rectangles_list() + self.assertEquals([], name_list) + + def test_bad_params(self): + # Bad name + resp = self._create_rectangle(1.0, 30, 40) + self.assertEquals(400, resp.status) + + # Bad length value + resp = self._create_rectangle('test', -10.0, 40) + self.assertEquals(400, resp.status) + + # Missing param for width + req = json.dumps({'name': 'nowidth', 'length': 40}) + resp = self.request('/plugins/sample/rectangles', req, 'POST') + self.assertEquals(400, resp.status) diff --git a/src/wok/plugins/kimchi/tests/test_rest.py b/src/wok/plugins/kimchi/tests/test_rest.py new file mode 100644 index 0000000..243074e --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_rest.py @@ -0,0 +1,1327 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import re +import time +import unittest +import urllib2 +import urlparse +from functools import partial + +from wok.rollbackcontext import RollbackContext +from wok.utils import add_task + +from wok.plugins.kimchi import mockmodel +from wok.plugins.kimchi.osinfo import get_template_default + +import iso_gen +from utils import get_free_port, patch_auth, request +from utils import run_server, wait_task + + +test_server = None +model = None +host = None +port = None +ssl_port = None +cherrypy_port = None +fake_iso = '/tmp/fake.iso' + + +def setUpModule(): + global test_server, model, host, port, ssl_port, cherrypy_port + + patch_auth() + model = mockmodel.MockModel('/tmp/obj-store-test') + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + cherrypy_port = get_free_port('cherrypy_port') + test_server = run_server(host, port, ssl_port, test_mode=True, + cherrypy_port=cherrypy_port, model=model) + + # Create fake ISO to do the tests + iso_gen.construct_fake_iso(fake_iso, True, '12.04', 'ubuntu') + iso_gen.construct_fake_iso("/var/lib/libvirt/images/fedora.iso", True, + "17", "fedora") + + +def tearDownModule(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + os.unlink(fake_iso) + os.unlink("/var/lib/libvirt/images/fedora.iso") + + +class RestTests(unittest.TestCase): + def _async_op(self, cb, opaque): + time.sleep(1) + cb('success', True) + + def _except_op(self, cb, opaque): + time.sleep(1) + raise Exception("Oops, this is an exception handle test." + " You can ignore it safely") + cb('success', True) + + def _intermid_op(self, cb, opaque): + time.sleep(1) + cb('in progress') + + def setUp(self): + self.request = partial(request, host, ssl_port) + model.reset() + + def assertHTTPStatus(self, code, *args): + resp = self.request(*args) + self.assertEquals(code, resp.status) + + def test_get_vms(self): + vms = json.loads(self.request('/plugins/kimchi/vms').read()) + # test_rest.py uses MockModel() which connects to libvirt URI + # test:///default. By default this driver already has one VM created + self.assertEquals(1, len(vms)) + + # Create a template as a base for our VMs + req = json.dumps({'name': 'test', 'cdrom': fake_iso}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + test_users = ['root'] + test_groups = ['wheel'] + # Now add a couple of VMs to the mock model + for i in xrange(10): + name = 'vm-%i' % i + req = json.dumps({'name': name, + 'template': '/plugins/kimchi/templates/test', + 'users': test_users, 'groups': test_groups}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + + vms = json.loads(self.request('/plugins/kimchi/vms').read()) + self.assertEquals(11, len(vms)) + + vm = json.loads(self.request('/plugins/kimchi/vms/vm-1').read()) + self.assertEquals('vm-1', vm['name']) + self.assertEquals('shutoff', vm['state']) + self.assertEquals([], vm['users']) + self.assertEquals([], vm['groups']) + + def test_edit_vm(self): + req = json.dumps({'name': 'test', 'cdrom': fake_iso}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + req = json.dumps({'name': 'vm-1', + 'template': '/plugins/kimchi/templates/test'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + + vm = json.loads(self.request('/plugins/kimchi/vms/vm-1').read()) + self.assertEquals('vm-1', vm['name']) + + resp = self.request('/plugins/kimchi/vms/vm-1/start', '{}', 'POST') + self.assertEquals(200, resp.status) + + req = json.dumps({'unsupported-attr': 'attr'}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(400, resp.status) + + req = json.dumps({'name': 'new-vm'}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(400, resp.status) + + req = json.dumps({'cpus': 3}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(200, resp.status) + + # Check if there is support to memory hotplug, once vm is running + resp = self.request('/plugins/kimchi/config/capabilities').read() + conf = json.loads(resp) + req = json.dumps({'memory': 2048}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + if conf['mem_hotplug_support']: + self.assertEquals(200, resp.status) + else: + self.assertEquals(400, resp.status) + + req = json.dumps({"graphics": {'passwd': "abcdef"}}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + info = json.loads(resp.read()) + self.assertEquals('abcdef', info["graphics"]["passwd"]) + self.assertEquals(None, info["graphics"]["passwdValidTo"]) + + resp = self.request('/plugins/kimchi/vms/vm-1/poweroff', '{}', 'POST') + self.assertEquals(200, resp.status) + + req = json.dumps({"graphics": {'passwd': "123456", + 'passwdValidTo': 20}}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + info = json.loads(resp.read()) + self.assertEquals('123456', info["graphics"]["passwd"]) + self.assertGreaterEqual(20, info["graphics"]["passwdValidTo"]) + + req = json.dumps({'name': 12}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(400, resp.status) + + req = json.dumps({'name': ''}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(400, resp.status) + + req = json.dumps({'cpus': -2}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(400, resp.status) + + req = json.dumps({'cpus': 'four'}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(400, resp.status) + + req = json.dumps({'memory': 100}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(400, resp.status) + + req = json.dumps({'memory': 'ten gigas'}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(400, resp.status) + + req = json.dumps({'name': 'new-name', 'cpus': 5, 'UUID': 'notallowed'}) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(400, resp.status) + + params = {'name': u'�����-����d��t��d', 'cpus': 5, 'memory': 3072} + req = json.dumps(params) + resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT') + self.assertEquals(303, resp.status) + vm = json.loads( + self.request('/plugins/kimchi/vms/�����-����d��t��d', req).read() + ) + for key in params.keys(): + self.assertEquals(params[key], vm[key]) + + # change only VM users - groups are not changed (default is empty) + resp = self.request('/plugins/kimchi/users', '{}', 'GET') + users = json.loads(resp.read()) + req = json.dumps({'users': users}) + resp = self.request('/plugins/kimchi/vms/�����-����d��t��d', req, 'PUT') + self.assertEquals(200, resp.status) + info = json.loads( + self.request('/plugins/kimchi/vms/�����-����d��t��d', '{}').read() + ) + self.assertEquals(users, info['users']) + + # change only VM groups - users are not changed (default is empty) + resp = self.request('/plugins/kimchi/groups', '{}', 'GET') + groups = json.loads(resp.read()) + req = json.dumps({'groups': groups}) + resp = self.request('/plugins/kimchi/vms/�����-����d��t��d', req, 'PUT') + self.assertEquals(200, resp.status) + info = json.loads( + self.request('/plugins/kimchi/vms/�����-����d��t��d', '{}').read() + ) + self.assertEquals(groups, info['groups']) + + # change VM users (wrong value) and groups + # when an error occurs, everything fails and nothing is changed + req = json.dumps({'users': ['userdoesnotexist'], 'groups': []}) + resp = self.request('/plugins/kimchi/vms/�����-����d��t��d', req, 'PUT') + self.assertEquals(400, resp.status) + + # change VM users and groups (wrong value) + # when an error occurs, everything fails and nothing is changed + req = json.dumps({'users': [], 'groups': ['groupdoesnotexist']}) + resp = self.request('/plugins/kimchi/vms/�����-����d��t��d', req, 'PUT') + self.assertEquals(400, resp.status) + + def test_vm_lifecycle(self): + # Create a Template + req = json.dumps({'name': 'test', 'disks': [{'size': 1}], + 'icon': 'images/icon-debian.png', + 'cdrom': fake_iso}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Create a VM + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + self.assertEquals(202, resp.status) + + # Verify the VM + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('shutoff', vm['state']) + self.assertEquals('images/icon-debian.png', vm['icon']) + + # Verify the volume was created + vol_uri = '/plugins/kimchi/storagepools/default-pool/storagevolumes/' \ + + '%s-0.img' + resp = self.request(vol_uri % vm['uuid']) + vol = json.loads(resp.read()) + self.assertEquals(1 << 30, vol['capacity']) + self.assertEquals(['test-vm'], vol['used_by']) + + # Start the VM + resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('running', vm['state']) + + # Test screenshot + resp = self.request(vm['screenshot'], method='HEAD') + self.assertEquals(200, resp.status) + self.assertTrue(resp.getheader('Content-type').startswith('image')) + + # Clone a running VM + resp = self.request('/plugins/kimchi/vms/test-vm/clone', '{}', 'POST') + self.assertEquals(400, resp.status) + + # Force poweroff the VM + resp = self.request('/plugins/kimchi/vms/test-vm/poweroff', '{}', + 'POST') + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('shutoff', vm['state']) + + # Test create VM with same name fails with 400 + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(400, resp.status) + + # Clone a VM + resp = self.request('/plugins/kimchi/vms/test-vm/clone', '{}', 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + task = json.loads( + self.request('/tasks/%s' % task['id'], '{}').read() + ) + self.assertEquals('finished', task['status']) + clone_vm_name = task['target_uri'].split('/')[-2] + self.assertTrue(re.match(u'test-vm-clone-\d+', clone_vm_name)) + + resp = self.request('/plugins/kimchi/vms/test-vm', '{}') + original_vm_info = json.loads(resp.read()) + resp = self.request('/plugins/kimchi/vms/%s' % clone_vm_name, '{}') + self.assertEquals(200, resp.status) + clone_vm_info = json.loads(resp.read()) + + self.assertNotEqual(original_vm_info['name'], clone_vm_info['name']) + del original_vm_info['name'] + del clone_vm_info['name'] + + self.assertNotEqual(original_vm_info['uuid'], clone_vm_info['uuid']) + del original_vm_info['uuid'] + del clone_vm_info['uuid'] + + self.assertEquals(original_vm_info, clone_vm_info) + + # Create a snapshot on a stopped VM + params = {'name': 'test-snap'} + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots', + json.dumps(params), + 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + task = json.loads( + self.request('/tasks/%s' % task['id']).read() + ) + self.assertEquals('finished', task['status']) + + # Look up a non-existing snapshot + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/snap404', + '{}', 'GET') + self.assertEquals(404, resp.status) + + # Look up a snapshot + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/%s' % + params['name'], '{}', 'GET') + self.assertEquals(200, resp.status) + snap = json.loads(resp.read()) + self.assertTrue(int(time.time()) >= int(snap['created'])) + self.assertEquals(params['name'], snap['name']) + self.assertEquals(u'', snap['parent']) + self.assertEquals(u'shutoff', snap['state']) + + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots', '{}', + 'GET') + self.assertEquals(200, resp.status) + snaps = json.loads(resp.read()) + self.assertEquals(1, len(snaps)) + + # Look up current snapshot (the one created above) + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/current', + '{}', 'GET') + self.assertEquals(200, resp.status) + snap = json.loads(resp.read()) + self.assertEquals(params['name'], snap['name']) + + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots', '{}', + 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + snap_name = task['target_uri'].split('/')[-1] + wait_task(self._task_lookup, task['id']) + resp = self.request('/tasks/%s' % task['id'], '{}', + 'GET') + task = json.loads(resp.read()) + self.assertEquals('finished', task['status']) + + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots', '{}', + 'GET') + self.assertEquals(200, resp.status) + snaps = json.loads(resp.read()) + self.assertEquals(2, len(snaps)) + + # Look up current snapshot (the one created above) + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/current', + '{}', 'GET') + self.assertEquals(200, resp.status) + snap = json.loads(resp.read()) + self.assertEquals(snap_name, snap['name']) + + # Revert to snapshot + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/%s/revert' % + params['name'], '{}', 'POST') + self.assertEquals(200, resp.status) + snap = json.loads(resp.read()) + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET') + self.assertEquals(200, resp.status) + vm = json.loads(resp.read()) + self.assertEquals(vm['state'], snap['state']) + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/current', + '{}', 'GET') + self.assertEquals(200, resp.status) + current_snap = json.loads(resp.read()) + self.assertEquals(snap, current_snap) + + # Delete a snapshot + resp = self.request('/plugins/kimchi/vms/test-vm/snapshots/%s' % + params['name'], '{}', 'DELETE') + self.assertEquals(204, resp.status) + + # Suspend the VM + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET') + self.assertEquals(200, resp.status) + vm = json.loads(resp.read()) + self.assertEquals(vm['state'], 'shutoff') + resp = self.request('/plugins/kimchi/vms/test-vm/suspend', '{}', + 'POST') + self.assertEquals(400, resp.status) + resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') + self.assertEquals(200, resp.status) + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET') + self.assertEquals(200, resp.status) + vm = json.loads(resp.read()) + self.assertEquals(vm['state'], 'running') + resp = self.request('/plugins/kimchi/vms/test-vm/suspend', '{}', + 'POST') + self.assertEquals(200, resp.status) + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET') + self.assertEquals(200, resp.status) + vm = json.loads(resp.read()) + self.assertEquals(vm['state'], 'paused') + + # Resume the VM + resp = self.request('/plugins/kimchi/vms/test-vm/resume', '{}', 'POST') + self.assertEquals(200, resp.status) + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET') + self.assertEquals(200, resp.status) + vm = json.loads(resp.read()) + self.assertEquals(vm['state'], 'running') + + # Delete the VM + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') + self.assertEquals(204, resp.status) + + # Delete the Template + resp = self.request('/plugins/kimchi/templates/test', '{}', 'DELETE') + self.assertEquals(204, resp.status) + + # Verify the volume was deleted + self.assertHTTPStatus(404, vol_uri % vm['uuid']) + + def test_vm_graphics(self): + # Create a Template + req = json.dumps({'name': 'test', 'cdrom': fake_iso}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Create a VM with default args + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + # Verify the VM + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('127.0.0.1', vm['graphics']['listen']) + self.assertEquals('vnc', vm['graphics']['type']) + # Delete the VM + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') + self.assertEquals(204, resp.status) + + # Create a VM with specified graphics type and listen + graphics = {'type': 'vnc', 'listen': '127.0.0.1'} + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test', + 'graphics': graphics}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + # Verify the VM + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('127.0.0.1', vm['graphics']['listen']) + self.assertEquals('vnc', vm['graphics']['type']) + # Delete the VM + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') + self.assertEquals(204, resp.status) + + # Create a VM with listen as ipv6 address + graphics = {'type': 'spice', 'listen': 'fe00::0'} + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test', + 'graphics': graphics}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + # Verify the VM + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('fe00::0', vm['graphics']['listen']) + self.assertEquals('spice', vm['graphics']['type']) + # Delete the VM + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') + self.assertEquals(204, resp.status) + + # Create a VM with specified graphics type and default listen + graphics = {'type': 'spice'} + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test', + 'graphics': graphics}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + # Verify the VM + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('127.0.0.1', vm['graphics']['listen']) + self.assertEquals('spice', vm['graphics']['type']) + # Delete the VM + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') + self.assertEquals(204, resp.status) + + # Try to create a VM with invalid graphics type + graphics = {'type': 'invalid'} + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test', + 'graphics': graphics}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(400, resp.status) + + # Try to create a VM with invalid graphics listen + graphics = {'type': 'spice', 'listen': 'invalid'} + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test', + 'graphics': graphics}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(400, resp.status) + + # Delete the Template + resp = self.request('/plugins/kimchi/templates/test', '{}', 'DELETE') + self.assertEquals(204, resp.status) + + def test_vm_storage_devices(self): + + with RollbackContext() as rollback: + # Create a template as a base for our VMs + req = json.dumps({'name': 'test', 'cdrom': fake_iso}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + # Delete the template + rollback.prependDefer(self.request, + '/plugins/kimchi/templates/test', '{}', + 'DELETE') + + # Create a VM with default args + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + # Delete the VM + rollback.prependDefer(self.request, '/plugins/kimchi/vms/test-vm', + '{}', 'DELETE') + + # Check storage devices + resp = self.request('/plugins/kimchi/vms/test-vm/storages', '{}', + 'GET') + devices = json.loads(resp.read()) + self.assertEquals(2, len(devices)) + dev_types = [] + for d in devices: + self.assertIn(u'type', d.keys()) + self.assertIn(u'dev', d.keys()) + self.assertIn(u'path', d.keys()) + dev_types.append(d['type']) + + self.assertEquals(['cdrom', 'disk'], sorted(dev_types)) + + # Attach cdrom with nonexistent iso + req = json.dumps({'dev': 'hdx', + 'type': 'cdrom', + 'path': '/tmp/nonexistent.iso'}) + resp = self.request('/plugins/kimchi/vms/test-vm/storages', req, + 'POST') + self.assertEquals(400, resp.status) + + # Create temp storage pool + req = json.dumps({'name': 'tmp', + 'capacity': 1024, + 'allocated': 512, + 'path': '/tmp', + 'type': 'dir'}) + resp = self.request('/plugins/kimchi/storagepools', req, 'POST') + self.assertEquals(201, resp.status) + resp = self.request('/plugins/kimchi/storagepools/tmp/activate', + req, 'POST') + self.assertEquals(200, resp.status) + + # 'name' is required for this type of volume + req = json.dumps({'capacity': 1024, + 'allocation': 512, + 'type': 'disk', + 'format': 'raw'}) + resp = self.request( + '/plugins/kimchi/storagepools/tmp/storagevolumes', req, 'POST' + ) + self.assertEquals(400, resp.status) + req = json.dumps({'name': "attach-volume", + 'capacity': 1024, + 'allocation': 512, + 'type': 'disk', + 'format': 'raw'}) + resp = self.request( + '/plugins/kimchi/storagepools/tmp/storagevolumes', req, 'POST' + ) + self.assertEquals(202, resp.status) + time.sleep(1) + + # Attach cdrom with both path and volume specified + open('/tmp/existent.iso', 'w').close() + req = json.dumps({'dev': 'hdx', + 'type': 'cdrom', + 'pool': 'tmp', + 'vol': 'attach-volume', + 'path': '/tmp/existent.iso'}) + resp = self.request( + '/plugins/kimchi/vms/test-vm/storages', req, 'POST' + ) + self.assertEquals(400, resp.status) + + # Attach disk with both path and volume specified + req = json.dumps({'dev': 'hdx', + 'type': 'disk', + 'pool': 'tmp', + 'vol': 'attach-volume', + 'path': '/tmp/existent.iso'}) + resp = self.request( + '/plugins/kimchi/vms/test-vm/storages', req, 'POST' + ) + self.assertEquals(400, resp.status) + + # Attach disk with only pool specified + req = json.dumps({'dev': 'hdx', + 'type': 'cdrom', + 'pool': 'tmp'}) + resp = self.request( + '/plugins/kimchi/vms/test-vm/storages', req, 'POST' + ) + self.assertEquals(400, resp.status) + + # Attach disk with pool and vol specified + req = json.dumps({'type': 'disk', + 'pool': 'tmp', + 'vol': 'attach-volume'}) + resp = self.request( + '/plugins/kimchi/vms/test-vm/storages', req, 'POST' + ) + self.assertEquals(201, resp.status) + cd_info = json.loads(resp.read()) + self.assertEquals('disk', cd_info['type']) + + # Attach a cdrom with existent dev name + req = json.dumps({'type': 'cdrom', + 'path': '/tmp/existent.iso'}) + resp = self.request( + '/plugins/kimchi/vms/test-vm/storages', req, 'POST' + ) + self.assertEquals(201, resp.status) + cd_info = json.loads(resp.read()) + cd_dev = cd_info['dev'] + self.assertEquals('cdrom', cd_info['type']) + self.assertEquals('/tmp/existent.iso', cd_info['path']) + # Delete the file and cdrom + rollback.prependDefer(self.request, + '/plugins/kimchi/vms/test-vm/storages/hdx', + '{}', 'DELETE') + os.remove('/tmp/existent.iso') + + # Change path of storage cdrom + cdrom = u'http://fedora.mirrors.tds.net/pub/fedora/releases/20/'\ + 'Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso' + req = json.dumps({'path': cdrom}) + resp = self.request('/plugins/kimchi/vms/test-vm/storages/' + + cd_dev, req, 'PUT') + self.assertEquals(200, resp.status) + cd_info = json.loads(resp.read()) + self.assertEquals(urlparse.urlparse(cdrom).path, + urlparse.urlparse(cd_info['path']).path) + + # Test GET + devs = json.loads( + self.request('/plugins/kimchi/vms/test-vm/storages').read() + ) + self.assertEquals(4, len(devs)) + + # Detach storage cdrom + resp = self.request('/plugins/kimchi/vms/test-vm/storages/' + + cd_dev, '{}', 'DELETE') + self.assertEquals(204, resp.status) + + # Test GET + devs = json.loads( + self.request('/plugins/kimchi/vms/test-vm/storages').read() + ) + self.assertEquals(3, len(devs)) + resp = self.request('/plugins/kimchi/storagepools/tmp/deactivate', + {}, 'POST') + self.assertEquals(200, resp.status) + resp = self.request('/plugins/kimchi/storagepools/tmp', {}, + 'DELETE') + self.assertEquals(204, resp.status) + + def test_vm_iface(self): + + with RollbackContext() as rollback: + # Create a template as a base for our VMs + req = json.dumps({'name': 'test', 'cdrom': fake_iso}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + # Delete the template + rollback.prependDefer(self.request, + '/plugins/kimchi/templates/test', '{}', + 'DELETE') + + # Create a VM with default args + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + # Delete the VM + rollback.prependDefer(self.request, + '/plugins/kimchi/vms/test-vm', '{}', + 'DELETE') + + # Create a network + req = json.dumps({'name': 'test-network', + 'connection': 'nat', + 'net': '127.0.1.0/24'}) + resp = self.request('/plugins/kimchi/networks', req, 'POST') + self.assertEquals(201, resp.status) + # Delete the network + rollback.prependDefer(self.request, + '/plugins/kimchi/networks/test-network', + '{}', 'DELETE') + + ifaces = json.loads( + self.request('/plugins/kimchi/vms/test-vm/ifaces').read() + ) + self.assertEquals(1, len(ifaces)) + + for iface in ifaces: + res = json.loads( + self.request('/plugins/kimchi/vms/test-vm/ifaces/%s' % + iface['mac']).read() + ) + self.assertEquals('default', res['network']) + self.assertEquals(17, len(res['mac'])) + self.assertEquals(get_template_default('old', 'nic_model'), + res['model']) + + # try to attach an interface without specifying 'model' + req = json.dumps({'type': 'network'}) + resp = self.request('/plugins/kimchi/vms/test-vm/ifaces', req, + 'POST') + self.assertEquals(400, resp.status) + + # attach network interface to vm + req = json.dumps({"type": "network", + "network": "test-network", + "model": "virtio"}) + resp = self.request('/plugins/kimchi/vms/test-vm/ifaces', req, + 'POST') + self.assertEquals(201, resp.status) + iface = json.loads(resp.read()) + + self.assertEquals('test-network', iface['network']) + self.assertEquals(17, len(iface['mac'])) + self.assertEquals('virtio', iface['model']) + self.assertEquals('network', iface['type']) + + # update vm interface + newMacAddr = '54:50:e3:44:8a:af' + req = json.dumps({"network": "default", "model": "virtio", + "type": "network", "mac": newMacAddr}) + resp = self.request('/plugins/kimchi/vms/test-vm/ifaces/%s' % + iface['mac'], req, 'PUT') + self.assertEquals(303, resp.status) + iface = json.loads( + self.request('/plugins/kimchi/vms/test-vm/ifaces/%s' % + newMacAddr).read() + ) + self.assertEquals(newMacAddr, iface['mac']) + + # detach network interface from vm + resp = self.request('/plugins/kimchi/vms/test-vm/ifaces/%s' % + iface['mac'], '{}', 'DELETE') + self.assertEquals(204, resp.status) + + def test_vm_customise_storage(self): + # Create a Template + req = json.dumps({'name': 'test', 'cdrom': fake_iso, + 'disks': [{'size': 1}]}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Create alternate storage + req = json.dumps({'name': 'alt', + 'capacity': 1024, + 'allocated': 512, + 'path': '/tmp', + 'type': 'dir'}) + resp = self.request('/plugins/kimchi/storagepools', req, 'POST') + self.assertEquals(201, resp.status) + resp = self.request('/plugins/kimchi/storagepools/alt/activate', req, + 'POST') + self.assertEquals(200, resp.status) + + # Create a VM + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test', + 'storagepool': '/plugins/kimchi/storagepools/alt'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + resp = self.request('/plugins/kimchi/vms/test-vm', {}, 'GET') + vm_info = json.loads(resp.read()) + + # Test template not changed after vm customise its pool + t = json.loads(self.request('/plugins/kimchi/templates/test').read()) + self.assertEquals(t['storagepool'], + '/plugins/kimchi/storagepools/default-pool') + + # Verify the volume was created + vol_uri = '/plugins/kimchi/storagepools/alt/storagevolumes/%s-0.img' \ + % vm_info['uuid'] + resp = self.request(vol_uri) + vol = json.loads(resp.read()) + self.assertEquals(1 << 30, vol['capacity']) + + # Delete the VM + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') + self.assertEquals(204, resp.status) + + # Verify the volume was deleted + self.assertHTTPStatus(404, vol_uri) + + def test_scsi_fc_storage(self): + # Create scsi fc pool + req = json.dumps({'name': 'scsi_fc_pool', + 'type': 'scsi', + 'source': {'adapter_name': 'scsi_host2'}}) + resp = self.request('/plugins/kimchi/storagepools', req, 'POST') + self.assertEquals(201, resp.status) + + # Test create vms using lun of this pool + # activate the storage pool + resp = self.request( + '/plugins/kimchi/storagepools/scsi_fc_pool/activate', '{}', 'POST' + ) + + # Create template fails because SCSI volume is missing + tmpl_params = { + 'name': 'test_fc_pool', 'cdrom': fake_iso, + 'storagepool': '/plugins/kimchi/storagepools/scsi_fc_pool' + } + req = json.dumps(tmpl_params) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(400, resp.status) + + # Choose SCSI volume to create template + resp = self.request( + '/plugins/kimchi/storagepools/scsi_fc_pool/storagevolumes' + ) + lun_name = json.loads(resp.read())[0]['name'] + + tmpl_params['disks'] = [{'index': 0, 'volume': lun_name}] + req = json.dumps(tmpl_params) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Create vm in scsi pool + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test_fc_pool'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + + # Start the VM + resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('running', vm['state']) + + # Force poweroff the VM + resp = self.request('/plugins/kimchi/vms/test-vm/poweroff', '{}', + 'POST') + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + self.assertEquals('shutoff', vm['state']) + + # Delete the VM + resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') + self.assertEquals(204, resp.status) + + def test_unnamed_vms(self): + # Create a Template + req = json.dumps({'name': 'test', 'cdrom': fake_iso}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Create 5 unnamed vms from this template + for i in xrange(1, 6): + req = json.dumps({'template': '/plugins/kimchi/templates/test'}) + task = json.loads(self.request('/plugins/kimchi/vms', + req, 'POST').read()) + wait_task(self._task_lookup, task['id']) + resp = self.request('/plugins/kimchi/vms/test-vm-%i' % i, {}, + 'GET') + self.assertEquals(resp.status, 200) + count = len(json.loads(self.request('/plugins/kimchi/vms').read())) + self.assertEquals(6, count) + + def test_create_vm_without_template(self): + req = json.dumps({'name': 'vm-without-template'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(400, resp.status) + resp = json.loads(resp.read()) + self.assertIn(u"KCHVM0016E:", resp['reason']) + + def test_create_vm_with_bad_template_uri(self): + req = json.dumps({'name': 'vm-bad-template', + 'template': '/mytemplate'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(400, resp.status) + resp = json.loads(resp.read()) + self.assertIn(u"KCHVM0012E", resp['reason']) + + def test_create_vm_with_img_based_template(self): + resp = json.loads( + self.request( + '/plugins/kimchi/storagepools/default-pool/storagevolumes' + ).read() + ) + self.assertEquals(0, len(resp)) + + # Create a Template + mock_base = '/tmp/mock.img' + open(mock_base, 'w').close() + req = json.dumps({'name': 'test', 'disks': [{'base': mock_base}]}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + req = json.dumps({'template': '/plugins/kimchi/templates/test'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + + # Test storage volume created with backing store of base file + resp = json.loads( + self.request( + '/plugins/kimchi/storagepools/default-pool/storagevolumes' + ).read() + ) + self.assertEquals(1, len(resp)) + + def _create_pool(self, name): + req = json.dumps({'name': name, + 'capacity': 10240, + 'allocated': 5120, + 'path': '/var/lib/libvirt/images/', + 'type': 'dir'}) + resp = self.request('/plugins/kimchi/storagepools', req, 'POST') + self.assertEquals(201, resp.status) + + # Verify the storage pool + storagepool = json.loads(self.request('/plugins/kimchi/storagepools/%s' + % name).read()) + self.assertEquals('inactive', storagepool['state']) + return name + + def _delete_pool(self, name): + # Delete the storage pool + resp = self.request('/plugins/kimchi/storagepools/%s' % name, '{}', + 'DELETE') + self.assertEquals(204, resp.status) + + def test_iso_scan_shallow(self): + # fake environment preparation + self._create_pool('pool-3') + self.request('/plugins/kimchi/storagepools/pool-3/activate', '{}', + 'POST') + params = {'name': 'fedora.iso', + 'capacity': 1073741824, # 1 GiB + 'type': 'file', + 'format': 'iso'} + task_info = model.storagevolumes_create('pool-3', params) + wait_task(self._task_lookup, task_info['id']) + + storagevolume = json.loads( + self.request( + '/plugins/kimchi/storagepools/kimchi_isos/storagevolumes/' + ).read() + )[0] + self.assertEquals('fedora.iso', storagevolume['name']) + self.assertEquals('iso', storagevolume['format']) + self.assertEquals('/var/lib/libvirt/images/fedora.iso', + storagevolume['path']) + self.assertEquals(1073741824, storagevolume['capacity']) # 1 GiB + self.assertEquals(0, storagevolume['allocation']) + self.assertEquals('17', storagevolume['os_version']) + self.assertEquals('fedora', storagevolume['os_distro']) + self.assertEquals(True, storagevolume['bootable']) + + # Create a template + # In real model os distro/version can be omitted + # as we will scan the iso + req = json.dumps({'name': 'test', + 'cdrom': storagevolume['path'], + 'os_distro': storagevolume['os_distro'], + 'os_version': storagevolume['os_version']}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Verify the template + t = json.loads(self.request('/plugins/kimchi/templates/test').read()) + self.assertEquals('test', t['name']) + self.assertEquals('fedora', t['os_distro']) + self.assertEquals('17', t['os_version']) + self.assertEquals(get_template_default('old', 'memory'), t['memory']) + + # Deactivate or destroy scan pool return 405 + resp = self.request( + '/plugins/kimchi/storagepools/kimchi_isos/storagevolumes' + '/deactivate', '{}', 'POST' + ) + self.assertEquals(405, resp.status) + + resp = self.request( + '/plugins/kimchi/storagepools/kimchi_isos/storagevolumes', + '{}', 'DELETE' + ) + self.assertEquals(405, resp.status) + + # Delete the template + resp = self.request('/plugins/kimchi/templates/%s' % t['name'], '{}', + 'DELETE') + self.assertEquals(204, resp.status) + + resp = self.request('/plugins/kimchi/storagepools/pool-3/deactivate', + '{}', 'POST') + self.assertEquals(200, resp.status) + self._delete_pool('pool-3') + + def test_screenshot_refresh(self): + # Create a VM + req = json.dumps({'name': 'test', 'cdrom': fake_iso}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + req = json.dumps({'name': 'test-vm', + 'template': '/plugins/kimchi/templates/test'}) + resp = self.request('/plugins/kimchi/vms', req, 'POST') + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + + # Test screenshot for shut-off state vm + resp = self.request('/plugins/kimchi/vms/test-vm/screenshot') + self.assertEquals(404, resp.status) + + # Test screenshot for running vm + resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + + resp = self.request(vm['screenshot'], method='HEAD') + self.assertEquals(200, resp.status) + self.assertTrue(resp.getheader('Content-type').startswith('image')) + + # Test screenshot sub-resource redirect + resp = self.request('/plugins/kimchi/vms/test-vm/screenshot') + self.assertEquals(200, resp.status) + self.assertEquals('image/png', resp.getheader('content-type')) + lastMod1 = resp.getheader('last-modified') + + # Take another screenshot instantly and compare the last Modified date + resp = self.request('/plugins/kimchi/vms/test-vm/screenshot') + lastMod2 = resp.getheader('last-modified') + self.assertEquals(lastMod2, lastMod1) + + resp = self.request('/plugins/kimchi/vms/test-vm/screenshot', '{}', + 'DELETE') + self.assertEquals(405, resp.status) + + # No screenshot after stopped the VM + self.request('/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST') + resp = self.request('/plugins/kimchi/vms/test-vm/screenshot') + self.assertEquals(404, resp.status) + + # Picture link not available after VM deleted + self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST') + vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read()) + img_lnk = vm['screenshot'] + self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE') + resp = self.request(img_lnk) + self.assertEquals(404, resp.status) + + def test_interfaces(self): + resp = self.request('/plugins/kimchi/interfaces').read() + self.assertIn('name', resp) + interfaces = json.loads(resp) + keys = ['name', 'type', 'ipaddr', 'netmask', 'status'] + for interface in interfaces: + self.assertEquals(sorted(keys), sorted(interface.keys())) + + def _task_lookup(self, taskid): + return json.loads( + self.request('/tasks/%s' % taskid).read() + ) + + def test_tasks(self): + id1 = add_task('/tasks/1', self._async_op, + model.objstore) + id2 = add_task('/tasks/2', self._except_op, + model.objstore) + id3 = add_task('/tasks/3', self._intermid_op, + model.objstore) + + target_uri = urllib2.quote('^/tasks/*', safe="") + filter_data = 'status=running&target_uri=%s' % target_uri + tasks = json.loads( + self.request('/tasks?%s' % filter_data).read() + ) + self.assertEquals(3, len(tasks)) + + tasks = json.loads(self.request('/tasks').read()) + tasks_ids = [int(t['id']) for t in tasks] + self.assertEquals(set([id1, id2, id3]) - set(tasks_ids), set([])) + wait_task(self._task_lookup, id2) + foo2 = json.loads( + self.request('/tasks/%s' % id2).read() + ) + keys = ['id', 'status', 'message', 'target_uri'] + self.assertEquals(sorted(keys), sorted(foo2.keys())) + self.assertEquals('failed', foo2['status']) + wait_task(self._task_lookup, id3) + foo3 = json.loads( + self.request('/tasks/%s' % id3).read() + ) + self.assertEquals('in progress', foo3['message']) + self.assertEquals('running', foo3['status']) + + def test_config(self): + resp = self.request('/plugins/kimchi/config').read() + conf = json.loads(resp) + keys = ["display_proxy_port", "version"] + self.assertEquals(keys, sorted(conf.keys())) + + def test_capabilities(self): + resp = self.request('/plugins/kimchi/config/capabilities').read() + conf = json.loads(resp) + + keys = [u'libvirt_stream_protocols', u'qemu_stream', u'qemu_spice', + u'screenshot', u'system_report_tool', u'update_tool', + u'repo_mngt_tool', u'federation', u'kernel_vfio', u'auth', + u'nm_running', u'mem_hotplug_support'] + self.assertEquals(sorted(keys), sorted(conf.keys())) + + def test_peers(self): + resp = self.request('/plugins/kimchi/peers').read() + self.assertEquals([], json.loads(resp)) + + def test_distros(self): + resp = self.request('/plugins/kimchi/config/distros').read() + distros = json.loads(resp) + for distro in distros: + self.assertIn('name', distro) + self.assertIn('os_distro', distro) + self.assertIn('os_version', distro) + self.assertIn('path', distro) + + # Test in X86 + ident = "Fedora 20" + resp = self.request('/plugins/kimchi/config/distros/%s' % + urllib2.quote(ident)).read() + distro = json.loads(resp) + if os.uname()[4] in ['x86_64', 'amd64']: + self.assertEquals(distro['name'], ident) + self.assertEquals(distro['os_distro'], "fedora") + self.assertEquals(distro['os_version'], "20") + self.assertEquals(distro['os_arch'], "x86_64") + self.assertIn('path', distro) + else: + # Distro not found error + self.assertIn('KCHDISTRO0001E', distro.get('reason')) + + # Test in PPC + ident = "Fedora 20 (PPC64)" + resp = self.request('/plugins/kimchi/config/distros/%s' % + urllib2.quote(ident)).read() + distro = json.loads(resp) + if os.uname()[4] == 'ppc64': + self.assertEquals(distro['name'], ident) + self.assertEquals(distro['os_distro'], "fedora") + self.assertEquals(distro['os_version'], "20") + self.assertEquals(distro['os_arch'], "ppc64") + self.assertIn('path', distro) + else: + # Distro not found error + self.assertIn('KCHDISTRO0001E', distro.get('reason')) + + def test_debugreports(self): + resp = request(host, ssl_port, '/plugins/kimchi/debugreports') + self.assertEquals(200, resp.status) + + def _report_delete(self, name): + request(host, ssl_port, '/plugins/kimchi/debugreports/%s' % name, '{}', + 'DELETE') + + def test_create_debugreport(self): + req = json.dumps({'name': 'report1'}) + with RollbackContext() as rollback: + resp = request(host, ssl_port, '/plugins/kimchi/debugreports', req, + 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + # make sure the debugreport doesn't exist until the + # the task is finished + wait_task(self._task_lookup, task['id']) + rollback.prependDefer(self._report_delete, 'report2') + resp = request(host, ssl_port, + '/plugins/kimchi/debugreports/report1') + debugreport = json.loads(resp.read()) + self.assertEquals("report1", debugreport['name']) + self.assertEquals(200, resp.status) + req = json.dumps({'name': 'report2'}) + resp = request(host, ssl_port, + '/plugins/kimchi/debugreports/report1', req, 'PUT') + self.assertEquals(303, resp.status) + + def test_debugreport_download(self): + req = json.dumps({'name': 'report1'}) + with RollbackContext() as rollback: + resp = request(host, ssl_port, '/plugins/kimchi/debugreports', req, + 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + # make sure the debugreport doesn't exist until the + # the task is finished + wait_task(self._task_lookup, task['id'], 20) + rollback.prependDefer(self._report_delete, 'report1') + resp = request(host, ssl_port, + '/plugins/kimchi/debugreports/report1') + debugreport = json.loads(resp.read()) + self.assertEquals("report1", debugreport['name']) + self.assertEquals(200, resp.status) + resp = request(host, ssl_port, + '/plugins/kimchi/debugreports/report1/content') + self.assertEquals(200, resp.status) + resp = request(host, ssl_port, + '/plugins/kimchi/debugreports/report1') + debugre = json.loads(resp.read()) + resp = request(host, ssl_port, debugre['uri']) + self.assertEquals(200, resp.status) + + def test_repositories(self): + def verify_repo(t, res): + for field in ('repo_id', 'enabled', 'baseurl', 'config'): + if field in t.keys(): + self.assertEquals(t[field], res[field]) + + base_uri = '/plugins/kimchi/host/repositories' + resp = self.request(base_uri) + self.assertEquals(200, resp.status) + # Already have one repo in Kimchi's system + self.assertEquals(1, len(json.loads(resp.read()))) + + # Create a repository + repo = {'repo_id': 'fedora-fake', + 'baseurl': 'http://www.fedora.org'} + req = json.dumps(repo) + resp = self.request(base_uri, req, 'POST') + self.assertEquals(201, resp.status) + + # Verify the repository + res = json.loads(self.request('%s/fedora-fake' % base_uri).read()) + verify_repo(repo, res) + + # Update the repository + params = {} + params['baseurl'] = repo['baseurl'] = 'http://www.fedoraproject.org' + resp = self.request('%s/fedora-fake' % base_uri, json.dumps(params), + 'PUT') + + # Verify the repository + res = json.loads(self.request('%s/fedora-fake' % base_uri).read()) + verify_repo(repo, res) + + # Delete the repository + resp = self.request('%s/fedora-fake' % base_uri, '{}', 'DELETE') + self.assertEquals(204, resp.status) + + +class HttpsRestTests(RestTests): + """ + Run all of the same tests as above, but use https instead + """ + def setUp(self): + self.request = partial(request, host, ssl_port) + model.reset() diff --git a/src/wok/plugins/kimchi/tests/test_rollbackcontext.py b/src/wok/plugins/kimchi/tests/test_rollbackcontext.py new file mode 100644 index 0000000..6eac6d0 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_rollbackcontext.py @@ -0,0 +1,99 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import unittest + +from wok.rollbackcontext import RollbackContext + + +class FirstError(Exception): + '''A hypothetical exception to be raise in the test firstly.''' + pass + + +class SecondError(Exception): + '''A hypothetical exception to be raise in the test secondly.''' + pass + + +class RollbackContextTests(unittest.TestCase): + + def setUp(self): + self._counter = 0 + + def _inc_counter(self): + self._counter += 1 + + def _raise(self, exception=FirstError): + raise exception() + + def test_rollback(self): + with RollbackContext() as rollback: + rollback.prependDefer(self._inc_counter) + rollback.prependDefer(self._inc_counter) + self.assertEquals(self._counter, 2) + + def test_raise(self): + try: + with RollbackContext() as rollback: + rollback.prependDefer(self._inc_counter) + rollback.prependDefer(self._inc_counter) + raise FirstError() + rollback.prependDefer(self._inc_counter) + except FirstError: + # All undo before the FirstError should be run + self.assertEquals(self._counter, 2) + else: + self.fail('Should have raised FirstError') + + def test_raise_undo(self): + try: + with RollbackContext() as rollback: + rollback.prependDefer(self._inc_counter) + rollback.prependDefer(self._raise) + rollback.prependDefer(self._inc_counter) + except FirstError: + # All undo should be run + self.assertEquals(self._counter, 2) + else: + self.fail('Should have raised FirstError') + + def test_raise_prefer_original(self): + try: + with RollbackContext() as rollback: + rollback.prependDefer(self._raise, SecondError) + raise FirstError() + except FirstError: + pass + except SecondError: + self.fail('Should have preferred FirstError to SecondError') + else: + self.fail('Should have raised FirstError') + + def test_raise_prefer_first_undo(self): + try: + with RollbackContext() as rollback: + rollback.prependDefer(self._raise, SecondError) + rollback.prependDefer(self._raise, FirstError) + except FirstError: + pass + except SecondError: + self.fail('Should have preferred FirstError to SecondError') + else: + self.fail('Should have raised FirstError') diff --git a/src/wok/plugins/kimchi/tests/test_server.py b/src/wok/plugins/kimchi/tests/test_server.py new file mode 100644 index 0000000..d5ef565 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_server.py @@ -0,0 +1,289 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import base64 +import cherrypy +import json +import os +import tempfile +import threading +import unittest +from functools import partial + +from wok.control.base import Collection, Resource + +from wok.plugins.kimchi import mockmodel + +import utils + + +test_server = None +model = None +host = None +port = None +ssl_port = None +cherrypy_port = None +tmpfile = None + + +def setUpModule(): + global test_server, model, host, port, ssl_port, cherrypy_port, tmpfile + + utils.patch_auth() + tmpfile = tempfile.mktemp() + model = mockmodel.MockModel(tmpfile) + host = '127.0.0.1' + port = utils.get_free_port('http') + ssl_port = utils.get_free_port('https') + cherrypy_port = utils.get_free_port('cherrypy_port') + test_server = utils.run_server(host, port, ssl_port, test_mode=True, + cherrypy_port=cherrypy_port, model=model) + + +def tearDownModule(): + test_server.stop() + os.unlink(tmpfile) + + +class ServerTests(unittest.TestCase): + def setUp(self): + self.request = partial(utils.request, host, ssl_port) + model.reset() + + def assertValidJSON(self, txt): + try: + json.loads(txt) + except ValueError: + self.fail("Invalid JSON: %s" % txt) + + def test_server_start(self): + """ + Test that we can start a server and receive HTTP:200. + """ + resp = self.request('/') + self.assertEquals(200, resp.status) + + def test_multithreaded_connection(self): + def worker(): + for i in xrange(100): + ret = model.vms_get_list() + self.assertEquals('test', ret[0]) + + threads = [] + for i in xrange(100): + t = threading.Thread(target=worker) + t.setDaemon(True) + t.start() + threads.append(t) + for t in threads: + t.join() + + def test_collection(self): + c = Collection(model) + + # The base Collection is always empty + cherrypy.request.method = 'GET' + cherrypy.request.headers['Accept'] = 'application/json' + self.assertEquals('[]', c.index()) + + # POST and DELETE raise HTTP:405 by default + for method in ('POST', 'DELETE'): + cherrypy.request.method = method + try: + c.index() + except cherrypy.HTTPError, e: + self.assertEquals(405, e.code) + else: + self.fail("Expected exception not raised") + + def test_resource(self): + r = Resource(model) + + # Test the base Resource representation + cherrypy.request.method = 'GET' + cherrypy.request.headers['Accept'] = 'application/json' + self.assertEquals('{}', r.index()) + + # POST and DELETE raise HTTP:405 by default + for method in ('POST', 'DELETE'): + cherrypy.request.method = method + try: + r.index() + except cherrypy.HTTPError, e: + self.assertEquals(405, e.code) + else: + self.fail("Expected exception not raised") + + def test_404(self): + """ + A non-existent path should return HTTP:404 + """ + url_list = ['/plugins/kimchi/doesnotexist', '/plugins/kimchi/vms/blah'] + for url in url_list: + resp = self.request(url) + self.assertEquals(404, resp.status) + + # Verify it works for DELETE too + resp = self.request('/plugins/kimchi/templates/blah', '', 'DELETE') + self.assertEquals(404, resp.status) + + def test_accepts(self): + """ + Verify the following expectations regarding the client Accept header: + If omitted, default to html + If 'application/json', serve the rest api + If 'text/html', serve the UI + If both of the above (in any order), serve the rest api + If neither of the above, HTTP:406 + """ + resp = self.request("/", headers={}) + location = resp.getheader('location') + self.assertTrue(location.endswith("login.html")) + resp = self.request("/login.html", headers={}) + self.assertTrue('<!doctype html>' in resp.read().lower()) + + resp = self.request("/", headers={'Accept': 'application/json'}) + self.assertValidJSON(resp.read()) + + resp = self.request("/", headers={'Accept': 'text/html'}) + location = resp.getheader('location') + self.assertTrue(location.endswith("login.html")) + + resp = self.request("/", headers={'Accept': + 'application/json, text/html'}) + self.assertValidJSON(resp.read()) + + resp = self.request("/", headers={'Accept': + 'text/html, application/json'}) + self.assertValidJSON(resp.read()) + + h = {'Accept': 'text/plain'} + resp = self.request('/', None, 'GET', h) + self.assertEquals(406, resp.status) + + def test_auth_unprotected(self): + hdrs = {'AUTHORIZATION': ''} + uris = ['/plugins/kimchi/js/kimchi.min.js', + '/plugins/kimchi/css/theme-default.min.css', + '/plugins/kimchi/images/icon-vm.png', + '/libs/jquery-1.10.0.min.js', + '/login.html', + '/logout'] + + for uri in uris: + resp = self.request(uri, None, 'HEAD', hdrs) + self.assertEquals(200, resp.status) + + def test_auth_protected(self): + hdrs = {'AUTHORIZATION': ''} + uris = ['/plugins/kimchi/vms', + '/plugins/kimchi/vms/doesnotexist', + '/tasks'] + + for uri in uris: + resp = self.request(uri, None, 'GET', hdrs) + self.assertEquals(401, resp.status) + + def test_auth_bad_creds(self): + # Test HTTPBA + hdrs = {'AUTHORIZATION': "Basic " + base64.b64encode("nouser:badpass")} + resp = self.request('/plugins/kimchi/vms', None, 'GET', hdrs) + self.assertEquals(401, resp.status) + + # Test REST API + hdrs = {'AUTHORIZATION': ''} + req = json.dumps({'username': 'nouser', 'password': 'badpass'}) + resp = self.request('/login', req, 'POST', hdrs) + self.assertEquals(401, resp.status) + + def test_auth_browser_no_httpba(self): + # Kimchi detects REST requests from the browser by looking for a + # specific header + hdrs = {"X-Requested-With": "XMLHttpRequest"} + + # Try our request (Note that request() will add a valid HTTPBA header) + resp = self.request('/plugins/kimchi/vms', None, 'GET', hdrs) + self.assertEquals(401, resp.status) + self.assertEquals(None, resp.getheader('WWW-Authenticate')) + + def test_auth_session(self): + hdrs = {'AUTHORIZATION': '', + 'Content-Type': 'application/json', + 'Accept': 'application/json'} + + # Test we are logged out + resp = self.request('/tasks', None, 'GET', hdrs) + self.assertEquals(401, resp.status) + + # Execute a login call + user, pw = mockmodel.fake_user.items()[0] + req = json.dumps({'username': user, 'password': pw}) + resp = self.request('/login', req, 'POST', hdrs) + self.assertEquals(200, resp.status) + + user_info = json.loads(resp.read()) + self.assertEquals(sorted(user_info.keys()), + ['groups', 'roles', 'username']) + roles = user_info['roles'] + for tab, role in roles.iteritems(): + self.assertEquals(role, u'admin') + + cookie = resp.getheader('set-cookie') + hdrs['Cookie'] = cookie + + # Test we are logged in with the cookie + resp = self.request('/tasks', None, 'GET', hdrs) + self.assertEquals(200, resp.status) + + # Execute a logout call + resp = self.request('/logout', '{}', 'POST', hdrs) + self.assertEquals(200, resp.status) + del hdrs['Cookie'] + + # Test we are logged out + resp = self.request('/tasks', None, 'GET', hdrs) + self.assertEquals(401, resp.status) + + def test_get_param(self): + # Create a mock ISO file + mockiso = '/tmp/mock.iso' + open('/tmp/mock.iso', 'w').close() + + # Create 2 different templates + req = json.dumps({'name': 'test-tmpl1', 'cdrom': mockiso}) + self.request('/plugins/kimchi/templates', req, 'POST') + + req = json.dumps({'name': 'test-tmpl2', 'cdrom': mockiso}) + self.request('/plugins/kimchi/templates', req, 'POST') + + # Remove mock iso + os.unlink(mockiso) + + # Get the templates + resp = self.request('/plugins/kimchi/templates') + self.assertEquals(200, resp.status) + res = json.loads(resp.read()) + self.assertEquals(2, len(res)) + + # Get a specific template + resp = self.request('/plugins/kimchi/templates?name=test-tmpl1') + self.assertEquals(200, resp.status) + res = json.loads(resp.read()) + self.assertEquals(1, len(res)) + self.assertEquals('test-tmpl1', res[0]['name']) diff --git a/src/wok/plugins/kimchi/tests/test_storagepoolxml.py b/src/wok/plugins/kimchi/tests/test_storagepoolxml.py new file mode 100644 index 0000000..7e45cca --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_storagepoolxml.py @@ -0,0 +1,171 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import lxml.etree as ET +import unittest + +from wok.plugins.kimchi.model.libvirtstoragepool import StoragePoolDef + + +class StoragepoolXMLTests(unittest.TestCase): + def test_get_storagepool_xml(self): + poolDefs = [ + {'def': + {'type': 'dir', + 'name': 'unitTestDirPool', + 'path': '/var/temp/images'}, + 'xml': + """ + <pool type='dir'> + <name>unitTestDirPool</name> + <target> + <path>/var/temp/images</path> + </target> + </pool> + """}, + {'def': + {'type': 'netfs', + 'name': 'unitTestNFSPool', + 'source': {'host': '127.0.0.1', + 'path': '/var/export'}}, + 'xml': + """ + <pool type='netfs'> + <name>unitTestNFSPool</name> + <source> + <host name='127.0.0.1'/> + <dir path='/var/export'/> + </source> + <target> + <path>/var/lib/kimchi/nfs_mount/unitTestNFSPool</path> + </target> + </pool> + """}, + {'def': + {'type': 'logical', + 'name': 'unitTestLogicalPool', + 'source': {'devices': ['/dev/hda', '/dev/hdb']}}, + 'xml': + """ + <pool type='logical'> + <name>unitTestLogicalPool</name> + <source> + <device path="/dev/hda" /> + <device path="/dev/hdb" /> + </source> + <target> + <path>/dev/unitTestLogicalPool</path> + </target> + </pool> + """}, + {'def': + {'type': 'iscsi', + 'name': 'unitTestISCSIPool', + 'source': { + 'host': '127.0.0.1', + 'target': 'iqn.2003-01.org.linux-iscsi.localhost'}}, + 'xml': + """ + <pool type='iscsi'> + <name>unitTestISCSIPool</name> + <source> + <host name='127.0.0.1' /> + <device path='iqn.2003-01.org.linux-iscsi.localhost'/> + </source> + <target> + <path>/dev/disk/by-id</path> + </target> + </pool> + """}, + {'def': + {'type': 'iscsi', + 'name': 'unitTestISCSIPoolPort', + 'source': { + 'host': '127.0.0.1', + 'port': 3266, + 'target': 'iqn.2003-01.org.linux-iscsi.localhost'}}, + 'xml': + """ + <pool type='iscsi'> + <name>unitTestISCSIPoolPort</name> + <source> + <host name='127.0.0.1' port='3266' /> + <device path='iqn.2003-01.org.linux-iscsi.localhost'/> + </source> + <target> + <path>/dev/disk/by-id</path> + </target> + </pool> + """}, + {'def': + {'type': 'iscsi', + 'name': 'unitTestISCSIPoolAuth', + 'source': { + 'host': '127.0.0.1', + 'target': 'iqn.2003-01.org.linux-iscsi.localhost', + 'auth': {'username': 'testUser', + 'password': 'ActuallyNotUsedInPoolXML'}}}, + 'xml': + """ + <pool type='iscsi'> + <name>unitTestISCSIPoolAuth</name> + <source> + <host name='127.0.0.1' /> + <device path='iqn.2003-01.org.linux-iscsi.localhost'/> + <auth type='chap' username='testUser'> + <secret type='iscsi' usage='unitTestISCSIPoolAuth'/> + </auth> + </source> + <target> + <path>/dev/disk/by-id</path> + </target> + </pool> + """}, + {'def': + {'type': 'scsi', + 'name': 'unitTestSCSIFCPool', + 'path': '/dev/disk/by-path', + 'source': { + 'name': 'scsi_host3', + 'adapter': { + 'type': 'fc_host', + 'wwpn': '0123456789abcdef', + 'wwnn': 'abcdef0123456789'}}}, + 'xml': + """ + <pool type='scsi'> + <name>unitTestSCSIFCPool</name> + <source> + <adapter type='fc_host' name='scsi_host3' + wwnn='abcdef0123456789' wwpn='0123456789abcdef'></adapter> + </source> + <target> + <path>/dev/disk/by-path</path> + </target> + </pool> + """}] + + for poolDef in poolDefs: + defObj = StoragePoolDef.create(poolDef['def']) + xmlStr = defObj.xml + + parser = ET.XMLParser(remove_blank_text=True) + t1 = ET.fromstring(xmlStr, parser) + t2 = ET.fromstring(poolDef['xml'], parser) + self.assertEquals(ET.tostring(t1), ET.tostring(t2)) diff --git a/src/wok/plugins/kimchi/tests/test_template.py b/src/wok/plugins/kimchi/tests/test_template.py new file mode 100644 index 0000000..c7de182 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_template.py @@ -0,0 +1,387 @@ +# -*- coding: utf-8 -*- +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +import unittest +from functools import partial + +from wok.plugins.kimchi.config import READONLY_POOL_TYPE +from wok.plugins.kimchi.mockmodel import MockModel + +from utils import get_free_port, patch_auth, request, run_server + + +model = None +test_server = None +host = None +port = None +ssl_port = None +cherrypy_port = None + + +def setUpModule(): + global test_server, model, host, port, ssl_port, cherrypy_port + + patch_auth() + model = MockModel('/tmp/obj-store-test') + host = '127.0.0.1' + port = get_free_port('http') + ssl_port = get_free_port('https') + cherrypy_port = get_free_port('cherrypy_port') + test_server = run_server(host, port, ssl_port, test_mode=True, + cherrypy_port=cherrypy_port, model=model) + + +def tearDownModule(): + test_server.stop() + os.unlink('/tmp/obj-store-test') + + +class TemplateTests(unittest.TestCase): + def setUp(self): + self.request = partial(request, host, ssl_port) + model.reset() + + def test_tmpl_lifecycle(self): + resp = self.request('/plugins/kimchi/templates') + self.assertEquals(200, resp.status) + self.assertEquals(0, len(json.loads(resp.read()))) + + # Create a template without cdrom and disk specified fails with 400 + t = {'name': 'test', 'os_distro': 'ImagineOS', + 'os_version': '1.0', 'memory': 1024, 'cpus': 1, + 'storagepool': '/plugins/kimchi/storagepools/alt'} + req = json.dumps(t) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(400, resp.status) + + # Create a template + t = {'name': 'test', 'cdrom': '/tmp/mock.iso'} + req = json.dumps(t) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Verify the template + keys = ['name', 'icon', 'invalid', 'os_distro', 'os_version', 'cpus', + 'memory', 'cdrom', 'disks', 'storagepool', 'networks', + 'folder', 'graphics', 'cpu_info'] + tmpl = json.loads( + self.request('/plugins/kimchi/templates/test').read() + ) + self.assertEquals(sorted(tmpl.keys()), sorted(keys)) + + # Verify if default disk format was configured + self.assertEquals(tmpl['disks'][0]['format'], 'qcow2') + + # Clone a template + resp = self.request('/plugins/kimchi/templates/test/clone', '{}', + 'POST') + self.assertEquals(303, resp.status) + + # Verify the cloned template + tmpl_cloned = json.loads( + self.request('/plugins/kimchi/templates/test-clone1').read() + ) + del tmpl['name'] + del tmpl_cloned['name'] + self.assertEquals(tmpl, tmpl_cloned) + + # Delete the cloned template + resp = self.request('/plugins/kimchi/templates/test-clone1', '{}', + 'DELETE') + self.assertEquals(204, resp.status) + + # Create a template with same name fails with 400 + req = json.dumps({'name': 'test', 'cdrom': '/tmp/mock.iso'}) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(400, resp.status) + + # Create an image based template + open('/tmp/mock.img', 'w').close() + t = {'name': 'test_img_template', + 'disks': [{'base': '/tmp/mock.img'}]} + req = json.dumps(t) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + os.remove('/tmp/mock.img') + + # Test disk format + t = {'name': 'test-format', 'cdrom': '/tmp/mock.iso', + 'disks': [{'index': 0, 'size': 10, 'format': 'vmdk'}]} + req = json.dumps(t) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + tmpl = json.loads( + self.request('/plugins/kimchi/templates/test-format').read() + ) + self.assertEquals(tmpl['disks'][0]['format'], 'vmdk') + + def test_customized_tmpl(self): + # Create a template + t = {'name': 'test', 'cdrom': '/tmp/mock.iso'} + req = json.dumps(t) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + tmpl = json.loads( + self.request('/plugins/kimchi/templates/test').read() + ) + + # Update name + new_name = u'k������h��Tmpl' + new_tmpl_uri = '/plugins/kimchi/templates/%s' \ + % new_name.encode('utf-8') + req = json.dumps({'name': new_name}) + resp = self.request('/plugins/kimchi/templates/test', req, 'PUT') + self.assertEquals(303, resp.status) + resp = self.request(new_tmpl_uri) + update_tmpl = json.loads(resp.read()) + self.assertEquals(new_name, update_tmpl['name']) + del tmpl['name'] + del update_tmpl['name'] + self.assertEquals(tmpl, update_tmpl) + + # Update icon + req = json.dumps({'icon': 'kimchi/images/icon-fedora.png'}) + resp = self.request(new_tmpl_uri, req, 'PUT') + self.assertEquals(200, resp.status) + update_tmpl = json.loads(resp.read()) + self.assertEquals('kimchi/images/icon-fedora.png', update_tmpl['icon']) + + # Update os_distro and os_version + req = json.dumps({'os_distro': 'fedora', 'os_version': '21'}) + resp = self.request(new_tmpl_uri, req, 'PUT') + self.assertEquals(200, resp.status) + update_tmpl = json.loads(resp.read()) + self.assertEquals('fedora', update_tmpl['os_distro']) + self.assertEquals('21', update_tmpl['os_version']) + + # Update cpus + req = json.dumps({'cpus': 2}) + resp = self.request(new_tmpl_uri, req, 'PUT') + self.assertEquals(200, resp.status) + update_tmpl = json.loads(resp.read()) + self.assertEquals(2, update_tmpl['cpus']) + + # Update memory + req = json.dumps({'memory': 2048}) + resp = self.request(new_tmpl_uri, req, 'PUT') + self.assertEquals(200, resp.status) + update_tmpl = json.loads(resp.read()) + self.assertEquals(2048, update_tmpl['memory']) + + # Update cpu_info + resp = self.request(new_tmpl_uri) + cpu_info = json.loads(resp.read())['cpu_info'] + self.assertEquals(cpu_info, {}) + self.assertEquals(cpu_info.get('topology'), None) + + cpu_info_data = {'cpu_info': {'topology': {'sockets': 1, + 'cores': 2, + 'threads': 1}}} + resp = self.request(new_tmpl_uri, json.dumps(cpu_info_data), 'PUT') + self.assertEquals(200, resp.status) + update_tmpl = json.loads(resp.read()) + self.assertEquals(update_tmpl['cpu_info'], cpu_info_data['cpu_info']) + + # Update cdrom + cdrom_data = {'cdrom': '/tmp/mock2.iso'} + resp = self.request(new_tmpl_uri, json.dumps(cdrom_data), 'PUT') + self.assertEquals(200, resp.status) + update_tmpl = json.loads(resp.read()) + self.assertEquals(update_tmpl['cdrom'], cdrom_data['cdrom']) + + # Update disks + disk_data = {'disks': [{'index': 0, 'size': 10}, + {'index': 1, 'size': 20}]} + resp = self.request(new_tmpl_uri, json.dumps(disk_data), 'PUT') + self.assertEquals(200, resp.status) + resp = self.request(new_tmpl_uri) + self.assertEquals(200, resp.status) + updated_tmpl = json.loads(resp.read()) + self.assertEquals(updated_tmpl['disks'], disk_data['disks']) + + # For all supported types, edit the template and check if + # the change was made. + disk_types = ['bochs', 'cloop', 'cow', 'dmg', 'qcow', 'qcow2', + 'qed', 'raw', 'vmdk', 'vpc'] + for disk_type in disk_types: + disk_data = {'disks': [{'index': 0, 'format': disk_type, + 'size': 10}]} + resp = self.request(new_tmpl_uri, json.dumps(disk_data), 'PUT') + self.assertEquals(200, resp.status) + + resp = self.request(new_tmpl_uri) + self.assertEquals(200, resp.status) + updated_tmpl = json.loads(resp.read()) + self.assertEquals(updated_tmpl['disks'], disk_data['disks']) + + # Update folder + folder_data = {'folder': ['mock', 'isos']} + resp = self.request(new_tmpl_uri, json.dumps(folder_data), 'PUT') + self.assertEquals(200, resp.status) + update_tmpl = json.loads(resp.read()) + self.assertEquals(update_tmpl['folder'], folder_data['folder']) + + # Update graphics + req = json.dumps({'graphics': {'type': 'spice'}}) + resp = self.request(new_tmpl_uri, req, 'PUT') + self.assertEquals(200, resp.status) + update_tmpl = json.loads(resp.read()) + self.assertEquals('spice', update_tmpl['graphics']['type']) + + req = json.dumps({'graphics': {'type': 'vnc', 'listen': 'fe00::0'}}) + resp = self.request(new_tmpl_uri, req, 'PUT') + self.assertEquals(200, resp.status) + update_tmpl = json.loads(resp.read()) + self.assertEquals('vnc', update_tmpl['graphics']['type']) + self.assertEquals('fe00::0', update_tmpl['graphics']['listen']) + + def test_customized_network(self): + # Create a template + t = {'name': 'test', 'cdrom': '/tmp/mock.iso'} + req = json.dumps(t) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Create networks to be used for testing + networks = [{'name': u'k������h��-��et', 'connection': 'isolated'}, + {'name': u'nat-network', 'connection': 'nat'}, + {'name': u'subnet-network', 'connection': 'nat', + 'subnet': '127.0.100.0/24'}] + + # Verify the current system has at least one interface to create a + # bridged network + interfaces = json.loads( + self.request('/plugins/kimchi/interfaces?type=nic').read() + ) + if len(interfaces) > 0: + iface = interfaces[0]['name'] + networks.append({'name': u'bridge-network', 'connection': 'bridge', + 'interface': iface}) + networks.append({'name': u'bridge-network', 'connection': 'bridge', + 'interface': iface, 'vlan_id': 987}) + + tmpl_nets = [] + for net in networks: + self.request('/plugins/kimchi/networks', json.dumps(net), 'POST') + tmpl_nets.append(net['name']) + req = json.dumps({'networks': tmpl_nets}) + resp = self.request('/plugins/kimchi/templates/test', req, 'PUT') + self.assertEquals(200, resp.status) + + def test_customized_storagepool(self): + # Create a template + t = {'name': 'test', 'cdrom': '/tmp/mock.iso'} + req = json.dumps(t) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # MockModel always returns 2 partitions (vdx, vdz) + partitions = json.loads( + self.request('/plugins/kimchi/host/partitions').read() + ) + devs = [dev['path'] for dev in partitions] + + # MockModel always returns 3 FC devices + fc_devs = json.loads( + self.request('/plugins/kimchi/host/devices?_cap=fc_host').read() + ) + fc_devs = [dev['name'] for dev in fc_devs] + + poolDefs = [ + {'type': 'dir', 'name': u'k������h��UnitTestDirPool', + 'path': '/tmp/kimchi-images'}, + {'type': 'netfs', 'name': u'k������h��UnitTestNSFPool', + 'source': {'host': 'localhost', + 'path': '/var/lib/kimchi/nfs-pool'}}, + {'type': 'scsi', 'name': u'k������h��UnitTestSCSIFCPool', + 'source': {'adapter_name': fc_devs[0]}}, + {'type': 'iscsi', 'name': u'k������h��UnitTestISCSIPool', + 'source': {'host': '127.0.0.1', + 'target': 'iqn.2015-01.localhost.kimchiUnitTest'}}, + {'type': 'logical', 'name': u'k������h��UnitTestLogicalPool', + 'source': {'devices': [devs[0]]}}] + + for pool in poolDefs: + self.request('/plugins/kimchi/storagepools', json.dumps(pool), + 'POST') + pool_uri = '/plugins/kimchi/storagepools/%s' \ + % pool['name'].encode('utf-8') + self.request(pool_uri + '/activate', '{}', 'POST') + + req = None + if pool['type'] in READONLY_POOL_TYPE: + resp = self.request(pool_uri + '/storagevolumes') + vols = json.loads(resp.read()) + if len(vols) > 0: + vol = vols[0]['name'] + req = json.dumps({'storagepool': pool_uri, + 'disks': [{'volume': vol}]}) + else: + req = json.dumps({'storagepool': pool_uri}) + + if req is not None: + resp = self.request('/plugins/kimchi/templates/test', req, + 'PUT') + self.assertEquals(200, resp.status) + + def test_tmpl_integrity(self): + # Create a network and a pool for testing template integrity + net = {'name': u'nat-network', 'connection': 'nat'} + self.request('/plugins/kimchi/networks', json.dumps(net), 'POST') + + pool = {'type': 'dir', 'name': 'dir-pool', 'path': '/tmp/dir-pool'} + self.request('/plugins/kimchi/storagepools', json.dumps(pool), 'POST') + pool_uri = '/plugins/kimchi/storagepools/%s' \ + % pool['name'].encode('utf-8') + self.request(pool_uri + '/activate', '{}', 'POST') + + # Create a template using the custom network and pool + t = {'name': 'test', 'cdrom': '/tmp/mock.iso', + 'networks': ['nat-network'], + 'storagepool': '/plugins/kimchi/storagepools/dir-pool'} + req = json.dumps(t) + resp = self.request('/plugins/kimchi/templates', req, 'POST') + self.assertEquals(201, resp.status) + + # Try to delete network + # It should fail as it is associated to a template + resp = self.request('/plugins/kimchi/networks/nat-network', '{}', + 'DELETE') + self.assertIn("KCHNET0017E", json.loads(resp.read())["reason"]) + + # Update template to release network and then delete it + params = {'networks': []} + req = json.dumps(params) + self.request('/plugins/kimchi/templates/test', req, 'PUT') + resp = self.request('/plugins/kimchi/networks/nat-network', '{}', + 'DELETE') + self.assertEquals(204, resp.status) + + # Try to delete the storagepool + # It should fail as it is associated to a template + resp = self.request('/plugins/kimchi/storagepools/dir-pool', '{}', + 'DELETE') + self.assertEquals(400, resp.status) + + # Verify the template + res = json.loads(self.request('/plugins/kimchi/templates/test').read()) + self.assertEquals(res['invalid']['cdrom'], ['/tmp/mock.iso']) diff --git a/src/wok/plugins/kimchi/tests/test_utils.py b/src/wok/plugins/kimchi/tests/test_utils.py new file mode 100644 index 0000000..bcb14e2 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_utils.py @@ -0,0 +1,69 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import unittest + +from wok.exception import InvalidParameter +from wok.utils import convert_data_size + + +class UtilsTests(unittest.TestCase): + def test_convert_data_size(self): + failure_data = [{'val': None, 'from': 'MiB'}, + {'val': self, 'from': 'MiB'}, + {'val': 1, 'from': None}, + {'val': 1, 'from': ''}, + {'val': 1, 'from': 'foo'}, + {'val': 1, 'from': 'kib'}, + {'val': 1, 'from': 'MiB', 'to': None}, + {'val': 1, 'from': 'MiB', 'to': ''}, + {'val': 1, 'from': 'MiB', 'to': 'foo'}, + {'val': 1, 'from': 'MiB', 'to': 'kib'}] + + for d in failure_data: + if 'to' in d: + self.assertRaises(InvalidParameter, convert_data_size, + d['val'], d['from'], d['to']) + else: + self.assertRaises(InvalidParameter, convert_data_size, + d['val'], d['from']) + + success_data = [{'got': convert_data_size(5, 'MiB', 'MiB'), + 'want': 5}, + {'got': convert_data_size(5, 'MiB', 'KiB'), + 'want': 5120}, + {'got': convert_data_size(5, 'MiB', 'M'), + 'want': 5.24288}, + {'got': convert_data_size(5, 'MiB', 'GiB'), + 'want': 0.0048828125}, + {'got': convert_data_size(5, 'MiB', 'Tb'), + 'want': 4.194304e-05}, + {'got': convert_data_size(5, 'KiB', 'MiB'), + 'want': 0.0048828125}, + {'got': convert_data_size(5, 'M', 'MiB'), + 'want': 4.76837158203125}, + {'got': convert_data_size(5, 'GiB', 'MiB'), + 'want': 5120}, + {'got': convert_data_size(5, 'Tb', 'MiB'), + 'want': 596046.4477539062}, + {'got': convert_data_size(5, 'MiB'), + 'want': convert_data_size(5, 'MiB', 'B')}] + + for d in success_data: + self.assertEquals(d['got'], d['want']) diff --git a/src/wok/plugins/kimchi/tests/test_vmtemplate.py b/src/wok/plugins/kimchi/tests/test_vmtemplate.py new file mode 100644 index 0000000..0bca215 --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_vmtemplate.py @@ -0,0 +1,116 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import unittest +import uuid + +from wok.xmlutils.utils import xpath_get_text + +from wok.plugins.kimchi.osinfo import get_template_default +from wok.plugins.kimchi.vmtemplate import VMTemplate + + +class VMTemplateTests(unittest.TestCase): + def setUp(self): + self.iso = '/tmp/mock.iso' + open(self.iso, 'w').close() + + def tearDown(self): + os.unlink(self.iso) + + def test_minimal_construct(self): + disk_bus = get_template_default('old', 'disk_bus') + memory = get_template_default('old', 'memory') + nic_model = get_template_default('old', 'nic_model') + fields = (('name', 'test'), ('os_distro', 'unknown'), + ('os_version', 'unknown'), ('cpus', 1), + ('memory', memory), ('networks', ['default']), + ('disk_bus', disk_bus), ('nic_model', nic_model), + ('graphics', {'type': 'vnc', 'listen': '127.0.0.1'}), + ('cdrom', self.iso)) + + args = {'name': 'test', 'cdrom': self.iso} + t = VMTemplate(args) + for name, val in fields: + self.assertEquals(val, t.info.get(name)) + + def test_construct_overrides(self): + graphics = {'type': 'spice', 'listen': '127.0.0.1'} + args = {'name': 'test', 'disks': [{'size': 10}, {'size': 20}], + 'graphics': graphics, "cdrom": self.iso} + t = VMTemplate(args) + self.assertEquals(2, len(t.info['disks'])) + self.assertEquals(graphics, t.info['graphics']) + + def test_specified_graphics(self): + # Test specified listen + graphics = {'type': 'vnc', 'listen': '127.0.0.1'} + args = {'name': 'test', 'disks': [{'size': 10}, {'size': 20}], + 'graphics': graphics, 'cdrom': self.iso} + t = VMTemplate(args) + self.assertEquals(graphics, t.info['graphics']) + + # Test specified type + graphics = {'type': 'spice', 'listen': '127.0.0.1'} + args['graphics'] = graphics + t = VMTemplate(args) + self.assertEquals(graphics, t.info['graphics']) + + # If no listen specified, test the default listen + graphics = {'type': 'vnc'} + args['graphics'] = graphics + t = VMTemplate(args) + self.assertEquals(graphics['type'], t.info['graphics']['type']) + self.assertEquals('127.0.0.1', t.info['graphics']['listen']) + + def test_to_xml(self): + graphics = {'type': 'spice', 'listen': '127.0.0.1'} + vm_uuid = str(uuid.uuid4()).replace('-', '') + if os.uname()[4] in ['ppc', 'ppc64', 'ppc64le']: + maxmem = 3328 + else: + maxmem = 3072 + t = VMTemplate({'name': 'test-template', 'cdrom': self.iso, + 'max_memory': maxmem << 10}) + xml = t.to_vm_xml('test-vm', vm_uuid, graphics=graphics) + self.assertEquals(vm_uuid, xpath_get_text(xml, "/domain/uuid")[0]) + self.assertEquals('test-vm', xpath_get_text(xml, "/domain/name")[0]) + expr = "/domain/devices/graphics/@type" + self.assertEquals(graphics['type'], xpath_get_text(xml, expr)[0]) + expr = "/domain/devices/graphics/@listen" + self.assertEquals(graphics['listen'], xpath_get_text(xml, expr)[0]) + expr = "/domain/maxMemory/@slots" + self.assertEquals('2', xpath_get_text(xml, expr)[0]) + + def test_arg_merging(self): + """ + Make sure that default parameters from osinfo do not override user- + provided parameters. + """ + graphics = {'type': 'vnc', 'listen': '127.0.0.1'} + args = {'name': 'test', 'os_distro': 'opensuse', 'os_version': '12.3', + 'cpus': 2, 'memory': 2048, 'networks': ['foo'], + 'cdrom': self.iso, 'graphics': graphics} + t = VMTemplate(args) + self.assertEquals(2, t.info.get('cpus')) + self.assertEquals(2048, t.info.get('memory')) + self.assertEquals(['foo'], t.info.get('networks')) + self.assertEquals(self.iso, t.info.get('cdrom')) + self.assertEquals(graphics, t.info.get('graphics')) diff --git a/src/wok/plugins/kimchi/tests/test_yumparser.py b/src/wok/plugins/kimchi/tests/test_yumparser.py new file mode 100644 index 0000000..be5e95c --- /dev/null +++ b/src/wok/plugins/kimchi/tests/test_yumparser.py @@ -0,0 +1,162 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import tempfile +import unittest + +from wok.rollbackcontext import RollbackContext + +from wok.plugins.kimchi.model import model +from wok.plugins.kimchi.yumparser import delete_repo_from_file, get_repo_files +from wok.plugins.kimchi.yumparser import get_yum_packages_list_update +from wok.plugins.kimchi.yumparser import get_yum_repositories +from wok.plugins.kimchi.yumparser import write_repo_to_file, YumRepoObject + + +TEMP_REPO_FILE = '' + + +def _is_yum_distro(): + inst = model.Model('test:///default') + repo_type = inst.capabilities_lookup()['repo_mngt_tool'] + return repo_type == 'yum' + + +def _create_fake_repos(repo_file_name): + repo1 = YumRepoObject('fake-repo-1', repo_file_name) + repo2 = YumRepoObject('fake-repo-2', repo_file_name) + repo3 = YumRepoObject('fake-repo-3', repo_file_name) + repo4 = YumRepoObject('fake-repo-4', repo_file_name) + repos = [repo1, repo2, repo3, repo4] + return repos + + +def _create_empty_repo_file(): + data = """ +# +# This is a repository file with no repositories at all +# No repositories must be added after reading this file. +# + """ + _, tmp_file_name = tempfile.mkstemp(suffix='.repo', + dir='/etc/yum.repos.d') + with open(tmp_file_name, 'w') as f: + f.writelines(data) + + return tmp_file_name + + +def _create_fake_repos_file(): + _, tmp_file_name = tempfile.mkstemp(suffix='.repo', + dir='/etc/yum.repos.d') + + fake_repos = _create_fake_repos(tmp_file_name) + file_data = '' + for repo in fake_repos: + file_data += str(repo) + '\n' + + with open(tmp_file_name, 'w') as f: + f.writelines(file_data) + + return tmp_file_name + + +def _generate_yumcheckupdate_output(): + output = """ +Repository 'REPOSITORY1' is missing name in configuration, using id +Repository 'REPOSITORY1-OPTIONAL' is missing name in configuration, using id + +PACKAGE1.noarch 20150611.-gg-FAKE1 REPOSITORY1 +PACKAGE2.x86_64 20150611.-no-FAKE2 REPOSITORY2 +PACKAGE3.dot.dot.i386 20150611.-re-FAKE3 REPOSITORY3 + +Obsoleting Packages +OBSOLETE4.dot.dot.i386 20150611.FAKE4 REPOSITORY4 +OBSOLETE5.dot.dot.fakearch 20150611.FAKE5 REPOSITORY5 + """ + return output + + +@unittest.skipIf(not _is_yum_distro(), 'Skipping: YUM exclusive test') +def setUpModule(): + global TEMP_REPO_FILE + TEMP_REPO_FILE = _create_fake_repos_file() + + +@unittest.skipIf(not _is_yum_distro(), 'Skipping: YUM exclusive test') +def tearDownModule(): + os.remove(TEMP_REPO_FILE) + + +@unittest.skipIf(not _is_yum_distro(), 'Skipping: YUM exclusive test') +class YumParserTests(unittest.TestCase): + + def test_get_yum_repositories(self): + repo_files = get_repo_files() + repo_objects = get_yum_repositories() + self.assertGreaterEqual(len(repo_objects), len(repo_files)) + + def test_empty_repo_file(self): + with RollbackContext() as rollback: + repos = get_yum_repositories() + tmp_file_name = _create_empty_repo_file() + rollback.prependDefer(os.remove, tmp_file_name) + repos_after = get_yum_repositories() + self.assertEqual(len(repos_after), len(repos)) + + def test_update_repo_attributes(self): + repos = get_yum_repositories() + fake_repo_2 = repos['fake-repo-2'] + fake_repo_2.disable() + fake_repo_2.name = 'This is a fake repo' + fake_repo_2.baseurl = 'http://a.fake.repo.url' + fake_repo_2.gpgkey = 'file://a/fake/gpg/key.fake' + fake_repo_2.gpgcheck = False + fake_repo_2.metalink = 'this is not a true metalink' + fake_repo_2.mirrorlist = 'fake mirrorlist' + write_repo_to_file(fake_repo_2) + + repos = get_yum_repositories() + fake_repo_2 = repos['fake-repo-2'] + self.assertEqual(False, fake_repo_2.enabled) + self.assertEqual(False, fake_repo_2.gpgcheck) + self.assertEqual('This is a fake repo', fake_repo_2.name) + self.assertEqual('http://a.fake.repo.url', fake_repo_2.baseurl) + self.assertEqual('file://a/fake/gpg/key.fake', fake_repo_2.gpgkey) + self.assertEqual('this is not a true metalink', fake_repo_2.metalink) + self.assertEqual('fake mirrorlist', fake_repo_2.mirrorlist) + + def test_delete_repo_from_file(self): + repos = get_yum_repositories() + fake_repo_3 = repos['fake-repo-3'] + delete_repo_from_file(fake_repo_3) + + repos = get_yum_repositories() + repos_id = repos.keys() + self.assertNotIn('fake-repo-3', repos_id) + + def test_yum_checkupdate_parsing(self): + output = _generate_yumcheckupdate_output() + packages = get_yum_packages_list_update(output) + self.assertEqual(len(packages), 3) + self.assertEqual(packages[0].ui_from_repo, 'REPOSITORY1') + self.assertEqual(packages[1].version, '20150611.-no-FAKE2') + self.assertEqual(packages[2].name, 'PACKAGE3.dot.dot') + self.assertEqual(packages[2].arch, 'i386') diff --git a/src/wok/plugins/kimchi/tests/utils.py b/src/wok/plugins/kimchi/tests/utils.py new file mode 100644 index 0000000..ecaa87f --- /dev/null +++ b/src/wok/plugins/kimchi/tests/utils.py @@ -0,0 +1,260 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import base64 +import cherrypy +import grp +import httplib +import inspect +import json +import os +import socket +import ssl +import sys +import threading +import time +import unittest +from contextlib import closing +from lxml import etree + +import wok.server +from wok.config import config, PluginPaths +from wok.auth import User, USER_NAME, USER_GROUPS, USER_ROLES, tabs +from wok.exception import NotFoundError, OperationFailed +from wok.utils import wok_log + +from wok.plugins.kimchi import mockmodel + + +_ports = {} + +# provide missing unittest decorators and API for python 2.6; these decorators +# do not actually work, just avoid the syntax failure +if sys.version_info[:2] == (2, 6): + def skipUnless(condition, reason): + if not condition: + sys.stderr.write('[expected failure] ') + raise Exception(reason) + return lambda obj: obj + + unittest.skipUnless = skipUnless + unittest.expectedFailure = lambda obj: obj + + def assertGreater(self, a, b, msg=None): + if not a > b: + self.fail('%s not greater than %s' % (repr(a), repr(b))) + + def assertGreaterEqual(self, a, b, msg=None): + if not a >= b: + self.fail('%s not greater than or equal to %s' + % (repr(a), repr(b))) + + def assertIsInstance(self, obj, cls, msg=None): + if not isinstance(obj, cls): + self.fail('%s is not an instance of %r' % (repr(obj), cls)) + + def assertIn(self, a, b, msg=None): + if a not in b: + self.fail("%s is not in %b" % (repr(a), repr(b))) + + def assertNotIn(self, a, b, msg=None): + if a in b: + self.fail("%s is in %b" % (repr(a), repr(b))) + + unittest.TestCase.assertGreaterEqual = assertGreaterEqual + unittest.TestCase.assertGreater = assertGreater + unittest.TestCase.assertIsInstance = assertIsInstance + unittest.TestCase.assertIn = assertIn + unittest.TestCase.assertNotIn = assertNotIn + + +def get_free_port(name='http'): + global _ports + if _ports.get(name) is not None: + return _ports[name] + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + with closing(sock): + try: + sock.bind(("0.0.0.0", 0)) + except: + raise Exception("Could not find a free port") + _ports[name] = sock.getsockname()[1] + return _ports[name] + + +def run_server(host, port, ssl_port, test_mode, cherrypy_port=None, + model=None, environment='development'): + + if cherrypy_port is None: + cherrypy_port = get_free_port('cherrypy_port') + + if ssl_port is None: + ssl_port = get_free_port('https') + + args = type('_', (object,), + {'host': host, 'port': port, 'ssl_port': ssl_port, + 'cherrypy_port': cherrypy_port, 'max_body_size': '4*1024', + 'ssl_cert': '', 'ssl_key': '', + 'test': test_mode, 'access_log': '/dev/null', + 'error_log': '/dev/null', 'environment': environment, + 'log_level': 'debug'})() + if model is not None: + setattr(args, 'model', model) + + s = wok.server.Server(args) + t = threading.Thread(target=s.start) + t.setDaemon(True) + t.start() + cherrypy.engine.wait(cherrypy.engine.states.STARTED) + return s + + +def silence_server(): + """ + Silence server status messages on stdout + """ + cherrypy.config.update({"environment": "embedded"}) + + +def running_as_root(): + return os.geteuid() == 0 + + +def _request(conn, path, data, method, headers): + if headers is None: + headers = {'Content-Type': 'application/json', + 'Accept': 'application/json'} + if 'AUTHORIZATION' not in headers.keys(): + user, pw = mockmodel.fake_user.items()[0] + hdr = "Basic " + base64.b64encode("%s:%s" % (user, pw)) + headers['AUTHORIZATION'] = hdr + conn.request(method, path, data, headers) + return conn.getresponse() + + +def request(host, port, path, data=None, method='GET', headers=None): + # verify if HTTPSConnection has context parameter + if "context" in inspect.getargspec(httplib.HTTPSConnection.__init__).args: + context = ssl._create_unverified_context() + conn = httplib.HTTPSConnection(host, port, context=context) + else: + conn = httplib.HTTPSConnection(host, port) + + return _request(conn, path, data, method, headers) + + +def get_remote_iso_path(): + """ + Get a remote iso with the right arch from the distro files shipped + with kimchi. + """ + host_arch = os.uname()[4] + remote_path = '' + with open(os.path.join(PluginPaths('kimchi').conf_dir, 'distros.d', + 'fedora.json')) as fedora_isos: + # Get a list of dicts + json_isos_list = json.load(fedora_isos) + for iso in json_isos_list: + if (iso.get('os_arch')) == host_arch: + remote_path = iso.get('path') + break + + return remote_path + + +class FakeUser(User): + auth_type = "fake" + sudo = True + + def __init__(self, username): + self.user = {} + self.user[USER_NAME] = username + self.user[USER_GROUPS] = None + self.user[USER_ROLES] = dict.fromkeys(tabs, 'user') + + def get_groups(self): + return sorted([group.gr_name for group in grp.getgrall()])[0:3] + + def get_roles(self): + if self.sudo: + self.user[USER_ROLES] = dict.fromkeys(tabs, 'admin') + return self.user[USER_ROLES] + + def get_user(self): + return self.user + + @staticmethod + def authenticate(username, password, service="passwd"): + try: + return mockmodel.fake_user[username] == password + except KeyError, e: + raise OperationFailed("WOKAUTH0001E", {'username': 'username', + 'code': e.message}) + + +def patch_auth(sudo=True): + """ + Override the authenticate function with a simple test against an + internal dict of users and passwords. + """ + config.set("authentication", "method", "fake") + FakeUser.sudo = sudo + + +def normalize_xml(xml_str): + return etree.tostring(etree.fromstring(xml_str, + etree.XMLParser(remove_blank_text=True))) + + +def wait_task(task_lookup, taskid, timeout=10): + for i in range(0, timeout): + task_info = task_lookup(taskid) + if task_info['status'] == "running": + wok_log.info("Waiting task %s, message: %s", + taskid, task_info['message']) + time.sleep(1) + else: + return + wok_log.error("Timeout while process long-run task, " + "try to increase timeout value.") + + +# The action functions in model backend raise NotFoundError exception if the +# element is not found. But in some tests, these functions are called after +# the element has been deleted if test finishes correctly, then NofFoundError +# exception is raised and rollback breaks. To avoid it, this wrapper ignores +# the NotFoundError. +def rollback_wrapper(func, resource, *args): + try: + func(resource, *args) + except NotFoundError: + # VM has been deleted already + return + + +# This function is used to test storage volume upload. +# If we use self.request, we may encode multipart formdata by ourselves +# requests lib take care of encode part, so use this lib instead +def fake_auth_header(): + headers = {'Accept': 'application/json'} + user, pw = mockmodel.fake_user.items()[0] + hdr = "Basic " + base64.b64encode("%s:%s" % (user, pw)) + headers['AUTHORIZATION'] = hdr + return headers diff --git a/src/wok/plugins/kimchi/ui/Makefile.am b/src/wok/plugins/kimchi/ui/Makefile.am new file mode 100644 index 0000000..21fe703 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/Makefile.am @@ -0,0 +1,20 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SUBDIRS = config css images js pages spice-html5 + +uidir = $(datadir)/wok/plugins/kimchi/ui diff --git a/src/wok/plugins/kimchi/ui/config/Makefile.am b/src/wok/plugins/kimchi/ui/config/Makefile.am new file mode 100644 index 0000000..e3b3d19 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/config/Makefile.am @@ -0,0 +1,22 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +xmldir = $(datadir)/wok/plugins/kimchi/ui/config + +dist_xml_DATA = \ + tab-ext.xml \ + $(NULL) diff --git a/src/wok/plugins/kimchi/ui/config/tab-ext.xml b/src/wok/plugins/kimchi/ui/config/tab-ext.xml new file mode 100644 index 0000000..ee88c88 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/config/tab-ext.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<tabs-ext> + <tab> + <access role="admin" mode="admin"/> + <access role="user" mode="none"/> + + <title>Host</title> + <path>plugins/kimchi/host.html</path> + </tab> + <tab> + <access role="admin" mode="admin"/> + <access role="user" mode="byInstance"/> + + <title>Guests</title> + <path>plugins/kimchi/guests.html</path> + </tab> + <tab> + <access role="admin" mode="admin"/> + <access role="user" mode="none"/> + + <title>Templates</title> + <path>plugins/kimchi/templates.html</path> + </tab> + <tab> + <access role="admin" mode="admin"/> + <access role="user" mode="read-only"/> + + <title>Storage</title> + <path>plugins/kimchi/storage.html</path> + </tab> + <tab> + <access role="admin" mode="admin"/> + <access role="user" mode="read-only"/> + + <title>Network</title> + <path>plugins/kimchi/network.html</path> + </tab> +</tabs-ext> diff --git a/src/wok/plugins/kimchi/ui/css/Makefile.am b/src/wok/plugins/kimchi/ui/css/Makefile.am new file mode 100644 index 0000000..5071d29 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/Makefile.am @@ -0,0 +1,26 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +EXTRA_DIST = theme-default + +cssdir = $(datadir)/wok/plugins/kimchi/ui/css +dist_css_DATA = theme-default.min.css + +theme-default.min.css: theme-default/*.css + cat $^ > $@ + +CLEANFILES = theme-default.min.css diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/guest-edit.css b/src/wok/plugins/kimchi/ui/css/theme-default/guest-edit.css new file mode 100644 index 0000000..b661159 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/guest-edit.css @@ -0,0 +1,424 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#guest-edit-window { + font-size: 13px; + height: 420px; + width: 820px; +} + +#guest-edit-window #action-button-container { + padding-right: 0; +} + +#guest-edit-window #guest-edit-button-cancel { + margin-left: 10px; +} + +#guest-edit-tabs { + background: transparent; + border: none; + height: 100%; + padding: 0; +} + +#form-guest-edit-general { + padding: 1em; +} + +#form-guest-edit-general .edit-general-inline { + display: inline-block; +} + +#form-guest-edit-storage input[readonly] { + background: none; + border-color: transparent; + text-overflow: ellipsis; +} + +.guest-edit-fieldset { + padding-right: 0; +} + +.guest-edit-wrapper-label { + height: 30px; + line-height: 30px; + margin-top: 10px; + vertical-align: top; + min-width: 100px; + font-weight: lighter; + font-family: 'Helvetica Neue', Helvetica, Arial; +} + +#form-guest-edit-storage .guest-edit-wrapper-label { + width: 60px; +} + +.guest-edit-wrapper-controls { + width: 470px; + margin-top: 5px;�� +} + +#form-guest-edit-storage .guest-edit-wrapper-controls { + width: 486px; +} + +.guest-edit-wrapper-controls input[type="text"] { + font-size: 16px; + height: 30px; + width: 450px; + border: 1px solid #CCCCCC; +} + +.guest-edit-wrapper-controls input[type="text"][disabled] { + color: #bbb; + background-color: #fafafa; + cursor: not-allowed; + border: 1px solid #CCCCCC; +} + +.guest-edit-cdrom-row-container { + max-height: 180px; + overflow: auto; +} + +.guest-edit-cdrom-row-container input[type="text"] { + width: 400px; +} + +#form-guest-edit-storage .header, +.guest-edit-snapshot .header, +.guest-edit-interface .header, +#form-guest-edit-permission .ldap .header { + margin-bottom: 8px; + padding-bottom: 2px; + font-weight: bold; + border-bottom: 1px solid #999999; + overflow: hidden; +} + +#form-guest-edit-storage .body .item, +.guest-edit-snapshot .body .item, +.guest-edit-snapshot .task .item, +.guest-edit-interface .body .item { + margin: 5px 0; +} + +#form-guest-edit-storage .cell, +.guest-edit-interface .cell { + display: inline-block; + width: 200px; +} + +.guest-edit-snapshot .cell { + display: inline-block; +} + +.guest-edit-snapshot .sel { + width: 25px; + vertical-align: top; +} + +.guest-edit-snapshot .icon { + background: url('../images/theme-default/kimchi-loading15x15.gif') no-repeat; + display: block; + width: 16px; + height: 16px; + vertical-align: middle; + margin-left: 2px; +} + +.guest-edit-snapshot .name { + width: 400px; +} + +.guest-edit-snapshot .created { + width: 270px; +} + +#form-guest-edit-storage .cell.dev { + width: 60px; +} + +#form-guest-edit-storage .cell.path { + width: 440px; +} + +#form-guest-edit-storage .cell.dev input, +#form-guest-edit-storage .cell.path input { + box-sizing: border-box; + width: 100%; +} + +.guest-edit-interface .body select { + width: 180px; + padding: 0px; +} + +#form-guest-edit-storage .action-area, +.guest-edit-snapshot .action-area, +.guest-edit-interface .action-area { + float: right; +} + +#form-guest-edit-storage .action-area { + line-height: 24px; +} + +#form-guest-edit-storage button, +.guest-edit-snapshot button, +.guest-edit-interface button { + width: 20px; + height: 20px; +} + +#form-guest-edit-storage .body button:not(:last-child), +.guest-edit-interface .body button:not(:last-child) { + margin-right: 2px; +} + +.guest-edit-snapshot .hide, +.guest-edit-interface .hide { + display: none!important; +} + +.guest-edit-permission .pam { + height: 220px; + padding: 5px 10px!important; +} + +.guest-edit-permission .hide { + display: none; +} + +.guest-edit-permission .pam .column { + display: inline-block; + vertical-align: top; +} + +.guest-edit-permission .pam .title { + margin-bottom: 3px; +} + +.guest-edit-permission .pam input[type="text"] { + margin-bottom: 3px; + font-size: 12px; + width: 97%; +} + +.guest-edit-permission .pam .body { + border: 1px solid #999999; + font-size: 12px; + padding: 1px; + height: 192px; + overflow: auto; +} + +.guest-edit-permission .pam .body .head { + margin-bottom: 3px; + font-weight: bold; + background: linear-gradient(to bottom, #E5E5E5 0%, #C4C4C4 100%) repeat scroll 0 0 transparent; +} + +.guest-edit-permission .pam .body .item { + padding: 2px 3px; + margin-bottom: 1px; + cursor: pointer; +} + +.guest-edit-permission .pam .body .item:hover { + background-color: #AAAAAA; +} + +.guest-edit-permission .pam .body .item-picked { + background-color: #BBBBBB; +} + +.guest-edit-permission .pam .body .item .icon { + display: inline-block; + height: 15px; + width: 15px; + vertical-align: bottom; +} + +.guest-edit-permission .pam .body .item .user-icon { + background: url('../images/theme-default/user.png') no-repeat scroll; + background-size: 15px 15px; +} + +.guest-edit-permission .pam .body .item .group-icon { + background: url('../images/theme-default/group.png') no-repeat scroll; + background-size: 15px 15px; +} + +.guest-edit-permission .pam .body .column-user { + width: 48%; +} +.guest-edit-permission .pam .body .column-group { + width: 50%; +} + +.guest-edit-permission .pam .control { + width: 5%; +} + +.guest-edit-permission .pam .control button { + width: 26px; + margin-left: 7px; +} + +.guest-edit-permission .pam .control button:first-child { + margin-top: 110px; + margin-bottom: 2px; +} + +.guest-edit-permission .pam .control .ui-button-text-only .ui-button-text { + padding: 2px 8px; +} + +.guest-edit-permission .pam .avail { + width: 46%; +} + +.guest-edit-permission .pam .selected { + width: 46%; + float: right; +} + +#form-guest-edit-permission .ldap .body .item { + margin: 8px 0; +} + +#form-guest-edit-permission .ldap .cell { + width: 250px; +} + +#form-guest-edit-permission .ldap .action-area { + float: right; + line-height: 24px; +} + +#form-guest-edit-permission .ldap button { + width: 20px; + height: 20px; +} + +#form-guest-edit-permission input[type="text"] { + width: 300px; +} + +#form-guest-edit-permission .ldap .header button { + margin-bottom: 1px; +} + +#form-guest-edit-permission .ldap .checked { + border-color: red; + border-style: solid; + border-width: 1px; +} + +#form-guest-edit-permission .ldap .checked.hide { + display: none; +} + +.guest-edit-pci { + height: 79%; + overflow: auto; + font-size: 12px; +} + +.guest-edit-pci .guest-scroll-indent { + width: 783px; +} + +.guest-edit-pci .filter { + height: 35px; + margin-right: 5px; + overflow: hidden; +} + +.guest-edit-pci .group { + float: right; +} + +.guest-edit-pci .filter .control { + border: 1px solid #AAAAAA; + font-size: 12px; + background-color: white; +} + +.guest-edit-pci .filter select { + border-right: 0px!important; + border-radius: 7px 0px 0px 7px; + padding: 2px 2px 2px 7px; + width: 100px; + height: 24px; +} + +.guest-edit-pci .filter select option { + padding-left: 7px; +} + +.guest-edit-pci .filter input { + border-radius: 0px 7px 7px 0px; + padding: 3px 3px 3px 10px; + width: 200px; + height: 16px; + font-style: italic; +} + +.guest-edit-pci .header { + margin-bottom: 8px; + padding-bottom: 2px; + font-weight: bold; + border-bottom: 1px solid #999999; +} + +.guest-edit-pci .item { + margin-bottom: 4px; + overflow: hidden; +} + +.guest-edit-pci .cell { + display: inline-block; + vertical-align: middle; + margin-right: 10px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.guest-edit-pci .item button { + width: 20px; + height: 20px; + float: right; +} + +.guest-edit-pci .name { + width: 18%; + max-width: 18%; +} + +.guest-edit-pci .product { + width: 45%; + max-width: 45%; +} + +.guest-edit-pci .vendor { + width: 25%; + max-width: 25%; +} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/guest-storage-add.css b/src/wok/plugins/kimchi/ui/css/theme-default/guest-storage-add.css new file mode 100644 index 0000000..9cc41e8 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/guest-storage-add.css @@ -0,0 +1,81 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#guest-storage-add-window { + font-size: 13px; + height: 600px; + width: 700px; +} + +.guest-storage-add-fieldset { + padding: 1em; +} + +#guest-storage-add-window .btn { + width: 587px; +} + +#form-guest-storage-add .form-section .field { + overflow: visible; +} + +#guest-storage-add-window input[type="text"] { + font-size: 16px; + height: 38px; + background: #fff; + -webkit-border-radius: 5px; + border-radius: 5px; + box-shadow: 2px 2px 2px #eee inset; + border-top: 1px solid #bbb; + border-left: 1px solid #bbb; + padding-left: 10px; + width: 600px; +} + +#guest-storage-add-window input[type="text"][disabled] { + color: #bbb; + background-color: #fafafa; + cursor: not-allowed; +} + +.guest-storage-add-wrapper-label, .guest-storage-add-wrapper-controls { + display: inline-block; +} + +.guest-storage-add-wrapper-label { + height: 38px; + line-height: 38px; + margin-top: 5px; + vertical-align: top; + width: 80px; +} + +.guest-storage-add-wrapper-controls { + width: 470px; +} + +#vm-storage-button-add[disabled] { + background: #c0c0c0; + color: #ddd; + padding-left: 26px; +} + +#vm-storage-button-add.loading[disabled] { + background: url("../../images/theme-default/loading.gif") 7px center no-repeat #c0c0c0; + color: #ddd; + padding-left: 26px; +} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/host.css b/src/wok/plugins/kimchi/ui/css/theme-default/host.css new file mode 100644 index 0000000..a0cccb1 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/host.css @@ -0,0 +1,287 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.host-panel { + font-size: 12px; + margin-bottom: 100px; +} + +.host-panel .logo-container, .host-panel .info-container, +.host-panel .section-label, .host-panel .section-value { + display: inline-block; + vertical-align: top; +} + +.host-panel .section-label { + display: inline-block; + margin-right: 1em; + vertical-align: top; +} + +.host-panel .logo { + background: url("plugins/kimchi/images/icon-vm.png") no-repeat left top; + height: 128px; + width: 128px; +} + +.host-panel .hostname { + text-decoration: underline; +} + +.host-panel .action-panel { + margin-top: 2em; + padding-left: 10px; +} + +.host-panel .button-icon { + background: url("../images/theme-default/host-icon-sprite.png") no-repeat + left top; + display: inline-block; + height: 12px; + width: 12px; +} + +.host-panel .action-icon-stop { + background-position: -14px 0; +} + +.host-panel .action-icon-restart { + background-position: -28px 0; +} + +.host-panel .action-icon-download { + background-position: -42px 0; +} + +.host-panel .action-icon-connect { + background-position: -56px 0; +} + +.host-panel .action-icon-add { + background-position: -70px 0; +} + +.host-panel .action-icon-edit { + background-position: -84px 0; +} + +.host-panel .action-icon-remove { + background-position: -98px 0; +} + +.host-panel button:disabled .action-icon-start { + background-position: 0 -14px; +} + +.host-panel button:disabled .action-icon-stop { + background-position: -14px -14px; +} + +.host-panel button:disabled .action-icon-restart { + background-position: -28px -14px; +} + +.host-panel button:disabled .action-icon-download { + background-position: -42px -14px; +} + +.host-panel button:disabled .action-icon-connect { + background-position: -56px -14px; +} + +.host-panel button:disabled .action-icon-add { + background-position: -70px -14px; +} + +.host-panel button:disabled .action-icon-edit { + background-position: -84px -14px; +} + +.host-panel button:disabled .action-icon-remove { + background-position: -98px -14px; +} + +.host-panel .info-container { + padding-top: 16px; + width: 890px; +} + +.host-panel .section-header { + background: #EEE; + border-radius: 5px; + cursor: pointer; + line-height: 2em; + margin: 1em 0 1em; + padding-left: 6px; +} + +.host-panel .section-header:hover { + background: #06f; + color: white; +} + +.host-panel .section-content { + padding-left: 1em; +} + +.host-panel .section-header .arrow { + border-color: transparent; + border-style: solid; + display: inline-block; + margin-right: 6px; + width: 0; +} + +.host-panel .section-header[aria-expanded="true"] .arrow { + border-top-color: black; + border-width: 8px 4px 0; + border-bottom: none; +} + +.host-panel .section-header[aria-expanded="true"]:hover .arrow { + border-top-color: white; +} + +.host-panel .section-header[aria-expanded="false"] .arrow { + border-left-color: black; + border-right: none; + border-width: 4px 0 4px 8px; +} + +.host-panel .section-header[aria-expanded="false"]:hover .arrow { + border-left-color: white; +} + +.host-panel .section-row { + line-height: 1.6em; + margin-bottom: 1em; +} + +.host-panel .section-label { + width: 100px; +} + +#frequency-textbox { + width: 20px; +} + +#container-chart-cpu, +#container-chart-memory, +#container-chart-disk-io, +#container-chart-network-io { + border: 1px solid white; + box-shadow: 2px 2px 2px gray, 2px -2px 2px gray, -2px -2px 2px gray, -2px + 2px 2px gray; + height: 100px; + width: 500px; +} + +#container-chart-disk-io .disk-write, +#container-chart-network-io .network-sent { + stroke: #f80; +} + +/* Debug Report */ +.cell-text-wrapper { + margin-left: 10px; +} + +.host-panel #available-reports-grid { + border-color: #ddd; + height: 400px; + width: 850px; +} + +.host-panel select#available-reports-list { + width: 300px; +} + +.host-panel select#available-reports-list option { + margin: .2em 1em; +} + +.debug-report-name, +.debug-report-time { + width: 424px; +} + +#id-debug-img { + background: url(../images/theme-default/kimchi-loading15x15.gif) 12px + center no-repeat; + padding-left: 23px; +} + +/* End of Debug Report */ + +/* Software Updates */ +.host-panel #software-updates-grid { + border-color: #ddd; + height: 300px; + width: 850px; +} + +.software-update-name, +.software-update-repos { + width: 224px; +} + +.software-update-version, +.software-update-arch { + width: 200px; +} + +.host-panel #software-updates-progress-textarea { + border: 1px solid #ddd; + box-sizing: border-box; + height: 100px; + padding: .2em .5em; + resize: vertical; + width: 852px; +} +/* End of Software Updates */ + +/* Repository */ +.host-panel #repositories-grid { + border-color: #ddd; + height: 200px; + width: 850px; +} + +.host-panel #repositories-grid .repository-id { + width: 120px; +} + +.host-panel #repositories-grid .repository-name { + width: 640px; +} + +.host-panel #repositories-grid .repository-enabled { + width: 88px; +} + +.host-panel #repositories-grid .repository-baseurl.deb { + width: 400px; +} + +.host-panel #repositories-grid .repository-enabled.deb { + width: 100px; +} + +.host-panel #repositories-grid .repository-gpgcheck.deb { + width: 150px; +} +/* End of Repository */ diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/icon.css b/src/wok/plugins/kimchi/ui/css/theme-default/icon.css new file mode 100644 index 0000000..f82d45d --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/icon.css @@ -0,0 +1,106 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /* Generated at http://colorzilla.com/gradient-editor/ */ + +.btn.loading { + box-shadow: none; + cursor: default; +} + +.btn.loading .icon { + background: url(../images/theme-default/icon-load.png) center + center no-repeat; +} + +.btn.pause-gray .icon { + background: url(../images/theme-default/ac22_pause_grey.png) center + center no-repeat; +} + +.btn.resume-gray .icon { + background: url(../images/theme-default/ac24_resume_grey.png) center + center no-repeat; +} + +.icon.reset { + background: url(../images/theme-default/icon-reset.png) center + center no-repeat; +} + +.icon.power-up { + background: url(../images/theme-default/icon-power-up.png) center + center no-repeat; +} + +.icon.power-down { + background: url(../images/theme-default/icon-power-down.png) center + center no-repeat; +} + +.icon.pause { + background: url(../images/theme-default/ac22_pause.png) center + center no-repeat; +} + +.icon.resume { + background: url(../images/theme-default/ac24_resume.png) center + center no-repeat; +} + +.icon.search { + background: url(../images/theme-default/icon-search.png) no-repeat + center center; +} + +.icon.sort { + background: url(../images/theme-default/icon-sort.png) no-repeat + center center; +} + +.icon.design { + background: url(../images/theme-default/icon-design.png) no-repeat + center center; +} + +.icon.list { + background: url(../images/theme-default/icon-list.png) no-repeat + center center; +} + +.icon.detail { + background: url(../images/theme-default/icon-detail.png) no-repeat + center center; +} + +.icon.add { + line-height: 32px; + text-align: center; + text-shadow: -1px -1px 1px #aaa, 1px 1px 1px #eee; + font-size: 38px; + font-weight: bold; + color: #7cae0a; +} + +.icon.tree { + width: 42px; + background: url(../images/theme-default/icon-tree.png) no-repeat + center center; +} + + diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/list.css b/src/wok/plugins/kimchi/ui/css/theme-default/list.css new file mode 100644 index 0000000..8c78623 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/list.css @@ -0,0 +1,326 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.list-vm { + margin: 10px; +} + +/* Generated at http://colorzilla.com/gradient-editor/ */ +.list-vm>li { + margin-bottom: 10px; + background: #ffffff; + background: -moz-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: -webkit-gradient(linear, left top, left bottom, + color-stop(0%, #ffffff), color-stop(100%, #e5e5e5)); + background: -webkit-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: -o-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: -ms-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: linear-gradient(to bottom, #ffffff 0%, #e5e5e5 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', + endColorstr='#e5e5e5', GradientType=0); + border: 1px solid #ccc; + color: #333; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; +} + +.list-vm li>* { + height: 130px; + display: table-cell; + vertical-align: top; + position: relative; + border-left: 1px solid #ccc; + border-right: 1px solid #fff; +} + +.list-vm li>*:FIRST-CHILD { + border-left: none; +} + +.list-vm li>*:LAST-CHILD { + border-right: none; +} + +.list-vm li>.guest-tile{ + text-align: center; + vertical-align: middle; +} + +.list-vm .handle { + display: block; + width: 50px; + height: 130px; + box-sizing: border-box; + box-shadow: inset 4px 4px 4px #0289e2, inset -4px -4px 4px #04385d; + background: #0b6bad url(../images/theme-default/arrow_out.png) center + center no-repeat; + border-top-right: 1px solid #CCC; + -webkit-border-top-right-radius: 8px; + -moz-border-top-right-radius: 8px; + border-top-right-radius: 8px; + border-bottom-right: 1px solid #CCC; + -webkit-border-bottom-right-radius: 8px; + -moz-border-bottom-right-radius: 8px; + border-bottom-right-radius: 8px; +} + +.list-vm .subtitle { + color: #666; + font-size: 13px; + text-align: center; + line-height: 10px; + font-weight: bold; +} + +.list-vm .tile .imgload { + display: none; +} + +.list-vm .tile.shutoff .imgactive { + max-height: 110px; + max-width: 170px; + height: auto; + width: auto; + display:inline; + border: none; + position: relative; +} + +.list-vm .tile.paused .imgactive { + max-height: 110px; + max-width: 170px; + height: auto; + width: auto; + display:inline; + border: none; + position: relative; +} + +.list-vm .tile.running .imgactive{ + max-height: 110px; + max-width: 170px; + height: auto; + width: auto; + display:inline; + border: none; + cursor: crosshair; + cursor: -moz-zoom-in; + cursor: -webkit-zoom-in; +} + +.list-vm .tile .overlay { + max-height: 110px; + max-width: 170px; + height: auto; + width: auto; + position:absolute; + bottom:0; + right:0; + display:none; +} + +.guest-type { + width: 257px; +} + +.guest-cpu { + width: 91px; +} + +.guest-network { + width: 91px; +} + +.guest-storage { + width: 91px; +} + +.guest-tile { + width: 190px; +} + +.guest-users { + width: 93px; +} + +.guest-actions { + width: 125px; + min-width: 125px; +} + +.guest-handle { + width: 50px; +} + +.guest-general { + padding: 10px; + border-bottom: 1px solid #ccc; + width: 237px; +} + +.guest-ip { + padding: 0 10px; + border-top: 1px solid #fff; +} + +.guest-general .title { + color: #666; + font-size: 16px; + font-weight: normal; + height: 25px; + line-height: 25px; + text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; + max-width: 237px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.guest-general .text { + font-weight: bold; + color: #999; + font-size: 11px; + text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; +} + +.guest-users .top { + border-bottom: 1px solid #ccc; + padding: 3px 10px; +} + +.guest-users .bottom { + border-top: 1px solid #fff; + padding: 3px 10px; +} + +.guest-users .users { + height: 45px; + line-height: 45px; + background: url(../images/theme-default/icon-user.png) left + center no-repeat; + padding-left: 50px; + font-size: 36px; + font-weight: bold; +} + +.guest-users .snapshots { + height: 40px; + line-height: 40px; + background: url(../images/theme-default/icon-camera.png) left + center no-repeat; + padding-left: 50px; + font-size: 36px; + font-weight: bold; +} + +.guest-users .mini-text { + font-size: 11px; + font-weight: normal; + text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; +} + +.guest-actions .top { + padding: 7px 10px; + width: 200px; +} + +.guest-actions .top button { + display: inline-block; + width: 42px; + height: 42px; +} + +@-moz-document url-prefix() { + .guest-actions .top button span { + margin-left: -3px; + margin-top: -1px; + } +} + +.guest-actions .bottom { + padding: 0 10px; +} + +.list-vm .tile { + max-width: 170px; + max-height: 110px; + width: auto; + height: auto; + margin: 10px; +} + +.list-vm .tile:not(.shutoff) && .tile:not(.paused) img { + box-shadow: -1px -1px 2px rgb(0, 0, 0, .25), 3px 3px 3px #fff; +} + +.list-vm .shutoff { + position: relative; + box-shadow: none !important; +} + +.list-vm .shutoff img { + opacity: 0.4; +} + +.list-vm .paused { + position: relative; + box-shadow: none !important; +} + +.list-vm .paused img { + opacity: 0.6; +} + +.list-title { + color: #666; + font-weight: bold; + font-size: 12px; + overflow: hidden; + margin: 10px; +} + +.list-title li { + display: table-cell; + padding: 0 1px; +} + +.list-no-result { + font-size: 16px; + height: 48px; + line-height: 48px; + text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; + padding-left: 10px; +} + +.guest-pending { + margin: 10px; +} + +.guest-pending .icon { + background: url('../images/theme-default/kimchi-loading15x15.gif') no-repeat; + display: inline-block; + width: 20px; + height: 20px; + vertical-align: middle; +} + +.guest-pending .text { + color: #666666; + margin-left: 5px; + text-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #FFFFFF; +} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/network.css b/src/wok/plugins/kimchi/ui/css/theme-default/network.css new file mode 100644 index 0000000..fc8a24f --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/network.css @@ -0,0 +1,267 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.network { + margin: 5px; +} + +.network .grid-control { + height: 40px; + padding: 5px 0; +} + +.network .grid-control .filter { + width: 300px; + padding: 5px; + float: right; +} + +.network .list .column-name { + width: 20%; + max-width: 20%; + text-overflow: ellipsis; +} + +.network .list .column-state { + width: 10%; +} + +.network .list .column-type { + width: 15%; +} + +.network .list .column-interface { + width: 15%; +} + +.network .list .column-space { + width: 25%; +} + +.network .list .column-action { + display: inline-block; + float: right; + height: 40px; +} + +.network .list .hide-action-item { + display: none; +} + +.network .list .menu-container { + display: none; + top: 58px; +} + +.network .list .action-button { + float: right; + margin-top: 2px; + margin-left: 5px; +} + +.network .list .action-button-icon { + background: url("../images/theme-default/arrow-down-black.png") no-repeat + scroll center center transparent; +} + +.network .list .ui-state-disabled { + margin: 0px; +} + +.network .list .network-state { + display: inline-block; + height: 16px; + width: 16px; + border-radius: 8px; + margin-left: 10px; +} + +.network .list .nw-loading { + background: #c0c0c0 url(../images/theme-default/loading.gif) + center no-repeat; +} + +.network .list .up { + background: linear-gradient(to bottom, #BFD255 0%, #8EB92A 50%, + #72AA00 51%, #9ECB2D 100%) repeat scroll 0 0 transparent; +} + +.network .list .down { + background: linear-gradient(to bottom, #AFAFAF 0%, #AFAFAF 50%, + #AFAFAF 51%, #AFAFAF 100%) repeat scroll 0 0 transparent; +} + +.network-config { + font-family: Arial; + font-size: 12px; + margin-bottom: 40px; + display: none; +} + +.network-config .section-container { + margin-top: 20px; +} + +.network-config .section-container:first-child { + margin-top: 10px; +} + +.network-config .section-container:last-child { + height: 200px; +} + +.network-config .section-container .bridged-inline { + display: inline-block; + vertical-align: top; + max-width: 520px; +} + +.network-config .section-header { + font-size: 14px; + font-weight: lighter; +} + +.network-config .section-content { + margin-top: 10px; +} + +.network-config input[type="text"] { + border: 1px solid #CCCCCC; + font-size: 16px; + height: 30px; + width: 300px; + line-height: 30px; + padding: 0 5px; +} + +.network-config input.invalid-field[type="text"] { + border-color: #FF4444; +} + +.network-config input.invalid-field[type="text"][disabled] { + border-color: #666666; +} + +.network-config input[type="radio"] { + margin-right: 5px; + margin-top: 0px; +} + +.network-config select { + color: #666666; + border: solid 1px; + background-color: white; + padding: 3px 4px 3px 0; +} + +.network-config .input-container { + height: 20px; +} + +.network-config label { + vertical-align: top; +} + +.network-type-wrapper-controls input[type="text"] { + height: 38px; + line-height: 38px; + background: #fff; + -webkit-border-radius: 5px; + border-radius: 5px; + box-shadow: 2px 2px 2px #eee inset; + border-top: 1px solid #bbb; + border-left: 1px solid #bbb; + padding: 0 10px; + margin-top: 5px; + width: 50px; +} + +.network-type-wrapper-controls > .dropdown { + margin: 5px 0 0 1px; + width: 180px; +} + +.network-type-wrapper-controls input[type="text"][disabled] { + color: #bbb; + background-color: #fafafa; + cursor: not-allowed; +} + +.network-type-wrapper-controls span[type="text"] { + padding: 0 10px; +} + +.bridge-option-column { + display: inline-block; + vertical-align: middle; +} + +.bridge-option-column label { + margin-left: 42px; +} + +.network-type-wrapper-controls { + width: 80px; + display: inline-block; + vertical-align: top; + padding: 5px 5px 5px 22px; +} + +#enableVlan { + margin-left: 42px; + vertical-align: middle; +} + +#labelEnableVlan { + vertical-align: middle; +} + +#labelNetworkVlanID { + margin-left: 42px; + vertical-align: middle; + display: none; +} + +#networkVlanID { + width: 80px; + vertical-align: middle; + display: none; +} + +.network-config .input-hint-icon { + margin: -1px 1px 0 0; + display: inline-block; +} + +.network-config .input-hint { + margin-top: 3px; +} + +.network-config .input-hint-text { + color: #999999; + font-weight: lighter; + font-size: 12px; +} + +.ui-state-default a { + color: #212121; +} + +#networkConfig { + padding-left: 30px; +} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/report-add.css b/src/wok/plugins/kimchi/ui/css/theme-default/report-add.css new file mode 100644 index 0000000..8020182 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/report-add.css @@ -0,0 +1,37 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#report-add-window { + height: 300px; + width: 400px; +} + +#report-add-window .field { + font-size: 12px; +} + +#report-name-textbox { + margin: 0; + width: 100%; +} + +.info-add-debug-report { + font-size: 12px; + color: #999999; + font-weight: lighter; + font-family: 'Helvetica Neue', Helvetica, Arial; +} \ No newline at end of file diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/report-rename.css b/src/wok/plugins/kimchi/ui/css/theme-default/report-rename.css new file mode 100644 index 0000000..2fb2698 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/report-rename.css @@ -0,0 +1,39 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#report-rename-window { + height: 300px; + width: 400px; +} + +#report-rename-window .field { + font-size: 12px; +} + +#report-name-textbox { + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: 0; + width: 100%; +} + +.info-debug-report-rename { + font-size: 12px; + color: #999999; + font-weight: lighter; + font-family: 'Helvetica Neue', Helvetica, Arial; +} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/repository-add.css b/src/wok/plugins/kimchi/ui/css/theme-default/repository-add.css new file mode 100644 index 0000000..4344569 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/repository-add.css @@ -0,0 +1,42 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#repository-add-window { + height: 500px; + width: 1000px; +} + +#repository-add-window span.required { + color: red; + padding-left: 5px; + vertical-align: top; +} + +#repository-add-window .textbox-wrapper input[type="text"] { + box-sizing: border-box; + width: 100%; +} + +#repository-add-window .textbox-wrapper label { + vertical-align: middle; +} + +#isMirrorLabel { + font-size: 14px; + font-weight: lighter; + font-family: 'Helvetica Neue', Helvetica, Arial; +} \ No newline at end of file diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/repository-edit.css b/src/wok/plugins/kimchi/ui/css/theme-default/repository-edit.css new file mode 100644 index 0000000..383a7fe --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/repository-edit.css @@ -0,0 +1,88 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.yum div#repository-edit-window { + height: 680px; + width: 1000px; +} + +.deb div#repository-edit-window { + height: 480px; + width: 1000px; +} + + +.repository-edit-fieldset { + float: left; + padding: 0 30px; + width: 95%; +} + +.repository-edit-wrapper-label, .repository-edit-wrapper-controls { + display: inline-block; + height: 30px; + line-height: 30px; + font-size: 14px; + vertical-align: top; +} + +.repository-edit-wrapper-label { + margin-top: 10px; + width: 150px; +} + +.repository-edit-wrapper-controls label { + vertical-align: middle; +} + +.repository-edit-wrapper-controls { + width: 100%; +} + +.repository-edit-wrapper-controls input[type="text"] { + font-size: 16px; + height: 30px; + line-height: 30px; + padding: 0 10px; + width: 100%; + -moz-box-sizing: border-box; + box-sizing: border-box; + border: 1px solid #CCCCCC; +} + + +.repository-edit-wrapper-controls input[type="text"][readonly] { + color: #bbb; + background-color: #fafafa; +} + + +.repository-edit-wrapper-controls input[type="text"][disabled] { + color: #bbb; + background-color: #fafafa; + cursor: not-allowed; +} + + +.deb .yum{ + display: none; +} + + +.yum .deb{ + display: none; +} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/storage.css b/src/wok/plugins/kimchi/ui/css/theme-default/storage.css new file mode 100644 index 0000000..88447b5 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/storage.css @@ -0,0 +1,550 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* STORAGE */ +.storage { + margin: 5px; +} + + +.storage .grid-control { + height: 40px; + padding: 5px 0; +} + +.storage .grid-control .filter { + width: 300px; + padding: 5px; + float: right; +} + +.storage-allocate-padding-user { + padding-right: 108px; +} + +.usage { + float: right; + margin-right: 30px; +} + +.list-storage .storage-li>.guest-tile { + text-align: center; + vertical-align: middle; +} + +.list-storage .subtitle { + color: #666; + font-size: 13px; + text-align: center; + line-height: 10px; + font-weight: bold; +} + +.list-storage .tile .imgload { + display: none; + max-height: 110px; + max-width: 170px; + height: auto; + width: auto; +} + +.list-storage .tile .imgactive { + max-height: 110px; + max-width: 170px; + height: auto; + width: auto; +} + +.storage-volum { + height: 40px; + width: 186px; + display: table-cell; + vertical-align: top; + position: relative; + border-left: 1px solid #ccc; + border-right: 1px solid #fff; +} + +.storage-name { + width: 15%; +} + +.storage-state { + width: 10%; +} + +.storage-type { + width: 10%; +} + +.storage-capacity { + width: 10%; +} + +.storage-allocate { + width: 10%; +} + +.storage-location { + width: 30%; +} + +.storage-button { + width: 9%; +} + +.handle { + width: 2%; +} + +.status-dot { + background: #72AA00; + background: linear-gradient(to bottom, #BFD255 0%, #8EB92A 50%, + #72AA00 51%, #9ECB2D 100%) repeat scroll 0 0 transparent; + border: 1px solid #72AA00; + border-radius: 13px; + box-shadow: 3px 3px 3px #FFFFFF, -3px -3px 3px #DDDDDD; + height: 13px; + width: 13px; + margin-left: 10px; +} + +.toolable { + position: relative; +} + +.toolable .tooltip { + display: none; + border: 2px solid #0B6BAD; + background: #fff; + padding: 6px; + position: absolute; + color: #666666; + font-weight: bold; + font-size: 11px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + z-index: 100; + top: -300%; + left: -140%; + white-space: nowrap; +} + +.toolable:hover .tooltip { + display: block; +} + +.toolable .tooltip:after { + -moz-border-bottom-colors: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; + border-color: #fff transparent transparent; + border-image: none; + border-style: solid; + border-width: 7px; + content: ""; + display: block; + left: 15px; + position: absolute; + bottom: -14px; +} + +.toolable .tooltip:before { + -moz-border-bottom-colors: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; + border-color: #0B6BAD transparent transparent; + border-image: none; + border-style: solid; + border-width: 8px; + content: ""; + display: block; + left: 14px; + position: absolute; + bottom: -18px; +} + +.inactive { + background: #E80501; + background: linear-gradient(to bottom, #E88692 0%, #E84845 50%, + #E80501 51%, #E84845 100%) repeat scroll 0 0 transparent; + border: 1px solid #FF340C; +} + +.storage-volumes { + width: 90px; +} + +.storage-actions { + width: 125px; +} + +.storage-action { + width: 70px; +} + +.detail-view-icon { + background: url(../images/large_details_icon.png) no-repeat center + center; + height: 30px; + width: 42px; +} + +.volumes { + background: #73716F; + width: 1004px; + display: none; + margin-top: 10px; + border: 1px solid rgb(204, 204, 204); +} + +.volumeslist { + padding: 7px; + max-height: 272px; + min-height: 136px; + overflow: auto; + color: #ffffff; +} + +.volumes>.footer { + height: 48px; + z-index: 100; + box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.15); +} + +.volume-title { + float: left; + padding: 4px; + margin-bottom: 5px; + width: 130px; +} + +.pool-empty { + text-align:center; + line-height:136px; +} +.volume-title>.volume-name { + font-size: 14px; + font-weight: normal; + padding-bottom: 5px; + max-width: 120px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.volume-box { + border-radius: 8px; + background: white; + color: #666666; + float: left; + height: 100px; + margin: 7px; + padding: 10px; + width: 205px; + border: 1px solid rgb(204, 204, 204); +} + +.volume-box .volume-state { + font-size: 75%; +} + +.volume-box .label { + color: white; + font-weight: bold; + padding: 1px 5px; + text-shadow: none; +} + +.volume-box .used { + background-color: #FF7121; + border-radius: 5px 5px 5px 5px; +} + +.volume-box .free { + background: none repeat scroll 0 0 #72AA00; + border-radius: 5px 5px 5px 5px; +} + +.volume-setting { + float: right; + padding: 5px; +} + +.volume-setting>* { + height: 16px; + width: 16px; + border: none; + float: left; + padding: 2px; + cursor: pointer; +} + +.field>select { + height: 30px; + width: 160px; + font-size: 14px; + padding-left: 8px; +} + +.clear { + clear: both; +} + +.volume-text { + color: #999999; + float: left; + font-size: 10px; + font-weight: bold; + height: 18px; + line-height: 18px; + width: 142px; + max-width: 85px; + overflow: hidden; + text-overflow: ellipsis; +} + +.volume-textquota { + color: #999999; + float: left; + font-size: 10px; + font-weight: bold; + height: 18px; + line-height: 18px; + width: 142px; + max-width: 95px; + overflow: hidden; + text-overflow: ellipsis; +} + +.volume-type-position { + display: inline; + padding-right: 5px; + clear: both; + width: 90px; + border-right: 1px solid #999; + float: left; + white-space: nowrap; +} + +.volume-quota-position { + display: inline; + width: 90px; + padding-left: 5px; + float: left; + border-left: 1px solid #eee; + white-space: nowrap; +} + +.list-storage .storage-li[data-stat="active"]>.handle>.arrow-down { + background: url(../images/theme-default/arrow-down.png) no-repeat center + center; + height: 18px; + width: 18px; +} + +.list-storage .storage-li[data-stat="inactive"]>.handle>.arrow-down { + background: url(../images/theme-default/arrow-down-disable.png) no-repeat + center center; + height: 18px; + width: 18px; +} + +.arrow-up { + background: url(../images/theme-default/arrow-up.png) no-repeat center + center; + height: 18px; + width: 18px; +} + +.storage-icon { + border: 1px solid #CCCCCC; + border-radius: 8px 8px 8px 8px; + height: 40px; + width: 40px; + margin: 0 10px 10px 0; + float: left; + display: inline; +} + +.volume-default { + background: url(../images/theme-default/icon-volume-default.png) + no-repeat center center; +} + +.icon-raw { + background: url(../images/theme-default/icon-raw.png) no-repeat center + center; +} + +.icon-qcow2 { + background: url(../images/theme-default/icon-qcow2.png) no-repeat center + center; +} + +.icon-iso { + background: url(../images/theme-default/icon-iso.png) no-repeat center + center; +} + +.host-partition { + padding-left:13px; +} + +.host-partition>div { + font-size: 13px; + height: 18px; + padding: 10px; + color: #666; + float: left; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + font-weight: bold; + line-height: 18px; + white-space: nowrap; +} + +.storage-type-wrapper-controls { + width: 300px; + display: inline-block; + vertical-align: top; + padding: 5px 5px 5px 22px; +} + +.storage-type-wrapper-controls input[type="text"] { + height: 38px; + line-height: 38px; + background: #fff; + -webkit-border-radius: 5px; + border-radius: 5px; + box-shadow: 2px 2px 2px #eee inset; + border-top: 1px solid #bbb; + border-left: 1px solid #bbb; + padding: 0 10px; + margin-top: 5px; + width: 250px; +} + +.storage-type-wrapper-controls > .dropdown { + margin: 5px 0 0 1px; + width: 200px; +} + +.storage-type-wrapper-controls input[type="text"][disabled] { + color: #bbb; + background-color: #fafafa; + cursor: not-allowed; +} + +.storage-add-input-width { + width: 285px; +} + +.form-section .storage-field { + overflow: visible; +} + +.storage-base-input-width { + width: 300px; +} + +.storage-window { + width: 600px; + height: 700px; +} + +.storage-port-width { + width:40px; +} + +.storage-auth-width { + width: 150px; +} + +.storage-window .form-section .field { + overflow: visible; +} + +#pool-loading { + margin: 10px 15px; + background: #C0C0C0 url(../images/theme-default/loading.gif) 7px + center no-repeat; + padding: 0 20px 0 26px; +} + +.storage-admin .filter-select { + display: inline-block; + position: relative; +} + +#iscsiportId, .storage-admin .filter-select input { + border: 1px solid #CCCCCC; + border-radius: 1px; + font-size: 14px; + padding: 3px 3px 3px 10px; + height: 30px; +} + +.storage-admin .filter-select input::-ms-clear { + display: none; +} + +#iSCSIServer input { + width: 410px; +} + +#iscsiportId { + width: 60px; +} + +#iSCSITarget input { + width: 493px; +} + +/* Progress bar */ +.volume-progress { + clear: both; + width: 140px; +} + +.volume-progress .progress-bar-outer { + background: #ccc; + height: 4px; + overflow: hidden; + width: 100%; +} + +.volume-progress .progress-bar-inner { + background: #090; + height: 100%; + width: 0%; +} + +.volume-progress .progress-label { + color: #999; + font-size: 10px; + line-height: 16px; +} + +.volume-progress .progress-transferred { + float: right; +} +/* End of Progress bar */ diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/storagepool-add-volume.css b/src/wok/plugins/kimchi/ui/css/theme-default/storagepool-add-volume.css new file mode 100644 index 0000000..6e8a551 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/storagepool-add-volume.css @@ -0,0 +1,36 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#sp-add-volume-window { + height: 400px; + width: 500px; +} + +#sp-add-volume-window .textbox-wrapper input[type="text"] { + box-sizing: border-box; + width: 100%; +} + +#sp-add-volume-window .textbox-wrapper label { + vertical-align: middle; +} + +#sp-add-volume-window input[type="text"][disabled] { + color: #bbb; + background-color: #fafafa; + cursor: not-allowed; +} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/template-edit.css b/src/wok/plugins/kimchi/ui/css/theme-default/template-edit.css new file mode 100644 index 0000000..7c93117 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/template-edit.css @@ -0,0 +1,175 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#template-edit-window { + font-size: 13px; + height: 500px; + width: 800px; +} + +#edit-template-tabs { + background: none repeat scroll 0 0 transparent; + border: medium none; + height: 100%; + padding: 0; +} + +#edit-template-tabs .form-template-inline-wrapper { + display: inline-block; + vertical-align: top; +} + +.template-edit-wrapper-label { + vertical-align: top; + min-width: 100px; + height: 35px; + line-height: 35px; + margin: 7px 0 8px; +} + +.template-edit-wrapper-controls { + vertical-align: top; + width: 400px; +} + +.template-edit-wrapper-controls input[type="text"] { + height: 38px; + line-height: 38px; + background: #fff; + -webkit-border-radius: 5px; + border-radius: 5px; + box-shadow: 2px 2px 2px #eee inset; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + border-top: 1px solid #bbb; + border-left: 1px solid #bbb; + padding: 0 10px; + margin-top: 5px; + width: 100%; +} + +.template-edit-wrapper-controls > .dropdown { + margin: 5px 0 0 1px; + width: 372px; +} + +.template-edit-wrapper-controls input[type="text"][disabled] { + color: #bbb; + background-color: #fafafa; + cursor: not-allowed; +} + +#edit-template-tabs .template-tab-header { + margin-bottom: 8px; + padding-bottom: 2px; + font-weight: bold; + border-bottom: 1px solid #999999; + overflow: hidden; +} + +#edit-template-tabs .template-tab-header .action-area { + float: right; + height: 20px; + width: 20px; +} + +#edit-template-tabs .template-interface-cell { + display: inline-block; + width: 250px; +} + +#edit-template-tabs .template-storage-cell{ + display: inline-block; + width: 180px; +} + +#edit-template-tabs .template-storage-cell label { + height: 25px; + padding: 2px; + border: 1px; +} + +#form-template-storage .template-tab-body select { + width: 140px; +} + +#form-template-storage .template-tab-body input { + width: 56px; + height: 17px; +} + +#form-template-storage .template-tab-body .template-storage-name { + width: 170px; +} + +#form-template-storage .template-tab-body .template-storage-disk-format { + width: 160px; +} + +#edit-template-tabs .template-tab-body input[readonly] { + background: none repeat scroll 0 0 rgba(0, 0, 0, 0); + border-color: transparent; + text-overflow: ellipsis; +} + +#edit-template-tabs .template-tab-body .item { + height: 25px; +} + +#form-template-interface .template-tab-body select { + width: 180px; +} + +#edit-template-tabs .template-tab-body .action-area { + float: right; +} + +#edit-template-tabs .template-tab-body .action-area button { + width: 20px; + height: 20px; +} + +#edit-template-tabs .hide { + display: none; +} + +#form-template-processor select, +#form-template-processor input[type="text"] { + margin-left: 10px; +} + +#form-template-processor input[type="checkbox"] { + margin-right: 5px; +} + +#form-template-processor .manual { + margin-top: 10px; + margin-left: -3px; +} + +#form-template-processor .topology { + margin: 10px 30px; +} + +#form-template-processor .topology div { + margin-bottom: 10px; +} + +#form-template-processor .topology select { + width: 80px; +} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/template.css b/src/wok/plugins/kimchi/ui/css/theme-default/template.css new file mode 100644 index 0000000..27fe404 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/template.css @@ -0,0 +1,85 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.tile-template>li>label:hover .summary { + opacity: 0.1; +} + +.tile-template>li>label:hover .list-info { + top: 0; +} + +.tile-template .summary { + -webkit-transition: opacity 0.25s; + -moz-transition: opacity 0.25s; + transition: opacity 0.25s; +} + +.tile-template .list-info { + -webkit-transition: top 0.25s; + -moz-transition: top 0.25s; + transition: top 0.25s; + position: absolute; + top: 100%; + width: 100%; +} + +.tile-template .list-info>li { + border-bottom: 1px dotted #ccc; + padding: 5px; + font-size: 12px; + line-height: 20px; + overflow: hidden; + width: 96%; +} + +.tile-template .list-info>li>label { + display: inline-block; + color: #111; + width: auto; + text-align: left; + cursor: pointer; +} + +.tile-template .list-info>li>span { + float: right; + color: #444693; + width: auto; + text-align: right; +} + +.os-icon { + text-align: center; +} + +.os-icon .title { + display: block; + font-size: 14px; + margin-bottom: 5px; + overflow: hidden; + width: 260px; + word-break: break-all; + word-wrap: break-word; + height: 50px; + line-height: 25px; +} + +.os-icon img { + margin-top: 7px; + width: 64px; + height: 64px; +} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/template_add.css b/src/wok/plugins/kimchi/ui/css/theme-default/template_add.css new file mode 100644 index 0000000..f1e28c5 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/template_add.css @@ -0,0 +1,317 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.page-list { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + overflow: hidden; +} + +.page { + position: absolute; + left: 100%; + width: 100%; + height: 100%; + overflow: auto; +} + +.page>header { + position: relative; + overflow: hidden; +} + +.button-group { + margin-left: 5px; +} + +.back { + float: left; display : block; + width: 50px; + height: 52px; + background: url(../images/theme-default/icon-back.png) center + center no-repeat; + cursor: pointer; + display: block; +} + +.step-title { + color: #333; + font-size: 18px; + font-weight: normal; + padding: 15px 10px; +} + +.step-choose>li>a { + display: block; + margin: 0 10px 10px; + padding: 20px 10px 20px 65px; + border: 2px solid #ccc; + background: url(../images/theme-default/icon-local.png) 15px + center no-repeat; + cursor: pointer; +} + +.step-choose>li>a.local { + background-image: url(../images/theme-default/icon-local.png); +} + +.step-choose>li>a.remote { + background-image: url(../images/theme-default/icon-remote.png); +} + +.step-choose>li>a:HOVER { + border: 2px solid #06C; +} + +.step-subtitle { + font-size: 16px; + height: 48px; + line-height: 48px; + color: #06C; + margin: 0 10px; + font-weight: bold; + text-shadow: -1px -1px 1px #eaeaea, 1px 1px 1px #fff; +} + +.custom-iso-field { + position: relative; + padding: 0 10px 10px; +} + +.custom-iso-field>.input-wrapper { + margin-right: 110px; +} + +.custom-iso-field>.input-wrapper>input.text { + padding: 10px; + color: #333; + font-size: 13px; + background: #fff; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + box-shadow: 2px 2px 2px #eee inset; + border-top: 1px solid #bbb; + border-left: 1px solid #bbb; + width: 100%; +} + +.custom-iso-field>button { + position: absolute; + top: -6px; + right: 8px; +} + +.iso-field .button-field { + padding: 0 20px; + text-align: right; +} + +.check-all { + display: inline-block; + position: relative; + height: 38px; + line-height: 38px; + margin: 5px; + font-size: 13px; +} + +.check-all input { + margin: 0 5px 0 0; +} + +.box { + background: #ffffff; + background: -moz-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: -webkit-gradient(linear, left top, left bottom, + color-stop(0%, #ffffff), color-stop(100%, #e5e5e5)); + background: -webkit-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: -o-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: -ms-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: linear-gradient(to bottom, #ffffff 0%, #e5e5e5 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', + endColorstr='#e5e5e5', GradientType=0); + border: 1px solid #ccc; + color: #333; + text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; +} + +.box:HOVER { + border: 1px solid #aaa; + -webkit-box-shadow: #bbb 0px 0px 5px; + box-shadow: #bbb 0px 0px 5px; +} + +.box-iso { + padding: 10px; + margin: 5px; + overflow: hidden; +} + +.iso-icon { + float: left; + width: 58px; + height: 58px; + margin: 0 5px 0 0; + border: 1px solid #CCCCCC; + border-radius: 8px; + background: url(../images/icon-vm.png) center center no-repeat; + background-size: 58px; +} + +.iso-icon.centos { + background-image: url(../images/icon-centos.png); +} + +.iso-icon.debian { + background-image: url(../images/icon-debian.png); +} + +.iso-icon.fedora { + background-image: url(../images/icon-fedora.png); +} + +.iso-icon.opensuse { + background-image: url(../images/icon-opensuse.png); +} + +.iso-icon.ubuntu { + background-image: url(../images/icon-ubuntu.png); +} + +.iso-icon.gentoo { + background-image: url(../images/icon-gentoo.png); +} + +.list-iso { + overflow: hidden; + margin: 5px; +} + +.list-iso li { + float: left; + width: 320px; +} + +.list-iso>li>label { + display: block; + cursor: pointer; +} + +.list-iso>li>label>input[type="checkbox"] { + display: none; +} + +.list-iso>li>label>input[type="checkbox"]:CHECKED+.box-iso { + border: 1px solid rgb(11, 107, 173); + -webkit-box-shadow: rgb(11, 107, 173) 0px 0px 4px; + box-shadow: rgb(11, 107, 173) 0px 0px 4px; +} + +.iso-title { + margin: 0; + display: block; + position: relative; + height: 23px; + line-height: 23px; + font-size: 14px; + font-weight: normal; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.iso-title>label>input { + display: block; + position: absolute; + top: 0; + right: 2px; +} + +.iso-info { + margin-top: 5px; + overflow: hidden; +} + +.iso-info-col { + float: left; + width: 50%; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 0 0 0 5px; +} + +.iso-info-col:FIRST-CHILD { + padding: 0 5px 0 0; + border-right: 1px solid #999; +} + +.iso-info-item { + font-weight: bold; + color: #999; + font-size: 11px; + line-height: 18px; + max-width: 106px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +#iso-search { + margin: 10px 15px; +} + +#iso-search-loading { + margin: 10px 15px; + background: #C0C0C0 url(../images/theme-default/loading.gif) 7px + center no-repeat; + padding: 0 20px 0 26px; +} + +#iso-more-loading { + background: #C0C0C0 url(../images/theme-default/loading.gif) 7px + center no-repeat; + padding: 0 20px 0 26px; +} + +#vm-image-local-box .body { + margin: 30px 0 0 26px; +} + +#vm-image-local-box .body input { + background: none repeat scroll 0 0 #FFFFFF; + border-left: 1px solid #BBBBBB; + border-radius: 5px 5px 5px 5px; + border-top: 1px solid #BBBBBB; + box-shadow: 2px 2px 2px #EEEEEE inset; + color: #333333; + font-size: 13px; + padding: 10px; + margin-left: 10px; + width: 600px; +} + +#vm-image-local-box .body button { + margin-left: 10px; +} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/template_list.css b/src/wok/plugins/kimchi/ui/css/theme-default/template_list.css new file mode 100644 index 0000000..3161a33 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/css/theme-default/template_list.css @@ -0,0 +1,267 @@ +/* +* Project Kimchi +* +* Copyright IBM, Corp. 2013-2014 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +.list-template.framework { + float: left; + clear: both; +} + +.template-box { + border-radius: 8px 8px 8px 8px; + box-shadow: none; + color: #666666; + float: left; + height: auto; + margin: 10px 11px 10px 0; + padding: 10px; + width: 308px; +} + +.template-title { + font-size: 16px; + height: 25px; + line-height: 25px; +} + +.template-icon { + border: 1px solid #CCCCCC; + border-radius: 8px 8px 8px 8px; + height: 58px; + margin: 0 10px 10px 0; + width: 48px; +} + +.template-icon img { + width: 58px; +} + +.template-text { + color: #999999; + float: left; + font-size: 11px; + font-weight: bold; + height: 18px; + line-height: 18px; + width: 142px; + display: table; +} + +.white-box { + background: #ffffff; + background: -moz-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: -webkit-gradient(linear, left top, left bottom, + color-stop(0%, #ffffff), color-stop(100%, #e5e5e5)); + background: -webkit-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: -o-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: -ms-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); + background: linear-gradient(to bottom, #ffffff 0%, #e5e5e5 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', + endColorstr='#e5e5e5', GradientType=0); + border: 1px solid #CCCCCC; + color: #333333; + text-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #FFFFFF; +} + +.row-select { + -moz-border-bottom-colors: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; + background: linear-gradient(to bottom, #FFFFFF 0%, #E5E5E5 100%) repeat + scroll 0 0 transparent; + border-color: #999999 #AAAAAA #AAAAAA #999999; + border-image: none; + border-radius: 5px 5px 5px 5px; + border-right: 1px solid #AAAAAA; + border-style: solid; + border-width: 1px; + float: left; + font-size: 13px; + height: 42px; + line-height: 42px; + margin: 5px 0 0 10px; + padding-left: 10px; + text-align: left; + text-shadow: -1px -1px 1px #AAAAAA, 1px 1px 1px #FFFFFF; + width: 100px; +} + +.bevel3 { + box-shadow: -2px -2px 2px #EAEAEA, 2px 2px 2px #FFFFFF, 3px 3px 3px white + inset, -3px -3px 3px rgba(0, 0, 0, 0.25) inset; + color: #333333; +} + +.row-drop { + left: 10px; + position: relative; + top: 50px; +} + +.template-action-hidden { + visibility: hidden; +} + +.template-action-show { + visibility: visible; + display: block; +} + +template-hidden { + display: none; +} + +.select-drop { + background: none repeat scroll 0 0 #EEEEEE; + border: 2px solid #096AAD; + border-radius: 5px 5px 5px 5px; + box-shadow: 6px 6px 6px; + height: 147px; + left: 0; + position: absolute; + top: 8px; + width: 250px; + z-index: 2147483647; +} + +.button-drop { + background: linear-gradient(to bottom, #EEEEEE 0%, #CCCCCC 10px, #CCCCCC + 96%, #A5A5A5 100%) repeat scroll 0 0 transparent; +} + +.action-bevel { + box-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #EEEEEE; +} + +.template-border { + border: 1px solid rgb(204, 204, 204); +} + +.template-button-position { + position: relative; + left: 250px; + top: 55px; + z-index: 5555; +} + +.tempate-action-position { + float: right; + width: 83px; + margin: 0; +} + +.template-actiontext-position { + width: 250px; + height: 160px; +} + +.template-line { + left: 200px; +} + +.template-os-position { + padding-right: 10px; + clear: both; + width: 142px; + border-right: 1px solid #999; + float: left; +} + +.template-cpu-position { + border-left: 1px solid #eee; + padding-left: 10px; + float: left; + width: 132px; +} + +.template-icon-position { + float: left; + height: 58px; + width: 58px; +} + +.template-icon img.template-type-icon-position { + width: 20px; + height: 20px; + position: relative; + top: -15px; + left: 49px; +} + +.template-title-position { + float: left; + width: 120px; +} + +.template-results { + background: linear-gradient(to bottom, #FFFFFF 35px, rgba(255, 255, 255, 0) + 100%) repeat scroll 0 0 transparent; + float: left; + height: 60px; + margin-bottom: -22px; + padding-left: 10px; + width: 1014px; +} + +.select-row-action { + background: linear-gradient(to bottom, #FFFFFF 0%, #E5E5E5 100%) repeat + scroll 0 0 transparent; + border: 1px solid #CCCCCC; + border-radius: 5px 5px 5px 5px; + float: left; + font-size: 13px; + height: 38px; + line-height: 38px; + margin: 10px 10px 0; + text-align: center; + text-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #FFFFFF; + width: 230px; +} + +.select-row-delete { + background: linear-gradient(to bottom, #FF3019 0%, #CF0404 100%) repeat + scroll 0 0 transparent; + border: 1px solid #B10F14; + border-radius: 5px 5px 5px 5px; + color: #FFFFFF; + float: left; + font-size: 13px; + font-weight: bold; + height: 38px; + line-height: 38px; + margin: 10px 10px 0; + text-align: center; + text-shadow: -1px -1px 1px #9E0505, 1px 1px 1px #FC5D4C; + width: 230px; +} + +.template-general .title { + color: black; + font-size: 16px; + font-weight: normal; + height: 25px; + line-height: 25px; + text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; + max-width: 130px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.processing { + cursor: wait; +} diff --git a/src/wok/plugins/kimchi/ui/images/Makefile.am b/src/wok/plugins/kimchi/ui/images/Makefile.am new file mode 100644 index 0000000..ca3ee6e --- /dev/null +++ b/src/wok/plugins/kimchi/ui/images/Makefile.am @@ -0,0 +1,22 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SUBDIRS = theme-default + +imagedir = $(datadir)/wok/plugins/kimchi/ui/images + +dist_image_DATA = *.png diff --git a/src/wok/plugins/kimchi/ui/images/icon-centos.png b/src/wok/plugins/kimchi/ui/images/icon-centos.png new file mode 100644 index 0000000000000000000000000000000000000000..5afb7b4b63462412d825f63542beb1f7e26b3d7f GIT binary patch literal 4734 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 M07*qoM6N<$f~4IfuK)l5 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/icon-debian.png b/src/wok/plugins/kimchi/ui/images/icon-debian.png new file mode 100644 index 0000000000000000000000000000000000000000..ff49a39696fdfa5f232b0e79de04d90af6557111 GIT binary patch literal 4239 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 D^V29c literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/icon-fedora.png b/src/wok/plugins/kimchi/ui/images/icon-fedora.png new file mode 100644 index 0000000000000000000000000000000000000000..7b9dd06d1f766a3285cd0fb587c0be4114bfac47 GIT binary patch literal 4449 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 S9$oyI0D9VncWN{pBmW0TFKp8Q literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/icon-gentoo.png b/src/wok/plugins/kimchi/ui/images/icon-gentoo.png new file mode 100644 index 0000000000000000000000000000000000000000..50d928fbfa30560fe873cf3de438a8f0c10a8f96 GIT binary patch literal 15307 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/icon-opensuse.png b/src/wok/plugins/kimchi/ui/images/icon-opensuse.png new file mode 100644 index 0000000000000000000000000000000000000000..83fe4d5df0f59b52dd609b3bd16838f4d2570ab8 GIT binary patch literal 3046 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/icon-ubuntu.png b/src/wok/plugins/kimchi/ui/images/icon-ubuntu.png new file mode 100644 index 0000000000000000000000000000000000000000..d92c00f357b6b0e1542413f6aaf0de8ef4b8d130 GIT binary patch literal 4818 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 T?|XFr3GiA;OR-Yk^22`sn~zF< literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/icon-vm.png b/src/wok/plugins/kimchi/ui/images/icon-vm.png new file mode 100644 index 0000000000000000000000000000000000000000..50dac50c5a0ee59f4e79170434f53bb3b94390e3 GIT binary patch literal 2976 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/Makefile.am b/src/wok/plugins/kimchi/ui/images/theme-default/Makefile.am new file mode 100644 index 0000000..7e11d75 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/images/theme-default/Makefile.am @@ -0,0 +1,20 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +imagedir = $(datadir)/wok/plugins/kimchi/ui/images/theme-default + +dist_image_DATA = *.png *.gif diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/ac22_pause.png b/src/wok/plugins/kimchi/ui/images/theme-default/ac22_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9258aee87f0e2f430cf1fb12a4588f763f3c0a62 GIT binary patch literal 1219 zcmbVMO>Em#9CtTbM!QYZ3R7EwV!5LOiP*7Yo5gCV96yIfTDmTcw6Ieh`=v3h{fzyx zq`hSAssY^&+X3-;7(IbDF^V*#0ostNNpJ&chiPJ(*f=3gfS^*?io$c-6b{vpux!5% z|9-#!$NT^N=IF@FyE^+iDT>;a83s8r_K~M&M+bTTG<W|x8G5l^z+<R{tA-CL)j~x` zXB=Y!=AdCszxFL0q^RvBJ72(s>><TO4r_!Mw&r+*O;LkGHP0|7A*PFP!giC)FJE3` zXxmCMN2P2m>uIoT56}2;Y-S{H&P<vKiy3-}9;_)uz=7DHYtED#D77TBrmK*7xXm&2 z8U#-!nRTZM*-=_UKBOf!9yMb;Ps=jPi;^t!FVI4a7q}R?<tQ&IlB@_X(i;~;toc?+ z$$|8SEwV~7WsE(A<EqsvTaB~GpWygJA`xl`LX;q)!L*BwTGS2tTM7UMrf+-LMlKyH z8bwsWNrrg39)ja#vzx+hu#qT|GOlKL9M8r$#|h(FLkBnq|8ZkWbdaC+AeVyys`w^3 zk5Ye&Omg>VLm`lOqa5~aawx_WKxV~(F3x}?L%y(<Z7H#MN&~u_5<ptiMV?RbaS4!> zrVD8v@O(>SE3PK#KozA#S`-LU7gZ6cs;KfBkmKouAhfs{H^7E#!j@f|*xleBd?Z)V zd}v_g=MkD}RlsN&VHA{+M{8p;{oGO8wNN#9K0KcFXaV%?<Iqa`$f4KrtJquEkBR>k z_d3`5KRM%wGhA34|0<T&7OB8+x>@>UvDrM(B^~3F);Mrp0;H{e&j2-FyH#9mHixz+ zsjfH1Eo=U_E3<{C2X?pDPc)w0Q`h${U)cTry;r_#-0i-(^1+#R+i$(o+oLyy)rrPR zGqQa6RQ*y<Z%_B&waD#}Gs^kZ<Eed1jiuqwm$peKfB56{kCElaPu<xWX*Tygy#8yQ z9UWc(m4ngZo|4tA&$sX2aW%f${zc=`{>0DYC!VN3CJ3Lly+xgTeKuD)G@tA0Klky% zS!JL@nLTnk9qqeZzOi_&{C$L3`Rl_Qi*JAZ>Yq=2M&<4|=XMg!2b~wc+G{MR(t(fO w>*#y%<Tu#??U}`^+b$Q*9#iveH;<`QTL-02da<sDMK=7cWb_g6NosuVZ*kO>5C8xG literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/ac22_pause_grey.png b/src/wok/plugins/kimchi/ui/images/theme-default/ac22_pause_grey.png new file mode 100644 index 0000000000000000000000000000000000000000..7cde85bcb26ca808b9b02d5336872f10556585a0 GIT binary patch literal 1175 zcmbVMUue{J98c{SYPo?ZqV0n};)|2JOMXc%y~}#Gy(HIO+0}Br&chc?lV97|CciBC z)w`CVuHZZen`;>q!NH~v?x9Y7Dzb+TRHmS);FB+cii#l4hoNGz{?hikJroBENq)cY zFW=AS`#;Bfx;rB48`m=o6UlXI1-drUXUp1;>HE>d^Q&~(O7s%x#RH^l_=st@a6bY$ z#~4HfWLRTgUPmnqQ$JuAOQe+lTrsf|H$t6w#qlVbVOm-%o?#9n0{YRQ?WWlmzt6G2 zw$kjLM4r!kDjKpo$9>d0-d!}uhs~75w(bHg6@?Nwh!~*ajJSbPNwbT*3f+gt919jz z$Z(ona;lW?0V?(pNW{gM$wLTaIS!?SEW;=ecqni@z2z8`l!UAZ&0zUrsWsmkPzqXh z*%p=3><}TI!g1wtIbIgy*dOFzDwPU31R+K>V!@b8j7rQ6w$~Um6qvs45gWT8WHkEm zC`q%_)1?p`FP~o_c7x?a(Ufr&!{cC_=Nu=DYf(EO1@w;_t7-?uF%NMC6yQ<cr1cos zUIWwIeb`W_NWD>Z`!+3#F`{8})Il!EX=#>ziCea%@M1>QbU7nvSxJ{5%s?@rQAyQ> zEYu*Zajb?-3eBR(C#7sshY;#gQphxC+ck+-)ufnJ#Tqu}2E=epRI_VSyUSSdgIGoN zkwLIu#CW9E0X;*Q;9v-QK<$;mjy<+(;d1b4Se~V5HRRg|k(Kqa0~YhE*sIv*rT>b1 z32XhIoN?3{E^Ll}HB0S?c3`+&X?-fJ3=eYY#Q1bH&XxYUOvmcaoYr2f-0PoTSZJ+J zGaKuFVj6^FlarIb%*@=_c<offl__vP^D+Rfmu6?npH+9yD5o}m%``PNmBebKF#qJ% zwr}PRFLb?o`wG|fbgrw;O`ZPatR9U<r+E2BU)xQvuUdEVLEBd+HjQdmH|(hH-!gr< z+Sf6Ag+FlTSN+W9@AgUu?sylUrsSi4bUlxpeCF-_aZPc)@rz)Bzwqs$H?Lnl-1+nE zZNlC5ogI&|9~C0kBj>)K9Pawz@pRkY`;PY=8`;oyq>edy=*0QyXoDR7Dsp<a_FHEE F#Cyajgunm* literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/ac24_resume.png b/src/wok/plugins/kimchi/ui/images/theme-default/ac24_resume.png new file mode 100644 index 0000000000000000000000000000000000000000..6f1f16f52f2c000a7413e22a0105c5d0b09c7a2b GIT binary patch literal 1341 zcmeAS@N?(olHy`uVBq!ia0vp^Qa~)h!3HFsG`&3vq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FfgZOhD4M^`1)8S=jZArg4F0$<Q4#RGcefLR}>^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&iz}FXUa9%MqpnyT9Uy)d#Z>VRWpPLKv7g%+1Nl+@n8CX>phg24%>IbD3 z=a&{G1LGr28KxN+cK9s<DFnL4%D*TR7%7Q4F8Rr&xv6<2o-VdZKpDN1%oHmVGXql# zXG>!vb2k%L6GKBMLt|4HCnFbUS0gt=7ehms8QAn18<-kc7?=Qc8Ua<hnpheen>)I> zSh!jkI9dYZ2Bz0Duec;JFF6%vZzj-Qs9rO?daay`QWHz^i$e1Ab6_bTAS1sdzc?em zK*2fKOhF?&GcP5-yjT+yJrLizq!wkCrKY$Q<>xAZ!`CVki~T0%g!~QBn?g>Q=>r|3 z4@w+Ji3KJEOo1RKJm~{D@XV8%2h1@=z^w7aYe@nF17ohIi(^Q|tu52`dL3~PIG%1+ z{qdYj)BS{nN)a4Uzgfz@U5|{==-~Rr(X?J+hS&Y0>>I9~a|+n7!)e0@qjPDSCqysa zelqu;f#OV^&$nmJ^%d*n=n)W<QMqBXLNn7=f3xbe`~%;@s_sSHJo4k~OgVK%Rrc$T zR+%%`o}PbiUixvh#eaiq9=uWhwou#SM&C=8Uq&o5x)^q~e*7C)>7$^?RXt(u(xzEy zOPU;}B=89}ep{<6u&4Nh>w+5DRCa}Vt_$zQ-(mgo)$`M{6pJ-XGfMySzIu_fqb8xM zIo&>rjjbj2?e)nA^GjETTIn!NmEN#PGO#~*Y439ez4xkDnXXRN&Pke}eTMr4>oZ;x zKDC3Jd3;tjEd1V+bK{)Y%G$QIDJfg_xop@z_u<1l?(CE;R_hhlnjVf9c&{M6XkYI= z$N!Fd8jm^dX^2q>UEnA^L2H7Q^pY(86$;1V><mnqe;9lYxu>o-;m`U@4@9nbC@(Pk bs(gUqpHO<9rrQcmP=V&@>gTe~DWM4fDsR{! literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/ac24_resume_grey.png b/src/wok/plugins/kimchi/ui/images/theme-default/ac24_resume_grey.png new file mode 100644 index 0000000000000000000000000000000000000000..1714ba2d00294e99222f833b8cf5e33da31448f9 GIT binary patch literal 1282 zcmeAS@N?(olHy`uVBq!ia0vp^Qa~)h!3HFsG`&3vq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FfgZOhD4M^`1)8S=jZArg4F0$<Q4#RGcefLR}>^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&iz}FXUa9%MqpnyT9Uy)d#Z>VRWpPLKv7g%+1Nl+@n8CX>phg24%>IbD3 z=a&{G1LGr28KxN+cK9s<DFnL4%D*TR7%7Q4F8Rr&xv6<2o-VdZKpDN1%oHmVGXql# zXG>!vb2k%L6GKBMLt|4HCnFbUS0gt=7ehms8QAn1xSBb;n7f#|S-2V*8oHV|I=Y#< zS~!~;n_HL~7+4y?^m^tMmn7yTr^4*b1lkMLYl2s=m2**QVo82cNPd0}ECmE)<d@_Z zXXF<sI0u_4XoP3xrR0|vYl5N&;#-&0qRg_?6t|-MTm^9WT4iFf-^84dzae^4$O$uj zpkwqwi32IIz=VJ)5X6KheIN&(c~bL$Ii?7hH7ag6?Pg$LH1c$D45_%aXWGTy76pMe z#*54EzIj}xurI?=?19(<x7iySHaBM<W7^hSeW!Y#j`idYMV)ys4*D7$JRonE*5IhM zRONpX$ECYRU+uDc`!t~V)3Qvv1uJ>(TJRk9Wv+EDZnJyEl{9T%m!aDtjZ3lzucwwy zndkU9=XRJJn_^3`-z1gDJsMmxyH<Q*>Nrw(reMu$E6&J{ZI{m9FXEiM!sA2qLEql4 zs%w7|zTdl|J2^M+!yb)}zAv@<{Ec(`CoA{--l4?RW_EbR_l}&24;eYxZZ#R+pPI&d z%xQ`#>*>!j(GTAm-0<OWJhe&0QQ7NqNc)}Uh8%(S3rsu0FXRj4E66fk{VliT+D?am zJVmW*?k+Ywy~(S-d0FN!6W0ZWZ4v(^pOtgWf7`vVwxRwd<J#Omaudp{ISm*X#7kc9 TIKK2Js8sTF^>bP0l+XkKJo~{m literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/arrow-down-black.png b/src/wok/plugins/kimchi/ui/images/theme-default/arrow-down-black.png new file mode 100644 index 0000000000000000000000000000000000000000..2c05f00498232213a081497051c94d16537daab8 GIT binary patch literal 2942 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/arrow-down-disable.png b/src/wok/plugins/kimchi/ui/images/theme-default/arrow-down-disable.png new file mode 100644 index 0000000000000000000000000000000000000000..2d04c841780fa57153d4a73f3bee69824f6efb57 GIT binary patch literal 472 zcmV;}0Vn>6P)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B00004b3#c}2nYxW zd<bNS0004xNkl<ZIE~%Wzi-W99L4e1`D&V|3LS(5xxKfOSt3TG2s0reX(TMQ_!VNZ zh#xUYy4w5!VnqmI7D4*Gx9xXeu`;OkG58Xc5{txVd6FmRyg%nW5C821>bed}RaJVu z-XEK1W@bjQKFOP^uIrRiwwF?NFD@>w`cp_<*TXo4o7h=lGtOZe`|G;?Ev(<~594T( zsU*8_bqJG5_F)J&FwyV#r}1`TV&Z3z5gcomk6{7tsw5ARJWBF0$yk!pxP+}gLS|=Y zD@@`{k_|}~lH5)*RpB8{;0~6s7Kd?pFc^G=4F-d%l(IL;xg?vCXak&2@+z$eMsNj( zunvoOf(uEWmQoJlV*92Gcz`2#-Rt!}fB!epM{yie-&A{vTWzIrd}!03$IEWF3*UoU z*c$A?b!=&`-(z*FzuPW)(d~B27vC}v%+1XOJ8-Q%hub=j+dA{(<Ky3XehPy5`T1ZQ zPT~OW;VhnaI-O<uUxJ`%8l{wtE$BX;bvm7;l{_m>(==7nG=J^?H}eT{w|+~olSG{W O0000<MNUMnLSTa0@YLi0 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/arrow-down.png b/src/wok/plugins/kimchi/ui/images/theme-default/arrow-down.png new file mode 100644 index 0000000000000000000000000000000000000000..3f5239bbb93ad8660f47d3def443e42b8f57c6e6 GIT binary patch literal 537 zcmV+!0_OdRP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B00004b3#c}2nYxW zd<bNS0005dNkl<ZIE~$sze^Nw7>A$d6~#>G7g3=>Q#G^&cL#z*Q$%}FLnMWF=;0ky z&|yo<#f2xjw6^sJL}L+>rbk<lQf`6m4I+8ox1kd>!=xqXGrqjf!~62S@ZUy&d_HeP zq|VMxrlzL$3=a<v_W}piuaVE^O(~t<*x0zVwzk%>S4p8z=mPEn&wyM2ed+_?sd}|g zDEv`2GBVPo-j0Z3L|jmxbYwD_l6og14yzZ{&P*orF`Lb<HX4l`lF`x89-yE;RF9}l zbve`-b+%nN6cP8-Dsb{wNx57Obtoe4t4Gy!^@UpO$Y!%&)b|n5ubx)BBjTLem&@fE z3kwV107|7&q?E1zkJS?@?IFtQCjrLB#sGR!N;UNca6sJv-T~w4LQ3g6@CfJw)`1z| zW~<d&nVz2hdHyY<_X2sKxVf6T1Uv_ZQc9<Q@4!o-0xV5VP6BKfwPpJw;xbSN`rGAI zU|+lcHBd|`E!OMxw8`x__5A$&`oO@zVnocUXCvZxM07_)Q+=!60+uHxCbn_E{h7JB zIR*y@SJZj6S3RS?Qp*wXxmK&~V0NswHRI#sG@H$1z%}5F`k`8_wsvE7O{G$aN~QAG b{J+T$+X03p_V~Q~00000NkvXXu0mjf`lS0g literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/arrow-up.png b/src/wok/plugins/kimchi/ui/images/theme-default/arrow-up.png new file mode 100644 index 0000000000000000000000000000000000000000..40ce708941a35d8e1578e3cafb13d330fcf37c10 GIT binary patch literal 510 zcmV<a0RjGrP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B00004b3#c}2nYxW zd<bNS0005CNkl<ZIE~$rJ!?~O6vlt&78gOQf)-b$iZ2KSmn<r{=pcRoKR^>nFL|-K z<P!wcpd?CfHn&cG04E2BSc>ALR0_q4C<tzXLwz0xuM%P+9mQw+bI$X7&N+YhZxw$l zw%cuhqd)?D=yW<$dy{E}EXzXDIorAIN0Jt@ESnlU6=eH_?XILNk}lfr+Foe2S`+*K zNN6^jGZAqXSOrdwgb8>L+_1gY?RIxYeKVtvMx(I@xN7?WaJqnO0H1(4;DGH5z`IhZ zv^5+KzfWAv_T^%QGm=8mhNNXlHA$}}Vf&cvySA^_>-FFM07%nxFK`XWfmt9TVjW16 zBv}KHbRM`}OccO3AO%)?z24WTR;&AgMW7iGM~Z-T;AX$ye=$07nx?00KLjoTVfzbk z2gnoK%eGs#=OiKNne7_za{MEDz1|z!4M|TW+4iBrpCyv!CC%!mp4eWr{k-4rdmL2U z@s;he?Z=XKB<+(lALVlSxb1s@BVsAf^X*B1aaAgn!;<a;2P2}E09!x<ShBq<2*Aq9 z%4gsfPy;rTJkJGe0^5VZV7HuK`Ut!&82^}l07Tsjb=)@&!~g&Q07*qoM6N<$f&;VO AtpET3 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/arrow_out.png b/src/wok/plugins/kimchi/ui/images/theme-default/arrow_out.png new file mode 100644 index 0000000000000000000000000000000000000000..f5b4b8ed7de68dc79673472aab7c9672233bc8a7 GIT binary patch literal 3048 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/group.png b/src/wok/plugins/kimchi/ui/images/theme-default/group.png new file mode 100644 index 0000000000000000000000000000000000000000..1160bd97178375f202c3c20fef689ddf4a6dcfae GIT binary patch literal 1703 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/host-icon-sprite.png b/src/wok/plugins/kimchi/ui/images/theme-default/host-icon-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..da1cd3f2562a5905a526446bcc8fc18bea06c734 GIT binary patch literal 1034 zcmV+l1oiugP)<h;3K|Lk000e1NJLTq003?P000^Y1^@s6R_JLg00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3t>283nlSO%wnC03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00VAGL_t(&-tAexPZU8E z{`PW&1_K4^OH?eZvAftnL5(5A#KOeLoryLc6xvbn7idfrLqY*-qLqe%L|Ypgg$i36 z(dbjkBSwPpvl)`j+}`fa-u^(2muzw~^LF01^X{8@Zysm_jzUN2Fh`A~Pjc5hKFL~I z+Z}W#NVXC{Y>}KuY7;pNNspw5tO0f7IFeP8D-r4|QCJ)u*CII!fKd<0S(2@?9Y=DD z<R_9!@=PZG-V7bLl9r_@9LG4P1)Rq+9Y?Z{<af)|`7qr|9MBxV)c`acbbCfT&pQC{ z%j$mX<hUFic+YA-2XN6mak_;`9K$+|XK?mUTkTPj&CIsEF5cU<hDHKoBi7iJvbM^i z*Tus8!czN9a>$8s1<N-8RRC8_`$GnE?vb2Jz_2+0dq-p)ngI3#?S24@sTh|bQ+;d5 zH%uEL`5>TIAzA4bYua?6Ovagcnjz|Ai5Da5sM6$aQ8E^l$E3xZb^24#IlFC{{Sv!X zdPZ`HoHhZhMyRZj95%WP!xe@3m<5`5?4yL_;89M%??>JmIN;83>nfaa#_lVU`y{Vr z67H9I<>i9?7&xxqKI>29L{6meTNYI%0Emdw!G8E&QVE-1Rcq#UWYToK0q{&jHq+Sd zU}FNnI)H(=d=J2sh`dW;({;UEMO8gxC-hsZHn6+_8Cz8V%OQ7`GXQ2(brnD(BP{Cx z=6&CP5~WnH*XNDysWO?Qs#^et%pdJCfS-x(Dpi%PY)T=^F&E8^3~dd>ISl}e&Opgd z>jQ8Oz$E}@0sK%^x9UJ%4m8_i!$G%aL_`u-2dYWWvJAJ-u<F2q`TaRWw_eh}pDyEv z>yyFRKMi0z&>mIQrid&iVqA_4oV3~tBC;bQJ7_QMEcIHnC?X#LytKL>s%r052kP~D zY<0ls{5RDBFDZ*`N~hftRMj`pW7t-CT|^!ky^4A7udB@<*0kwB7vI-)nq=l_0(fe5 zkBi7gBF9Bcoc6<NF-#g4k&RAyOj^9%=3_<YamMC0fYCtLR}r}oxmAjYmj^hLTt`+1 zRCTyh@)?Dxh{Y^e+NuMpIv5&N7WDCVBl5M=0B!+z9Oa;-3`iRt9+5!hy{f(jFa_X- zh^)1x14RNBkv{-#tLjpkD=*u5$B=13xe4GPc-8~JKL<=Y@!??g0{{R307*qoM6N<$ Ef;%S0RsaA1 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-back.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-back.png new file mode 100644 index 0000000000000000000000000000000000000000..eca9948ca7f0c4eaa3c36d20e4fb2d72ac79b2d8 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ-JULvArbCxuSRn<C<w3y#71eK zT)K72v}tTjuGj8VdL~>5@BMC(b=2TTSM%q?EFRVyo~rsxN}a;s^<!54Nr^X)q~g@x z^JN^q%lN$@{6O#y=>_6_at*5DZ*m1wnKN6b$4D%Y<YV4)Sh2y?LNY=0pS;7ws8U8N zRxu8ago~UK3wje6O$2ieNH=}5eE-k*!lQ-zA6s=>GtE7+RQk>%v4gUYTRgh7os8Nz s0?gB1y)!t(JaL}EzvtS*278#<8D&)ztBkXBf!<*7boFyt=akR{0KU{)8UO$Q literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-camera.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-camera.png new file mode 100644 index 0000000000000000000000000000000000000000..f181545ed44db658aa6373c28ca33724f84a3d05 GIT binary patch literal 4860 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-design.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-design.png new file mode 100644 index 0000000000000000000000000000000000000000..c8931dae58e4d3d95d7a1ebba04ed0481f4b74ff GIT binary patch literal 4562 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-detail.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-detail.png new file mode 100644 index 0000000000000000000000000000000000000000..978df03ca7480d0f9ebb3b4f1a1f73226fcbe246 GIT binary patch literal 3079 zcmV+i4EXbjP)<h;3K|Lk000e1NJLTq000~S000{Z1^@s6ZwT)!00009a7bBm000XU z000XU0RWnu7ytkYPiaF#P*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-oy)XH-+^7Crag z^g>IBfRsybQWXdwQbLP>6p<z>Aqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uh<iVD~V z<RPMtgQJLw%KPDaqifc@_vX$1wbwr9tn;0-&j-K=43<bUQ8j=JsX`tR;Dg7+#^K~H zK!FM*Z~zbpvt%K2{UZSY_<lS*D<Z%Lz5oGu(+dayz)hRLFdT>f59&ghTmgWD0l;*T zI7<kC6aYYajzXpYKt=(8otP$50H6c_V9R4-;{Z@C0AMG7=F<Rxo%or10RUT+Ar%3j zkpLhQWr#!oXgdI`&sK^>09Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-<?i z0%4j!F2Z@488U%158(66005wo6%pWr^Zj_v4zAA5HjcIqUoGmt2LB>rV&nehQ1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_<lS*MWK+n+1cgf z<k(8YLR(?VSAG6x!e78w{cQPuJpA|d;J)G{fihizM+Erb!p!tcr5w+a34~(Y=8s4G zw+sLL9n&JjNn*KJDiq^U5^;`1nvC-@r6P$!k}1U{(*I=Q-z@tBKHoI}uxdU5dyy@u zU1J0GOD7Ombim^G008p4Z^6_k2m^p<gW=D2|L;HjN1!DDfM!XOaR2~bL?kX$%CkSm z2mk;?pn)o|K^yeJ7%adB9Ki+L!3+FgHiSYX#KJ-lLJDMn9CBbOtb#%)hRv`YDqt_v zKpix|QD}yfa1JiQRk#j4a1Z)n2%f<xynzV>LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_Ifq<Ex{*7`05XF7hP+2Hl!3BQJ=6@fL%FCo z8iYoo3(#bAF`ADSpqtQgv>H8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ<AYmRsNLWl*PS{AOARHt#5!wki2?K;t z!Y3k=s7tgax)J%r7-BLphge7~Bi0g+6E6^Zh(p9TBoc{3GAFr^0!gu?RMHaCM$&Fl zBk3%un>0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 z<uv66WtcKSRim0x-Ke2d5jBrmLam{;Qm;{ms1r1GnmNsb7D-E`t)i9F8fX`2_i3-_ zbh;7Ul^#x)&{xvS=|||7=mYe33=M`AgU5(xC>fg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vF<Q0r40Q)j6=sE4X&sBct1q<&fbi3VB2Ov6t@q*0);U*o*SAPZv|vv@2aYYnT0 zb%8a+Cb7-ge0D0knEf5Qi#@8Tp*ce{N;6lpQuCB%KL_KOarm5cP6_8Ir<e17iry6O zDdH&`rZh~sF=bq9s+O0QSgS~@QL9Jmy*94xr=6y~MY~!1fet~(N+(<=M`w@D1)b+p z*;C!83a1uLJv#NSE~;y#8=<>IcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a<fJbF^|4I#xQ~n$Dc= zKYhjYmgz5NSkDm8*fZm{6U!;YX`NG>(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-k<Mujg;0Lz*3buG=3$G&ehepthlN*$KaOySSQ^nWmo<0M+(UEUMEXRQ zMBbZcF;6+KElM>iKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BK<z=<L*0kfKU@CX*zeqbYQT4(^U>T#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot<a{81DF0~rvGr5Xr~8u`lav1h z1DNytV>2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0003pNkl<Zc-rjNKTg9i6oB#Xy(D%}o3>nnl_4EC2vUxQI+vN_AT9x__!AOR{8;RY z1Gt^yB}1fqdbWR3#LT$lDgi`f18jgRKr?<n06p*yd;-TZzG$3t_o~{RVW?ncyKx-% zfTdtr6h$W@TUA9wvKGy37>3~ys8aA(L~fjOR8@tl<__KhYv3ydCsloR&fR(Mvrkyp z^$Sn~LkjjHa#U5$v8B$r67Z*63Vbw8^WeR&7K=rxs#%H>SKGEvfB-?v3=t7CtAJ}@ z1r(WvlgR7`H~@zfTmws>O6Q!>;deAR{%5iB-gm0no#6~a2w~Uv{T`T34pp@ik*$bi zzci{knAz-bb~rnn9nKDOI*c5e=x~|QVX`;?ufSUhYK;2$%(<rln4-f;F8$~IHvo#L Voc;M?!D;{i002ovPDHLkV1gS<wu1lw literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-iso.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-iso.png new file mode 100644 index 0000000000000000000000000000000000000000..d76290427e75fd1c6ad914acde114e065760b30d GIT binary patch literal 4188 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-list.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-list.png new file mode 100644 index 0000000000000000000000000000000000000000..7b3b595ffce5fab49dbd2588cebd113922b9dcbd GIT binary patch literal 2983 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-load.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-load.png new file mode 100644 index 0000000000000000000000000000000000000000..2ad195ca84691697a63e720003fe48b1573590f9 GIT binary patch literal 3678 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-local.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-local.png new file mode 100644 index 0000000000000000000000000000000000000000..092026fbc9301b311d5e9bb8556450cd6fa93ff9 GIT binary patch literal 425 zcmV;a0apHrP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004SNkl<ZSV!%a z3vt3g5QaekH~<v14oDTWC}^snNB{>oAXQKt6bFEU4h~uc@P9LR3`t0`$1CkjcIF>Q z*t`919|`SN&DO3teyag!GGNU>tY)1DHtd`Hld3fqfJmEsRc%!8`;+c3%hpx_Ji6dr zeNLr`5o9L6cj-q0VqLVZ41l1V9EcBzGKAPd&d)A55WwWD41m-PrH%9=eL5Hm1ScLz zKs-q71%w$Ok>{)QEA=H(%5{jb2W11MBXLb*rtDM(VtLT<1drSXA%U~LlyK#4<|ZQx zKtSK|rZF;-`9tBJnv7$BY{yeSU}(lm%ufOkxykSV*^VE}`TGjNJva~pDUni>;Q^NV z!FN1mI5{$xq`|G_pu{>%1^`eUcl@n_d;Y$@93}&R-4#xD_7?vNfKufiBn3yO<4teR z&<t20%)x;V1vtCbMGG5%Kal|*JiIRJuq_#g+|#gkXM(Nb#Z~_aZ_d;J)SiJoPBKc^ Ts5X1J00000NkvXXu0mjf;iIrQ literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-power-down.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-power-down.png new file mode 100644 index 0000000000000000000000000000000000000000..2c653bc6af72f628cea721d618849d912c1aa186 GIT binary patch literal 4372 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 O0000<MNUMnLSTY^CsYvt literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-power-up.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-power-up.png new file mode 100644 index 0000000000000000000000000000000000000000..a4575f90120e56d21d42dc4fbefcfc571a30ef71 GIT binary patch literal 4367 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 JPDHLkV1k37QX&8V literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-qcow2.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-qcow2.png new file mode 100644 index 0000000000000000000000000000000000000000..a5220093e8143db08887f31decf8af059d654ba7 GIT binary patch literal 4684 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 O0000<MNUMnLSTX?tJj49 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-raw.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-raw.png new file mode 100644 index 0000000000000000000000000000000000000000..b5def8f3dddd81a3a570f3acbd3b206684275cbf GIT binary patch literal 4679 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 JPDHLkV1mo3<ud>P literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-remote.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-remote.png new file mode 100644 index 0000000000000000000000000000000000000000..e316dc0701db28b51db92b5e6e6985f3b82b25e9 GIT binary patch literal 1005 zcmV<J0}}j+P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F8000BDNkl<ZSVxuC zkM$Ep5C?FmK&Zf@0<Z$l3WN#>6^IoWD-bF$Rv=bjr~s(IPytwh&gb4t+~2yJgn4gX z_U7i#cjw>b{=F}wr=k9R@DltW_(__-kKfP1r{Fiif86T!{tb$P{S+*?ptle(fc%)i zrZ(3A?8EYhCh&)Jd`!n~j${J3HGw`(IUuisf1V+j0pRS<bj<d*U|>$STt9S{)PJ7( zfPR;t@3<HNa2vsa_?S1Uo8B1ztR^Fe;IA_{5O;j_00jLjgG=|zJXe!R>6en;`8EBp zf7E881<<Gcl#w3B?=iuYtOrr@rFr4}E(5pvF7r(ZS^)bH>h_+b4FIL_UPB3ZDI06N zck32V>z5Dl?iGL;S~`Lqg3Y!YA<v@`lSO6YT=$!x5uHm>0646Uo!D$ySQCgdn?4Im z$nfq4e<o{J066+8SmV_U&w!lMH&FmUBby)@;aB#YzYTtyzhXWFK$rfW!ELWmA5^Rj z^$c0a*I*;8$pi$3zF<Ik|19l2KLg+pEd6Q<z%kg|_T)wy@lx{%x=(xhHO7FD`;M?b zrLWfj2q-nx?Q4Pp;_qN%!+_pl0IU@W_)8;jA;gw{09twrfB@<)ZO(`zEbyALC7(MV z=SS~Hb6*Nod(Xfq)q4Q`NsWFh?nACLY9_UndZ0#Spns`<*jZ|t@=TWiP*U?<@G-d3 z+1j_~YXIo#3qa_~z_y601klYI%%l_`y<r-FY6;j{R5OtL8{<Rpr{E8xCY%|sg*p{v zq(-W200l(JoJZ62I^=9+U~58X)cV?jDZLipi?kns7Nqa`+9NeB+ZaM>5h=y_D>d*q z0zmB)EVaFD`E6ZQnXByEB0?PK&PVBRbfYDNw%3TP+Uk>fzs6x}w1$8biyu4YK>;|# zgECxOwWGB1-;Xfa2!Q$D2U~nwtTNOzr(jvAjX1n&2y1WDdkaRep7_-1MVjvztlVzD z1b=RkLuQev4-m7FYyn99?t*UB8VKJS{|^K{H+-MEGJq6_p4JdlUERVnn;8M;pOMcz z;6~Kh??yd<wiKgGltZ>|^y)%zuWBE-xuECN&j659JO=BBQ?Ob0jP}9GWC3Z&YqW-f zuVV%Gd?#b0?&TD6LF?bqA<nfz^+rE(J&+}V?(&7S3;w^pngJ+>Zft9{UogPPIW30( z11kt{RbwevCi+9V27nRgoN#>SQ#x}Ra)Ffy_}MgV=C=T7;{bt|1Xd-gY^d)sgI~b+ b->ZKC*A4Oh7Gf$=00000NkvXXu0mjfz>VSq literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-reset.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-reset.png new file mode 100644 index 0000000000000000000000000000000000000000..eae8449a556d68a44c28144727f7bb3c5d2fc13c GIT binary patch literal 4576 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 KMNUMnLSTYcw5GuT literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-search.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-search.png new file mode 100644 index 0000000000000000000000000000000000000000..b38cf6cba2ae18095f990c7dd3736365d9965fe1 GIT binary patch literal 4197 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-sort.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-sort.png new file mode 100644 index 0000000000000000000000000000000000000000..78e8b3930368c9ee163ea6f28a0c5a1d631241a9 GIT binary patch literal 3421 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 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-tree.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-tree.png new file mode 100644 index 0000000000000000000000000000000000000000..5f7ed5312dac8d3bfb26010ea6555682f5a43f3d GIT binary patch literal 3526 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 A0ssI2 literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-user.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-user.png new file mode 100644 index 0000000000000000000000000000000000000000..f4258d420b98a019332bc742e15d53497e1012cf GIT binary patch literal 5366 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 U)&>o#U;qFB07*qoM6N<$f|wvR(EtDd literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/icon-volume-default.png b/src/wok/plugins/kimchi/ui/images/theme-default/icon-volume-default.png new file mode 100644 index 0000000000000000000000000000000000000000..ac906c7723e9c26900c347cf5e47e3192a5b2f88 GIT binary patch literal 4265 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 LNkvXXu0mjfnm8lp literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/kimchi-loading15x15.gif b/src/wok/plugins/kimchi/ui/images/theme-default/kimchi-loading15x15.gif new file mode 100644 index 0000000000000000000000000000000000000000..aaa4f85a0560dcb59d4bb70154a9144417aae926 GIT binary patch literal 1653 zcmZ?wbhEHb6krfwcz&0`fx$V3fzy*s(30KRoyj+pP0*a%B9B4Xkl)0X$H9|dJd8D} zo<ZDBSSFF7*jZT0OhTc9Q7nTgk3rREDud*7MxI>8&Ju=(ISf+93MQOdag7Y~1hic{ z8T#{u6)cohTNtM^7+W$J#50+i$>`cj=^O84k`pyFn#{1$Ur8%a&i6QjtgEuCfQhw> zh77A6gQ$gokA@_-E$2dp^>Sv?oMy2Rvbjr`S1FsTIOwZtnQE_R*m$2oUC1KhF@wT7 z#vS5TPBXdYi#jqhIC*|#&}Xr)`pY25?86wZk@$x}Azj<#4}*rAu{Vcnu(UhJUj}_& zGsWW!mvn9Irz#jqI|d0m<_4Kq$D4?%x#%8bJFV#KwS(tqvz9fdTmMyIV-~+CKU<>^ zTODbStQ;$e9OEp8kfaJrQB(IojUXN?PfLA&1ruKlE$<Ybz{O>Dnh|c+IZj3l84L_z z+ZiGkGQ_8gg)Ec{ZB|VbVu;;p8Ir+}TJcZ8St};J)7e)ugI_wAy~kUSA^Gq;v#nzB zo6<uZ9TN=&l6EuXHCx41&a>X&p6tkweNrgxtWY&KLrITauKX0wDL;*ZSPITdWuHCl z7S2#|o1wN-skGcGd-j}YNrw7v?ff;HUH7htly%83WoVk=SR=P3TA8QnVNZtdt|Td^ z4tBRT;l<gOCKJSuq^f)gOk<w3o@>%d>z1S5joVY2V;E+x4Cszxn7#dGQiZ}|@k{wq ze5<)H#@>~ixp+mvx~nC^*GqKvReGJxyd=J8Z|Hp0)LG8{Q?7j|(|J;(^S(;?X-VtX z{Ej0{$vo>WNUb@RHtpd12Emt&YTJ7ve>HRaY*WxWB$BmO<7<oVrMfE&d+u577yI7H zdv${AuTG6`J!)PD74G*(XRN&WpI$)mKewN2NU*bGfUA+70W%{51B2pE7EU3C{|q`n zHZYS2Ffee)GW_S1@z}87U^9oXR?LYF3lFyoD0|KE*tqCuBO@a=9coY=j!k!j<aB0i zc<9u4hfS*nq@!EHIP1=djf>s;v1`@Ep>^V-!(BqkNq@`*laF`Fn|H~0Zd!7(0h{Hf zM42F;^~FLc<zy?bzucZ38xtI`nPf?{Nk)rZI#dI#a%KcAJ>AR3%!JJ}Tb!mjcL>V+ z&Dl|qe5_B>QtnB`#6;Il`9QBD85<TlO;@&EX5(p~fXzf_h=~b~c^s@tPtrczcWUF8 zl$)Y)G4W`lxU|rj6$Xj!z4E$EBA!9O@K)2-%Q<1V)NzW4rQ4Q{qQ@s^Df6<iU^CYa zVJ@$f%ZvcUgKd2BZZRt+Jap&~-N|`mN5EtIK6cxtnin4*pO_@<TefG1V5)aFPwc)q zGcP6L3rdhvk&Uz{R5;QluAbJjV`8#<o~Uk<jm4+?Cwh5=mxY`NNH{%#3wux+Vs{|2 sX~(-16pJpOC{Q`pufUDnn>s|9;tWh`McC5^G?`;~3OSj#0+YEl0GD)I?EnA( literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/loading.gif b/src/wok/plugins/kimchi/ui/images/theme-default/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..60d46d2683817f81a678c5e3eef14ef35089d119 GIT binary patch literal 2190 zcmb7_`)^a%9l+0hKYVRpUtc?ZTqoD@wG*cy3TcL*WhlA#65q>!8Yk0A87qcR5=z^Y zJ}6yLW8%anCg23f7(z>6v~*HCLD#C)V8TgAFyR#lkMIsJ2?Pk}#t-{tn<Fg<w4ZkV zfO9_jobTtHkX|!=MwA6Cc<KdxeSQ7?{R0C7hYuef92^`P8ai_1NH&{2di3b<@bIx? z$BrLAe&WQ5lP6D}I(2GfWMp)7^z7NQ=g*%X8ymZL@#5vnm#<v8a`o!f>({T}ym|BX z?b~<m+_`)A?)dol>C>k#UApw};lrm-pWeH7@A2cuH*VZGbLPysbLXBsd2->xh5PsK z-@0|{(W6J#u3dZZ;6Wyn0ssH<{@XBrc3rJf9iClLR*pcq9lZaVGA~-cTwJ<V{Ke|% z2aWGEu8xZHm#<vbu>9kwSiEM<nzB{zMe7^iee1olcb9({1m1t57!ACjbmI64F96?~ zNjEu4wk5OaB@yzSY2Ieh>Dp5^|8B3&GwnsKbC7a$H`o>bJ6m5!w>ATZM9Td{e3$tc zjWsG1+oB*VWX5JIAat18f--iyEv<EJRR~i;Cf-a2+&r9sn5K5WWP~^dMM?AWd`gCE z4IaD(EhZaO$j*A%VPl~Ei22Rqa||PO<e*;tUr^ukpc^xtP18S}nbda0%ZKZ0T8G8p z_-8v_JHB!bzj0=-y7w>S?6jprX^u%;*E})&m@X<btU+0Z`K?TbG#Drbp10yUgr|`W zsSa&(r-C#3M;hzlG(efi#Oyo+#L@^tFaR@dgJjB%nal{gP3J>3K01G|X8g?nL><w6 z1aWE-(DOXthRmj>vG=DZwWyk1N)@fI550V^^3~sM{VqGB(zZ9UqMYs4nAn|Im0Hn~ z{i;yVrft2O-bY1gl?bVTGbl921)4R0peU3hjHkO4jMfoIh0S)hN5$!GBTqrAU<9K! zQ>fBI7Nbm~>HA2)=sDmanMH~IArHQ2N4Gjj=YF1UW2U3&$7p$uu5sV~x@o8$(JFq{ zQ?RMoL9TM`Q0{C2YvY$s-1?Rb3kd}E6@MR4w9p)(etw>YhcpYVkSyy*b-Kjm@=y4q zJG&H=)FGf5t!5p;=gNiv2^a!~zXVWjG;kK7D2V<_1Nn&qZj7o02i=E3cdd+`d<G~z z516XzYSP{)O=^*G@1AhHbI(t(cZP25_-<_K+yL2$T<n!#uC4F!K60k8Aw2Tu!l}LH z*y~}*ODTleyiBJ&PN%sg9!a*(l@US%Tu6av3j<Wx?R8)>m5&1ogCH1zEIykIdN33G zHozeXK{SSx-ahn21eb>-c#)EcObQg9=WDOp)RbLNoD-;II<@#0d(uBO%<_AJMbY5) zxrDK0fG^8H$=%_mFuG}8{n+-Iuo|0PS<SJ!nNTpM4bjQcl&LkbAysNpU`)4!RMJGL z0Cg7S<wg+&I069YM*LHF4WS_vF?c_y*Qjn36&x=m^}Rwyz-)tWK%YFz<AshB6CKN9 zQoA9Ou{gfDs-k{ne8;a+ACiDy5RV)kS;$%Qk@1+wI=ZS_>NuRY)O3A2)tE#G-K3&a z0@ewe-OjWn+Y4;APe1-#V{>pAjcbTQEI{Qp1fVeei4!&poCd9QmC!{W)ncE!-QK)l zt#^a>kZc_~ytH;w-3#faCenRHNM<df#qsleU$yT~|0v!$LbSe8QH7gBeO>Id108Vl z`woUrXKup3EEFgZITI5xOlNQf!4oS~+{*KYwxpiwFem`l&7{_bY*+1tR;3w&+#E%* z4%p<fXcn)*<Dta-1v_7I_?%8(fzYEOwwP1$q1>;P*XkzuUMM#?QErgWJuTJQC1jo+ z*gg87a_(tUpSOVvk7m+o2jE&`;0Y-ecSNiAOSssb$js78Hpvi*zNKRUj-%JdK~9}w z;B*tAVh*nxRbk%Et@GG?7Q|^GSJ@X!ei>QkFQQ9J3Bj~5nCJPyV|6Wnt#Za=S*Vx} zJiFKz!tIy{*UKg~FSJjWrp3^ge_veLL!aVjgjFk&go4E=Xp2=fEdlJ8gH7rAvjRp* zOshhx-?g6BQ9sL)F;_`kYfF*}ZPA%!YF?2O(KrvQSf}`52TKqp9x~*aWmwJ^sRA3} zS_^%qz(RrBW_Jf9UFJdqxv|Wu43nMI_d>a?6Xm*?oW81t^71YH{rh#fJY5sXfCgH? zI3Rw#u`re!ykhCEe^7brrP2hbQ7vMbq!S_8>~wlo>*f@ZD?>AF%zY_39aYc*(V??; z^BPXbhj-0mIEdnnorR>;ihB%U$z_#zUSjjs=@$8K@%|qTKRk2yzs*u;Qajlj8D~iW zRL*!kx^qN^gKUkQ>Jxh%V(^<YOMDQ(@!&xD!JQSO(f(LfNuiD{mQAH?>okN(VXcX} z6f;jI%sRPNwieo3WXNnaDi*g1=1mwzvk(z5D2o}_z5r%lqzfKS;0~GjgMwe~6W~7% L$~1kj8oc@+?)_VM literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/images/theme-default/user.png b/src/wok/plugins/kimchi/ui/images/theme-default/user.png new file mode 100644 index 0000000000000000000000000000000000000000..c57a81a92757ef31c424a4e6c741f71db62a1092 GIT binary patch literal 1322 zcmV+_1=aeAP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$%t=H+RCwCFS6xgTRTRGSvwt(QEW2!% zZEC<RY*%PmU|~TT(9l}brY~)zO*HkzHZ`VcV>GER{yyo84?Y{zXpHs6S4l9Y#$eJ` zmI9TeNz<hS;wC6n(*0#;*YAuwlVv;L6r^`@m^(Xj@A=NT=X~eDmCI%J$6w2=dc>kV zY@@+(9ODK4xF85;1zu=k91CHOq^hbvsYP|PR4&aWrYD(|;jiDtI5Pm<(b&U^nWnhO zZnuB!bUFte4hIuOQ3F&emDt+a8q4K!YCf0$1oO+2)4!@#0EkwQl5$ualok1!EXhHq z%gJmu8{>K206<bG6ogDB^F}6}*^Ol{S=pO6{k6PaIG$r3kLNqL+Z|Ng3M1<QNK>wD z0wClKm&?WQ4U=X0#ew+2^IHe7-h8rlfP@r~VhtmXu2yJ}XCzr-e!u_2cz2($B>?5B zi|2UO+S2;E!|Bj0HB)Q`0>S806y@n{9{~c7$%@p!ndP-YM`IIhEY=e{_Fn+RjXY4D zb{x;w(OtLDQsClyUxV+7?FS)7Fxa?e#qxE6tFbYV-gXdDdWFN`J9K{(0F)I&&kRj$ zI|#vW?8M0vpCb(|D<`nShlY!hry^t9K7x{3LJ-PdzWUnvKdl1r@A9)#r$@fP4l7&p zK#etB9o>b2g9B$ST)a@CRMeTzOi1}V@4bC5&=`2jO0Zg@ViXxFP-BUi$(LJN_Ksfp z=3D3WYuB~o(FYyT;UkCH$jA$KK}644v0lp-vto3ht%C^2h1~xbJa874jpHaz!TRjf zY@!{XyqnEtPcAMl+BGYX^P$j_DNIKpA3+{;9_VVv`tOm%b^yJ6^VZZ?maAd3z0;0@ z^8+}4h*+&yEHYHNtJz%k6}(OoDNW5J6wD))C57Iu_-s)vYB2+#M<hwQVt3em#0U9& zo&oSVtQoZgARg=c6uf^<=YBd{Y`}8a9F^U1Jl{ry%u<!a_#1N%?h2Ge@cpwW*%8Sl zF#ymAiApspWGS6aAB88zHwA!z8&qWFXDTRUy%7gEZ}J3fMsuAPv~1!2Wj+Ec3L+D2 zqQ(OhuzFCF7qC8cf8~C7W^Vd{X+O}>78M%&4WH3QB-PYQo53<|<J#h5P&Rc-l^#J? ztdGi32J7nTKEUIfrfCS5pT-%6Ny$cqM^~a*D~g8DbG5~0>&O6nb1AyN(`O36>+`;^ zE8i^Fw<;AciT(!v#fQ?cbAMMCx}7NsJl&F=7!*g?e<hVl1yaAKR6|o}Z|D*QkY09o zN@#y%ln=dSY#kHg^-=2m9;N1QW$4+`+|+aik2gd;`n?U_M)dhR4nPNiKf{Ix&_Fij z3wd5}JSG6RifhF^Mi%tOdm`1jyVF9%1!9s64=8STpq4mxa*!S{s%Us%UnHDGZax<4 zb!iSYtJOTviuu)rdkcFeCVpX4i3FROnWX~qzgZm!1kk2;v%da**4x{|>b>>js0Gj0 z79%RJ$03IxgUidyp5)ymo1dR&^T~O(w6w(16;L1%wz|4%C<yKjGVr{ij5;GUFVxVY zR|qke<XXV1A0cCv`|^h6xNTp%_8-x2w{KCTwpR&x%A<1^#8<T}S=9xRvL(nY<R)Z} gniR8!<R1YB09_*wa#VgYhyVZp07*qoM6N<$f^kM~^#A|> literal 0 HcmV?d00001 diff --git a/src/wok/plugins/kimchi/ui/js/Makefile.am b/src/wok/plugins/kimchi/ui/js/Makefile.am new file mode 100644 index 0000000..c9d1218 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/Makefile.am @@ -0,0 +1,27 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +EXTRA_DIST = src + +jsdir = $(datadir)/wok/plugins/kimchi/ui/js + +dist_js_DATA = kimchi.min.js $(filter-out kimchi.min.js, $(wildcard *.js)) + +kimchi.min.js: src/*.js + cat $(sort $^) > $@ + +CLEANFILES = kimchi.min.js diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.api.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.api.js new file mode 100644 index 0000000..fde803a --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.api.js @@ -0,0 +1,1355 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var kimchi = { + + widget: {}, + + trackingTasks: [], + + /** + * + * Get host capabilities + * suc: callback if succeed err: callback if failed + */ + getCapabilities : function(suc, err, done) { + done = typeof done !== 'undefined' ? done: function(){}; + wok.requestJSON({ + url : "plugins/kimchi/config/capabilities", + type : "GET", + contentType : "application/json", + dataType : "json", + success: suc, + error: err, + complete: done + }); + }, + + /** + * Get the i18 strings. + */ + getI18n: function(suc, err, url, sync) { + wok.requestJSON({ + url : url ? url : 'plugins/kimchi/i18n.json', + type : 'GET', + resend: true, + dataType : 'json', + async : !sync, + success : suc, + error: err + }); + }, + + /** + * Get the host static information. + */ + getHost: function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/host', + type : 'GET', + resend: true, + contentType : 'application/json', + dataType : 'json', + success : suc, + error: err + }); + }, + + /** + * Get the dynamic host stats (usually used for monitoring). + */ + getHostStats : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/host/stats', + type : 'GET', + contentType : 'application/json', + headers: {'Wok-Robot': 'wok-robot'}, + dataType : 'json', + success : suc, + error: err + }); + }, + + /** + * Get the historic host stats. + */ + getHostStatsHistory : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/host/stats/history', + type : 'GET', + resend: true, + contentType : 'application/json', + headers: {'Wok-Robot': 'wok-robot'}, + dataType : 'json', + success : suc, + error: err + }); + }, + + /** + * + * Create a new Virtual Machine. Usage: kimchi.createVM({ name: 'MyUbuntu', + * template: '/templates/ubuntu_base' }, creationSuc, creationErr); + * + * settings: name *(optional)*: The name of the VM. Used to identify the VM + * in this API. If omitted, a name will be chosen based on the template + * used. template: The URI of a Template to use when building the VM + * storagepool *(optional)*: Assign a specific Storage Pool to the new VM + * suc: callback if succeed err: callback if failed + */ + createVM : function(settings, suc, err) { + wok.requestJSON({ + url : "plugins/kimchi/vms", + type : "POST", + contentType : "application/json", + data : JSON.stringify(settings), + dataType : "json" + }).done(suc).fail(err); + }, + + /** + * + * Create a new Template. settings name: The name of the Template. Used to + * identify the Template in this API suc: callback if succeed err: callback + * if failed + */ + createTemplate : function(settings, suc, err) { + wok.requestJSON({ + url : "plugins/kimchi/templates", + type : "POST", + contentType : "application/json", + data : JSON.stringify(settings), + dataType : "json", + success: suc, + error: err + }); + }, + + deleteTemplate : function(tem, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/templates/' + encodeURIComponent(tem), + type : 'DELETE', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + cloneTemplate : function(tem, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/templates/' + encodeURIComponent(tem) + "/clone", + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + listTemplates : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/templates', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + /** + * Retrieve the information of a template by the given name. + */ + retrieveTemplate : function(templateName, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/templates/' + encodeURIComponent(templateName), + type : 'GET', + contentType : 'application/json', + dataType : 'json' + }).done(suc); + }, + + /** + * Update a template with new information. TODO: Update me when the RESTful + * API is available. Now work it around by remove the template and then + * recreate it with new information. + */ + updateTemplate : function(name, settings, suc, err) { + $.ajax({ + url : 'plugins/kimchi/templates/' + encodeURIComponent(name), + type : 'PUT', + contentType : 'application/json', + data : JSON.stringify(settings), + dataType : 'json' + }).done(suc).fail(err); + }, + + /** + * Create a new Storage Pool. settings name: The name of the Storage Pool + * path: The path of the defined Storage Pool type: The type of the defined + * Storage Pool capacity: The total space which can be used to store volumes + * The unit is MBytes suc: callback if succeed err: callback if failed + */ + createStoragePool : function(settings, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/storagepools', + type : 'POST', + contentType : 'application/json', + data : JSON.stringify(settings), + dataType : 'json' + }).done(suc).fail(err); + }, + + updateStoragePool : function(name, content, suc, err) { + $.ajax({ + url : "plugins/kimchi/storagepools/" + encodeURIComponent(name), + type : 'PUT', + contentType : 'application/json', + dataType : 'json', + data : JSON.stringify(content) + }).done(suc).fail(err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + }); + }, + + startVM : function(vm, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/start', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + poweroffVM : function(vm, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/poweroff', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + shutdownVM : function(vm, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/shutdown', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + resetVM : function(vm, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/reset', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + suspendVM : function(vm, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/suspend', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + resumeVM : function(vm, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/resume', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + /** + * Retrieve the information of a given VM by its name. + * + * @param vm VM name + * @param suc callback for success + * @param err callback for error + */ + retrieveVM : function(vm, suc, err) { + $.ajax({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm), + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success: suc, + error: err + }); + }, + + /** + * Update a VM with new information. + */ + updateVM : function(name, settings, suc, err) { + $.ajax({ + url : "plugins/kimchi/vms/" + encodeURIComponent(name), + type : 'PUT', + contentType : 'application/json', + data : JSON.stringify(settings), + dataType : 'json', + success: suc, + error: err + }); + }, + + deleteVM : function(vm, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm), + type : 'DELETE', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + vncToVM : function(vm) { + wok.requestJSON({ + url : 'plugins/kimchi/config', + type : 'GET', + dataType : 'json' + }).done(function(data, textStatus, xhr) { + proxy_port = data['display_proxy_port']; + wok.requestJSON({ + url : "plugins/kimchi/vms/" + encodeURIComponent(vm) + "/connect", + type : "POST", + dataType : "json" + }).done(function() { + url = 'https://' + location.hostname + ':' + proxy_port; + url += "/console.html?url="; + url += encodeURIComponent("plugins/kimchi/novnc/vnc_auto.html"); + url += "&port=" + proxy_port; + /* + * From python documentation base64.urlsafe_b64encode(s) + * substitutes - instead of + and _ instead of / in the + * standard Base64 alphabet, BUT the result can still + * contain = which is not safe in a URL query component. + * So remove it when needed as base64 can work well without it. + * */ + url += "&path=?token=" + wok.urlSafeB64Encode(vm).replace(/=*$/g, ""); + url += "&wok=" + location.port; + url += '&encrypt=1'; + window.open(url); + }); + }).error(function() { + wok.message.error.code('KCHAPI6002E'); + }); + }, + + spiceToVM : function(vm) { + wok.requestJSON({ + url : 'plugins/kimchi/config', + type : 'GET', + dataType : 'json' + }).done(function(data, textStatus, xhr) { + proxy_port = data['display_proxy_port']; + wok.requestJSON({ + url : "plugins/kimchi/vms/" + encodeURIComponent(vm) + "/connect", + type : "POST", + dataType : "json" + }).done(function(data, textStatus, xhr) { + url = 'https://' + location.hostname + ':' + proxy_port; + url += "/console.html?url=plugins/kimchi/spice_auto.html"; + url += "&port=" + proxy_port + "&listen=" + location.hostname; + /* + * From python documentation base64.urlsafe_b64encode(s) + * substitutes - instead of + and _ instead of / in the + * standard Base64 alphabet, BUT the result can still + * contain = which is not safe in a URL query component. + * So remove it when needed as base64 can work well without it. + * */ + url += "&token=" + wok.urlSafeB64Encode(vm).replace(/=*$/g, ""); + url += "&wok=" + location.port; + url += '&encrypt=1'; + window.open(url); + }); + }).error(function() { + wok.message.error.code('KCHAPI6002E'); + }); + }, + + listVMs : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms', + type : 'GET', + contentType : 'application/json', + headers: {'Wok-Robot': 'wok-robot'}, + dataType : 'json', + resend: true, + success : suc, + error : err + }); + }, + + listTemplates : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/templates', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend: true, + success : suc, + error : err + }); + }, + + listStoragePools : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/storagepools', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend: true, + success : suc, + error : err + }); + }, + + listStorageVolumes : function(poolName, suc, err) { + $.ajax({ + url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + listIsos : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/storagepools/kimchi_isos/storagevolumes', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + listDistros : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/config/distros', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + stepListDeepScanIsos : function(suc, err) { + var deepScanHandler = { + stop : false + }; + var isoPool = 'iso' + new Date().getTime(); + kimchi.createStoragePool({ + name : isoPool, + type : 'kimchi-iso', + path : '/' + }, function(result) { + var taskId = result.task_id; + function monitorTask() { + if (deepScanHandler.stop) { + return; + } + kimchi.getTask(taskId, function(result) { + var status = result.status; + if (status === "finished") { + if (deepScanHandler.stop) { + return; + } + kimchi.listStorageVolumes(isoPool, function(isos) { + if (deepScanHandler.stop) { + return; + } + suc(isos, true); + }, err); + } else if (status === "running") { + if (deepScanHandler.stop) { + return; + } + kimchi.listStorageVolumes(isoPool, function(isos) { + if (deepScanHandler.stop) { + return; + } + suc(isos, false); + setTimeout(monitorTask, 2000); + }, err); + } else if (status === "failed") { + if (deepScanHandler.stop) { + return; + } + err(result.message); + } + }, err); + } + setTimeout(monitorTask, 2000); + }, err); + return deepScanHandler; + }, + + getTask : function(taskId, suc, err) { + wok.requestJSON({ + url : 'tasks/' + encodeURIComponent(taskId), + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + getTasksByFilter : function(filter, suc, err, sync) { + wok.requestJSON({ + url : 'tasks?' + filter, + type : 'GET', + contentType : 'application/json', + dataType : 'json', + async : !sync, + success : suc, + error : err + }); + }, + + deleteStoragePool : function(poolName, suc, err) { + $.ajax({ + url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName), + type : 'DELETE', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + changePoolState : function(poolName, state, suc, err) { + if (state === 'activate' || state === 'deactivate') + $.ajax({ + url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/' + state, + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + listNetworks : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/networks', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + toggleNetwork : function(name, on, suc, err) { + var action = on ? "activate" : "deactivate"; + wok.requestJSON({ + url : 'plugins/kimchi/networks/' + encodeURIComponent(name) + '/' + action, + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + createNetwork : function(network, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/networks', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + data : JSON.stringify(network), + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getInterfaces : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/interfaces', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + deleteNetwork : function(name, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/networks/' + encodeURIComponent(name), + type : 'DELETE', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + listReports : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/debugreports', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend: true, + success : suc, + error : err + }); + }, + + trackTask : function(taskID, suc, err, progress) { + var onTaskResponse = function(result) { + var taskStatus = result['status']; + switch(taskStatus) { + case 'running': + progress && progress(result); + setTimeout(function() { + kimchi.trackTask(taskID, suc, err, progress); + }, 2000); + break; + case 'finished': + suc && suc(result); + break; + case 'failed': + err && err(result); + break; + default: + break; + } + }; + + kimchi.getTask(taskID, onTaskResponse, err); + if(kimchi.trackingTasks.indexOf(taskID) < 0) + kimchi.trackingTasks.push(taskID); + }, + + createReport: function(settings, suc, err, progress) { + var onResponse = function(data) { + taskID = data['id']; + kimchi.trackTask(taskID, suc, err, progress); + }; + + wok.requestJSON({ + url : 'plugins/kimchi/debugreports', + type : "POST", + contentType : "application/json", + data : JSON.stringify(settings), + dataType : "json", + success : onResponse, + error : err + }); + }, + + renameReport : function(name, settings, suc, err) { + $.ajax({ + url : "plugins/kimchi/debugreports/" + encodeURIComponent(name), + type : 'PUT', + contentType : 'application/json', + data : JSON.stringify(settings), + dataType : 'json', + success: suc, + error: err + }); + }, + + deleteReport: function(settings, suc, err) { + var reportName = encodeURIComponent(settings['name']); + wok.requestJSON({ + url : 'plugins/kimchi/debugreports/' + reportName, + type : 'DELETE', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + downloadReport: function(settings, suc, err) { + window.open(settings['file']); + }, + + shutdown: function(settings, suc, err) { + var reboot = settings && settings['reboot'] === true; + var url = 'plugins/kimchi/host/' + (reboot ? 'reboot' : 'shutdown'); + wok.requestJSON({ + url : url, + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + listHostPartitions : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/host/partitions', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + getStorageServers: function(type, suc, err) { + var url = 'plugins/kimchi/storageservers?_target_type=' + type; + wok.requestJSON({ + url : url, + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getStorageTargets: function(server,type, suc, err) { + var url = 'plugins/kimchi/storageservers/' + server + '/storagetargets?_target_type=' + type; + wok.requestJSON({ + url : url, + type : 'GET', + contentType : 'application/json', + timeout: 2000, + dataType : 'json', + success : suc, + error : err + }); + }, + + getStoragePool: function(poolName, suc, err) { + var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName); + wok.requestJSON({ + url : url, + type : 'GET', + contentType : 'application/json', + timeout: 2000, + dataType : 'json', + success : suc, + error : err + }); + }, + + getStoragePoolVolume: function(poolName, volumeName, suc, err) { + var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName); + wok.requestJSON({ + url : url, + type : 'GET', + contentType : 'application/json', + timeout: 2000, + dataType : 'json', + success : suc, + error : err + }); + }, + + addVMStorage : function(settings, suc, err) { + var vm = encodeURIComponent(settings['vm']); + delete settings['vm']; + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + vm + '/storages', + type : 'POST', + contentType : 'application/json', + data : JSON.stringify(settings), + dataType : 'json', + success : suc, + error : err + }); + }, + + retrieveVMStorage : function(settings, suc, err) { + var vm = encodeURIComponent(settings['vm']); + var dev = encodeURIComponent(settings['dev']); + wok.requestJSON({ + url : "plugins/kimchi/vms/" + vm + '/storages/' + dev, + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success: suc, + error: err + }); + }, + + replaceVMStorage : function(settings, suc, err) { + var vm = encodeURIComponent(settings['vm']); + var dev = encodeURIComponent(settings['dev']); + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + vm + '/storages/' + dev, + type : 'PUT', + contentType : 'application/json', + data : JSON.stringify({ + path: settings['path'] + }), + dataType : 'json', + success : suc, + error : err + }); + }, + + deleteVMStorage : function(settings, suc, err) { + var vm = settings['vm']; + var dev = settings['dev']; + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + + '/storages/' + encodeURIComponent(dev), + type : 'DELETE', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + listVMStorages : function(params, suc, err) { + var vm = encodeURIComponent(params['vm']); + var type = params['storageType']; + var url = 'plugins/kimchi/vms/' + vm + '/storages'; + if(type) { + url += '?type=' + type; + } + wok.requestJSON({ + url : url, + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + listSoftwareUpdates : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/host/packagesupdate', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend: true, + success : suc, + error : err + }); + }, + + updateSoftware : function(suc, err, progress) { + var taskID = -1; + var onResponse = function(data) { + taskID = data['id']; + trackTask(); + }; + + var trackTask = function() { + kimchi.getTask(taskID, onTaskResponse, err); + }; + + var onTaskResponse = function(result) { + var taskStatus = result['status']; + switch(taskStatus) { + case 'running': + progress && progress(result); + setTimeout(function() { + trackTask(); + }, 200); + break; + case 'finished': + case 'failed': + suc(result); + break; + default: + break; + } + }; + + wok.requestJSON({ + url : 'plugins/kimchi/host/swupdate', + type : "POST", + contentType : "application/json", + dataType : "json", + success : onResponse, + error : err + }); + }, + + createRepository : function(settings, suc, err) { + wok.requestJSON({ + url : "plugins/kimchi/host/repositories", + type : "POST", + contentType : "application/json", + data : JSON.stringify(settings), + dataType : "json", + success: suc, + error: err + }); + }, + + retrieveRepository : function(repository, suc, err) { + var reposID = encodeURIComponent(repository); + wok.requestJSON({ + url : "plugins/kimchi/host/repositories/" + reposID, + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + updateRepository : function(name, settings, suc, err) { + var reposID = encodeURIComponent(name); + $.ajax({ + url : "plugins/kimchi/host/repositories/" + reposID, + type : 'PUT', + contentType : 'application/json', + data : JSON.stringify(settings), + dataType : 'json', + success : suc, + error : err + }); + }, + + enableRepository : function(name, enable, suc, err) { + var reposID = encodeURIComponent(name); + $.ajax({ + url : "plugins/kimchi/host/repositories/" + reposID + + '/' + (enable === true ? 'enable' : 'disable'), + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + deleteRepository : function(repository, suc, err) { + var reposID = encodeURIComponent(repository); + wok.requestJSON({ + url : 'plugins/kimchi/host/repositories/' + reposID, + type : 'DELETE', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + listRepositories : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/host/repositories', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend: true, + success : suc, + error : err + }); + }, + + getHostFCDevices: function(suc, err) { + var url = 'plugins/kimchi/host/devices?_cap=fc_host'; + wok.requestJSON({ + url : url, + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getGuestInterfaces: function(name, suc, err) { + var url = 'plugins/kimchi/vms/' + encodeURIComponent(name) + '/ifaces'; + wok.requestJSON({ + url : url, + type : 'GET', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err || function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + createGuestInterface : function(name, interface, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(name) + '/ifaces', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + data : JSON.stringify(interface), + success : suc, + error : err || function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + deleteGuestInterface : function(vm, mac, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/ifaces/' + encodeURIComponent(mac), + type : 'DELETE', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + updateGuestInterface : function(vm, mac, interface, suc, err) { + $.ajax({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/ifaces/' + encodeURIComponent(mac), + type : 'PUT', + contentType : 'application/json', + data : JSON.stringify(interface), + dataType : 'json', + success: suc, + error: err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getUserById : function(data, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/users?_user_id=' + data.user_id, + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + async : false, + success : suc && suc(data), + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getUsers : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/users', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getGroups : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/groups', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getHostPCIDevices : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/host/devices?_passthrough=true&_cap=pci', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getPCIDeviceCompanions : function(pcidev, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/host/devices?_passthrough_affected_by=' + pcidev, + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getISCSITargets : function(server, port, suc, err) { + server = encodeURIComponent(server); + port = port ? '&_server_port='+encodeURIComponent(port) : ''; + wok.requestJSON({ + url : 'plugins/kimchi/storageservers/' + server + '/storagetargets?_target_type=iscsi' + port, + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getPeers : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/peers', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getVMPCIDevices : function(id, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(id) + '/hostdevs', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + addVMPCIDevice : function(vm, device, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/'+ encodeURIComponent(vm) +'/hostdevs', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + data : JSON.stringify(device), + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + removeVMPCIDevice : function(vm, device, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/'+ encodeURIComponent(vm) +'/hostdevs/' + encodeURIComponent(device), + type : 'DELETE', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + /** + * Create a new volume with capacity + */ + createVolumeWithCapacity: function(poolName, settings, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes', + type : 'POST', + contentType : "application/json", + data : JSON.stringify(settings), + dataType : "json", + success : suc, + error : err + }); + }, + + /** + * Upload volume content + */ + uploadVolumeToSP: function(poolName, volumeName, settings, suc, err) { + var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName); + var fd = settings['formData']; + wok.requestJSON({ + url : url, + type : 'PUT', + data : fd, + processData : false, + contentType : false, + dataType: 'json', + success : suc, + error : err + }); + }, + + /** + * Add a volume to a given storage pool by URL. + */ + downloadVolumeToSP: function(settings, suc, err) { + var sp = encodeURIComponent(settings['sp']); + delete settings['sp']; + wok.requestJSON({ + url : 'plugins/kimchi/storagepools/' + sp + '/storagevolumes', + type : 'POST', + data : JSON.stringify(settings), + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err + }); + }, + + cloneGuest: function(vm, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + "/clone", + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + listSnapshots : function(vm, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getCurrentSnapshot : function(vm, suc, err, sync) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots/current', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + async : !sync, + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + revertSnapshot : function(vm, snapshot, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots/' + encodeURIComponent(snapshot) + '/revert', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + createSnapshot : function(vm, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots', + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + deleteSnapshot : function(vm, snapshot, suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots/' + encodeURIComponent(snapshot), + type : 'DELETE', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + getCPUInfo : function(suc, err) { + wok.requestJSON({ + url : 'plugins/kimchi/host/cpuinfo', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + } +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_add_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_add_main.js new file mode 100644 index 0000000..6be6f9a --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_add_main.js @@ -0,0 +1,86 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.guest_add_main = function() { + var showTemplates = function() { + wok.topic('templateCreated').unsubscribe(showTemplates); + kimchi.listTemplates(function(result) { + if (result && result.length) { + $('#prompt-create-template').addClass('hidden'); + $('#prompt-choose-template').removeClass('hidden'); + var html = ''; + var tmpl = $('#tmpl-template').html(); + $.each(result, function(index, value) { + html += wok.substitute(tmpl, value); + }); + $('#templateTile').html(html); + return; + } + + $('#btn-create-template').on('click', function(event) { + wok.topic('templateCreated').subscribe(showTemplates); + + wok.window.open('plugins/kimchi/template-add.html'); + + event.preventDefault(); + }); + + $('#prompt-choose-template').addClass('hidden'); + $('#prompt-create-template').removeClass('hidden'); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }; + + function validateForm() { + if (!$('input[name=template]:checked', '#templateTile').val()) { + return false; + } + return true; + } + + $('#form-vm-add').change(function() { + if (validateForm()) { + $('#vm-doAdd').attr('disabled', false); + } + }); + + var addGuest = function(event) { + $('#vm-doAdd').attr('disabled', true); + $('#vm-doAdd').attr('style', 'display:none'); + $('#vm-doAdding').attr('style', 'display'); + var formData = $('#form-vm-add').serializeObject(); + kimchi.createVM(formData, function() { + kimchi.listVmsAuto(); + wok.window.close(); + }, function(jqXHR, textStatus, errorThrown) { + $('#vm-doAdd').attr('style', 'display'); + $('#vm-doAdding').attr('style', 'display:none'); + var reason = jqXHR && + jqXHR['responseJSON'] && + jqXHR['responseJSON']['reason']; + wok.message.error(reason); + }); + + return false; + }; + + $('#form-vm-add').on('submit', addGuest); + $('#vm-doAdd').on('click', addGuest); + + showTemplates(); +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js new file mode 100644 index 0000000..7105c88 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_edit_main.js @@ -0,0 +1,759 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.guest_edit_main = function() { + var buttonContainer = $('#action-button-container'); + $('#guest-edit-tabs').tabs({ + beforeActivate: function(event, ui) { + var display_list = null; + if(kimchi.thisVMState === "running") { + display_list = ['form-guest-edit-permission']; + } else { + display_list = ['form-guest-edit-general', 'form-guest-edit-permission']; + } + $(buttonContainer).addClass('hidden'); + var deactivated = ui['newPanel']; + if(display_list.indexOf($(deactivated).attr('id')) >= 0) { + $(buttonContainer).removeClass('hidden'); + } + } + }); + + var guestEditForm = $('#form-guest-edit-general'); + var saveButton = $('#guest-edit-button-save'); + var authType; + + var refreshCDROMs = function() { + kimchi.listVMStorages({ + vm: kimchi.selectedGuest + }, function(storages) { + var container = $('#form-guest-edit-storage .body'); + $(container).empty(); + $.each(storages, function(index, storage) { + storage['vm'] = kimchi.selectedGuest; + rowHTML = $('#' + storage['type'] + '-row-tmpl').html(); + var templated = wok.substitute(rowHTML, storage); + container.append(templated); + }); + + $('.replace', container).button({ + icons: { + primary: 'ui-icon-pencil' + }, + text: false + }); + + $('.detach', container).button({ + icons: { + primary: 'ui-icon-trash' + }, + text: false + }); + if (kimchi.thisVMState === 'running') { + $('.detach[data-type="cdrom"]', container).remove(); + } + + $('.save', container).button({ + icons: { + primary: 'ui-icon-disk' + }, + text: false + }); + + $('.cancel', container).button({ + icons: { + primary: 'ui-icon-arrowreturnthick-1-w' + }, + text: false + }); + }); + }; + + var initStorageListeners = function() { + var container = $('#form-guest-edit-storage .body'); + var toggleCDROM = function(rowNode, toEdit) { + $('button.replace,button.detach', rowNode) + [(toEdit ? 'add' : 'remove') + 'Class']('hidden'); + $('button.save,button.cancel', rowNode) + [(toEdit ? 'remove' : 'add') + 'Class']('hidden'); + var pathBox = $('.path input', rowNode) + .prop('readonly', !toEdit); + toEdit && pathBox.select(); + pathBox.val(pathBox.attr('value')); + }; + + var replaceCDROM = function(event) { + event.preventDefault(); + kimchi.selectedGuestStorage = $(this).data('dev'); + $('.item', container).each(function(i, n) { + toggleCDROM(n); + }); + var rowNode = $('#cdrom-' + kimchi.selectedGuestStorage); + toggleCDROM(rowNode, true); + }; + + $(container).on('click', 'button.replace', replaceCDROM); + + $(container).on('click', 'button.detach', function(e) { + e.preventDefault(); + var settings = { + title : i18n['KCHAPI6004M'], + content : i18n['KCHVMCD6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + if ($(this).data('type') == "disk") + settings['content'] = i18n['KCHVMCD6009M']; + + var dev = $(this).data('dev'); + wok.confirm(settings, function() { + kimchi.deleteVMStorage({ + vm: kimchi.selectedGuest, + dev: dev + }, function() { + wok.topic('kimchi/vmCDROMDetached').publish(); + }); + }); + }); + + $(container).on('click', 'button.save', function(event) { + event.preventDefault(); + var path = $('#cdrom-path-' + kimchi.selectedGuestStorage).val(); + var settings = { + vm: kimchi.selectedGuest, + dev: kimchi.selectedGuestStorage, + path: path + }; + + kimchi.replaceVMStorage(settings, function(result) { + wok.topic('kimchi/vmCDROMReplaced').publish({ + result: result + }); + }, function(result) { + var errText = result['reason'] || + result['responseJSON']['reason']; + wok.message.error(errText); + }); + }); + + $(container).on('click', 'button.cancel', function(event) { + event.preventDefault(); + var rowNode = $('#cdrom-' + kimchi.selectedGuestStorage); + toggleCDROM(rowNode); + }); + }; + + var setupInterface = function() { + $(".add", "#form-guest-edit-interface").button({ + icons: { primary: "ui-icon-plusthick" }, + text: false + }).click(function(evt){ + evt.preventDefault(); + addItem({ + id: -1, + mac: "", + network: "", + type: "network", + viewMode: "hide", + editMode: "" + }); + }); + var toggleEdit = function(item, on, itemId){ + $("#label-mac-" + itemId, item).toggleClass("hide", on); + $("#edit-mac-" + itemId, item).toggleClass("hide", !on); + $("#label-network-" + itemId, item).toggleClass("hide", false); + $("select", item).toggleClass("hide", true); + $(".action-area", item).toggleClass("hide"); + }; + var addItem = function(data) { + if (data.id == -1) { + data.id = $('#form-guest-edit-interface > .body').children().size() + } + var itemNode = $.parseHTML(wok.substitute($('#interface-tmpl').html(),data)); + $(".body", "#form-guest-edit-interface").append(itemNode); + $("select", itemNode).append(networkOptions); + if(data.network!==""){ + $("select", itemNode).val(data.network); + } + $(".edit", itemNode).button({ + disabled: kimchi.thisVMState === "running", + icons: { primary: "ui-icon-pencil" }, + text: false + }).click(function(evt){ + evt.preventDefault(); + toggleEdit($(this).closest('div'), true, data.id); + }); + $(".delete", itemNode).button({ + icons: { primary: "ui-icon-trash" }, + text: false + }).click(function(evt){ + evt.preventDefault(); + var item = $(this).parent().parent(); + kimchi.deleteGuestInterface(kimchi.selectedGuest, item.prop("id"), function(){ + item.remove(); + }); + }); + $(".save", itemNode).button({ + icons: { primary: "ui-icon-disk" }, + text: false + }).click(function(evt){ + evt.preventDefault(); + var item = $(this).parent().parent(); + var interface = { + network: $("select", item).val(), + type: "network", + mac: $(":text", item).val() + }; + var postUpdate = function(mac){ + $("#label-network-" + data.id, item).text(interface.network); + $("#label-mac-" + data.id, item).text(mac); + $("#edit-mac-" + data.id, item).val(mac); + toggleEdit(item, false, data.id); + }; + if(item.prop("id")==""){ + kimchi.createGuestInterface(kimchi.selectedGuest, interface, function(data){ + item.prop("id", data.mac); + postUpdate(data.mac); + }); + }else{ + if (item.prop('id') == interface.mac) { + toggleEdit(item, false, data.id); + } else { + kimchi.updateGuestInterface(kimchi.selectedGuest, item.prop('id'), + interface, function(data){ + item.prop("id", data.mac); + postUpdate(data.mac); + }); + } + } + }); + $(".cancel", itemNode).button({ + icons: { primary: "ui-icon-arrowreturnthick-1-w" }, + text: false + }).click(function(evt){ + evt.preventDefault(); + var item = $(this).parent().parent(); + $("label", item).text()==="" ? item.remove() : toggleEdit(item, false, data.id); + }); + }; + var networkOptions = ""; + kimchi.listNetworks(function(data){ + for(var i=0;i<data.length;i++){ + var isSlected = i==0 ? " selected" : ""; + networkOptions += "<option"+isSlected+">"+data[i].name+"</option>"; + } + kimchi.getGuestInterfaces(kimchi.selectedGuest, function(data){ + for(var i=0;i<data.length;i++){ + data[i].viewMode = ""; + data[i].editMode = "hide"; + data[i].id = i; + addItem(data[i]); + } + }); + }); + }; + + var setupPermission = function() { + //set up for LDAP + $(".add", "#form-guest-edit-permission").button({ + icons: { primary: "ui-icon-plusthick" }, + text: false + }).click(function(evt){ + evt.preventDefault(); + addItem({ + user: "", + freeze: false, + viewMode: "hide", + editMode: "", + checked: true + }); + }); + var addItem = function(data) { + var itemNode = $.parseHTML(wok.substitute($('#ldap-user-tmpl').html(),data)); + $(".body", "#form-guest-edit-permission .ldap").append(itemNode); + $(".delete", itemNode).button({ + icons: { primary: "ui-icon-trash" }, + text: false + }).click(function(evt){ + evt.preventDefault(); + var item = $(this).parent().parent(); + item.remove(); + }); + $("input").focusout(function() { + var item = $(this).parent().parent(); + var user= $(this).val(); + item.prop("id", user); + $("label", item).text(user); + }); + $("input").focusin(function() { + $(this).removeClass("checked"); + }); + + if (data.checked == true) { + $(".checked", itemNode).addClass("hide"); + } + }; + var toggleEdit = function(item, on){ + $("label", item).toggleClass("hide", on); + $("input", item).toggleClass("hide", !on); + $(".action-area", item).toggleClass("hide"); + }; + //set up for PAM + var userNodes = {}, groupNodes = {}; + authType = kimchi.capabilities['auth'] + if (authType == 'pam') { + $("#form-guest-edit-permission .ldap").hide(); + kimchi.retrieveVM(kimchi.selectedGuest, function(vm){ + kimchi.getUsers(function(users){ + kimchi.getGroups(function(groups){ + var subArray = function(a1, a2){ //a1-a2 + for(var i=0; i<a2.length; i++){ + for(var j=0; j<a1.length; j++){ + if(a2[i] == a1[j]){ + a1.splice(j, 1); + break; + } + } + } + }; + subArray(users, vm.users); subArray(groups, vm.groups); + init(users, groups, vm.users, vm.groups); + }); + }); + }); + } else if (authType == 'ldap') { + $("#form-guest-edit-permission .pam").hide(); + kimchi.retrieveVM(kimchi.selectedGuest, function(vm){ + for (var i=0; i<vm.users.length; i++) { + addItem({ + user: vm.users[i], + viewMode: "", + freeze: true, + editMode: "hide", + checked: true}); + } + }); + } + var sortNodes = function(container, isUser){ + nodes = container.children(); + var keys = []; + nodes.each(function(){ + keys.push($("label", this).text()); + }); + keys.sort(); + container.empty(); + for(var i=0; i<keys.length; i++){ + var itemNode = isUser ? userNodes[keys[i]] : groupNodes[keys[i]]; + $(itemNode).click(function(){ + $(this).toggleClass("item-picked"); + }); + container.append(itemNode); + } + }; + var init = function(availUsers, availGroups, selUsers, selGroups){ + var initNode = function(key, isUserNode){ + var nodeGroups = isUserNode ? userNodes : groupNodes; + nodeGroups[key] = $.parseHTML(wok.substitute($('#permission-item-pam').html(), { + val: key, + class: isUserNode? "user-icon" : "group-icon" + })); + }; + for(var i=0; i<availUsers.length; i++){ + initNode(availUsers[i], true); + $("#permission-avail-users").append(userNodes[availUsers[i]]); + sortNodes($("#permission-avail-users"), true); + } + for(var i=0; i<selUsers.length; i++){ + initNode(selUsers[i], true); + $("#permission-sel-users").append(userNodes[selUsers[i]]); + sortNodes($("#permission-sel-users"), true); + } + for(var i=0; i<availGroups.length; i++){ + initNode(availGroups[i], false); + $("#permission-avail-groups").append(groupNodes[availGroups[i]]); + sortNodes($("#permission-avail-groups"), false); + } + for(var i=0; i<selGroups.length; i++){ + initNode(selGroups[i], false); + $("#permission-sel-groups").append(groupNodes[selGroups[i]]); + sortNodes($("#permission-sel-groups"), false); + } + }; + var filterNodes = function(key, container){ + container.children().each(function(){ + $(this).css("display", $("label", this).text().indexOf(key)==-1 ? "none" : ""); + }); + } + $("#permission-avail-searchBox").on("keyup", function() { + var key = $(this).val(); + filterNodes(key, $("#permission-avail-users")); + filterNodes(key, $("#permission-avail-groups")); + }); + $("#permission-sel-searchBox").on("keyup", function() { + var key = $(this).val(); + filterNodes(key, $("#permission-sel-users")); + filterNodes(key, $("#permission-sel-groups")); + }); + $('#permissionGo').button().click(function(evt) { + evt.preventDefault(); + $("#permission-avail-users").children(".item-picked").appendTo("#permission-sel-users").removeClass("item-picked"); + sortNodes($("#permission-sel-users"), true); + $("#permission-avail-groups").children(".item-picked").appendTo("#permission-sel-groups").removeClass("item-picked"); + sortNodes($("#permission-sel-groups"), false); + $("#permission-sel-searchBox").val(""); + filterNodes("", $("#permission-sel-users")); + filterNodes("", $("#permission-sel-groups")); + }); + $('#permissionBack').button().click(function(evt) { + evt.preventDefault(); + $("#permission-sel-users").children(".item-picked").appendTo("#permission-avail-users").removeClass("item-picked"); + sortNodes($("#permission-avail-users"), true); + $("#permission-sel-groups").children(".item-picked").appendTo("#permission-avail-groups").removeClass("item-picked"); + sortNodes($("#permission-avail-groups"), false); + $("#permission-avail-searchBox").val(""); + filterNodes("", $("#permission-avail-users")); + filterNodes("", $("#permission-avail-groups")); + }); + } + var setupPCIDevice = function(){ + kimchi.getHostPCIDevices(function(hostPCIs){ + kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs){ + var pciEnabled = kimchi.capabilities.kernel_vfio; + for(var i=0; i<hostPCIs.length; i++){ + var itemNode = $.parseHTML(wok.substitute($('#pci-tmpl').html(),{ + name: hostPCIs[i].name, + product: hostPCIs[i].product.description, + vendor: hostPCIs[i].vendor.description + })); + $(".body", "#form-guest-edit-pci").append(itemNode); + var iconClass = "ui-icon-plus"; + for(var j=0; j<vmPCIs.length; j++){ + if(hostPCIs[i].name==vmPCIs[j].name){ + iconClass = "ui-icon-minus"; + break; + } + } + pciEnabled || $("button", itemNode).remove(); + $("button", itemNode).button({ + icons: { primary: iconClass }, + text: false + }).click(function(){ + var obj = $(this); + if(obj.button("option", "icons").primary == "ui-icon-minus"){ + kimchi.removeVMPCIDevice(kimchi.selectedGuest, obj.parent().prop("id"), function(){ + kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs1){ + for(var k=0; k<hostPCIs.length; k++) { + $("button", "#" + hostPCIs[k].name).button("option", "icons", {primary: "ui-icon-plus"}); + } + for(var k=0; k<vmPCIs1.length; k++) { + $("button", "#" + vmPCIs1[k].name).button("option", "icons", {primary: "ui-icon-minus"}); + } + }); + filterNodes($("select", "#form-guest-edit-pci").val(), $("input", "#form-guest-edit-pci").val()); + }); + } else { + kimchi.addVMPCIDevice(kimchi.selectedGuest, { name: obj.parent().prop("id") }, function(){ + kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs1){ + for(var k=0; k<vmPCIs1.length; k++) { + $("button", "#" + vmPCIs1[k].name).button("option", "icons", {primary: "ui-icon-minus"}); + } + }); + filterNodes($("select", "#form-guest-edit-pci").val(), $("input", "#form-guest-edit-pci").val()); + }); + } + }); + kimchi.getPCIDeviceCompanions(hostPCIs[i].name, function(infoData) { + var pciTitle = i18n["KCHVMED6007M"] + "\n"; + var haveCompanions = false; + for(var p=0; p<infoData.length; p++) { + if(infoData[p].device_type === "net") { + haveCompanions = true; + pciTitle += " " + infoData[p].name + "\n"; + pciTitle += " " + i18n["KCHVMED6001M"] + " " + infoData[p].interface; + pciTitle += ", " + i18n["KCHVMED6002M"] + " " + infoData[p].address; + pciTitle += ", " + i18n["KCHVMED6003M"] + " " + infoData[p].link_type + "\n"; + } else if(infoData[p].device_type === "storage") { + haveCompanions = true; + pciTitle += " " + infoData[p].name + "\n"; + pciTitle += " " + i18n["KCHVMED6004M"] + " " + infoData[p].block; + pciTitle += ", " + i18n["KCHVMED6005M"] + " " + infoData[p].drive_type; + pciTitle += ", " + i18n["KCHVMED6006M"] + " " + infoData[p].model + "\n"; + } + } + for(var q=0; q<infoData.length; q++) { + haveCompanions && $(".name", "#" + infoData[q].parent).attr("title", pciTitle); + haveCompanions && $(".product", "#" + infoData[q].parent).attr("title", pciTitle); + haveCompanions && $(".vendor", "#" + infoData[q].parent).attr("title", pciTitle); + } + }); + } + }); + }); + var filterNodes = function(group, text){ + text = text.toLowerCase(); + $(".body", "#form-guest-edit-pci").children().each(function(){ + var textFilter = $(".name", this).text().toLowerCase().indexOf(text)!=-1; + textFilter = textFilter || $(".product", this).text().toLowerCase().indexOf(text)!=-1; + textFilter = textFilter || $(".vendor", this).text().toLowerCase().indexOf(text)!=-1; + var display = "none"; + var itemGroup = $("button", this).button("option", "icons").primary; + if(textFilter){ + if(group == "all"){ + display = ""; + }else if(group=="toAdd" && itemGroup=="ui-icon-plus"){ + display = "" + }else if(group == "added" && itemGroup=="ui-icon-minus"){ + display = "" + } + } + $(this).css("display", display); + }); + }; + $("select", "#form-guest-edit-pci").change(function(){ + filterNodes($(this).val(), $("input", "#form-guest-edit-pci").val()); + }); + $("input", "#form-guest-edit-pci").on("keyup", function() { + filterNodes($("select", "#form-guest-edit-pci").val(), $(this).val()); + }); + }; + + var setupSnapshot = function() { + var currentSnapshot; + var setCurrentSnapshot = function(aSnapshot){ + if(!aSnapshot) + kimchi.getCurrentSnapshot(kimchi.selectedGuest, function(snapshot){ + if(snapshot&&snapshot.name) aSnapshot = snapshot.name; + }, null, true); + if(aSnapshot){ + if(currentSnapshot) $(".ui-icon-check", "#"+currentSnapshot).addClass("hide"); + $(".ui-icon-check", "#"+aSnapshot).removeClass("hide"); + currentSnapshot = aSnapshot; + } + }; + var addItem = function(data, container) { + var itemNode = $.parseHTML(wok.substitute($('#snapshot-tmpl').html(),data)); + $("."+container, "#form-guest-edit-snapshot").append(itemNode); + $(".delete", itemNode).button({ + icons: { primary: "ui-icon-trash" }, + text: false + }).click(function(evt){ + evt.preventDefault(); + var item = $(this).parent().parent(); + $("button", "#form-guest-edit-snapshot").button("disable"); + kimchi.deleteSnapshot(kimchi.selectedGuest, item.prop("id"), function(){ + item.remove(); + setCurrentSnapshot(); + $("button", "#form-guest-edit-snapshot").button("enable"); + }, function(data){ + wok.message.error(data.responseJSON.reason); + $("button", "#form-guest-edit-snapshot").button("enable"); + }); + }); + $(".revert", itemNode).button({ + icons: { primary: "ui-icon-arrowthick-1-ne" }, + text: false + }).click(function(evt){ + evt.preventDefault(); + var item = $(this).parent().parent(); + $(".ui-icon-check", item).addClass("hide"); + $(".icon", item).removeClass("hide"); + $("button", "#form-guest-edit-snapshot").button("disable"); + kimchi.revertSnapshot(kimchi.selectedGuest, item.prop("id"), function(){ + $(".icon", item).addClass("hide"); + $("button", "#form-guest-edit-snapshot").button("enable"); + setCurrentSnapshot(item.prop("id")); + kimchi.listVmsAuto(); + wok.window.close(); + }, function(data){ + wok.message.error(data.responseJSON.reason); + $(".icon", item).addClass("hide"); + $("button", "#form-guest-edit-snapshot").button("enable"); + }); + }); + }; + var addOngoingItem = function(task){ + var uri = task.target_uri; + addItem({ + name: uri.substring(uri.lastIndexOf('/')+1, uri.length), + created: "", + listMode: "hide", + createMode: "" + }, 'task'); + if(kimchi.trackingTasks.indexOf(task.id)==-1) + kimchi.trackTask(task.id, function(task){ + listGeneratingSnapshots(); + $("button", "#form-guest-edit-snapshot").button("enable"); + }, function(err){ + wok.message.error(err.message); + listGeneratingSnapshots(); + $("button", "#form-guest-edit-snapshot").button("enable"); + }); + }; + var listGeneratingSnapshots = function(){ + kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/plugins/kimchi/snapshots/*'), function(tasks) { + $(".task", "#form-guest-edit-snapshot").empty(); + for(var i=0;i<tasks.length;i++){ + addOngoingItem(tasks[i]); + } + if(tasks.length==0) listSnapshots(); + }); + }; + var listSnapshots = function(){ + kimchi.listSnapshots(kimchi.selectedGuest, function(data){ + $(".body", "#form-guest-edit-snapshot").empty(); + for(var i=0;i<data.length;i++){ + data[i].created = new Date(data[i].created*1000).toLocaleString(); + data[i].createMode = "hide"; + data[i].listMode = ""; + addItem(data[i], 'body'); + } + setCurrentSnapshot(); + }); + }; + listGeneratingSnapshots(); + $(".add", "#form-guest-edit-snapshot").button({ + icons: { primary: "ui-icon-plusthick" }, + text: false + }).click(function(evt){ + evt.preventDefault(); + kimchi.createSnapshot(kimchi.selectedGuest, function(task){ + $("button", "#form-guest-edit-snapshot").button("disable"); + addOngoingItem(task); + }); + }); + if(kimchi.thisVMState=="running") $("button", "#form-guest-edit-snapshot").remove(); + }; + + var initContent = function(guest) { + guest['icon'] = guest['icon'] || 'plugins/kimchi/images/icon-vm.png'; + $('#form-guest-edit-general').fillWithObject(guest); + kimchi.thisVMState = guest['state']; + refreshCDROMs(); + $('#guest-edit-attach-cdrom-button').button({ + icons: { + primary: "ui-icon-plusthick" + }, + text: false + }).click(function(event) { + event.preventDefault(); + wok.window.open("plugins/kimchi/guest-storage-add.html"); + }); + if(kimchi.thisVMState === "running") { + $("#form-guest-edit-general input").prop("disabled", true); + } else { + $("#action-button-container").removeClass("hidden"); + } + + var onAttached = function(params) { + refreshCDROMs(); + }; + var onReplaced = function(params) { + refreshCDROMs(); + }; + var onDetached = function(params) { + refreshCDROMs(); + }; + + initStorageListeners(); + setupInterface(); + setupPermission(); + setupPCIDevice(); + setupSnapshot(); + + wok.topic('kimchi/vmCDROMAttached').subscribe(onAttached); + wok.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced); + wok.topic('kimchi/vmCDROMDetached').subscribe(onDetached); + + kimchi.clearGuestEdit = function() { + wok.topic('kimchi/vmCDROMAttached').unsubscribe(onAttached); + wok.topic('kimchi/vmCDROMReplaced').unsubscribe(onReplaced); + wok.topic('kimchi/vmCDROMDetached').unsubscribe(onDetached); + }; + }; + + kimchi.retrieveVM(kimchi.selectedGuest, initContent); + + var generalSubmit = function(event) { + $(saveButton).prop('disabled', true); + var data=$('#form-guest-edit-general').serializeObject(); + if(data['memory']!=undefined) { + data['memory'] = Number(data['memory']); + } + if(data['cpus']!=undefined) { + data['cpus'] = Number(data['cpus']); + } + + kimchi.updateVM(kimchi.selectedGuest, data, function() { + kimchi.listVmsAuto(); + wok.window.close(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + $(saveButton).prop('disabled', false); + }); + } + + var permissionSubmit = function(event) { + var content = { users: [], groups: [] }; + authType = kimchi.capabilities['auth'] + if (authType == 'pam') { + $("#permission-sel-users").children().each(function(){ + content.users.push($("label", this).text()); + }); + $("#permission-sel-groups").children().each(function(){ + content.groups.push($("label", this).text()); + }); + kimchi.updateVM(kimchi.selectedGuest, content, function(){ + wok.window.close(); + }); + } else if (authType == 'ldap') { + $(saveButton).prop('disabled', true); + var errors = 0; + + $(".body", "#form-guest-edit-permission .ldap").children().each(function () { + var elem = $(this); + content.users.push(elem.attr("id")); + + if (!$('input', elem).hasClass('hide')) { + var user = {'user_id': $(this).attr("id")}; + kimchi.getUserById(user, null, function (data) { + errors += 1; + $("input", elem).addClass("checked"); + }); + } + }); + if (errors == 0) { + kimchi.updateVM(kimchi.selectedGuest, content, function(){ + wok.window.close(); + }); + } else { + $(saveButton).prop('disabled', false); + } + } + } + + // tap map, "general": 0, "storage": 1, "interface": 2, "permission": 3, "password": 4 + var submit_map = {0: generalSubmit, 3:permissionSubmit}; + var submitForm = function(event) { + var current = $('#guest-edit-tabs').tabs( "option", "active" ); + var submitFun = submit_map[current]; + submitFun && submitFun(event); + event.preventDefault(); + }; + + $(guestEditForm).on('submit', submitForm); + $(saveButton).on('click', submitForm); +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_main.js new file mode 100644 index 0000000..7dd5d84 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_main.js @@ -0,0 +1,511 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +kimchi.sampleGuestObject = { + "name": "", + "uuid": "", + "state": "shutoff", + "persistent": true, + "icon": null, + "cpus": 0, + "memory": 0, + "stats": { + "net_throughput": 0, + "io_throughput_peak": 100, + "cpu_utilization": 0, + "io_throughput": 0, + "net_throughput_peak": 100 + }, + "screenshot": null, + "graphics": { + "passwd": null, + "passwdValidTo": null, + "type": "vnc", + "port": null, + "listen": "127.0.0.1" + }, + "users": [], + "groups": [], + "access": "full" +}; + +kimchi.vmstart = function(event) { + var button=$(this); + if (!button.hasClass('loading')) { + button.addClass('loading'); + var vm=$(this).closest('li[name=guest]'); + var vm_id=vm.attr("id"); + kimchi.startVM(vm_id, function(result) { + button.removeClass('loading'); + kimchi.listVmsAuto(); + }, function(err) { + button.removeClass('loading'); + wok.message.error(err.responseJSON.reason); + } + ); + } else { + event.preventDefault(); + event.stopPropagation(); + return; + } +}; + +kimchi.vmsuspend = function(event) { + var button=$(this); + if (!button.hasClass('pause-gray')) { + button.addClass('pause-gray'); + var vm=$(this).closest('li[name=guest]'); + var vm_id=vm.attr("id"); + kimchi.suspendVM(vm_id, function(result) { + button.removeClass('pause-gray'); + kimchi.listVmsAuto(); + }, function(err) { + button.removeClass('pause-gray'); + wok.message.error(err.responseJSON.reason); + } + ); + } else { + event.preventDefault(); + event.stopPropagation(); + return; + } +}; + +kimchi.vmresume = function(event) { + var button=$(this); + if (!button.hasClass('resume-gray')) { + button.addClass('resume-gray'); + var vm=$(this).closest('li[name=guest]'); + var vm_id=vm.attr("id"); + kimchi.resumeVM(vm_id, function(result) { + button.removeClass('resume-gray'); + kimchi.listVmsAuto(); + }, function(err) { + button.removeClass('resume-gray'); + wok.message.error(err.responseJSON.reason); + } + ); + } else { + event.preventDefault(); + event.stopPropagation(); + return; + } +}; + +kimchi.vmpoweroff = function(event) { + var button=$(this); + if (!button.hasClass('loading')) { + button.addClass('loading'); + var vm=button.closest('li[name=guest]'); + var vm_id=vm.attr("id"); + var vmObject=vm.data(); + var vm_persistent=vmObject.persistent == true; + var content_msg = vm_persistent ? i18n['KCHVM6003M'] : + i18n['KCHVM6009M']; + var settings = { + title : i18n['KCHVM6002M'], + content : content_msg, + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + wok.confirm(settings, function() { + kimchi.poweroffVM(vm_id, function(result) { + button.removeClass('loading'); + kimchi.listVmsAuto(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }, function() { + }); + } else { + event.preventDefault(); + event.stopPropagation(); + } +}; + +kimchi.vmshutdown = function(event){ + var vm=$(this).closest('li[name=guest]'); + var vm_id=vm.attr("id"); + var settings = { + title : i18n['KCHVM6006M'], + content : i18n['KCHVM6007M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + wok.confirm(settings, function() { + kimchi.shutdownVM(vm_id, function(result) { + kimchi.listVmsAuto(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + } + ); + }, function() { + }); +}; + +kimchi.vmreset = function(event){ + var vm=$(this).closest('li[name=guest]'); + var vm_id=vm.attr("id"); + var settings = { + title : i18n['KCHVM6004M'], + content : i18n['KCHVM6005M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + wok.confirm(settings, function() { + kimchi.resetVM(vm_id, function(result) { + kimchi.listVmsAuto(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + } + ); + }, function() { + }); +}; + +kimchi.vmdelete = function(event) { + var vm = $(this).closest('li[name=guest]'); + var vm_id=vm.attr("id"); + var settings = { + title : i18n['KCHVM6008M'], + content : i18n['KCHVM6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + wok.confirm(settings, function() { + kimchi.deleteVM(vm_id, function(result) { + kimchi.listVmsAuto(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }, function() { + }); +}; + +kimchi.vmedit = function(event) { + var vm = $(this).closest('li[name=guest]'); + var vm_id=vm.attr("id"); + kimchi.selectedGuest = vm_id; + wok.window.open({ + url: 'plugins/kimchi/guest-edit.html', + close: function() { + kimchi.clearGuestEdit(); + } + }); +}; + +kimchi.openVmConsole = function(event) { + var vm=$(this).closest('li[name=guest]'); + var vmObject=vm.data(); + if (vmObject.graphics['type'] == 'vnc') { + kimchi.vncToVM(vm.attr('id')); + } + else if (vmObject.graphics['type'] == 'spice') { + kimchi.spiceToVM(vm.attr('id')); + } + +}; + +kimchi.getVmsCurrentConsoleImgs = function() { + var res = new Object(); + $('#guestList').children().each(function() { + res[$(this).attr('id')] = $(this).find('img.imgactive').attr('src'); + }) + return res; +}; + +kimchi.getOpenMenuVmId = function() { + var result; + var openMenu = $('#guestList div[name="actionmenu"] .popover:visible'); + if(openMenu) { + var li_element=openMenu.closest('li'); + result=li_element.attr('id'); + } + return result; +}; + +kimchi.listVmsAuto = function() { + if (kimchi.vmTimeout) { + clearTimeout(kimchi.vmTimeout); + } + var getCreatingGuests = function(){ + var guests = []; + kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/plugins/kimchi/vms/[^/]+$'), function(tasks) { + for(var i=0;i<tasks.length;i++){ + var guestUri = tasks[i].target_uri; + var guestName = guestUri.split('/')[2] + guests.push($.extend({}, kimchi.sampleGuestObject, {name: guestName, isCreating: true})); + if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1) + kimchi.trackTask(tasks[i].id, null, function(err){ + wok.message.error(err.message); + }, null); + } + }, null, true); + return guests; + }; + var getCloningGuests = function(){ + var guests = []; + kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/plugins/kimchi/vms/.+/clone'), function(tasks) { + for(var i=0;i<tasks.length;i++){ + var guestUri = tasks[i].target_uri; + var guestName = guestUri.split('/')[2] + guests.push($.extend({}, kimchi.sampleGuestObject, {name: guestName, isCloning: true})); + if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1) + kimchi.trackTask(tasks[i].id, null, function(err){ + wok.message.error(err.message); + }, null); + } + }, null, true); + return guests; + }; + kimchi.listVMs(function(result, textStatus, jqXHR) { + if (result && textStatus=="success") { + result = getCloningGuests().concat(result); + result = getCreatingGuests().concat(result); + if(result.length) { + var listHtml = ''; + var guestTemplate = kimchi.guestTemplate; + var currentConsoleImages = kimchi.getVmsCurrentConsoleImgs(); + var openMenuGuest = kimchi.getOpenMenuVmId(); + $('#guestList').empty(); + $('#guestListField').show(); + $('#noGuests').hide(); + + $.each(result, function(index, vm) { + var guestLI = kimchi.createGuestLi(vm, currentConsoleImages[vm.name], vm.name==openMenuGuest); + $('#guestList').append(guestLI); + }); + } else { + $('#guestListField').hide(); + $('#noGuests').show(); + } + } + + kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); + }, function(errorResponse, textStatus, errorThrown) { + if(errorResponse.responseJSON && errorResponse.responseJSON.reason) { + wok.message.error(errorResponse.responseJSON.reason); + } + kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); + }); +}; + +kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { + var result=kimchi.guestElem.clone(); + + //Setup the VM list entry + var vmRunningBool=(vmObject.state=="running"); + var vmSuspendedBool = (vmObject.state=="paused"); + var vmPoweredOffBool = (vmObject.state=="shutoff"); + var vmPersistent = (vmObject.persistent == true); + result.attr('id',vmObject.name); + result.data(vmObject); + + //Add the Name + var guestTitle=result.find('.title').attr('title',vmObject.name); + guestTitle.html(vmObject.name); + + //Setup the VM console thumbnail display + var curImg = vmObject.icon; + if (vmObject.screenshot) { + curImg = vmObject.screenshot.replace(/^\//,''); + } + var load_src = curImg || 'plugins/kimchi/images/icon-vm.png'; + var tile_src = prevScreenImage || vmObject['load-src']; + var liveTile=result.find('div[name=guest-tile] > .tile'); + liveTile.addClass(vmObject.state); + liveTile.find('.imgactive').attr('src',tile_src); + var imgLoad=liveTile.find('.imgload'); + imgLoad.on('load', function() { + var oldImg=$(this).parent().find('.imgactive'); + oldImg.removeClass("imgactive").addClass("imgload"); + oldImg.attr("src",""); + $(this).addClass("imgactive").removeClass("imgload"); + $(this).off('load'); + }); + imgLoad.attr('src',load_src); + + //Link the stopped tile to the start action, the running tile to open the console, and the paused tile to resume + if(!(vmObject.isCloning || vmObject.isCreating)){ + if (vmPoweredOffBool) { + liveTile.off("click", kimchi.openVmConsole); + liveTile.off("click", kimchi.vmresume); + liveTile.on("click", kimchi.vmstart); + liveTile.hover(function(event){$(this).find('.overlay').show()}, function(event){$(this).find('.overlay').hide()}); + } else if (vmSuspendedBool) { + liveTile.off("click", kimchi.vmstart); + liveTile.off("click", kimchi.openVmConsole); + liveTile.on("click", kimchi.vmresume); + if(vmObject.state="paused") { + liveTile.find('.overlay').attr('src',"plugins/kimchi/images/theme-default/ac24_resume.png"); + liveTile.find('.overlay').attr('alt',"Resume"); + } + liveTile.hover(function(event){$(this).find('.overlay').show()}, function(event){$(this).find('.overlay').hide()}); + } else { + liveTile.off("click", kimchi.vmstart); + liveTile.off("click", kimchi.vmresume); + liveTile.on("click", kimchi.openVmConsole); + } + } + + //Setup the gauges + var stats=vmObject.stats; + var gaugeValue=0; + gaugeValue=parseInt(stats.net_throughput); + kimchi.circleGaugeInit(result, "net_throughput",gaugeValue,(gaugeValue*100/stats.net_throughput_peak)); + gaugeValue=parseInt(stats.io_throughput); + kimchi.circleGaugeInit(result, "io_throughput",gaugeValue,(gaugeValue*100/stats.io_throughput_peak)); + gaugeValue=parseInt(stats.cpu_utilization); + kimchi.circleGaugeInit(result, "cpu_utilization",gaugeValue+"%",gaugeValue); + + //Setup the VM Actions + var guestActions=result.find("div[name=guest-actions]"); + guestActions.find(".shutoff-disabled").prop("disabled", !vmRunningBool); + guestActions.find(".running-disabled").prop("disabled", vmRunningBool); + guestActions.find(".non-persistent-disabled").prop("disabled", !vmPersistent); + guestActions.find(".reset-disabled").prop("disabled", vmPoweredOffBool || !vmPersistent); + guestActions.find(".pause-disabled").prop("disabled", vmPoweredOffBool || !vmPersistent); + + if (vmSuspendedBool) { //VM is paused + //Hide Start + guestActions.find(".running-hidden").hide(); + //Hide Pause button and menu + guestActions.find(".pause-disabled").hide(); + guestActions.find(".pause-hidden").hide(); + } + + if (vmRunningBool) { //VM IS running + //Hide Start + guestActions.find(".running-hidden").hide(); + //Hide Resume + guestActions.find(".resume-hidden").hide(); + } + + if (vmPoweredOffBool) { //VM is powered off + //Hide PowerOff + guestActions.find(".shutoff-hidden").hide(); + //Hide Pause + guestActions.find(".pause-hidden").hide(); + //Hide Resume + guestActions.find(".resume-hidden").hide(); + } + + var consoleActions=guestActions.find("[name=vm-console]"); + + if ((vmObject.graphics['type'] == 'vnc') || (vmObject.graphics['type'] == 'spice')) { + consoleActions.on("click", kimchi.openVmConsole); + consoleActions.show(); + } else { //we don't recognize the VMs supported graphics, so hide the menu choice + consoleActions.hide(); + consoleActions.off("click",kimchi.openVmConsole); + } + + //Setup action event handlers + if(!(vmObject.isCloning || vmObject.isCreating)){ + guestActions.find("[name=vm-start]").on({click : kimchi.vmstart}); + guestActions.find("[name=vm-poweroff]").on({click : kimchi.vmpoweroff}); + if ((vmRunningBool) || (vmSuspendedBool)) { + //If the guest is not running, do not enable reset; otherwise, reset is enabled (when running or paused) + guestActions.find("[name=vm-reset]").on({click : kimchi.vmreset}); + + //If the guest is not running, do not enable shutdown;otherwise, shutdown is enabled (when running or paused) + guestActions.find("[name=vm-shutdown]").on({click : kimchi.vmshutdown}); + } + + if (vmSuspendedBool) { + guestActions.find("[name=vm-resume]").on({click : kimchi.vmresume}); + } + + if (vmRunningBool) { + guestActions.find("[name=vm-pause]").on({click : kimchi.vmsuspend}); + } + + guestActions.find("[name=vm-edit]").on({click : kimchi.vmedit}); + guestActions.find("[name=vm-delete]").on({click : kimchi.vmdelete}); + guestActions.find("[name=vm-clone]").click(function(){ + var guest = $(this).closest('li[name=guest]').attr("id"); + wok.confirm({ + title : i18n['KCHAPI6006M'], + content : i18n['KCHVM6010M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }, function() { + kimchi.cloneGuest(guest, function(data){ + kimchi.listVmsAuto(); + }); + }, null); + }); + + //Maintain menu open state + var actionMenu=guestActions.find("div[name=actionmenu]"); + if (openMenu) { + $('.popover', actionMenu).toggle(); + } + + }else{ + guestActions.find('.btn').attr('disabled', true); + $('.popover', guestActions.find("div[name=actionmenu]")).remove(); + + result.find('.guest-pending').removeClass('hide-content'); + pendingText = result.find('.guest-pending .text') + if(vmObject.isCloning) + pendingText.text(i18n['KCHAPI6009M']); + else + pendingText.text(i18n['KCHAPI6008M']); + } + + return result; +}; + +kimchi.circleGaugeInit = function(topElement, divName, display, percentage){ + var gauge=topElement.find('div[name="' + divName + '"] .circleGauge'); + if(gauge) { + var data=Object(); + data.percentage = percentage; + data.display = display; + gauge.data(data); + } + gauge.circleGauge(); + return(gauge); +}; + +kimchi.guestSetRequestHeader = function(xhr) { + xhr.setRequestHeader('Accept', 'text/html'); +}; + +kimchi.guest_main = function() { + if(wok.tabMode['guests'] === 'admin') { + $('.tools').attr('style','display'); + $("#vm-add").on("click", function(event) { + wok.window.open('plugins/kimchi/guest-add.html'); + }); + } + kimchi.guestTemplate = $('#guest-tmpl').html(); + kimchi.guestElem=$('<div/>').html(kimchi.guestTemplate).find('li'); + $('#guests-root-container').on('remove', function() { + kimchi.vmTimeout && clearTimeout(kimchi.vmTimeout); + }); + kimchi.listVmsAuto() +}; + +kimchi.editTemplate = function(guestTemplate, oldPopStat) { + if (oldPopStat) { + return guestTemplate.replace("vm-action", "vm-action open"); + } + return guestTemplate; +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_media_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_media_main.js new file mode 100644 index 0000000..b920527 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_media_main.js @@ -0,0 +1,56 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.guest_media_main = function() { + + var refreshCDROMs = function() { + kimchi.listVMStorages({ + vm: kimchi.selectedGuest, + storageType: 'cdrom' + }, function(storages) { + var rowHTML = $('#cdrom-row-tmpl').html(); + var container = $('#guest-edit-cdrom-row-container'); + $(container).empty(); + + $.each(storages, function(index, storage) { + storage['vm'] = kimchi.selectedGuest; + var templated = wok.substitute(rowHTML, storage); + container.append(templated); + }); + + var replaceCDROM = function(event) { + event.preventDefault(); + kimchi.selectedGuestStorage = $(this).data('dev'); + wok.window.open("plugins/kimchi/guest-cdrom-edit.html"); + }; + + $('input[type="text"][name="cdrom"]', container).on('click', replaceCDROM); + $('.replace', container).on('click', replaceCDROM); + }); + }; + + refreshCDROMs(); + + var onReplaced = function(params) { + refreshCDROMs(); + }; + wok.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced); + + kimchi.clearGuestMedia = function() { + wok.topic('kimchi/vmCDROMReplaced').unsubscribe(onReplaced); + }; +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_storage_add.main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_storage_add.main.js new file mode 100644 index 0000000..bc162e8 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.guest_storage_add.main.js @@ -0,0 +1,199 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.guest_storage_add_main = function() { + var types = [{ + label: 'cdrom', + value: 'cdrom', + }, + { + label: 'disk', + value: 'disk', + }]; + var typesRunning = [{ + label: 'disk', + value: 'disk' + }]; + + var storageAddForm = $('#form-guest-storage-add'); + var submitButton = $('#guest-storage-button-add'); + var typeTextbox = $('input[name="type"]', storageAddForm); + var pathTextbox = $('input[name="path"]', storageAddForm); + var poolTextbox = $('input[name="pool"]', storageAddForm); + var volTextbox = $('input[name="vol"]', storageAddForm); + + typeTextbox.change(function() { + var pathObject = {'cdrom': ".path-section", 'disk': '.volume-section'} + selectType = $(this).val(); + $.each(pathObject, function(type, value) { + if(selectType == type){ + $(value).removeClass('hidden'); + } else { + $(value).addClass('hidden'); + } + }); + + if ($(".path-section").hasClass('hidden')) { + $(poolTextbox).val('default'); + $(poolTextbox).change(); + $(pathTextbox).val(""); + } + else { + $(poolTextbox).val(""); + $(volTextbox).val(""); + } + }); + + kimchi.listStoragePools(function(result) { + var options = []; + if (result && result.length) { + $.each(result, function(index, storagePool) { + if ((storagePool.state=="active") && (storagePool.type !== 'kimchi-iso')) { + options.push({ + label: storagePool.name, + value: storagePool.name + }); + } + }); + wok.select('guest-add-storage-pool-list', options); + } + }); + + poolTextbox.change(function() { + var options = []; + kimchi.listStorageVolumes($(this).val(), function(result) { + var validVolType = { cdrom: /iso/, disk: /^(raw|qcow|qcow2|bochs|qed|vmdk)$/}; + $('#guest-disk').selectMenu(); + if (result.length) { + $.each(result, function(index, value) { + // Only unused volume can be attached + if (value.used_by.length == 0 && (value.type != 'file' || validVolType[selectType].test(value.format))) { + options.push({ + label: value.name, + value: value.name + }); + } + }); + if (options.length) { + $(volTextbox).val(options[0].value); + $(volTextbox).change(); + } + } + $('#guest-disk').selectMenu("setData", options); + }); + }); + + + typeTextbox.change(function() { + var pathObject = {'cdrom': ".path-section", 'disk': '.volume-section'} + var selectType = $(this).val(); + $.each(pathObject, function(type, value) { + if(selectType == type){ + $(value).removeClass('hidden'); + } else { + $(value).addClass('hidden'); + } + }); + }); + + if (kimchi.thisVMState === 'running') { + types =typesRunning; + $(typeTextbox).val('disk'); + typeTextbox.change(); + poolTextbox.change(); + } + var selectType = $(typeTextbox).val(); + wok.select('guest-storage-type-list', types); + + var validateCDROM = function(settings) { + if (/^((https|http|ftp|ftps|tftp|\/).*)+$/.test(settings['path'])) + return true; + else { + wok.message.error.code('KCHVMSTOR0001E'); + return false; + } + } + + var validateDisk = function(settings) { + if (settings['pool'] && settings['vol']) + return true; + else { + wok.message.error.code('KCHVMSTOR0002E'); + return false; + } + } + + validator = {cdrom: validateCDROM, disk: validateDisk}; + var submitForm = function(event) { + if (submitButton.prop('disabled')) { + return false; + } + + var formData = storageAddForm.serializeObject(); + var settings = { + vm: kimchi.selectedGuest, + type: typeTextbox.val(), + }; + + $(submitButton).prop('disabled', true); + $.each([pathTextbox, poolTextbox, volTextbox], function(i, c) { + $(c).prop('disabled', true); + val = $(c).val() + if (val && val != '') { + settings[$(c).attr('name')] = $(c).val(); + } + }); + // Validate form for cdrom and disk + validateSpecifiedForm = validator[settings['type']]; + if (!validateSpecifiedForm(settings)) { + $(submitButton).prop('disabled', false); + $.each([submitButton, pathTextbox, poolTextbox, volTextbox], function(i, c) { + $(c).prop('disabled', false); + }); + return false; + } + $(submitButton).addClass('loading').text(i18n['KCHVMCD6003M']); + + kimchi.addVMStorage(settings, function(result) { + wok.window.close(); + wok.topic('kimchi/vmCDROMAttached').publish({ + result: result + }); + }, function(result) { + var errText = result['reason'] || + result['responseJSON']['reason']; + wok.message.error(errText); + + $.each([submitButton, pathTextbox, poolTextbox, volTextbox], function(i, c) { + $(c).prop('disabled', false); + }); + $(submitButton).removeClass('loading').text(i18n['KCHVMCD6002M']); + }); + + event.preventDefault(); + }; + + storageAddForm.on('submit', submitForm); + submitButton.on('click', submitForm); + pathTextbox.on('change input propertychange', function(event) { + $(submitButton).prop('disabled', $(this).val() === ''); + }); + volTextbox.on('change propertychange', function (event) { + $(submitButton).prop('disabled', $(this).val() === ''); + }); + +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.host.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.host.js new file mode 100644 index 0000000..e2d2511 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.host.js @@ -0,0 +1,858 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.host={}; + +kimchi.host_main = function() { + var expand = function(header, toExpand) { + var controlledNode = $(header).attr('aria-controls'); + $('#' + controlledNode)[toExpand ? 'removeClass' : 'addClass']('hidden'); + $(header).attr('aria-expanded', toExpand ? 'true' : 'false'); + }; + + var repositoriesGrid = null; + var initRepositoriesGrid = function(repo_type) { + var gridFields=[]; + if (repo_type == "yum") { + gridFields=[{ + name: 'repo_id', + label: i18n['KCHREPO6004M'], + 'class': 'repository-id' + }, { + name: 'config[repo_name]', + label: i18n['KCHREPO6005M'], + 'class': 'repository-name' + }, { + name: 'enabled', + label: i18n['KCHREPO6009M'], + 'class': 'repository-enabled' + }]; + } + else if (repo_type == "deb") { + gridFields=[{ + name: 'baseurl', + label: i18n['KCHREPO6006M'], + makeTitle: true, + 'class': 'repository-baseurl deb' + }, { + name: 'enabled', + label: i18n['KCHREPO6009M'], + 'class': 'repository-enabled deb' + }, { + name: 'config[dist]', + label: "dist", + 'class': 'repository-gpgcheck deb' + }, { + name: 'config[comps]', + label: "comps", + 'class': 'repository-gpgcheck deb' + }]; + } + else { + gridFields=[{ + name: 'repo_id', + label: i18n['KCHREPO6004M'], + 'class': 'repository-id' + }, { + name: 'enabled', + label: i18n['KCHREPO6009M'], + 'class': 'repository-enabled' + }, { + name: 'baseurl', + label: i18n['KCHREPO6006M'], + makeTitle: true, + 'class': 'repository-baseurl' + }]; + } + repositoriesGrid = new wok.widget.Grid({ + container: 'repositories-grid-container', + id: 'repositories-grid', + title: i18n['KCHREPO6003M'], + toolbarButtons: [{ + id: 'repositories-grid-add-button', + label: i18n['KCHREPO6012M'], + onClick: function(event) { + wok.window.open({url:'plugins/kimchi/repository-add.html', + class: repo_type}); + } + }, { + id: 'repositories-grid-enable-button', + label: i18n['KCHREPO6016M'], + disabled: true, + onClick: function(event) { + var repository = repositoriesGrid.getSelected(); + if(!repository) { + return; + } + var name = repository['repo_id']; + var enable = !repository['enabled']; + $(this).prop('disabled', true); + kimchi.enableRepository(name, enable, function() { + wok.topic('kimchi/repositoryUpdated').publish(); + }); + } + }, { + id: 'repositories-grid-edit-button', + label: i18n['KCHREPO6013M'], + disabled: true, + onClick: function(event) { + var repository = repositoriesGrid.getSelected(); + if(!repository) { + return; + } + kimchi.selectedRepository = repository['repo_id']; + wok.window.open({url:'plugins/kimchi/repository-edit.html', + class: repo_type}); + } + }, { + id: 'repositories-grid-remove-button', + label: i18n['KCHREPO6014M'], + disabled: true, + onClick: function(event) { + var repository = repositoriesGrid.getSelected(); + if(!repository) { + return; + } + + var settings = { + title : i18n['KCHREPO6001M'], + content : i18n['KCHREPO6002M'], + confirm : i18n['KCHAPI6004M'], + cancel : i18n['KCHAPI6003M'] + }; + + wok.confirm(settings, function() { + kimchi.deleteRepository( + repository['repo_id'], + function(result) { + wok.topic('kimchi/repositoryDeleted').publish(result); + }, function(error) { + } + ); + }); + } + }], + onRowSelected: function(row) { + var repository = repositoriesGrid.getSelected(); + if(!repository) { + return; + } + $('#repositories-grid-remove-button').prop('disabled', false); + $('#repositories-grid-edit-button').prop('disabled', false); + var enabled = repository['enabled']; + $('#repositories-grid-enable-button') + .text(i18n[enabled ? 'KCHREPO6017M' : 'KCHREPO6016M']) + .prop('disabled', false); + }, + frozenFields: [], + fields: gridFields, + data: listRepositories + }); + }; + + var listRepositories = function(gridCallback) { + kimchi.listRepositories(function(repositories) { + if($.isFunction(gridCallback)) { + gridCallback(repositories); + } + else { + if(repositoriesGrid) { + repositoriesGrid.setData(repositories); + } + else { + initRepositoriesGrid(); + repositoriesGrid.setData(repositories); + } + } + }, + function(error) { + var message = error && error['responseJSON'] && error['responseJSON']['reason']; + + if($.isFunction(gridCallback)) { + gridCallback([]); + } + repositoriesGrid && + repositoriesGrid.showMessage(message || i18n['KCHUPD6008M']); + }); + + $('#repositories-grid-remove-button').prop('disabled', true); + $('#repositories-grid-edit-button').prop('disabled', true); + $('#repositories-grid-enable-button').prop('disabled', true); + }; + + var softwareUpdatesGridID = 'software-updates-grid'; + var softwareUpdatesGrid = null; + var progressAreaID = 'software-updates-progress-textarea'; + var reloadProgressArea = function(result) { + var progressArea = $('#' + progressAreaID)[0]; + $(progressArea).text(result['message']); + var scrollTop = $(progressArea).prop('scrollHeight'); + $(progressArea).prop('scrollTop', scrollTop); + }; + + var initSoftwareUpdatesGrid = function(softwareUpdates) { + softwareUpdatesGrid = new wok.widget.Grid({ + container: 'software-updates-grid-container', + id: softwareUpdatesGridID, + title: i18n['KCHUPD6001M'], + rowSelection: 'disabled', + toolbarButtons: [{ + id: softwareUpdatesGridID + '-update-button', + label: i18n['KCHUPD6006M'], + disabled: true, + onClick: function(event) { + var updateButton = $(this); + var progressArea = $('#' + progressAreaID)[0]; + $('#software-updates-progress-container').removeClass('hidden'); + $(progressArea).text(''); + !wok.isElementInViewport(progressArea) && + progressArea.scrollIntoView(); + $(updateButton).text(i18n['KCHUPD6007M']).prop('disabled', true); + + kimchi.updateSoftware(function(result) { + reloadProgressArea(result); + $(updateButton).text(i18n['KCHUPD6006M']).prop('disabled', false); + wok.topic('kimchi/softwareUpdated').publish({ + result: result + }); + }, function(error) { + var message = error && error['responseJSON'] && error['responseJSON']['reason']; + wok.message.error(message || i18n['KCHUPD6009M']); + $(updateButton).text(i18n['KCHUPD6006M']).prop('disabled', false); + }, reloadProgressArea); + } + }], + frozenFields: [], + fields: [{ + name: 'package_name', + label: i18n['KCHUPD6002M'], + 'class': 'software-update-name' + }, { + name: 'version', + label: i18n['KCHUPD6003M'], + 'class': 'software-update-version' + }, { + name: 'arch', + label: i18n['KCHUPD6004M'], + 'class': 'software-update-arch' + }, { + name: 'repository', + label: i18n['KCHUPD6005M'], + 'class': 'software-update-repos' + }], + data: listSoftwareUpdates + }); + }; + + var listSoftwareUpdates = function(gridCallback) { + kimchi.listSoftwareUpdates(function(softwareUpdates) { + if($.isFunction(gridCallback)) { + gridCallback(softwareUpdates); + } + else { + if(softwareUpdatesGrid) { + softwareUpdatesGrid.setData(softwareUpdates); + } + else { + initSoftwareUpdatesGrid(softwareUpdates); + } + } + + var updateButton = $('#' + softwareUpdatesGridID + '-update-button'); + $(updateButton).prop('disabled', softwareUpdates.length === 0); + }, function(error) { + var message = error && error['responseJSON'] && error['responseJSON']['reason']; + if($.isFunction(gridCallback)) { + gridCallback([]); + } + softwareUpdatesGrid && + softwareUpdatesGrid.showMessage(message || i18n['KCHUPD6008M']); + }); + }; + + var reportGridID = 'available-reports-grid'; + var reportGrid = null; + var enableReportButtons = function(toEnable) { + var buttonID = '#{grid}-{btn}-button'; + $.each(['rename', 'remove', 'download'], function(i, n) { + $(wok.substitute(buttonID, { + grid: reportGridID, + btn: n + })).prop('disabled', !toEnable); + }); + }; + var initReportGrid = function(reports) { + reportGrid = new wok.widget.Grid({ + container: 'available-reports-grid-container', + id: reportGridID, + title: i18n['KCHDR6002M'], + toolbarButtons: [{ + id: reportGridID + '-generate-button', + label: i18n['KCHDR6006M'], + onClick: function(event) { + wok.window.open('plugins/kimchi/report-add.html'); + } + }, { + id: reportGridID + '-rename-button', + label: i18n['KCHDR6008M'], + disabled: true, + onClick: function(event) { + var report = reportGrid.getSelected(); + if(!report) { + return; + } + + kimchi.selectedReport = report['name']; + wok.window.open('plugins/kimchi/report-rename.html'); + } + }, { + id: reportGridID + '-remove-button', + label: i18n['KCHDR6009M'], + disabled: true, + onClick: function(event) { + var report = reportGrid.getSelected(); + if(!report) { + return; + } + + var settings = { + title : i18n['KCHAPI6004M'], + content : i18n['KCHDR6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + + wok.confirm(settings, function() { + kimchi.deleteReport({ + name: report['name'] + }, function(result) { + listDebugReports(); + }, function(error) { + wok.message.error(error.responseJSON.reason); + }); + }); + } + }, { + id: reportGridID + '-download-button', + label: i18n['KCHDR6010M'], + disabled: true, + onClick: function(event) { + var report = reportGrid.getSelected(); + if(!report) { + return; + } + + kimchi.downloadReport({ + file: report['uri'] + }); + } + }], + onRowSelected: function(row) { + var report = reportGrid.getSelected(); + // Only enable report buttons if the selected line is not a + // pending report + if (report['time'] == i18n['KCHDR6007M']) { + var gridElement = $('#'+ reportGridID); + var row = $('tr:contains(' + report['name'] + ')', gridElement); + enableReportButtons(false); + row.attr('class', ''); + } + else { + enableReportButtons(true); + } + }, + frozenFields: [], + fields: [{ + name: 'name', + label: i18n['KCHDR6003M'], + 'class': 'debug-report-name' + }, { + name: 'time', + label: i18n['KCHDR6005M'], + 'class': 'debug-report-time' + }], + data: reports + }); + }; + + var getPendingReports = function() { + var reports = [] + var filter = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/debugreports/*') + + kimchi.getTasksByFilter(filter, function(tasks) { + for(var i = 0; i < tasks.length; i++) { + reportName = tasks[i].target_uri.replace(/^\/plugins\/kimchi\/debugreports\//, '') || i18n['KCHDR6012M']; + reports.push({'name': reportName, 'time': i18n['KCHDR6007M']}) + + if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) { + continue; + } + + kimchi.trackTask(tasks[i].id, function(result) { + wok.topic('kimchi/debugReportAdded').publish(); + }, function(result) { + // Error message from Async Task status + if (result['message']) { + var errText = result['message']; + } + // Error message from standard kimchi exception + else { + var errText = result['responseJSON']['reason']; + } + result && wok.message.error(errText); + wok.topic('kimchi/debugReportAdded').publish(); + }, null); + } + }, null, true); + + return reports; + }; + + var listDebugReports = function() { + kimchi.listReports(function(reports) { + pendingReports = getPendingReports(); + allReports = pendingReports.concat(reports); + $('#debug-report-section').removeClass('hidden'); + + // Row selection will be cleared so disable buttons here + enableReportButtons(false); + + if(reportGrid) { + reportGrid.setData(allReports); + } + else { + initReportGrid(allReports); + } + + // Set id-debug-img to pending reports + // It will display a loading icon + var gridElement = $('#' + reportGridID); + $.each($('td:contains(' + i18n['KCHDR6007M'] + ')', gridElement), function(index, row) { + $(row).parent().addClass('no-hover'); + $(row).attr('id', 'id-debug-img'); + }); + }, function(error) { + if(error['status'] == 403) { + $('#debug-report-section').addClass('hidden'); + return; + } + $('#debug-report-section').removeClass('hidden'); + }); + }; + + var shutdownButtonID = '#host-button-shutdown'; + var restartButtonID = '#host-button-restart'; + var shutdownHost = function(params) { + var settings = { + title : i18n['KCHAPI6004M'], + content : i18n['KCHHOST6008M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + + wok.confirm(settings, function() { + kimchi.shutdown(params); + $(shutdownButtonID).prop('disabled', true); + $(restartButtonID).prop('disabled', true); + // Check if there is any VM is running. + kimchi.listVMs(function(vms) { + for(var i = 0; i < vms.length; i++) { + if(vms[i]['state'] === 'running') { + wok.message.error.code('KCHHOST6001E'); + $(shutdownButtonID).prop('disabled', false); + $(restartButtonID).prop('disabled', false); + return; + } + } + + }); + }, function() { + }); + }; + + var initPage = function() { + $('#host-info-container .section-header').each(function(i, header) { + $('<span class="arrow"></span>').prependTo(header); + var toExpand = $(header).attr('aria-expanded') !== 'false'; + expand(header, toExpand); + }); + + $('#host-info-container').on('click', '.section-header', function(event) { + var toExpand = $(this).attr('aria-expanded') === 'false'; + expand(this, toExpand); + }); + + $('#host-button-shutdown').on('click', function(event) { + shutdownHost(null); + }); + + $('#host-button-restart').on('click', function(event) { + shutdownHost({ + reboot: true + }); + }); + + var setupUI = function() { + if (kimchi.capabilities == undefined) { + setTimeout(setupUI, 2000); + return; + } + + if((kimchi.capabilities['repo_mngt_tool']) && (kimchi.capabilities['repo_mngt_tool']!="None")) { + initRepositoriesGrid(kimchi.capabilities['repo_mngt_tool']); + $('#repositories-section').switchClass('hidden', kimchi.capabilities['repo_mngt_tool']); + wok.topic('kimchi/repositoryAdded') + .subscribe(listRepositories); + wok.topic('kimchi/repositoryUpdated') + .subscribe(listRepositories); + wok.topic('kimchi/repositoryDeleted') + .subscribe(listRepositories); + } + + if(kimchi.capabilities['update_tool']) { + $('#software-update-section').removeClass('hidden'); + initSoftwareUpdatesGrid(); + wok.topic('kimchi/softwareUpdated') + .subscribe(listSoftwareUpdates); + $('#software-updates-progress-container').accordion({ + collapsible: true + }); + } + + if(kimchi.capabilities['system_report_tool']) { + listDebugReports(); + wok.topic('kimchi/debugReportAdded') + .subscribe(listDebugReports); + wok.topic('kimchi/debugReportRenamed') + .subscribe(listDebugReports); + } + }; + setupUI(); + }; + + kimchi.getHost(function(data) { + var htmlTmpl = $('#host-tmpl').html(); + data['logo'] = data['logo'] || ''; + data['memory'] = wok.formatMeasurement(data['memory'], { + fixed: 2 + }); + var templated = wok.substitute(htmlTmpl, data); + $('#host-content-container').html(templated); + + initPage(); + initTracker(); + }); + + var StatsMgr = function() { + var statsArray = { + cpu: { + u: { + type: 'percent', + legend: i18n['KCHHOST6002M'], + points: [] + } + }, + memory: { + u: { + type: 'value', + base: 2, + fixed: 2, + legend: i18n['KCHHOST6003M'], + points: [] + } + }, + diskIO: { + r: { + type: 'value', + base: 2, + fixed: 2, + unit: 'B/s', + legend: i18n['KCHHOST6004M'], + points: [] + }, + w: { + type: 'value', + base: 2, + fixed: 2, + unit: 'B/s', + legend: i18n['KCHHOST6005M'], + 'class': 'disk-write', + points: [] + } + }, + networkIO: { + r: { + type: 'value', + base: 2, + fixed: 2, + unit: 'B/s', + legend: i18n['KCHHOST6006M'], + points: [] + }, + s: { + type: 'value', + base: 2, + fixed: 2, + unit: 'B/s', + legend: i18n['KCHHOST6007M'], + 'class': 'network-sent', + points: [] + } + } + }; + var SIZE = 20; + var cursor = SIZE; + + var add = function(stats) { + for(var key in stats) { + var item = stats[key]; + for(var metrics in item) { + var value = item[metrics]['v']; + var max = item[metrics]['max']; + var unifiedMetrics = statsArray[key][metrics]; + var ps = unifiedMetrics['points']; + if(!Array.isArray(value)){ + ps.push(value); + if(ps.length > SIZE + 1) { + ps.shift(); + } + } + else{ + ps=ps.concat(value); + ps.splice(0, ps.length-SIZE-1); + unifiedMetrics['points']=ps; + } + if(max !== undefined) { + unifiedMetrics['max'] = max; + } + else { + if(unifiedMetrics['type'] !== 'value') { + continue; + } + max = -Infinity; + $.each(ps, function(i, value) { + if(value > max) { + max = value; + } + }); + if(max === 0) { + ++max; + } + max *= 1.1; + unifiedMetrics['max'] = max; + } + } + } + cursor++; + }; + + var get = function(which) { + var stats = statsArray[which]; + var lines = []; + for(var k in stats) { + var obj = stats[k]; + var line = { + type: obj['type'], + base: obj['base'], + unit: obj['unit'], + fixed: obj['fixed'], + legend: obj['legend'] + }; + if(obj['max']) { + line['max'] = obj['max']; + } + if(obj['class']) { + line['class'] = obj['class']; + } + var ps = obj['points']; + var numStats = ps.length; + var unifiedPoints = []; + $.each(ps, function(i, value) { + unifiedPoints.push({ + x: cursor - numStats + i, + y: value + }); + }); + line['points'] = unifiedPoints; + lines.push(line); + } + return lines; + }; + + return { + add: add, + get: get + }; + }; + + var Tracker = function(charts) { + var charts = charts; + var timer = null; + var statsPool = new StatsMgr(); + var setCharts = function(newCharts) { + charts = newCharts; + for(var key in charts) { + var chart = charts[key]; + chart.updateUI(statsPool.get(key)); + } + }; + + var self = this; + + var UnifyStats = function(stats) { + var result= { + cpu: { + u: { + v: stats['cpu_utilization'] + } + }, + memory: { + u: { + } + }, + diskIO: { + r: { + v: stats['disk_read_rate'] + }, + w: { + v: stats['disk_write_rate'] + } + }, + networkIO: { + r: { + v: stats['net_recv_rate'] + }, + s: { + v: stats['net_sent_rate'] + } + } + }; + if(Array.isArray(stats['memory'])){ + result.memory.u['v']=[]; + result.memory.u['max']=-Infinity; + for(var i=0;i<stats['memory'].length;i++){ + result.memory.u['v'].push(stats['memory'][i]['avail']); + result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']); + } + } + else { + result.memory.u['v']=stats['memory']['avail'], + result.memory.u['max']=stats['memory']['total'] + } + return(result); + }; + + + var statsCallback = function(stats) { + var unifiedStats = UnifyStats(stats); + statsPool.add(unifiedStats); + for(var key in charts) { + var chart = charts[key]; + chart.updateUI(statsPool.get(key)); + } + timer = setTimeout(function() { + continueTrack(); + }, 1000); + }; + + var track = function() { + kimchi.getHostStatsHistory(statsCallback, + function() { + continueTrack(); + }); + }; + + var continueTrack = function() { + kimchi.getHostStats(statsCallback, + function() { + continueTrack(); + }); + }; + + var destroy = function() { + timer && clearTimeout(timer); + timer = null; + }; + + return { + setCharts: setCharts, + start: track, + stop: destroy + }; + }; + + var initTracker = function() { + // TODO: Extend tabs with onUnload event to unregister timers. + if(kimchi.hostTimer) { + kimchi.hostTimer.stop(); + delete kimchi.hostTimer; + } + + var trackedCharts = { + cpu: new wok.widget.LineChart({ + id: 'chart-cpu', + node: 'container-chart-cpu', + type: 'percent' + }), + memory: new wok.widget.LineChart({ + id: 'chart-memory', + node: 'container-chart-memory', + type: 'value' + }), + diskIO: new wok.widget.LineChart({ + id: 'chart-disk-io', + node: 'container-chart-disk-io', + type: 'value' + }), + networkIO: new wok.widget.LineChart({ + id: 'chart-network-io', + node: 'container-chart-network-io', + type: 'value' + }) + }; + + if(kimchi.hostTimer) { + kimchi.hostTimer.setCharts(trackedCharts); + } + else { + kimchi.hostTimer = new Tracker(trackedCharts); + kimchi.hostTimer.start(); + } + }; + + $('#host-root-container').on('remove', function() { + if(kimchi.hostTimer) { + kimchi.hostTimer.stop(); + delete kimchi.hostTimer; + } + + repositoriesGrid && repositoriesGrid.destroy(); + wok.topic('kimchi/repositoryAdded') + .unsubscribe(listRepositories); + wok.topic('kimchi/repositoryUpdated') + .unsubscribe(listRepositories); + wok.topic('kimchi/repositoryDeleted') + .unsubscribe(listRepositories); + + softwareUpdatesGrid && softwareUpdatesGrid.destroy(); + wok.topic('kimchi/softwareUpdated').unsubscribe(listSoftwareUpdates); + + reportGrid && reportGrid.destroy(); + wok.topic('kimchi/debugReportAdded').unsubscribe(listDebugReports); + wok.topic('kimchi/debugReportRenamed').unsubscribe(listDebugReports); + }); +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.main.js new file mode 100644 index 0000000..2fdeb85 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.main.js @@ -0,0 +1,26 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.capabilities = undefined; +kimchi.getCapabilities(function(result) { + kimchi.capabilities = result; + + if(kimchi.capabilities.federation=="on") + $('#peers').removeClass('hide-content'); +}, function() { + kimchi.capabilities = {}; +}); diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.network.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.network.js new file mode 100644 index 0000000..c43b59a --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.network.js @@ -0,0 +1,442 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +kimchi.NETWORK_TYPE_BRIDGE = "bridged"; + +kimchi.initNetwork = function() { + if(wok.tabMode['network'] === 'admin') { + $('.tools').attr('style','display'); + $('#network-content .header span:last-child').attr('style','display'); + kimchi.initNetworkCreation(); + } + kimchi.initNetworkListView(); + kimchi.initNetworkDialog(); + kimchi.initNetworkCleanup(); +}; + +kimchi.initNetworkListView = function() { + kimchi.listNetworks(function(data) { + for (var i = 0; i < data.length; i++) { + var network = { + name : data[i].name, + in_use : data[i].in_use, + state : data[i].state === "active" ? "up" : "down" + }; + if (data[i].connection === "bridge") { + network.type = kimchi.NETWORK_TYPE_BRIDGE; + } else { + network.type = data[i].connection; + } + network.interface = data[i].interface ? data[i].interface : null; + network.addrSpace = data[i].subnet ? data[i].subnet : null; + network.persistent = data[i].persistent; + kimchi.addNetworkItem(network); + } + $('#networkGrid').grid({enableSorting: false}); + $('input', $('.grid-control', '#network-content')).on('keyup', function(){ + $('#networkGrid').grid('filter', $(this).val()); + }); + }); +}; + +kimchi.addNetworkItem = function(network) { + var itemNode = $.parseHTML(kimchi.getNetworkItemHtml(network)); + $("#networkBody").append(itemNode); + if(wok.tabMode["network"] === "admin") { + $(".column-action").attr("style","display"); + } else { + $(".column-space").addClass('column-space-no-border-right'); + } + kimchi.addNetworkActions(network); + return itemNode; +}; + +kimchi.getNetworkItemHtml = function(network) { + if(!network.interface) { + network.interface = i18n["KCHNET6001M"]; + } + if(!network.addrSpace) { + network.addrSpace = i18n["KCHNET6001M"]; + } + if(i18n["network_type_" + network.type]) { + network.type = i18n["network_type_" + network.type]; + } + + var disable_in_use = network.in_use ? "ui-state-disabled" : ""; + var networkItem = wok.substitute($('#networkItem').html(), { + name : network.name, + state : network.state, + type : network.type, + interface: network.interface, + addrSpace : network.addrSpace, + startClass : network.state === "up" ? "hide-action-item" : "", + stopClass : network.state === "down" ? "hide-action-item" : disable_in_use, + stopDisabled : network.in_use ? "disabled" : "", + deleteClass : network.state === "up" || network.in_use ? "ui-state-disabled" : "", + deleteDisabled: network.state === "up" || network.in_use ? "disabled" : "" + }); + return networkItem; +}; + +kimchi.stopNetwork = function(network,menu) { + $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("up", "nw-loading"); + $("[nwAct='stop']", menu).addClass("ui-state-disabled"); + kimchi.toggleNetwork(network.name, false, function() { + $("[nwAct='start']", menu).removeClass("hide-action-item"); + $("[nwAct='stop']", menu).addClass("hide-action-item"); + $("[nwAct='stop']", menu).removeClass("ui-state-disabled"); + if (!network.in_use) { + $("[nwAct='delete']", menu).removeClass("ui-state-disabled"); + $(":first-child", $("[nwAct='delete']", menu)).removeAttr("disabled"); + } + $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("nw-loading", "down"); + }, function(err) { + $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("nw-loading", "up"); + if (!network.in_use) { + $("[nwAct='stop']", menu).removeClass("ui-state-disabled"); + } + wok.message.error(err.responseJSON.reason); + }); +} + +kimchi.addNetworkActions = function(network) { + $(".menu-container", "#" + wok.escapeStr(network.name)).menu(); + + $('#' + wok.escapeStr(network.name)).on('click', '.menu-container li', function(evt) { + var menu = $(evt.currentTarget).parent(); + if ($(evt.currentTarget).attr("nwAct") === "start") { + $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("down", "nw-loading"); + $("[nwAct='start']", menu).addClass("ui-state-disabled"); + $("[nwAct='delete']", menu).addClass("ui-state-disabled"); + $(":first-child", $("[nwAct='delete']", menu)).attr("disabled", true); + kimchi.toggleNetwork(network.name, true, function() { + $("[nwAct='start']", menu).addClass("hide-action-item"); + $("[nwAct='start']", menu).removeClass("ui-state-disabled"); + $("[nwAct='stop']", menu).removeClass("hide-action-item"); + network.state = "up"; + if (network.in_use) { + $("[nwAct='stop']", menu).addClass("ui-state-disabled"); + } + $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("nw-loading", "up"); + }, function(err) { + $(".network-state", $("#" + wok.escapeStr(network.name))).switchClass("nw-loading","down"); + $("[nwAct='start']", menu).removeClass("ui-state-disabled"); + if (!network.in_use) { + $("[nwAct='delete']", menu).removeClass("ui-state-disabled"); + } + $(":first-child", $("[nwAct='delete']", menu)).removeAttr("disabled"); + wok.message.error(err.responseJSON.reason); + }); + } else if ($(evt.currentTarget).attr("nwAct") === "stop") { + if (network.in_use) { + return false; + } + if (!network.persistent) { + var settings = { + title : i18n['KCHAPI6001M'], + content : i18n['KCHNET6004M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + wok.confirm(settings, function() { + kimchi.stopNetwork(network, menu); + $('#networkGrid').grid('deleteRow', $(evt.currentTarget).parents(".row")); + }, null); + } + else { + kimchi.stopNetwork(network, menu); + network.state = "down"; + } + } else if ($(evt.currentTarget).attr("nwAct") === "delete") { + if (network.state === "up" || network.in_use) { + return false; + } + wok.confirm({ + title : i18n['KCHAPI6006M'], + content : i18n['KCHNET6002M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }, function() { + kimchi.deleteNetwork(network.name, function() { + $('#networkGrid').grid('deleteRow', $(evt.currentTarget).parents(".row")); + }); + }, null); + } + }); + + $("#networkBody .column-action .popable").button({ + icons : { + secondary : "action-button-icon" + } + }); + +}; + +kimchi.initNetworkCreation = function() { + $("#networkAdd").on("click", function() { + kimchi.openNetworkDialog(function() { + var errorCallback = function(){ + $("#networkFormOk").button("enable"); + $("#networkName").removeAttr("readonly"); + $("#networkFormOk span").text(i18n.KCHAPI6005M); + }; + var network = kimchi.getNetworkDialogValues(); + var data = { + name : network.name, + connection: network.type + }; + if (network.type === kimchi.NETWORK_TYPE_BRIDGE) { + data.connection = "bridge"; + data.interface = network.interface; + if ($("#enableVlan").prop("checked")) { + data.vlan_id = network.vlan_id; + if (!(data.vlan_id >=1 && data.vlan_id <= 4094)) { + wok.message.error.code('KCHNET6001E'); + errorCallback(); + return; + } + } + } + kimchi.createNetwork(data, function(result) { + network.state = result.state === "active" ? "up" : "down"; + network.interface = result.interface ? result.interface : i18n["KCHNET6001M"]; + network.addrSpace = result.subnet ? result.subnet : i18n["KCHNET6001M"]; + network.persistent = result.persistent; + $('#networkGrid').grid('addRow', kimchi.addNetworkItem(network)); + $("#networkConfig").dialog("close"); + }, function(data) { + wok.message.error(data.responseJSON.reason); + errorCallback(); + }); + }); + }); +}; + +kimchi.initNetworkDialog = function() { + buttonsObj= {}; + buttonsObj['id'] = "networkFormOk"; + buttonsObj['text'] = i18n.KCHAPI6005M; + buttonsObj['class'] = "btn-normal"; + buttonsObj['disabled'] = true; + buttonsObj['click'] = function() { }; + buttonsObjCancel= {}; + buttonsObjCancel['id'] = "networkFormCancel"; + buttonsObjCancel['text'] = i18n.KCHAPI6003M; + buttonsObjCancel['class'] = "btn-normal"; + buttonsObjCancel['disabled'] = false; + buttonsObjCancel['click'] = function() { + $(this).dialog("close"); + }; + $("#networkConfig").dialog({ + autoOpen : false, + modal : true, + width : 600, + draggable : false, + resizable : false, + closeText: "X", + dialogClass : "network-ui-dialog remove-when-logged-off", + open : function(){ + $(".ui-dialog-titlebar-close", $("#networkConfig").parent()).removeAttr("title"); + $(".ui-widget-overlay").css({ + "background": "#FFFFFF", + "opacity": "0.5" + }); + }, + beforeClose : function() { + kimchi.cleanNetworkDialog(); + }, + buttons : [buttonsObj, buttonsObjCancel] + }); + $("#networkConfig").parent().css({ + "background": "#FFFFFF", + "border-radius": 0, + "border": "2px solid #999999" + }); + $(".ui-dialog-titlebar button", $("#networkConfig").parent()).remove(); + $(".ui-dialog-titlebar span", $("#networkConfig").parent()).css({ + "font-weight": "lighter", + "height": "48px", + "line-height": "48px", + "margin": "0 30px", + "color": "#444444", + "font-size": "22px" + }); + $(".ui-dialog-titlebar", $("#networkConfig").parent()).css({ + "box-shadow": "none", + "padding": "0", + }); + $(".ui-dialog-buttonpane", $("#networkConfig").parent()).css({ + "background": "#008ABF" + }); + $(".ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset").css({ + "padding": "0 10px", + "float": "left" + }); + $(".ui-dialog-buttonpane .ui-dialog-buttonset button").removeClass("ui-corner-all"); + $(".ui-dialog-buttonpane .ui-dialog-buttonset button").css({ + "background": "#FFFFFF", + "color": "#444444", + "font-size": "13px", + "border-radius": "0", + "opacity": "1" + }); + kimchi.setupNetworkFormEvent(); +}; + +kimchi.openNetworkDialog = function(okCallback) { + kimchi.getInterfaces(function(result) { + var options = []; + $('#networkDestinationID').selectMenu(); + var nics = {}; + for (var i = 0; i < result.length; i++) { + options.push({label:result[i].name,value:result[i].name}); + nics[result[i].name] = result[i]; + } + result.length>0 && $("#networkDestinationID").selectMenu("setData", options); + onChange = function() { + $("#networkDestinationLabel").text($("#networkDestinationID li:first-child").text()); + $("#networkDestinationID li:first-child").addClass("active"); + if (result.length>0 && nics[$("#networkDestinationLabel").text()].type === "bridge") { + $("#enableVlan").prop("checked", false); + $("#enableVlan").prop("disabled", true); + $("#networkVlanID").val(""); + $("#networkVlanID").toggle(false); + $("#labelNetworkVlanID").toggle(false); + } else { + $("#enableVlan").prop("disabled",false); + } + }; + $("#networkDestinationLabel").on("change", onChange); + kimchi.setDefaultNetworkType(result.length!==0); + onChange(); + }); + $("#networkConfig").dialog({ + title : i18n.KCHNET6003M + }); + $("#networkFormOk").on("click", function() { + $("#networkFormOk").button("disable"); + $("#networkName").prop("readonly", "readonly"); + $("#networkFormOk span").text(i18n.KCHAPI6008M); + okCallback(); + }); + $("#enableVlan").on("click", function() { + $("#networkVlanID").prop("disabled", !this.checked); + if (!this.checked) { + $("#networkVlanID").slideUp(100); + $("#labelNetworkVlanID").slideUp(100); + $("#networkVlanID").val(""); + } + else { + $("#networkVlanID").slideDown(100); + $("#labelNetworkVlanID").slideDown(100); + } + }); + $("#networkConfig").dialog("open"); +}; + +kimchi.enableBridgeOptions = function(enable) { + if (!enable) { + $("#enableVlan").prop("checked", false); + $("#networkVlanID").toggle(false); + $("#labelNetworkVlanID").toggle(false); + $("#networkVlanID").val(""); + $("#networkDestinationLabel").text(""); + $("#bridgeOptions").slideUp(100); + } else if (!$("#networkDestinationLabel").text()){ + $("#networkDestinationLabel").text($("#networkDestinationID li:first-child").text()); + $("#bridgeOptions").slideDown(100); + $("#networkVlanID").toggle(false); + $("#labelNetworkVlanID").toggle(false); + } +}; + + +kimchi.setDefaultNetworkType = function(isInterfaceAvail) { + $("#networkTypeBri").prop("checked", isInterfaceAvail); + $("#networkTypeBri").prop("disabled", !isInterfaceAvail); + $("#networkTypeNat").prop("checked", !isInterfaceAvail); + if (!isInterfaceAvail) { + kimchi.enableBridgeOptions(false); + $("#networkBriDisabledLabel").show(); + } else { + if (kimchi.capabilities && kimchi.capabilities.nm_running) { + wok.message.warn(i18n['KCHNET6001W']); + } + $("#bridgeOptions").slideDown(100); + $("#networkVlanID").toggle(false); + $("#labelNetworkVlanID").toggle(false); + $("#networkBriDisabledLabel").hide(); + } +}; + +kimchi.getNetworkDialogValues = function() { + var network = { + name : $("#networkName").val(), + type : $("input:radio[name=networkType]:checked").val() + }; + if (network.type === kimchi.NETWORK_TYPE_BRIDGE) { + network.interface = $("#networkDestinationLabel").text(); + network.vlan_id = parseInt($("#networkVlanID").val()); + } + return network; +}; + +kimchi.cleanNetworkDialog = function() { + $("input:text", "#networkConfig").val(null).removeClass("invalid-field"); + $("#networkTypeIso").prop("checked", false); + $("#networkTypeNat").prop("checked", false); + $("#networkTypeBri").prop("checked", false); + $("#networkDestinationLabel").text($("#networkDestinationID li:first-child").text()); + $("#networkFormOk").off("click"); + $("#networkFormOk").button("disable"); + $("#networkFormOk span").text(i18n.KCHAPI6005M); + $("#networkName").removeAttr("readonly"); + $("#networkVlanID").toggle(false); + $("#labelNetworkVlanID").toggle(false); + $("#enableVlan").prop("checked", false); + +}; +kimchi.setupNetworkFormEvent = function() { + $("#networkName").on("keyup", function(event) { + $("#networkName").toggleClass("invalid-field", !$("#networkName").val().match(/^[^\"\/]+$/)); + kimchi.updateNetworkFormButton(); + }); + $("#networkTypeIso").on("click", function(event) { + kimchi.enableBridgeOptions(false); + }); + $("#networkTypeNat").on("click", function(event) { + kimchi.enableBridgeOptions(false); + }); + $("#networkTypeBri").on("click", function(event) { + kimchi.enableBridgeOptions(true); + }); +}; + +kimchi.updateNetworkFormButton = function() { + if($("#networkName").hasClass("invalid-field")){ + $("#networkFormOk").button("disable"); + }else{ + $("#networkFormOk").button("enable"); + } +}; + +kimchi.initNetworkCleanup = function() { + $("#network-content").on("remove", function() { + $("#networkConfig").dialog("destroy"); + }); +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.report_add_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.report_add_main.js new file mode 100644 index 0000000..5f098d3 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.report_add_main.js @@ -0,0 +1,72 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.report_add_main = function() { + var reportGridID = 'available-reports-grid'; + var addReportForm = $('#form-report-add'); + var submitButton = $('#button-report-add'); + var nameTextbox = $('input[name="name"]', addReportForm); + nameTextbox.select(); + + var submitForm = function(event) { + if(submitButton.prop('disabled')) { + return false; + } + var reportName = nameTextbox.val(); + var validator = RegExp("^[_A-Za-z0-9-]*$"); + if (!validator.test(reportName)) { + wok.message.error.code('KCHDR6011M'); + return false; + } + var formData = addReportForm.serializeObject(); + var taskAccepted = false; + var onTaskAccepted = function() { + if(taskAccepted) { + return; + } + taskAccepted = true; + wok.window.close(); + wok.topic('kimchi/debugReportAdded').publish(); + }; + + kimchi.createReport(formData, function(result) { + onTaskAccepted(); + wok.topic('kimchi/debugReportAdded').publish(); + }, function(result) { + // Error message from Async Task status + if (result['message']) { + var errText = result['message']; + } + // Error message from standard kimchi exception + else { + var errText = result['responseJSON']['reason']; + } + result && wok.message.error(errText); + + taskAccepted && + $('.grid-body-view table tr:first-child', + '#' + reportGridID).remove(); + submitButton.prop('disabled', false); + nameTextbox.select(); + }, onTaskAccepted); + + event.preventDefault(); + }; + + addReportForm.on('submit', submitForm); + submitButton.on('click', submitForm); +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js new file mode 100644 index 0000000..1bdb8d9 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js @@ -0,0 +1,66 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.report_rename_main = function() { + var renameReportForm = $('#form-report-rename'); + var submitButton = $('#button-report-rename'); + var nameTextbox = $('input[name="name"]', renameReportForm); + var submitForm = function(event) { + if(submitButton.prop('disabled')) { + return false; + } + var reportName = nameTextbox.val(); + + // if the user hasn't changed the report's name, + // nothing should be done. + if (reportName == kimchi.selectedReport) { + wok.message.error.code('KCHDR6013M'); + return false; + } + + var validator = RegExp("^[A-Za-z0-9-]*$"); + if (!validator.test(reportName)) { + wok.message.error.code('KCHDR6011M'); + return false; + } + var formData = renameReportForm.serializeObject(); + submitButton.prop('disabled', true); + nameTextbox.prop('disabled', true); + kimchi.renameReport(kimchi.selectedReport, formData, function(result) { + submitButton.prop('disabled', false); + nameTextbox.prop('disabled', false); + wok.window.close(); + wok.topic('kimchi/debugReportRenamed').publish({ + result: result + }); + }, function(result) { + var errText = result && + result['responseJSON'] && + result['responseJSON']['reason']; + wok.message.error(errText); + submitButton.prop('disabled', false); + nameTextbox.prop('disabled', false).focus(); + }); + + event.preventDefault(); + }; + + renameReportForm.on('submit', submitForm); + submitButton.on('click', submitForm); + + nameTextbox.val(kimchi.selectedReport).select(); +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js new file mode 100644 index 0000000..656306b --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js @@ -0,0 +1,96 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.repository_add_main = function() { + + var addForm = $('#form-repository-add'); + var addButton = $('#button-repository-add'); + + var validateField = function(event) { + var valid=($(this).val()!==''); + $(addButton).prop('disabled', !valid); + return(valid); + }; + + var validateForm = function(event) { + var valid=false; + addForm.find('input.required').each( function() { + valid=($(this).val()!==''); + return(!valid); + }); + return(valid); + } + + addForm.find('input.required').on('input propertychange', validateField); + + var weedObject = function(obj) { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + if((typeof(obj[key])==="object") && !Array.isArray(obj[key])) { + weedObject(obj[key]); + } + else if(obj[key] == '') { + delete obj[key]; + } + } + } + } + + var addRepository = function(event) { + var valid = validateForm(); + if(!valid) { + return false; + } + + var formData = $(addForm).serializeObject(); + + if (formData && formData.isMirror!=undefined) { + formData.isMirror=(String(formData.isMirror).toLowerCase() === 'true'); + } + if(formData.isMirror) { + if(formData.config==undefined) { + formData.config=new Object(); + } + formData.config.mirrorlist=formData.baseurl; + delete formData.baseurl; + delete formData.isMirror; + } + weedObject(formData); + if(formData.config && formData.config.comps) { + formData.config.comps=formData.config.comps.split(/[,\s]/); + for(var i=0; i>formData.config.comps.length; i++) { + formData.config.comps[i]=formData.config.comps[i].trim(); + } + for (var j=formData.config.comps.indexOf(""); j!=-1; j=formData.config.comps.indexOf("")) { + formData.config.comps.splice(j, 1); + } + } + + kimchi.createRepository(formData, function() { + wok.topic('kimchi/repositoryAdded').publish(); + wok.window.close(); + }, function(jqXHR, textStatus, errorThrown) { + var reason = jqXHR && + jqXHR['responseJSON'] && + jqXHR['responseJSON']['reason']; + wok.message.error(reason); + }); + return false; + }; + + $(addForm).on('submit', addRepository); +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js new file mode 100644 index 0000000..5bfc51e --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js @@ -0,0 +1,74 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.repository_edit_main = function() { + + var editForm = $('#form-repository-edit'); + + var saveButton = $('#repository-edit-button-save'); + + if(kimchi.capabilities['repo_mngt_tool']=="yum") { + editForm.find('input.deb').prop('disabled', true); + } + else if(kimchi.capabilities['repo_mngt_tool']=="deb") { + editForm.find('input.yum').prop('disabled', true); + } + + kimchi.retrieveRepository(kimchi.selectedRepository, function(repository) { + editForm.fillWithObject(repository); + + $('input', editForm).on('input propertychange', function(event) { + if($(this).val() !== '') { + $(saveButton).prop('disabled', false); + } + }); + }); + + + var editRepository = function(event) { + var formData = $(editForm).serializeObject(); + + if (formData && formData.config) { + formData.config.gpgcheck=(String(formData.config.gpgcheck).toLowerCase() === 'true'); + } + + if(formData.config && formData.config.comps) { + formData.config.comps=formData.config.comps.split(/[,\s]/); + for(var i=0; i>formData.config.comps.length; i++) { + formData.config.comps[i]=formData.config.comps[i].trim(); + } + for (var j=formData.config.comps.indexOf(""); j!=-1; j=formData.config.comps.indexOf("")) { + formData.config.comps.splice(j, 1); + } + } + + kimchi.updateRepository(kimchi.selectedRepository, formData, function() { + wok.topic('kimchi/repositoryUpdated').publish(); + wok.window.close(); + }, function(jqXHR, textStatus, errorThrown) { + var reason = jqXHR && + jqXHR['responseJSON'] && + jqXHR['responseJSON']['reason']; + wok.message.error(reason); + }); + + return false; + }; + + $(editForm).on('submit', editRepository); + $(saveButton).on('click', editRepository); +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.storage_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.storage_main.js new file mode 100644 index 0000000..40a43f6 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.storage_main.js @@ -0,0 +1,428 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.doListStoragePools = function() { + kimchi.listStoragePools(function(result) { + var storageHtml = $('#storageTmpl').html(); + if (result && result.length) { + var listHtml = ''; + $.each(result, function(index, value) { + value.usage = Math.round(value.allocated / value.capacity * 100) || 0; + value.capacity = wok.changetoProperUnit(value.capacity,1); + value.allocated = wok.changetoProperUnit(value.allocated,1); + value.enableExt = value.type==="logical" ? "" : "hide-content"; + if ('kimchi-iso' !== value.type) { + listHtml += wok.substitute(storageHtml, value); + } + }); + if($('#storageGrid').hasClass('grid')) + $('#storageGrid').grid('destroy'); + $('#storagepoolsList').html(listHtml); + if(wok.tabMode['storage'] === 'admin') { + $('.storage-button').attr('style','display'); + } else { + $('.storage-allocate').addClass('storage-allocate-padding-user'); + } + $('#storageGrid').grid({enableSorting: false}); + $('input', $('.grid-control', '.storage')).on('keyup', function(){ + $('#storageGrid').grid('filter', $(this).val()); + }); + kimchi.storageBindClick(); + } else { + $('#storagepoolsList').html(''); + } + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); +} + +kimchi.storageBindClick = function() { + + $('.inactive').each(function(index) { + if ('active' === $(this).data('state')) { + $(this).hide(); + } else { + $(this).show(); + } + }); + + $('.list-storage .storage-state .active').each(function(index) { + if ('active' === $(this).data('state')) { + $(this).show(); + } else { + $(this).hide(); + } + }); + + $('.pool-activate').each(function(index) { + if ('active' === $(this).data('stat')) { + $(this).hide(); + } else { + $(this).show(); + } + }); + + $('.pool-deactivate').each(function(index) { + if ('active' === $(this).data('stat')) { + $(this).show(); + } else { + $(this).hide(); + } + }); + + $('.pool-add-volume').each(function(index) { + var canAddVolume = + $(this).data('stat') === 'active' && + $(this).data('type') !== 'iscsi' && + $(this).data('type') !== 'scsi'; + if(canAddVolume) { + $(this).show(); + } + else { + $(this).hide(); + } + }); + + if(wok.tabMode['storage'] === 'admin') { + $('.pool-delete').on('click', function(event) { + var $pool = $(this); + var settings = { + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + wok.confirm(settings, function() { + var poolName = $pool.data('name'); + kimchi.deleteStoragePool(poolName, function() { + kimchi.doListStoragePools(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }); + }); + + $('.pool-activate').on('click', function(event) { + var poolName = $(this).data('name'); + kimchi.changePoolState(poolName, 'activate', function() { + kimchi.doListStoragePools(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }); + + $('.pool-deactivate').on('click', function(event) { + var poolName = $(this).data('name'); + var settings = { + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6012M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + if (!$(this).data('persistent')) { + wok.confirm(settings, function() { + kimchi.changePoolState(poolName, 'deactivate', function() { + kimchi.doListStoragePools(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }, function() { + return false; + }); + } + else { + kimchi.changePoolState(poolName, 'deactivate', function() { + kimchi.doListStoragePools(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + } + }); + + $('.pool-add-volume').on('click', function(event) { + var poolName = $(this).data('name'); + kimchi.selectedSP = poolName; + wok.window.open('plugins/kimchi/storagepool-add-volume.html'); + }); + + $('.storage-action').on('click', function() { + var storage_action = $(this); + var deleteButton = storage_action.find('.pool-delete'); + if ('active' === deleteButton.data('stat')) { + deleteButton.attr('disabled', 'disabled'); + } else { + deleteButton.removeAttr('disabled'); + } + }); + + $('.pool-extend').on('click', function() { + $("#logicalPoolExtend").dialog("option", "poolName", $(this).data('name')); + $("#logicalPoolExtend").dialog("open"); + }); + } + + $('.row').on('click', function(event) { + if (!$(event.target).parents().hasClass('bottom')) { + if ($(this).data('stat') === 'active') { + var that = $(this); + var volumeDiv = $('#volume' + that.data('name')); + var slide = $('.volumes', this); + if (that.hasClass('in')) { + that.css('height','auto'); + kimchi.doListVolumes(that); + } else { + slide.slideUp('slow', function(){ + that.css('height',''); + }); + that.addClass('in'); + kimchi.changeArrow($('.arrow-up', this)); + } + } + } + }); +} + +kimchi._generateVolumeHTML = function(volume) { + if(volume['type'] === 'kimchi-iso') { + return ''; + } + var volumeHtml = $('#volumeTmpl').html(); + volume.capacity = wok.changetoProperUnit(volume.capacity,1); + volume.allocation = wok.changetoProperUnit(volume.allocation,1); + return wok.substitute(volumeHtml, volume); +}; + +kimchi.doListVolumes = function(poolObj) { + var poolName = poolObj.data('name') + + var getOngoingVolumes = function() { + var result = {} + var filter = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/storagepools/' + poolName + '/*') + kimchi.getTasksByFilter(filter, function(tasks) { + for(var i = 0; i < tasks.length; i++) { + var volumeName = tasks[i].target_uri.split('/').pop(); + result[volumeName] = tasks[i]; + + if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) { + continue; + } + + kimchi.trackTask(tasks[i].id, function(result) { + wok.topic('kimchi/volumeTransferFinished').publish(result); + }, function(result) { + wok.topic('kimchi/volumeTransferError').publish(result); + }, function(result) { + wok.topic('kimchi/volumeTransferProgress').publish(result); + }); + } + }, null, true); + return result; + }; + + var volumeDiv = $('#volume' + poolName); + $(volumeDiv).empty(); + var slide = $('.volumes', poolObj); + var handleArrow = $('.arrow-down', poolObj); + + kimchi.listStorageVolumes(poolName, function(result) { + var listHtml = ''; + var ongoingVolumes = []; + var ongoingVolumesMap = getOngoingVolumes(); + $.each(ongoingVolumesMap, function(volumeName, task) { + ongoingVolumes.push(volumeName) + var volume = { + poolName: poolName, + used_by: [], + capacity: 0, + name: volumeName, + format: '', + bootable: null, + os_distro: '', + allocation: 0, + os_version: '', + path: '', + type: 'file' + }; + listHtml += kimchi._generateVolumeHTML(volume); + }); + + $.each(result, function(index, value) { + if (ongoingVolumes.indexOf(value.name) == -1) { + value.poolname = poolName; + listHtml += kimchi._generateVolumeHTML(value); + } + }); + + if (listHtml.length > 0) { + volumeDiv.html(listHtml); + } else { + volumeDiv.html("<div class='pool-empty'>" + i18n['KCHPOOL6002M'] + "</div>"); + } + + $.each(ongoingVolumesMap, function(volumeName, task) { + wok.topic('kimchi/volumeTransferProgress').publish(task); + }); + + poolObj.removeClass('in'); + kimchi.changeArrow(handleArrow); + slide.slideDown('slow'); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); +} + +kimchi.initLogicalPoolExtend = function() { + $("#logicalPoolExtend").dialog({ + autoOpen : false, + modal : true, + width : 600, + resizable : false, + closeText: "X", + open : function(){ + $('#loading-info', '#logicalPoolExtend').removeClass('hidden'); + $(".ui-dialog-titlebar-close", $("#logicalPoolExtend").parent()).removeAttr("title"); + kimchi.listHostPartitions(function(data) { + $('#loading-info', '#logicalPoolExtend').addClass('hidden'); + if (data.length > 0) { + for(var i=0;i<data.length;i++){ + if (data[i].type === 'part' || data[i].type === 'disk') { + $('.host-partition', '#logicalPoolExtend').append(wok.substitute($('#logicalPoolExtendTmpl').html(), data[i])); + } + } + } else { + $('.host-partition').html(i18n['KCHPOOL6011M']); + $('.host-partition').addClass('text-help'); + } + }, function(err) { + $('#loading-info', '#logicalPoolExtend').addClass('hidden'); + $('.host-partition').html(i18n['KCHPOOL6013M'] + '<br/>(' + err.responseJSON.reason + ')'); + $('.host-partition').addClass('text-help'); + }); + }, + beforeClose : function() { $('.host-partition', '#logicalPoolExtend').empty(); }, + buttons : [{ + class: "ui-button-primary", + text: i18n.KCHAPI6007M, + click: function(){ + var devicePaths = []; + $("input[type='checkbox']:checked", "#logicalPoolExtend").each(function(){ + devicePaths.push($(this).prop('value')); + }) + kimchi.updateStoragePool($("#logicalPoolExtend").dialog("option", "poolName"),{disks: devicePaths},function(data){ + var item = $("#"+$("#logicalPoolExtend").dialog("option", "poolName")); + $(".usage", $(".storage-name", item)).text((Math.round(data.allocated/data.capacity*100)||0)+"%"); + $(".storage-text", $(".storage-capacity", item)).text(wok.changetoProperUnit(data.capacity,1)); + $(".storage-text", $(".storage-allocate", item)).text(wok.changetoProperUnit(data.allocated,1)); + }); + $(this).dialog("close"); + } + }] + }); +} + +kimchi.storage_main = function() { + if(wok.tabMode['storage'] === 'admin') { + $('.tools').attr('style','display'); + $('#storage-pool-add').on('click', function() { + wok.window.open('plugins/kimchi/storagepool-add.html'); + }); + $('.list-title .title-actions').attr('style','display'); + } + kimchi.doListStoragePools(); + kimchi.initLogicalPoolExtend(); + + wok.topic('kimchi/storageVolumeAdded').subscribe(function() { + pool = kimchi.selectedSP; + var poolNode = $('.storage-li[data-name="' + pool + '"]'); + kimchi.doListVolumes(poolNode); + }); + + wok.topic('kimchi/volumeTransferProgress').subscribe(function(result) { + var extractProgressData = function(data) { + var sizeArray = /(\d+)\/(\d+)/g.exec(data) || [0, 0, 0]; + var downloaded = sizeArray[1]; + var percent = 0; + if(downloaded) { + var total = sizeArray[2]; + if(!isNaN(total)) { + percent = downloaded / total * 100; + } + } + var formatted = wok.formatMeasurement(downloaded); + var size = (1.0 * formatted['v']).toFixed(1) + formatted['s']; + return { + size: size, + percent: percent + }; + }; + + var uriElements = result.target_uri.split('/'); + var poolName = uriElements[2]; + var volumeName = uriElements.pop(); + var progress = extractProgressData(result['message']); + var size = progress['size']; + var percent = progress['percent']; + + volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]'); + $('.progress-bar-inner', volumeBox).css({ + width: percent + '%' + }); + $('.progress-transferred', volumeBox).text(size); + $('.volume-progress', volumeBox).removeClass('hidden'); + $('.progress-status', volumeBox).text(i18n['KCHPOOL6014M']); + }); + + wok.topic('kimchi/volumeTransferFinished').subscribe(function(result) { + var uriElements = result.target_uri.split('/'); + var poolName = uriElements[2]; + var volumeName = uriElements.pop(); + var volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]'); + $('.volume-progress', volumeBox).addClass('hidden'); + kimchi.getStoragePoolVolume(poolName, volumeName, function(volume) { + var html = kimchi._generateVolumeHTML(volume); + $(volumeBox).replaceWith(html); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }); + + wok.topic('kimchi/volumeTransferError').subscribe(function(result) { + // Error message from Async Task status + if (result['message']) { + var errText = result['message']; + } + // Error message from standard kimchi exception + else { + var errText = result['responseJSON']['reason']; + } + result && wok.message.error(errText); + + var uriElements = result.target_uri.split('/'); + var poolName = uriElements[2]; + var volumeName = uriElements.pop(); + volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]'); + $('.progress-status', volumeBox).text(i18n['KCHPOOL6015M']); + }); +}; + +kimchi.changeArrow = function(obj) { + if ($(obj).hasClass('arrow-down')) { + $(obj).removeClass('arrow-down').addClass('arrow-up'); + } else { + $(obj).removeClass('arrow-up').addClass('arrow-down'); + } +} diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.storagepool_add_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.storagepool_add_main.js new file mode 100644 index 0000000..8c27539 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.storagepool_add_main.js @@ -0,0 +1,414 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +kimchi.storagepool_add_main = function() { + kimchi.initStorageAddPage(); + $('#form-pool-add').on('submit', kimchi.addPool); + $('#pool-doAdd').on('click', kimchi.addPool); + // 'pool-doAdd' button starts as disabled. + $("#pool-doAdd").attr("disabled", true); + // Make any change in the form fields enables the + // 'pool-doAdd' button if all the visible form + // fields are filled, disables it otherwise. + $('#form-pool-add').on('input change propertychange', function() { + if (!kimchi.inputsNotBlank()) + $("#pool-doAdd").attr("disabled", true); + else + $("#pool-doAdd").attr("disabled", false); + }); +}; + +kimchi.storageFilterSelect = function(id, isUpdate) { + var input = $('input', '#'+id); + var options = $(".option", '#'+id); + var filter = function(container, key){ + container.children().each(function(){ + $(this).css("display", $(this).text().indexOf(key)==-1 ? "none" : ""); + }); + }; + if(!isUpdate){ + input.on("keyup", function(){ + filter(options, input.val()); + }); + } + options.children().each(function(){ + $(this).click(function(){ + options.children().removeClass("active"); + input.val($(this).text()); + input.trigger("change"); + $(this).addClass("active"); + filter(options, ""); + }); + }); +}; + +kimchi.setupISCSI = function(){ + var loadTargets = function(server, port, callback){ + var isUpdate = $(".option", "#iSCSITarget").children().length > 0; + $(".option", "#iSCSITarget").empty(); + $('input', "#iSCSITarget").attr("placeholder", i18n['KCHPOOL6006M']); + kimchi.getISCSITargets(server, port, function(data){ + if(data.length==0){ + $('input', "#iSCSITarget").attr("placeholder", i18n['KCHPOOL6007M']); + }else{ + for(var i=0; i<data.length; i++){ + var itemNode = $.parseHTML("<li>"+data[i].target+"</li>"); + $(".option", "#iSCSITarget").append(itemNode); + } + $('input', "#iSCSITarget").attr("placeholder", ""); + $(".popover", "#iSCSITarget").css("display", "block"); + } + kimchi.storageFilterSelect('iSCSITarget', isUpdate); + $('input', "#iSCSITarget").trigger("focus"); + callback(); + }, function(data){ + $('input', "#iSCSITarget").attr("placeholder", i18n['KCHPOOL6008M']); + callback(); + wok.message.error(data.responseJSON.reason); + }); + }; + var triggerLoadTarget = function(){ + $('input', "#iSCSITarget").val(""); + var server = $("#iscsiserverId").val().trim(); + var port = $("#iscsiportId").val().trim(); + if(server!="" && !$("#iscsiserverId").hasClass("invalid-field") && !$("#iscsiportId").hasClass("invalid-field")){ + $("#iscsiserverId").attr("disabled", true); + $("#iscsiportId").attr("disabled", true); + loadTargets(server, port, function(){ + $("#iscsiserverId").attr("disabled", false); + $("#iscsiportId").attr("disabled", false); + }); + } + }; + $("#iscsiserverId").change(function(){ + $('input', "#iSCSITarget").off('focus', triggerLoadTarget); + $('input', "#iSCSITarget").one('focus', triggerLoadTarget); + }); + $("#iscsiportId").change(function(){ + $('input', "#iSCSITarget").off('focus', triggerLoadTarget); + $('input', "#iSCSITarget").one('focus', triggerLoadTarget); + }); + var initISCSIServers = function(){ + kimchi.getStorageServers("iscsi", function(data){ + for(var i=0;i<data.length;i++){ + var itemNode = $.parseHTML("<li>"+data[i].host+"</li>"); + $(".option", "#iSCSIServer").append(itemNode); + $(itemNode).click(function(){ + $("#iscsiportId").val($(this).prop("port")); + $("#iscsiserverId").val($(this).text()); + triggerLoadTarget(); + }).prop("port", data[i].port); + } + kimchi.storageFilterSelect('iSCSIServer', false); + }); + }; + initISCSIServers(); +}; + +kimchi.initStorageAddPage = function() { + kimchi.listHostPartitions(function(data) { + if (data.length > 0) { + var deviceHtml = $('#partitionTmpl').html(); + var listHtml = ''; + valid_types = ['part', 'disk', 'mpath']; + $.each(data, function(index, value) { + if (valid_types.indexOf(value.type) != -1) { + listHtml += wok.substitute(deviceHtml, value); + } + }); + $('.host-partition', '#form-pool-add').html(listHtml); + } else { + $('.host-partition').html(i18n['KCHPOOL6011M']); + $('.host-partition').addClass('text-help'); + } + }, function(err) { + $('.host-partition').html(i18n['KCHPOOL6013M'] + '<br/>(' + err.responseJSON.reason + ')'); + $('.host-partition').addClass('text-help'); + }); + + kimchi.getHostFCDevices(function(data){ + if(data.length>0){ + for(var i=0;i<data.length;i++){ + data[i].label = data[i].name; + data[i].value = data[i].name; + } + $('#scsiAdapter').selectMenu(); + $("input", "#scsiAdapter").val(data[0].name); + $('#scsiAdapter').selectMenu("setData", data); + } else { + $('#scsiAdapter').html(i18n['KCHPOOL6005M']); + $('#scsiAdapter').addClass('text-help'); + } + }); + + $('#poolTypeId').selectMenu(); + $('#serverComboboxId').combobox(); + $('#targetFilterSelectId').filterselect(); + var options = [ { + label : "DIR", + value : "dir" + }, { + label : "NFS", + value : "netfs" + }, { + label : "iSCSI", + value : "iscsi" + }, { + label : "LOGICAL", + value : "logical" + }, { + label : i18n.KCHPOOL6004M, + value : "scsi" + } ]; + $('#poolTypeId').selectMenu("setData", options); + + kimchi.getStorageServers('netfs', function(data) { + var serverContent = []; + if (data.length > 0) { + $.each(data, function(index, value) { + serverContent.push({ + label : value.host, + value : value.host + }); + }); + } + $('#serverComboboxId').combobox("setData", serverContent); + $('input[name=nfsServerType]').change(function() { + if ($(this).val() === 'input') { + $('#nfsServerInputDiv').removeClass('tmpl-html'); + $('#nfsServerChooseDiv').addClass('tmpl-html'); + } else { + $('#nfsServerInputDiv').addClass('tmpl-html'); + $('#nfsServerChooseDiv').removeClass('tmpl-html'); + } + }); + $('#nfsserverId').on("change keyup",function() { + if ($(this).val() !== '' && wok.isServer($(this).val())) { + $('#nfspathId').prop('disabled',false); + $(this).removeClass("invalid-field"); + } else { + $(this).addClass("invalid-field"); + $('#nfspathId').prop( "disabled",true); + } + $('#targetFilterSelectId').filterselect('clear'); + }); + $('#nfspathId').focus(function() { + var targetContent = []; + kimchi.getStorageTargets($('#nfsserverId').val(), 'netfs', function(data) { + if (data.length > 0) { + $.each(data, function(index, value) { + targetContent.push({ + label : value.target, + value : value.target + }); + }); + } + $('#targetFilterSelectId').filterselect("setData", targetContent); + }); + }); + }); + + $('#poolTypeInputId').change(function() { + var poolObject = {'dir': ".path-section", 'netfs': '.nfs-section', + 'iscsi': '.iscsi-section', 'scsi': '.scsi-section', + 'logical': '.logical-section'} + var selectType = $(this).val(); + $.each(poolObject, function(type, value) { + if(selectType == type){ + $(value).removeClass('tmpl-html'); + } else { + $(value).addClass('tmpl-html'); + } + }); + }); + $('#authId').click(function() { + if ($(this).prop("checked")) { + $('.authenticationfield').removeClass('tmpl-html'); + } else { + $('.authenticationfield').addClass('tmpl-html'); + } + }); + $('#iscsiportId').keyup(function(event) { + $(this).toggleClass("invalid-field",!/^[0-9]*$/.test($(this).val())); + }); + $('#iscsiserverId').keyup(function(event) { + $(this).toggleClass("invalid-field",!wok.isServer($(this).val().trim())); + }).change(function(event) { + $(this).toggleClass("invalid-field",!wok.isServer($(this).val().trim())); + }); + kimchi.setupISCSI(); +}; + +/* Returns 'true' if all form fields were filled, 'false' if + * any field is left blank. The function takes into account + * the current poolType selected. + * + * Any 'field is blank' verification that were done in other + * validate functions were deleted, since we're doing it here + * already. + */ +kimchi.inputsNotBlank = function() { + if (!$('#poolId').val()) return false; + var poolType = $("#poolTypeInputId").val(); + if (poolType === "dir") { + if (!$('#pathId').val()) return false; + } else if (poolType === "netfs") { + if (!$('#nfspathId').val()) return false; + if (!$('#nfsserverId').val()) return false; + } else if (poolType === "iscsi") { + if (!$('#iscsiserverId').val()) return false; + if (!$('#iscsiTargetId').val()) return false; + } else if (poolType === "logical") { + if ($("input[name=devices]:checked").length === 0) + return false; + } + return true; +}; + +kimchi.validateForm = function() { + var poolType = $("#poolTypeInputId").val(); + if (poolType === "dir") { + return kimchi.validateDirForm(); + } else if (poolType === "netfs") { + return kimchi.validateNfsForm(); + } else if (poolType === "iscsi") { + return kimchi.validateIscsiForm(); + } else if (poolType === "logical") { + return kimchi.validateLogicalForm(); + } else { + return true; + } +}; + +kimchi.validateDirForm = function () { + var path = $('#pathId').val(); + if (!/(^\/.*)$/.test(path)) { + wok.message.error.code('KCHAPI6003E'); + return false; + } + return true; +}; + +kimchi.validateNfsForm = function () { + var nfspath = $('#nfspathId').val(); + var nfsserver = $('#nfsserverId').val(); + if (!kimchi.validateServer(nfsserver)) { + return false; + } + if (!/((\/([0-9a-zA-Z-_\.]+)))$/.test(nfspath)) { + wok.message.error.code('KCHPOOL6005E'); + return false; + } + $('#nfs-mount-loading').removeClass('hidden'); + return true; +}; + +kimchi.validateIscsiForm = function() { + var iscsiServer = $('#iscsiserverId').val(); + var iscsiTarget = $('#iscsiTargetId').val(); + if (!kimchi.validateServer(iscsiServer)) { + return false; + } + return true; +}; + +kimchi.validateServer = function(serverField) { + if(!wok.isServer(serverField)) { + wok.message.error.code('KCHPOOL6009E'); + return false; + } + return true; +}; + +kimchi.validateLogicalForm = function () { + if ($("input[name=devices]:checked").length === 0) { + wok.message.error.code('KCHPOOL6006E'); + return false; + } else { + return true; + } +}; + +kimchi.addPool = function(event) { + if (kimchi.validateForm()) { + var formData = $('#form-pool-add').serializeObject(); + delete formData.authname; + var poolType = $('#poolTypeId').selectMenu('value'); + if (poolType === 'dir') { + formData.path = $('#pathId').val(); + } else if (poolType === 'logical') { + var source = {}; + if (!$.isArray(formData.devices)) { + var deviceObj = []; + deviceObj[0] = formData.devices; + source.devices = deviceObj; + } else { + source.devices = formData.devices; + } + delete formData.devices; + formData.source = source; + } else if (poolType === 'netfs'){ + var source = {}; + source.path = $('#nfspathId').val(); + source.host = $('#nfsserverId').val(); + formData.source = source; + } else if (poolType === 'iscsi') { + var source = {}; + source.target = $('#iscsiTargetId').val(); + source.host = $('#iscsiserverId').val(); + $('#iscsiportId').val() !== '' ? source.port = parseInt($('#iscsiportId').val()): null; + if ($('#authId').prop("checked")) { + source.auth = { + "username" : $('#usernameId').val(), + "password" : $('#passwordId').val() + }; + } + formData.source = source; + } else if (poolType === 'scsi'){ + formData.source = { adapter_name: $('#scsiAdapter').selectMenu('value') }; + } + var storagePoolAddingFunc = function() { + $('input', '#form-pool-add').attr('disabled','disabled'); + $('#pool-doAdd').hide(); + $('#pool-loading').show(); + kimchi.createStoragePool(formData, function() { + kimchi.doListStoragePools(); + wok.window.close(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + $('input', '#form-pool-add').removeAttr('disabled'); + $('#pool-loading').hide(); + $('#pool-doAdd').show(); + }); + }; + if (poolType === 'logical') { + var settings = { + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6003M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + wok.confirm(settings, function() { + storagePoolAddingFunc(); + }, function() { + }); + } else { + storagePoolAddingFunc(); + } + } +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.storagepool_add_volume_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.storagepool_add_volume_main.js new file mode 100644 index 0000000..8479ab2 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.storagepool_add_volume_main.js @@ -0,0 +1,179 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014-2015 + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.sp_add_volume_main = function() { + // download from remote server or upload from local file + var type = 'download'; + + var addButton = $('#sp-add-volume-button'); + var remoteURLBox = $('#volume-remote-url'); + var localFileBox = $('#volume-input-file'); + var typeRadios = $('input.volume-type'); + + var isValidURL = function() { + var url = $(remoteURLBox).val(); + return kimchi.template_check_url(url); + }; + + var isValidFile = function() { + var fileName = $(localFileBox).val(); + return fileName.length > 0; + }; + + $(typeRadios).change(function(event) { + $('.volume-input').prop('disabled', true); + $('.volume-input.' + this.value).prop('disabled', false); + type = this.value; + if(type == 'download') { + $(addButton).prop('disabled', !isValidURL()); + } + else { + $(addButton).prop('disabled', !isValidFile()); + } + }); + + $(remoteURLBox).on('input propertychange', function(event) { + $(addButton).prop('disabled', !isValidURL()); + }); + + $(localFileBox).on('change', function(event) { + $(addButton).prop('disabled', !isValidFile()); + }); + + var onError = function(result) { + $(this).prop('disabled', false); + $(typeRadios).prop('disabled', false); + if(!result) { + return; + } + var msg = result['message'] || ( + result['responseJSON'] && result['responseJSON']['reason'] + ); + wok.message.error(msg); + }; + + var fetchRemoteFile = function() { + var volumeURL = remoteURLBox.val(); + var volumeName = volumeURL.split(/(\\|\/)/g).pop(); + kimchi.downloadVolumeToSP({ + sp: kimchi.selectedSP, + url: volumeURL + }, function(result) { + wok.window.close(); + wok.topic('kimchi/storageVolumeAdded').publish(); + }, onError); + }; + + var uploadFile = function() { + var chunkSize = 8 * 1024 * 1024; // 8MB + var uploaded = 0; + + var blobFile = $(localFileBox)[0].files[0]; + + var createUploadVol = function() { + kimchi.createVolumeWithCapacity(kimchi.selectedSP, { + name: blobFile.name, + format: '', + capacity: blobFile.size, + upload: true + }, function(result) { + wok.window.close(); + trackVolCreation(result.id); + }, onError); + }; + + var uploadRequest = function(blob) { + var fd = new FormData(); + fd.append('chunk', blob); + fd.append('chunk_size', blob.size); + + kimchi.uploadVolumeToSP(kimchi.selectedSP, blobFile.name, { + formData: fd + }, function(result) { + if (uploaded < blobFile.size) + setTimeout(doUpload, 500); + }, onError); + + uploaded += blob.size + }; + + // Check file exists and has read permission + try { + var blob = blobFile.slice(0, 20); + var reader = new FileReader(); + reader.onloadend = function(e) { + if (e.loaded == 0) + wok.message.error.code('KCHAPI6008E'); + else + createUploadVol(); + }; + + reader.readAsBinaryString(blob); + } catch (err) { + wok.message.error.code('KCHAPI6008E'); + return; + } + + var doUpload = function() { + try { + var blob = blobFile.slice(uploaded, uploaded + chunkSize); + var reader = new FileReader(); + reader.onloadend = function(e) { + if (e.loaded == 0) + wok.message.error.code('KCHAPI6009E'); + else + uploadRequest(blob); + }; + + reader.readAsBinaryString(blob); + } catch (err) { + wok.message.error.code('KCHAPI6009E'); + return; + } + } + + var trackVolCreation = function(taskid) { + var onTaskResponse = function(result) { + var taskStatus = result['status']; + var taskMsg = result['message']; + if (taskStatus == 'running') { + if (taskMsg != 'ready for upload') { + setTimeout(function() { + trackVolCreation(taskid); + }, 2000); + } else { + wok.topic('kimchi/storageVolumeAdded').publish(); + doUpload(); + } + } + }; + kimchi.getTask(taskid, onTaskResponse, onError); + }; + }; + + $(addButton).on('click', function(event) { + $(this).prop('disabled', true); + $(typeRadios).prop('disabled', true); + if(type === 'download') { + fetchRemoteFile(); + } + else { + uploadFile(); + } + event.preventDefault(); + }); +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.template_add_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.template_add_main.js new file mode 100644 index 0000000..01a47c2 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.template_add_main.js @@ -0,0 +1,441 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.switchPage = function(fromPageId, toPageId, direction) { + direction = direction || 'left'; + var toLeftBegin; + var fromLeftEnd; + if('left' === direction) { + toLeftBegin = '100%'; + fromLeftEnd = '-100%'; + } else if('right' === direction) { + toLeftBegin = '-100%'; + fromLeftEnd = '100%'; + } + var formPage = $('#'+fromPageId); + var toPage = $('#'+toPageId); + toPage.css({ + left: toLeftBegin + }); + formPage.animate({ + left: fromLeftEnd, + opacity: 0.1 + }, 400); + toPage.animate({ + left: '0', + opacity: 1 + }, 400); +}; + +kimchi.template_add_main = function() { + kimchi.deepScanHandler = null; + // 1-1 local iso + $('#iso-local').click(function() { + kimchi.switchPage('iso-type-box', 'iso-local-box'); + initLocalIsoField(); + initIsoFileField(); + kimchi.listIsos(function(isos) { + if (isos && isos.length) { + showLocalIsoField(isos); + $('#iso-more').show(); + } else { + $('#iso-search').show(); + } + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }); + + $('#iso-local-box-back').click(function() { + if (kimchi.deepScanHandler) { + kimchi.deepScanHandler.stop = true; + } + kimchi.switchPage('iso-local-box', 'iso-type-box', 'right'); + }); + + $('#iso-search').click(function() { + var settings = { + content : i18n['KCHTMPL6002M'] + }; + wok.confirm(settings, function() { + $('#iso-search').hide(); + $('#iso-search-loading').show(); + deepScan('#iso-search'); + }); + }); + + $('#iso-more').click(function() { + var settings = { + content : i18n['KCHTMPL6002M'] + }; + wok.confirm(settings, function() { + $('#iso-more').hide(); + $('#iso-more-loading').show(); + deepScan('#iso-more'); + }); + }); + + $('#iso-search-loading').click(function() { + $('#iso-search-loading').hide(); + $('#iso-search').show(); + if (kimchi.deepScanHandler) { + kimchi.deepScanHandler.stop = true; + } + }); + + $('#iso-more-loading').click(function() { + $('#iso-more-loading').hide(); + $('#iso-more').show(); + if (kimchi.deepScanHandler) { + kimchi.deepScanHandler.stop = true; + } + }); + + var deepScan = function(button) { + kimchi.deepScanHandler = kimchi.stepListDeepScanIsos(function(isos, isFinished) { + if (isos && isos.length) { + if(button === '#iso-search') { + $(button + '-loading').hide(); + button = '#iso-more'; + $(button + '-loading').show(); + } + showLocalIsoField(isos); + } else { + if (isFinished) { + wok.message.warn(i18n['KCHTMPL6001W']); + } + } + if (isFinished) { + $(button + '-loading').hide(); + $(button).show(); + } + }, function(err) { + wok.message.error(err.responseJSON.reason); + $(button + '-loading').hide(); + $(button).show(); + }); + }; + + //1-1-1 local iso list + var initLocalIsoField = function() { + kimchi.isoInfo = {}; + $('#local-iso-field').hide(); + $('#select-all-local-iso').prop('checked', false); + $('#btn-template-local-iso-create').attr('disabled', 'disabled'); + $('#iso-search').hide(); + $('#iso-more').hide(); + $('#iso-search-loading').hide(); + $('#iso-more-loading').hide(); + $('#list-local-iso').empty(); + }; + + var showLocalIsoField = function(isos) { + var html = ''; + var template = $('#tmpl-list-local-iso').html(); + $.each(isos, function(index, volume) { + var isoId = volume.os_distro + '*' + volume.name + '*' + volume.os_version; + if (!kimchi.isoInfo[isoId]) { + volume.isoId = isoId; + volume.capacity = wok.changetoProperUnit(volume.capacity, 1); + kimchi.isoInfo[isoId] = volume; + html += wok.substitute(template, volume); + } + }); + $('#list-local-iso').append(html); + $('#local-iso-field').show(); + }; + + $('#select-all-local-iso').click(function() { + $('#list-local-iso [type="checkbox"]').prop('checked', $(this).prop('checked')); + if ($(this).prop('checked')) { + $('#btn-template-local-iso-create').removeAttr('disabled'); + } else { + $('#btn-template-local-iso-create').attr('disabled', 'disabled'); + } + }); + + $('#list-local-iso').on('click', '[type="checkbox"]', function() { + var checkedLength = $('#list-local-iso [type="checkbox"]:checked').length; + if (checkedLength) { + $('#btn-template-local-iso-create').removeAttr('disabled'); + var length = $('#list-local-iso [type="checkbox"]').length; + $('#select-all-local-iso').prop('checked', length == checkedLength); + } else { + $('#select-all-local-iso').prop('checked', false); + $('#btn-template-local-iso-create').attr('disabled', 'disabled'); + } + }); + + $('#btn-template-local-iso-create').click(function() { + submitIso('form-local-iso'); + }); + + //1-1-2 local iso file + var initIsoFileField = function() { + $('#iso-file-check').prop('checked', false); + $('#iso-file-box').hide(); + $('#iso-file').val(''); + $('#btn-template-file-create').attr('disabled', 'disabled'); + }; + + $('#iso-file-check').click(function() { + if ($(this).prop('checked')) { + $('#iso-file-box').slideDown(); + } else { + $('#iso-file-box').slideUp(); + } + }); + + $('#iso-file').on('input propertychange', function() { + if ($('#iso-file').val()) { + $('#btn-template-file-create').removeAttr('disabled'); + } else { + $('#btn-template-file-create').attr('disabled', 'disabled'); + } + }); + + $('#btn-template-file-create').click(function() { + var isoFile = $('#iso-file').val(); + if (!kimchi.template_check_path(isoFile)) { + wok.message.error.code('KCHAPI6003E'); + return; + } + var data = { + "cdrom" : isoFile + }; + addTemplate(data); + }); + + //1-2 remote iso + $('#iso-remote').css('opacity', 0.3).css('cursor', 'not-allowed'); + + var enabledRemoteIso = function() { + if (kimchi.capabilities == undefined) { + setTimeout(enabledRemoteIso, 2000); + return; + } + + if (kimchi.capabilities.qemu_stream != true) { + return; + } + + $('#iso-remote').css('opacity', 1).css('cursor', 'pointer'); + $('#iso-remote').click(function() { + kimchi.switchPage('iso-type-box', 'iso-remote-box'); + initRemoteIsoField(); + initIsoUrlField(); + kimchi.listDistros(function(isos) { + showRemoteIsoField(isos); + }, function() { + }); + }); + }; + enabledRemoteIso(); + + $('#iso-remote-box-back').click(function() { + kimchi.switchPage('iso-remote-box', 'iso-type-box', 'right'); + }); + + //1-2-1 remote iso list + var initRemoteIsoField = function() { + $('#load-remote-iso').show(); + $('#remote-iso-field').hide(); + $('#iso-url-field').hide(); + $('#select-all-remote-iso').prop('checked', false); + $('#btn-template-remote-iso-create').attr('disabled', 'disabled'); + }; + + var showRemoteIsoField = function(isos) { + if (isos && isos.length) { + kimchi.isoInfo = {}; + var html = ''; + var template = $('#tmpl-list-remote-iso').html(); + $.each(isos, function(index, volume) { + var isoId = volume.os_distro + '*' + volume.name + '*' + volume.os_version; + if (!kimchi.isoInfo[isoId]) { + volume.isoId = isoId; + kimchi.isoInfo[isoId] = volume; + html += wok.substitute(template, volume); + } + }); + $('#list-remote-iso').html(html); + $('#load-remote-iso').hide() + $('#remote-iso-field').show(); + $('#iso-url-field').show(); + } else { + $('#load-remote-iso').hide() + $('#iso-url-field').show(); + wok.message.warn(i18n['KCHTMPL6001W']); + } + }; + + $('#select-all-remote-iso').click(function() { + $('#list-remote-iso [type="checkbox"]').prop('checked', $(this).prop('checked')); + if ($(this).prop('checked')) { + $('#btn-template-remote-iso-create').removeAttr('disabled'); + } else { + $('#btn-template-remote-iso-create').attr('disabled', 'disabled'); + } + }); + + $('#list-remote-iso').on('click', '[type="checkbox"]', function() { + var checkedLength = $('#list-remote-iso [type="checkbox"]:checked').length; + if (checkedLength) { + $('#btn-template-remote-iso-create').removeAttr('disabled'); + var length = $('#list-remote-iso [type="checkbox"]').length; + $('#select-all-remote-iso').prop('checked', length == checkedLength); + } else { + $('#select-all-remote-iso').prop('checked', false); + $('#btn-template-remote-iso-create').attr('disabled', 'disabled'); + } + }); + + $('#btn-template-remote-iso-create').click(function() { + submitIso('form-remote-iso'); + }); + + //1-2-2 remote iso url + var initIsoUrlField = function() { + $('#iso-url-check').prop('checked', false); + $('#iso-url-box').hide(); + $('#iso-url').val(''); + $('#btn-template-url-create').attr('disabled', 'disabled'); + } + + $('#iso-url-check').click(function() { + if ($(this).prop('checked')) { + $('#iso-url-box').slideDown(); + } else { + $('#iso-url-box').slideUp(); + } + }); + + $('#iso-url').on('input propertychange', function() { + if ($('#iso-url').val()) { + $('#btn-template-url-create').removeAttr('disabled'); + } else { + $('#btn-template-url-create').attr('disabled', 'disabled'); + } + }); + + $('#vm-image-local').click(function(){ + kimchi.switchPage('iso-type-box', 'vm-image-local-box'); + }); + $('#vm-image-local-box-back').click(function(){ + kimchi.switchPage('vm-image-local-box', 'iso-type-box', 'right'); + }); + $('input', '#vm-image-local-box').on('keyup cut paste', function(){ + setTimeout(function(){ + var isValid = kimchi.template_check_path($('input', '#vm-image-local-box').val()); + $('input', '#vm-image-local-box').toggleClass('invalid-field', !isValid); + $('button', $('.body', '#vm-image-local-box')).button(isValid ? "enable" : "disable"); + }, 0); + }); + $('button', $('.body', '#vm-image-local-box')).button({ + disabled: true + }).click(function(){ + $('input', '#vm-image-local-box').prop('disabled', true); + $(this).button('option', { + label: i18n['KCHAPI6008M'], + disabled: true + }); + addTemplate({disks:[{base:$('input', '#vm-image-local-box').val()}]}, function(){ + $('input', '#vm-image-local-box').prop('disabled', false); + $('button', $('.body', '#vm-image-local-box')).button('option', { + label: i18n['KCHAPI6005M'], + disabled: false + }); + }); + }); + + $('#btn-template-url-create').click(function() { + var isoUrl = $('#iso-url').val(); + if (!kimchi.template_check_url(isoUrl)) { + wok.message.error.code('KCHAPI6004E'); + return; + } + var data = { + "cdrom" : isoUrl + }; + addTemplate(data); + }); + + //do create + var addTemplate = function(data, callback) { + kimchi.createTemplate(data, function() { + if(callback) callback(); + kimchi.doListTemplates(); + wok.window.close(); + wok.topic('templateCreated').publish(); + }, function(err) { + if(callback) callback(); + wok.message.error(err.responseJSON.reason); + }); + }; + + var submitIso = function(formId) { + var formData = $('#' + formId).serializeObject(); + if (formData.iso) { + var length = 0; + var successNum = 0; + var addTemplate = function(isoInfo) { + var data = { + "os_distro" : isoInfo.os_distro, + "os_version" : isoInfo.os_version, + "cdrom" : isoInfo.path + }; + kimchi.createTemplate(data, function() { + successNum++; + $('input[value="' + isoInfo.isoId + '"]').prop('checked', false); + $('.check-all>input').prop('checked', false); + kimchi.doListTemplates(); + wok.topic('templateCreated').publish(data); + if (successNum === length) { + wok.window.close(); + } + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }; + if (formData.iso instanceof Array) { + length = formData.iso.length; + $.each(formData.iso, function(index, value) { + addTemplate(kimchi.isoInfo[value]); + }); + } else { + length = 1; + addTemplate(kimchi.isoInfo[formData.iso]); + } + } + }; +}; + +kimchi.template_check_url = function(url) { + var reg = /(https|http|ftp|ftps|tftp):\/\//; + if (url.constructor === String) { + return reg.test(url); + } + return false; +}; + +kimchi.template_check_path = function(filePath) { + var reg = /((\/([0-9a-zA-Z-_ \.]+))+)$/; + if (filePath.constructor === String) { + return reg.test(filePath); + } + return false; +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js new file mode 100644 index 0000000..d40b6c7 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js @@ -0,0 +1,343 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.template_edit_main = function() { + var templateEditMain = $('#edit-template-tabs'); + var origDisks; + var origPool; + var origNetworks; + var templateDiskSize; + $('#template-name', templateEditMain).val(kimchi.selectedTemplate); + templateEditMain.tabs(); + + var initTemplate = function(template) { + origDisks = template.disks; + origPool = template.storagepool; + origNetworks = template.networks; + for(var i=0;i<template.disks.length;i++){ + if(template.disks[i].base){ + template["vm-image"] = template.disks[i].base; + $('.templ-edit-cdrom').addClass('hide'); + $('.templ-edit-vm-image').removeClass('hide'); + break; + } + } + for ( var prop in template) { + var value = template[prop]; + if (prop == 'graphics') { + value = value["type"]; + } + $('input[name="' + prop + '"]', templateEditMain).val(value); + } + + var vncOpt = [{label: 'VNC', value: 'vnc'}]; + $('#template-edit-graphics').append('<option selected>VNC</option>'); + $('#template-edit-graphics').append('<option>Spice</option>'); + wok.select('template-edit-graphics-list', vncOpt); + var enableSpice = function() { + if (kimchi.capabilities == undefined) { + setTimeout(enableSpice, 2000); + return; + } + if (kimchi.capabilities.qemu_spice == true) { + spiceOpt = [{label: 'Spice', value: 'spice'}] + wok.select('template-edit-graphics-list', spiceOpt); + } + }; + enableSpice(); + var initStorage = function(result) { + var scsipools = {}; + var addStorageItem = function(storageData) { + var thisName = storageData.storageName; + var nodeStorage = $.parseHTML(wok.substitute($('#template-storage-pool-tmpl').html(), storageData)); + $('.template-tab-body', '#form-template-storage').append(nodeStorage); + var storageOptions = ''; + var scsiOptions = ''; + $('#selectStorageName').find('option').remove(); + $.each(result, function(index, storageEntities) { + if((storageEntities.state === 'active') && (storageEntities.type != 'kimchi-iso')) { + if(storageEntities.type === 'iscsi' || storageEntities.type === 'scsi') { + kimchi.listStorageVolumes(storageEntities.name, function(currentVolume) { + $.each(currentVolume, function(indexSCSI, scsiEntities) { + var tmpPath = storageEntities.name + '/' + scsiEntities.name; + var isSlected = tmpPath === thisName ? ' selected' : ''; + scsiOptions += '<option' + isSlected + '>' + tmpPath + '</option>'; + }); + $('#selectStorageName').append(scsiOptions); + }, function() {}); + } else { + var isSlected = storageEntities.name === thisName ? ' selected' : ''; + storageOptions += '<option' + isSlected + '>' + storageEntities.name + '</option>'; + } + } + }); + $('#selectStorageName').append(storageOptions); + + // Set disk format + $('#diskFormat').val(storageData.storageDiskFormat); + $('#diskFormat').on('change', function() { + $('.template-storage-disk-format').val($(this).val()); + }); + + $('#selectStorageName').change(function() { + var selectedItem = $(this).parent().parent(); + var tempStorageNameFull = $(this).val(); + var tempName = tempStorageNameFull.split('/'); + var tempStorageName = tempName[0]; + $('.template-storage-name').val(tempStorageNameFull); + kimchi.getStoragePool(tempStorageName, function(info) { + tempType = info.type; + selectedItem.find('.template-storage-type').val(tempType); + if (tempType === 'iscsi' || tempType === 'scsi') { + kimchi.getStoragePoolVolume(tempStorageName, tempName[tempName.length-1], function(info) { + volSize = info.capacity / Math.pow(1024, 3); + $('.template-storage-disk', selectedItem).attr('readonly', true).val(volSize); + $('#diskFormat').val('raw'); + $('#diskFormat').prop('disabled', true).change(); + }); + } else if (tempType === 'logical') { + $('.template-storage-disk', selectedItem).attr('readonly', false); + $('#diskFormat').val('raw'); + $('#diskFormat').prop('disabled', true).change(); + } else { + $('.template-storage-disk', selectedItem).attr('readonly', false); + if ($('#diskFormat').prop('disabled') == true) { + $('#diskFormat').val('qcow2'); + $('#diskFormat').prop('disabled', false).change(); + } + } + }); + }); + }; + + if ((origDisks && origDisks.length) && (origPool && origPool.length)) { + splitPool = origPool.split('/'); + var defaultPool = splitPool[splitPool.length-1]; + var defaultType; + + kimchi.getStoragePool(defaultPool, function(info) { + defaultType = info.type; + $.each(origDisks, function(index, diskEntities) { + var storageNodeData = { + viewMode : '', + editMode : 'hide', + storageName : defaultPool, + storageType : defaultType, + storageDisk : diskEntities.size, + storageDiskFormat : diskEntities.format ? diskEntities.format : 'qcow2' + } + + if (diskEntities.volume) { + kimchi.getStoragePoolVolume(defaultPool, diskEntities.volume, function(info) { + var volSize = info.capacity / Math.pow(1024, 3); + var nodeData = storageNodeData + nodeData.storageName = defaultPool + '/' + diskEntities.volume; + nodeData.storageDisk = volSize; + addStorageItem(nodeData); + $('.template-storage-disk').attr('readonly', true); + $('#diskFormat').val('raw'); + $('#diskFormat').prop('disabled', true).change(); + }); + } else if (defaultType === 'logical') { + addStorageItem(storageNodeData); + $('#diskFormat').val('raw'); + $('#diskFormat').prop('disabled', true).change(); + } else { + addStorageItem(storageNodeData); + } + }); + }); + } + + $('#template-edit-storage-add-button').button({ + icons: { + primary: "ui-icon-plusthick" + }, + text: false, + disabled: true + }).click(function(event) { + event.preventDefault(); + var storageNodeData = { + viewMode : 'hide', + editMode : '', + storageName : 'null', + storageType : 'dir', + storageDisk : '10' + } + addStorageItem(storageNodeData); + }); + }; + var initInterface = function(result) { + var networkItemNum = 0; + var addInterfaceItem = function(networkData) { + var networkName = networkData.networkV; + var nodeInterface = $.parseHTML(wok.substitute($('#template-interface-tmpl').html(), networkData)); + $('.template-tab-body', '#form-template-interface').append(nodeInterface); + $('.delete', '#form-template-interface').button({ + icons : {primary : 'ui-icon-trash'}, + text : false + }).click(function(evt) { + evt.preventDefault(); + $(this).parent().parent().remove(); + }); + var networkOptions = ''; + for(var i=0;i<result.length;i++){ + if(result[i].state === "active") { + var isSlected = networkName===result[i].name ? ' selected' : ''; + networkOptions += '<option' + isSlected + '>' + result[i].name + '</option>'; + } + } + $('select', '#form-template-interface #networkID' + networkItemNum).append(networkOptions); + networkItemNum += 1; + }; + if(result && result.length > 0) { + for(var i=0;i<origNetworks.length;i++) { + addInterfaceItem({ + networkID : 'networkID' + networkItemNum, + networkV : origNetworks[i], + type : 'network' + }); + } + } + $('#template-edit-interface-add-button').button({ + icons: { + primary: 'ui-icon-plusthick' + }, + text: false + }).click(function(evt) { + evt.preventDefault(); + addInterfaceItem({ + networkID : 'networkID' + networkItemNum, + networkV : 'default', + type : 'network' + }); + }); + }; + var initProcessor = function(){ + var setCPUValue = function(){ + if(!$('#cores').hasClass("invalid-field")&&$('#cores').val()!=""){ + $("#cpus").val(parseInt($("#cores").val())*parseInt($("#threads").val())); + }else{ + $("#cpus").val(''); + } + }; + $("input:text", "#form-template-processor").on('keyup', function(){ + $(this).toggleClass("invalid-field", !$(this).val().match('^[0-9]*$')); + if($(this).prop('id')=='cores') setCPUValue(); + }); + $("input:checkbox", "#form-template-processor").click(function(){ + $(".topology", "#form-template-processor").toggleClass("hide", !$(this).prop("checked")); + $("#cpus").attr("disabled", $(this).prop("checked")); + setCPUValue(); + }); + $('select', '#form-template-processor').change(function(){ + setCPUValue(); + }); + kimchi.getCPUInfo(function(data){ + var options = ""; + for(var i=0;Math.pow(2,i)<=data.threads_per_core;i++){ + var lastOne = Math.pow(2,i+1)>data.threads_per_core?" selected":""; + options += "<option"+lastOne+">"+Math.pow(2,i)+"</option>"; + } + $('select', '#form-template-processor').append(options); + if(template.cpus) $("#cpus").val(template.cpus); + var topo = template.cpu_info.topology; + if(topo&&topo.cores) $("#cores").val(topo.cores); + if(topo&&topo.threads){ + $('select', '#form-template-processor').val(topo.threads); + $("input:checkbox", "#form-template-processor").trigger('click'); + } + }); + }; + kimchi.listNetworks(initInterface); + kimchi.listStoragePools(initStorage); + initProcessor(); + }; + kimchi.retrieveTemplate(kimchi.selectedTemplate, initTemplate); + + + $('#tmpl-edit-button-save').on('click', function() { + var editableFields = [ 'name', 'memory', 'disks', 'graphics']; + var data = {}; + //Fix me: Only support one storage pool now + var storages = $('.template-tab-body .item', '#form-template-storage'); + var tempName = $('.template-storage-name', storages).val(); + var tmpItem = $('#form-template-storage .item'); + tempName = tempName.split('/'); + var tempNameHead = tempName[0]; + var tempNameTail = tempNameHead; + if($('.template-storage-type', tmpItem).val() === 'iscsi' || $('.template-storage-type', tmpItem).val() == 'scsi') { + tempNameTail = tempName[tempName.length-1]; + } + tempName = '/plugins/kimchi/storagepools/' + tempNameHead; + data['storagepool'] = tempName; + $.each(editableFields, function(i, field) { + /* Support only 1 disk at this moment */ + if (field == 'disks') { + if($('.template-storage-type', tmpItem).val() === 'iscsi' || $('.template-storage-type', tmpItem).val() == 'scsi') { + origDisks[0]['size'] && delete origDisks[0]['size']; + origDisks[0]['volume'] = tempNameTail; + } else { + origDisks[0]['volume'] && delete origDisks[0]['volume']; + origDisks[0].size = Number($('.template-storage-disk', tmpItem).val()); + } + origDisks[0].format = $('.template-storage-disk-format', tmpItem).val(); + data[field] = origDisks; + } + else if (field == 'graphics') { + var type = $('#form-template-general [name="' + field + '"]').val(); + data[field] = {'type': type}; + } + else { + data[field] = $('#form-template-general [name="' + field + '"]').val(); + } + }); + data['memory'] = Number(data['memory']); + data['cpus'] = parseInt($('#cpus').val()); + if($("input:checkbox", "#form-template-processor").prop("checked")){ + data['cpu_info'] = { + topology: { + sockets: 1, + cores: parseInt($("#cores").val()), + threads: parseInt($("#threads").val()) + } + }; + }else{ + data['cpu_info'] = {}; + } + var networks = $('.template-tab-body .item', '#form-template-interface'); + var networkForUpdate = new Array(); + $.each(networks, function(index, networkEntities) { + var thisValue = $('select', networkEntities).val(); + networkForUpdate.push(thisValue); + }); + if (networkForUpdate instanceof Array) { + data.networks = networkForUpdate; + } else if (networkForUpdate != null) { + data.networks = [networkForUpdate]; + } else { + data.networks = []; + } + + kimchi.updateTemplate($('#template-name').val(), data, function() { + kimchi.doListTemplates(); + wok.window.close(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }); +}; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.template_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.template_main.js new file mode 100644 index 0000000..b09fe12 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.template_main.js @@ -0,0 +1,111 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +kimchi.doListTemplates = function() { + kimchi.listTemplates(function(result) { + if (result && result.length) { + $('#noTemplates').hide(); + var listHtml = ''; + var templateHtml = $('#templateTmpl').html(); + $.each(result, function(index, value) { + var isLocal; + if(value.cdrom){ + isLocal = /^\//.test(value['cdrom']); + }else{ + for(var i=0;i<value.disks.length;i++){ + if(value.disks[i].base){ + isLocal = /^\//.test(value.disks[i].base); + break; + } + } + } + if(isLocal){ + value.location = "plugins/kimchi/images/theme-default/icon-local.png"; + }else{ + value.location = "plugins/kimchi/images/theme-default/icon-remote.png"; + } + listHtml += wok.substitute(templateHtml, value); + }); + $('#templateList').html(listHtml); + kimchi.templateBindClick(); + } else { + $('#templateList').html(''); + $('#noTemplates').show(); + } + $('html').removeClass('processing'); + }, function(err) { + wok.message.error(err.responseJSON.reason); + $('html').removeClass('processing'); + }); +}; + +kimchi.templateBindClick = function() { + $('.template-edit').on('click', function(event) { + var templateName = $(this).data('template'); + kimchi.selectedTemplate = templateName; + wok.window.open("plugins/kimchi/template-edit.html"); + }); + $('.template-clone').on('click', function(event) { + kimchi.selectedTemplate = $(this).data('template'); + $('html').addClass('processing'); + kimchi.cloneTemplate(kimchi.selectedTemplate, function() { + kimchi.doListTemplates(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + kimchi.doListTemplates(); + }); + }); + $('.template-delete').on('click', function(event) { + var $template = $(this); + var settings = { + title : i18n['KCHAPI6001M'], + content : i18n['KCHTMPL6003M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + wok.confirm(settings, function() { + var templateName = $template.data('template'); + kimchi.deleteTemplate(templateName, function() { + kimchi.doListTemplates(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }, function() { + }); + }); +} +kimchi.hideTitle = function() { + $('#tempTitle').hide(); +}; + +kimchi.template_main = function() { + if(wok.tabMode['templates'] === 'admin') { + $('.tools').attr('style','display'); + $("#template-add").on("click", function(event) { + wok.window.open({ + url: 'plugins/kimchi/template-add.html', + close: function() { + if (kimchi.deepScanHandler) { + kimchi.deepScanHandler.stop = true; + } + } + }); + }); + } + + kimchi.doListTemplates(); +}; diff --git a/src/wok/plugins/kimchi/ui/pages/Makefile.am b/src/wok/plugins/kimchi/ui/pages/Makefile.am new file mode 100644 index 0000000..56288e3 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/Makefile.am @@ -0,0 +1,22 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SUBDIRS = help + +htmldir = $(datadir)/wok/plugins/kimchi/ui/pages + +dist_html_DATA = $(wildcard *.tmpl) $(NULL) diff --git a/src/wok/plugins/kimchi/ui/pages/guest-add.html.tmpl b/src/wok/plugins/kimchi/ui/pages/guest-add.html.tmpl new file mode 100644 index 0000000..3770d96 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/guest-add.html.tmpl @@ -0,0 +1,98 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<html> +<body> +<div class="window" style="width: 900px;height: 580px;"> + <header> + <h1 class="title h1 grey">$_("Create a New Virtual Machine")</h1> + </header> + <div class="content"> + <form id="form-vm-add"> + <section class="form-section"> + <h2>1. $_("Virtual Machine Name")</h2> + <div class="field"> + <input type="text" class="text" style="width: 300px" name="name"><br> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("The name used to identify the virtual machine. If omitted, a name will be chosen based on the template used.") + </p> + </div> + </section> + <section class="form-section"> + <h2>2. $_("Template")</h2> + <div class="field"> + <div class="text-help"> + <div id="prompt-create-template" class="hidden"> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <div class="text-help help-inline">$_("Please create a template first.")</div> + <a id="btn-create-template" class="btn-normal" href="templates.html"> + <span class="text">$_("Create a Template")</span> + </a> + </div> + <div id="prompt-choose-template" class="hidden"> + <span class="icon-info-circled light-grey c1"></span> + <span class="text-help">$_("Please choose a template.")</span> + </div> + </div> + <ul id="templateTile" class="tile-check tile-template"> + </ul> + <script type="html/text" id="tmpl-template" class="tmpl-html"> + <li> + <label> + <input type="radio" name="template" value="/plugins/kimchi/templates/{name}"> + <div class="info"> + <div class="summary os-icon"> + <img src="{icon}"> + <span class="title">{name}</span> + </div> + <ul class="list-info"> + <li><label>$_("OS")</label><span>{os_distro}</span></li> + <li><label>$_("OS Version")</label><span>{os_version}</span></li> + <li><label>$_("CPUS")</label><span>{cpus}</span></li> + <li><label>$_("Memory")</label><span>{memory}M</span></li> + </ul> + </div> + </label> + </li> + </script> + </div> + </section> + </form> + </div> + <footer> + <div class="btn-group"> + <button id="vm-doAdd" class="btn-normal" disabled="disabled" href="javascript:void(0);"><span class="text">$_("Create")</span></button> + <button id="vm-doAdding" class="btn-normal" disabled="disabled" style="display:none" href="javascript:void(0);"><span class="text">$_("Creating...")</span></button> + <button id="vm-add=cancel" class="btn-normal close" type="button"> + <span class="text">$_("Cancel")</span> + </button> + </div> + </footer> +</div> +<script> + kimchi.guest_add_main(); +</script> +</body> +</html> diff --git a/src/wok/plugins/kimchi/ui/pages/guest-edit.html.tmpl b/src/wok/plugins/kimchi/ui/pages/guest-edit.html.tmpl new file mode 100644 index 0000000..c5acf04 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/guest-edit.html.tmpl @@ -0,0 +1,311 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext + +<div id="guest-edit-window" class="window"> + <header> + <h1 class="title h1 grey">$_("Edit Guest")</h1> + </header> + <div class="content"> + <div id="guest-edit-tabs"> + <ul> + <li> + <a href="#form-guest-edit-general">$_("General")</a> + </li> + <li> + <a href="#form-guest-edit-storage">$_("Storage")</a> + </li> + <li> + <a href="#form-guest-edit-interface">$_("Interface")</a> + </li> + <li> + <a href="#form-guest-edit-permission">$_("Permission")</a> + </li> + <li> + <a href="#form-guest-edit-pci">$_("Host PCI Device")</a> + </li> + <li> + <a href="#form-guest-edit-snapshot">$_("Snapshot")</a> + </li> + </ul> + <form id="form-guest-edit-general"> + <fieldset class="guest-edit-fieldset"> + <div class="edit-general-inline"> + <div class="guest-edit-wrapper-label"> + <label for="guest-edit-id-textbox"> + $_("Name") + </label> + </div> + <div class="guest-edit-wrapper-label"> + <label for="guest-edit-cores-textbox"> + $_("CPUs") + </label> + </div> + <div class="guest-edit-wrapper-label"> + <label for="guest-edit-memory-textbox"> + $_("Memory (MB)") + </label> + </div> + <div class="guest-edit-wrapper-label"> + <label for="guest-edit-icon-textbox"> + $_("Icon") + </label> + </div> + </div> + <div class="edit-general-inline"> + <div class="guest-edit-wrapper-controls"> + <input id="guest-edit-id-textbox" + name="name" type="text" /> + </div> + <div class="guest-edit-wrapper-controls"> + <input + id="guest-edit-cores-textbox" + name="cpus" + type="text" /> + </div> + <div class="guest-edit-wrapper-controls"> + <input id="guest-edit-memory-textbox" + name="memory" + type="text" /> + </div> + <div class="guest-edit-wrapper-controls"> + <input + id="guest-edit-icon-textbox" + name="icon" + type="text" + disabled="disabled" /> + </div> + </div> + </fieldset> + </form> + <form id="form-guest-edit-storage"> + <div class="header"> + <span class="cell">$_("Device")</span> + <span class="cell">$_("Path")</span> + <button type="button" id="guest-edit-attach-cdrom-button" class="action-area attach"></button> + </div> + <div class="body"></div> + </form> + <form id="form-guest-edit-interface" class="guest-edit-interface"> + <div class="header"> + <span class="cell">$_("Network")</span> + <span class="cell">$_("Type")</span> + <span class="cell">$_("MAC Address")</span> + <button class="add action-area"></button> + </div> + <div class="body"></div> + </form> + <form id="form-guest-edit-permission" class="guest-edit-permission"> + <div class="pam"> + <div class="column avail"> + <div class="title">$_("Available system users and groups")</div> + <input type="text" id="permission-avail-searchBox"> + <div class="body"> + <div class="head"> + <div class="column column-user"><div class="item">Users</div></div> + <div class="column column-group"><div class="item">Groups</div></div> + </div> + <div id="permission-avail-users" class="column column-user"></div> + <div id="permission-avail-groups" class="column column-group"></div> + </div> + </div> + <div class="column control"> + <button id="permissionGo"> > </button> + <button id="permissionBack"> < </button> + </div> + <div class="column selected"> + <div class="title">$_("Selected system users and groups")</div> + <input type="text" id="permission-sel-searchBox"> + <div class="body"> + <div class="head"> + <div class="column column-user"><div class="item">Users</div></div> + <div class="column column-group"><div class="item">Groups</div></div> + </div> + <div id="permission-sel-users" class="column column-user"></div> + <div id="permission-sel-groups" class="column column-group"></div> + </div> + </div> + </div> + <div class="ldap"> + <div class="header"> + <span class="cell">$_("User")</span> + <button type="button" id="guest-edit-add-user-button" class="action-area add"></button> + </div> + <div class="body"></div> + </div> + </form> + <form id="form-guest-edit-pci" class="guest-edit-pci"> + <div class="guest-scroll-indent"> + <div class="filter"> + <span class="group"> + <select class="control"> + <option value="all">$_("All")</option> + <option value="toAdd">$_("To Add")</option> + <option value="added">$_("Added")</option> + </select><input type="text" class="control" placeholder="$_("filter")"> + </span> + </div> + <div class="header"> + <span class="cell name">$_("Name")</span> + <span class="cell product">$_("Product")</span> + <span class="cell vendor">$_("Vendor")</span> + </div> + <div class="body"></div> + </div> + </form> + <form id="form-guest-edit-snapshot" class="guest-edit-snapshot"> + <div class="header"> + <span class="cell sel"></span> + <span class="cell name">$_("Name")</span> + <span class="cell created">$_("Created")</span> + <button class="add action-area"></button> + </div> + <div class="task"></div> + <div class="body"></div> + </form> + </div> + </div> + <footer> + <div id="action-button-container" class="btn-group hidden"> + <button id="guest-edit-button-save" class="btn-normal"> + <span class="text">$_("Save")</span> + </button> + </div> + <button id="guest-edit-button-cancel" class="btn-normal close"> + <span class="text">$_("Cancel")</span> + </button> + </footer> +</div> +<script id="cdrom-row-tmpl" type="text/html"> + <div class="item view" id="cdrom-{dev}"> + <span class="cell dev"> + <input type="text" readonly="readonly" + id="cdrom-dev-{dev}" name="cdrom-dev-{dev}" value="{dev}" /> + </span> + <span class="cell path"> + <input id="cdrom-path-{dev}" name="cdrom" type="text" + data-vm="{vm}" data-dev="{dev}" + value="{path}" readonly="readonly" /> + </span> + <span class="action-area"> + <button type="button" class="guest-edit-cdrom-button replace" + data-vm="{vm}" data-dev="{dev}" + title='$_("Replace")'> + </button> + <button type="button" class="guest-edit-cdrom-button detach" + data-vm="{vm}" data-dev="{dev}" data-type="{type}" + title='$_("Detach")'> + </button> + <button type="button" class="guest-edit-cdrom-button save hidden" + data-vm="{vm}" data-dev="{dev}" + title='$_("Save")'> + </button> + <button type="button" class="guest-edit-cdrom-button cancel hidden" + data-vm="{vm}" data-dev="{dev}" + title='$_("Cancel")'> + </button> + </span> + </div> +</script> +<script id="interface-tmpl" type="text/html"> + <div class="item" id="{mac}"> + <span class="cell"> + <label id="label-network-{id}" class="{viewMode}">{network}</label> + <select class="{editMode}"></select> + </span> + <span class="cell"> + <span>{type}</span> + </span> + <span class="cell"> + <label id="label-mac-{id}" class="{viewMode}">{mac}</label> + <input class="{editMode}" type="text" + id="edit-mac-{id}" name="{mac}" value="{mac}" /> + </span> + <span class="action-area {editMode}"> + <button class="save"></button><button class="cancel"></button> + </span> + <span class="action-area {viewMode}"> + <button class="edit"></button><button class="delete"></button> + </span> + <div> +</script> +<script id="ldap-user-tmpl" type="text/html"> + <div class="item" id="{user}"> + <span class="cell"> + <label class="{viewMode}">{user}</label> + <input type="text" placeholder="LDAP User ID,e.g.foo@foo.com" class="{editMode}"/> + </span> + <span class="action-area"> + <button class="delete"></button> + </span> + <div> +</script> +<script id="disk-row-tmpl" type="text/html"> + <div class="item" id="cdrom-{dev}"> + <span class="cell dev"> + <input type="text" readonly="readonly" + id="disk-dev-{dev}" name="disk-dev-{dev}" value="{dev}" /> + </span> + <span class="cell path"> + <input id="disk-path-{dev}" name="path-{dev}" type="text" + data-vm="{vm}" data-dev="{dev}" + value="{path}" readonly="readonly" /> + </span> + <span class="action-area"> + <button type="button" class="guest-edit-cdrom-button detach" + data-vm="{vm}" data-dev="{dev}" data-type="{type}" + title="$_("Detach")"> + </button> + </span> + </div> +</script> +<script id="permission-item-pam" type="text/html"> +<div class="item"> + <span class="icon {class}"></span> + <label>{val}</label> +</div> +</script> +<script id="pci-tmpl" type="text/html"> +<div class="item" id="{name}"> + <span class="cell name" title="{name}">{name}</span> + <span class="cell product" title="{product}">{product}</span> + <span class="cell vendor" title="{vendor}">{vendor}</span> + <button></button> +</div> +</script> +<script id="snapshot-tmpl" type="text/html"> + <div class="item" id="{name}"> + <span class="cell sel"> + <span class="icon {createMode}"></span> + <span class="ui-icon ui-icon-check hide"></span> + </span> + <span class="cell name">{name}</span> + <span class="cell created">{created}</span> + <span class="action-area"> + <button class="revert {listMode}" title="$_("revert")"></button> + <button class="delete {listMode}"></button> + </span> + <div> +</script> +<script type="text/javascript"> + kimchi.guest_edit_main(); +</script> diff --git a/src/wok/plugins/kimchi/ui/pages/guest-storage-add.html.tmpl b/src/wok/plugins/kimchi/ui/pages/guest-storage-add.html.tmpl new file mode 100644 index 0000000..a26e0f9 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/guest-storage-add.html.tmpl @@ -0,0 +1,103 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<div id="guest-storage-add-window" class="window"> + <header> + <h1 class="title">$_("Add a Storage Device to VM")</h1> + <div class="close">X</div> + </header> + <div class="content"> + <form id="form-guest-storage-add"> + <section class="form-section"> + <h2>1. $_("Device Type")</h2> + <div class="field"> + <p class="text-help"> + $_("The device type. Currently, \"cdrom\" and \"disk\" are supported.") + </p> + <div class="btn dropdown popable"> + <input id="guest-storage-type" name="type" value="cdrom" type="hidden" /> + <span class="text" id="guest-storage-type-label"></span> + <span class="arrow"></span> + <div class="popover"> + <ul class="select-list" id="guest-storage-type-list" data-target="guest-storage-type" data-label="guest-storage-type-label"></ul> + </div> + </div> + </div> + </section> + <div class="volume-section hidden"> + <section class="form-section"> + <h2>2. $_("Storage Pool")</h2> + <div class="field storage-field"> + <p class="text-help"> + $_("Storage pool which volume located in") + </p> + <div class="btn dropdown popable"> + <input value="default" id="guest-disk-pool" name="pool" type="hidden"/> + <span class="text" id="guest-disk-pool-label">default</span><span class="arrow"></span> + <div class="popover" style="width: 100%"> + <ul class="select-list" id="guest-add-storage-pool-list" data-target="guest-disk-pool" data-label="guest-disk-pool-label"></ul> + </div> + </div> + </div> + </section> + <section class="form-section"> + <h2>3. $_("Storage Volume")</h2> + <div class="field storage-field"> + <p class="text-help"> + $_("Storage volume to be attached") + </p> + <div class="btn dropdown popable" id="guest-disk"> + <input id="guest-disk-vol" name="vol" type="hidden"> + <span class="text" id="guest-disk-vol-label"></span><span class="arrow"></span> + <div class="popover" style="width: 100%"> + <ul class="select-list" id="guest-add-storage-pool-list" data-target="guest-disk-vol" data-label="guest-disk-vol-label"></ul> + </div> + </div> + </div> + </section> + </div> + <div class="path-section"> + <section class="form-section"> + <h2>2. $_("File Path")</h2> + <div class="field"> + <p class="text-help"> + $_("The ISO file path in the server for CDROM.") + </p> + <input type="text" class="text" name="path" /> + </div> + </section> + </div> + </fieldset> + </form> + </div> + <footer> + <div class="btn-group"> + <button id="guest-storage-button-add" class="btn-normal" disabled="disabled"> + <span class="text">$_("Attach")</span> + </button> + </div> + </footer> +</div> +<script type="text/javascript"> + kimchi.guest_storage_add_main(); +</script> diff --git a/src/wok/plugins/kimchi/ui/pages/guest.html.tmpl b/src/wok/plugins/kimchi/ui/pages/guest.html.tmpl new file mode 100644 index 0000000..78e9161 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/guest.html.tmpl @@ -0,0 +1,77 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext + <li name="guest" class="guest"> + <div class="sortable guest-type"> + <div class="guest-general"> + <h2 class="title" title="{name}">{name}</h2> + </div> + <div class="guest-pending hide-content"> + <span class="icon"></span><span class="text"></span> + </div> + </div> + <div name="cpu_utilization" class="sortable"> + <div class="circleGauge"></div> + </div> + <div name="io_throughput" class="sortable"> + <div class="circleGauge"></div> + <div class="subtitle">KB/s</div> + </div> + <div name="net_throughput" class="sortable"> + <div class="circleGauge"></div> + <div class="subtitle">KB/s</div> + </div> + <div name="guest-tile" class="sortable guest-tile"> + <div class="tile "> + <img class="imgactive" alt="" src=""> + <img class="imgload" alt="" src=""> + <img class="overlay shutoff-hidden" alt="$_("Start")" src="plugins/kimchi/images/theme-default/icon-power-down.png" > + </div> + </div> + <div class="sortable guest-actions" name="guest-actions"> + <div class="top"> + <button class="btn reset-disabled" name="vm-reset" href="javascript:void(0);" title="$_("Reset")"><span class="icon reset"></span></button> + <button class="btn pause-disabled" name="vm-pause" href="javascript:void(0);" title="$_("Pause")"><span class="icon pause"></span></button> + <button class="btn resume-hidden" name="vm-resume" href="javascript:void(0);" title="$_("Resume")"><span class="icon resume"></span></button> + <button class="btn running-hidden" name="vm-start" href="javascript:void(0);" title="$_("Start")"><span class="icon power-down"></span></button> + <button class="btn shutoff-hidden" name="vm-poweroff" href="javascript:void(0);" title="$_("Power Off")"><span class="icon power-up"></span></button> + </div> + <div class="bottom"> + <div name="actionmenu" class="btn dropdown popable vm-action" style="width: 126px"> + <span class="text">$_("Actions")</span><span class="arrow"></span> + <div class="popover actionsheet right-side" style="width: 250px"> + <button class="button-big shutoff-disabled" name="vm-console" ><span class="text">$_("Connect")</span></button> + <button class="button-big running-disabled" name="vm-clone"><span class="text">$_("Clone")</span></button> + <button class="button-big" name="vm-edit"><span class="text">$_("Edit")</span></button> + <button class="button-big shutoff-hidden non-persistent-disabled" name="vm-reset"><span class="text">$_("Reset")</span></button> + <button class="button-big pause-hidden non-persistent-disabled" name="vm-pause"><span class="text">$_("Pause")</span></button> + <button class="button-big resume-hidden" name="vm-resume"><span class="text">$_("Resume")</span></button> + <button class="button-big shutoff-hidden" name="vm-shutdown"><span class="text">$_("Shut Down")</span></button> + <button class="button-big running-hidden" name="vm-start"><span class="text">$_("Start")</span></button> + <button class="button-big shutoff-hidden" name="vm-poweroff"><span class="text">$_("Power Off")</span></button> + <button class="button-big red non-persistent-disabled" name="vm-delete">$_("Delete")</button> + </div> + </div> + </div> + </div> + </li> diff --git a/src/wok/plugins/kimchi/ui/pages/guests.html.tmpl b/src/wok/plugins/kimchi/ui/pages/guests.html.tmpl new file mode 100644 index 0000000..b8a1259 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/guests.html.tmpl @@ -0,0 +1,65 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# + +#unicode UTF-8 +#import gettext +#from Cheetah.Template import Template +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext + +#silent ht = Template + +<!DOCTYPE html> +<html> +<head> +<link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> +<script src="plugins/kimchi/js/kimchi.min.js"></script> +</head> +<body> +<div id="guests-root-container"> + <div class="toolbar"> + <div class="tools" style="display:none"> + <a id="vm-add" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> + </div> + </div> + <div id="guestListField" style="display: none"> + <ul class="list-title"> + <li class="guest-type">$_("Name")</li> + <li class="guest-cpu">$_("CPU")</li> + <li class="guest-storage">$_("Disk I/O")</li> + <li class="guest-network">$_("Network I/O")</li> + <li class="guest-tile">$_("Livetile")</li> + <li class="guest-actions">$_("Actions")</li> + </ul> + <ul id="guestList" class="list-vm empty-when-logged-off"> + </ul> + </div> + <div id="noGuests" class="list-no-result" style="display: none;"> + $_("No guests found.") + </div> + <script id="guest-tmpl" type="kimchi/template"> + $ht(file=$data.ui_dir + "/pages/guest.html.tmpl", searchList=[self, {'lang':$lang}]) + </script> + <script type="text/javascript"> + kimchi.guest_main(); + </script> +</div> +</body> +</html> diff --git a/src/wok/plugins/kimchi/ui/pages/help/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/Makefile.am new file mode 100644 index 0000000..a4ee361 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/Makefile.am @@ -0,0 +1,34 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +SUBDIRS = zh_CN it_IT en_US zh_TW pt_BR ja_JP ru_RU ko_KR fr_FR de_DE es_ES + +DITA_HTML_FILES = $(patsubst %.dita,%.html,$(wildcard */*.dita)) +HTML_FILES = $(if $(DITA_HTML_FILES), $(DITA_HTML_FILES), $(wildcard */*.html)) +DITA_XSL_FILE = dita-help.xsl + +EXTRA_DIST = $(DITA_XSL_FILE) + +helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help + +dist_help_DATA = kimchi.css + +all: $(HTML_FILES) $(wildcard */*.dita) + +%.html: %.dita $(DITA_XSL_FILE) + xsltproc -o $@ $(DITA_XSL_FILE) $< + +CLEANFILES = $(HTML_FILES) diff --git a/src/wok/plugins/kimchi/ui/pages/help/de_DE/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/de_DE/Makefile.am new file mode 100644 index 0000000..3d99aae --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/de_DE/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +de_DE_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/de_DE + +dist_de_DE_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/de_DE/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/de_DE/guests.dita new file mode 100644 index 0000000..1d64469 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/de_DE/guests.dita @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="de-de"> +<title>G��ste</title> +<shortdesc>Auf der Seite <wintitle>G��ste</wintitle> sind die definierten virtuellen +Maschinen von KVM aufgelistet.</shortdesc> +<csbody> +<p>F��r jeden Gast werden die folgenden Informationen angezeigt:<dl><dlentry> +<dt>Name</dt> +<dd>Name der virtuellen Maschine.</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>Prozentsatz der Prozessorauslastung in der virtuellen Maschine.</dd> +</dlentry><dlentry> +<dt>Netz-E/A</dt> +<dd>Netz-E/A-��bertragungsrate in KB pro Sekunde.</dd> +</dlentry><dlentry> +<dt>Platten-E/A</dt> +<dd>Platten-E/A-��bertragungsrate in KB pro Sekunde.</dd> +</dlentry><dlentry> +<dt>Live Tile</dt> +<dd>Status der Konsole f��r das Gastbetriebssystem oder ein Symbol, das die +<tm tmtype="tm" trademark="Linux">Linux</tm>-Verteilung darstellt, wenn +der Gast nicht aktiv ist.</dd> +</dlentry></dl></p> +<p>Die folgenden Aktionssymbole werden f��r jeden Gast angezeigt:<dl> +<dlentry> +<dt>Zur��cksetzen</dt> +<dd>Klicken Sie hier, um den Gast zur��ckzusetzen. </dd> +</dlentry><dlentry> +<dt>Power (Starten oder Stoppen)</dt> +<dd>Klicken Sie hier, um den Gast ein- bzw. auszuschalten. Wenn das Symbol rot ist, +ist er ausgeschaltet. Wenn das Symbol gr��n ist, ist er eingeschaltet.</dd> +</dlentry></dl> </p> +<p>Die folgenden Aktionen k��nnen f��r jeden Gast ausgew��hlt werden:<ul> +<li>W��hlen Sie <uicontrol>Verbinden</uicontrol> aus, um eine Verbindung zur fernen Konsole +f��r das Gastbetriebssystem herzustellen.</li> +<li>W��hlen Sie <uicontrol>Medien verwalten</uicontrol> aus, um den Pfad zu den +Installationsmedien zu ��ndern.</li> +<li>W��hlen Sie <uicontrol>Zur��cksetzen</uicontrol> aus, um den Gast zur��ckzusetzen.</li> +<li>W��hlen Sie <uicontrol>Bearbeiten</uicontrol> aus, um die Eigenschaften eines +bestehenden Gastes zu bearbeiten. G��ste k��nnen nur bearbeitet werden, wenn sie gestoppt sind.</li> +<li>W��hlen Sie <uicontrol>L��schen</uicontrol> aus, um den Gast zu l��schen.</li> +</ul>Um einen Gast bzw. eine virtuelle Maschine zu erstellen, klicken Sie auf das <uicontrol>Plus (+)</uicontrol>-Symbol oben rechts auf der Seite.</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="de-de"> +<title>Virtuelle Maschine erstellen</title> +<shortdesc>Erstellen Sie eine virtuelle Maschine mithilfe einer bestehenden Vorlage.</shortdesc> +<csbody> +<p> <ol> +<li>Geben Sie den Namen ein, mit dem die virtuelle Maschine gekennzeichnet wird.</li> +<li rev="rev1">W��hlen Sie eine Vorlage aus. <ul> +<li>Wenn Vorlagen vorhanden sind, w��hlen Sie eine aus den angezeigten Vorlagen aus.</li> +<li>Wenn keine Vorlagen vorhanden sind, klicken Sie auf <uicontrol>Vorlage erstellen</uicontrol>, um eine Vorlage zu erstellen.</li> +</ul></li> +<li>Klicken Sie auf <uicontrol>Erstellen</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="de-de"> +<title>Gast bearbeiten</title> +<shortdesc>Bearbeiten Sie die Eigenschaften einer bestehenden virtuellen Maschine. Einige Eigenschaften k��nnen nur bearbeitet werden, solange der Gast gestoppt ist. Andere Eigenschaften treten beim n��chsten Booten in Kraft. </shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>F��r jeden Gast werden die folgenden Informationen auf der Registerkarte <wintitle>Allgemein</wintitle> angezeigt:<dl> +<dlentry> +<dt>Name</dt> +<dd>Name der virtuellen Maschine. (Kann nur bearbeitet werden, solange der Gast gestoppt ist.)</dd> +</dlentry><dlentry> +<dt>CPUs</dt> +<dd>Anzahl der Prozessoren. (Wenn der Gast aktiv ist, tritt die neue Menge beim n��chsten Booten in Kraft.) +</dd> +</dlentry><dlentry> +<dt>Speicher</dt> +<dd>Speicherkapazit��t in MB. (Wenn der Gast aktiv ist, tritt die neue Menge beim n��chsten Booten in Kraft.) +</dd> +</dlentry><dlentry> +<dt>Symbol</dt> +<dd>Grafikbild, das die Linux-Verteilung darstellt und anstelle des aktuellen Status (Live Tile) angezeigt werden soll, wenn der Gast nicht aktiv ist.</dd> +</dlentry></dl></p> +<p>Die folgenden Informationen werden auf der Registerkarte <wintitle>Speicher</wintitle> angezeigt.</p> +<dl><dlentry> +<dt>Speicher</dt> +<dd>Zeigt die Position der ISO-Datei an, die f��r die Installation verwendet wird.</dd> +</dlentry></dl> +<p> Felder, die nicht inaktiviert sind, k��nnen bearbeitet werden. Nachdem Sie ein Feld bearbeitet haben, klicken Sie auf <uicontrol>Speichern</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="de-de"> +<title>Speichereinheit hinzuf��gen, ersetzen oder abh��ngen</title> +<shortdesc rev="rev1">Sie k��nnen eine Speichereinheit zu Ihrer virtuellen Maschine hinzuf��gen oder diese ersetzen oder abh��ngen. Die einzige unterst��tzte Einheit ist CD-ROM. F��hren Sie die folgenden Schritte aus, um Ihre Speichereinheiten zu bearbeiten:</shortdesc> +<csbody> +<ol> +<li>W��hlen Sie im Fenster <wintitle>Gast bearbeiten</wintitle> die Option <wintitle>Speicher</wintitle> aus.</li> +<li>Um eine Speichereinheit zu ersetzen, klicken Sie auf das erste Symbol mit dem <uicontrol>orangefarbenen Schr��gstrich (/)</uicontrol>. Geben Sie den ISO-Dateipfad ein und klicken Sie auf <uicontrol>Ersetzen</uicontrol>.</li> +<li>Um eine Speichereinheit abzuh��ngen, klicken Sie auf das zweite Symbol mit dem <uicontrol>roten Gedankenstrich (-)</uicontrol>. Best��tigen Sie den L��schvorgang und klicken Sie auf <uicontrol>OK</uicontrol>.</li> +<li>Um eine Speichereinheit hinzuzuf��gen, klicken Sie auf das dritte Symbol mit dem gr��nen <uicontrol>Pluszeichen (+)</uicontrol>. Geben Sie einen Einheitennamen und einen ISO-Dateipfad ein und klicken Sie auf <uicontrol>Anh��ngen</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="de-de"> +<title>CD-ROM f��r VM ersetzen</title> +<shortdesc rev="rev1">Sie k��nnen den Inhalt der CD-ROM f��r eine virtuelle Maschine nach Abschluss der Installation ersetzen.</shortdesc> +<csbody> +<ol> +<li>Stellen Sie sicher, dass die virtuelle Maschine gestartet ist.</li> +<li>W��hlen Sie aus dem Aktionsmen�� die Option <uicontrol>Medien verwalten</uicontrol> aus.</li> +<li>Um das zu ��ndern, was aktuell in der CD-ROM geladen ist, klicken Sie auf das Symbol mit dem <uicontrol>orangefarbenen Schr��gstrich (/)</uicontrol> neben dem hdc-Feld.</li> +<li>Geben Sie auf der Seite <wintitle>CD-ROM f��r VM ersetzen</wintitle> den ISO-Dateipfad ein. Die anderen beiden Felder sind schreibgesch��tzt.</li> +<li>Klicken Sie auf <uicontrol>Ersetzen</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 231 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/de_DE/host.dita b/src/wok/plugins/kimchi/ui/pages/help/de_DE/host.dita new file mode 100644 index 0000000..33a40e3 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/de_DE/host.dita @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="de-de"> +<title>Host</title> +<shortdesc>Die Seite <wintitle>Host</wintitle> zeigt Informationen zum Hostsystem an und erm��glicht Ihnen, den Host herunterzufahren, erneut zu starten und eine Verbindung zu ihm herzustellen.</shortdesc> +<csbody> +<p>Sie k��nnen die folgenden Aktionen am Host durchf��hren:<ul> +<li>W��hlen Sie <uicontrol>Herunterfahren</uicontrol> aus, um das Hostsystem herunterzufahren.</li> +<li>W��hlen Sie <uicontrol>Erneut starten</uicontrol> aus, um das Hostsystem erneut zu starten.</li> +<li>W��hlen Sie <uicontrol>Verbinden</uicontrol> aus, um eine VNC-Verbindung zum Hostsystem herzustellen, wenn noch keine Verbindung besteht.</li> +</ul></p> +<p>Klicken Sie auf die folgenden Abschnitte, um Informationen zum Host anzuzeigen:<dl> +<dlentry> +<dt>Basisinformationen</dt> +<dd>Dieser Abschnitt zeigt die Verteilung, die Version und den Codenamen des Hostbetriebssystems sowie den Prozessortyp und die Speicherkapazit��t in GB an.</dd> +</dlentry><dlentry> +<dt>Systemstatistik</dt> +<dd>Dieser Abschnitt zeigt mithilfe von Grafiken Statistiken f��r CPU, Speicher, Platten-E/A und Netz-E/A f��r den Host an. W��hlen Sie <uicontrol>Daten werden nach dem Verlassen dieser Seite gesammelt</uicontrol> aus, um mit der Sammlung von Daten fortzufahren, wenn die Host-Registerkarte nicht angezeigt wird.</dd> +</dlentry><dlentry> +<dt>Software-Updates</dt> +<dd>Dieser Abschnitt zeigt Informationen f��r alle Pakete an, bei denen Aktualisierungen verf��gbar sind, einschlie��lich Paketname, Version, Architektur und Repository. Sie k��nnen alle aufgelisteten Pakete aktualisieren, indem Sie <uicontrol>Alle aktualisieren</uicontrol> ausw��hlen. Sie k��nnen nicht einzelne Pakete zur Aktualisierung ausw��hlen.</dd> +</dlentry><dlentry> +<dt>Repositorys</dt> +<dd>Dieser Abschnitt zeigt Repositorys an, die dem Hostsystem zugeordnet sind. Sie k��nnen Repositorys hinzuf��gen, aktivieren, bearbeiten oder entfernen. Beim Hinzuf��gen wird ein Repository dem Hostsystem zugeordnet. Das Aktivieren eines Repositorys dagegen erm��glicht dem Host den Zugriff auf das Repository. Wenn Ihr System Red Hat Enterprise +Linux oder Fedora ist, k��nnen Sie <filepath>yum</filepath>-Repositorys hinzuf��gen. +Wenn Ihr System Ubuntu oder Debian ist, f��gen Sie <filepath>deb</filepath>-Repositorys hinzu.<p>Wenn Sie mit yum-Repositorys arbeiten, k��nnen Sie eine GPG-Pr��fung hinzuf��gen, um sicherzustellen, dass ein Paket aus diesem Repository nicht besch��digt wurde. +W��hlen Sie ein Repository und dann <uicontrol>Bearbeiten</uicontrol> aus. W��hlen Sie <uicontrol>Ja</uicontrol> aus, um die GPG-Pr��fung zu aktivieren, und geben Sie dann ein URL zur GPG-Schl��sseldatei f��r das Repository ein.</p></dd> +</dlentry><dlentry> +<dt>Debugberichte</dt> +<dd>Dieser Abschnitt zeigt Debugberichte, einschlie��lich Name und Dateipfad, an. +Sie haben die M��glichkeit, einen neuen Bericht zu erstellen oder einen bestehenden Bericht umzubenennen, zu entfernen oder herunterzuladen.<p>Der Debugbericht wird w��hrend des Befehls <cmdname>sosreport</cmdname> generiert. Er ist verf��gbar f��r Red Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>-, Fedora- +und Ubuntu-Verteilungen. Der Befehl generiert eine .tar-Datei, die Konfigurations- und Diagnoseinformationen enth��lt, wie zum Beispiel Kernelversion, geladene Module sowie System- und Servicekonfigurationdateien. +Der Befehl f��hrt zudem externe Programme aus, um weitere Informationen zu sammeln, und speichert diese Ausgabe im resultierenden Archiv.</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 232 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/de_DE/network.dita b/src/wok/plugins/kimchi/ui/pages/help/de_DE/network.dita new file mode 100644 index 0000000..49a2935 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/de_DE/network.dita @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="de-de"> +<title>Netz</title> +<shortdesc>Die Seite <wintitle>Netz</wintitle> zeigt Informationen zur Netzverbindung an.</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>Netzname</dt> +<dd>Name des Netzes oder <uicontrol>Standard</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Status</dt> +<dd>Status des Netzes, aktiv (gr��n) oder inaktiv (rot). </dd> +</dlentry><dlentry> +<dt>Netztyp</dt> +<dd>Netztyp, zum Beispiel <uicontrol>NAT</uicontrol> (Network +Address Translation, Netzadressumsetzung).</dd> +</dlentry><dlentry> +<dt>Schnittstelle</dt> +<dd>Netzschnittstelle, zum Beispiel <uicontrol>virbr0</uicontrol> (Standard).</dd> +</dlentry><dlentry> +<dt>Adressraum</dt> +<dd>IP-Adresse.</dd> +</dlentry></dl></p> +<p>Die folgenden Aktionen k��nnen ausgew��hlt werden:<ul> +<li rev="rev1">W��hlen Sie <uicontrol>Starten</uicontrol> aus, um die Netzverbindung herzustellen.</li> +<li>W��hlen Sie <uicontrol>Stoppen</uicontrol> aus, um die Netzverbindung zu beenden.</li> +<li>W��hlen Sie <uicontrol>L��schen</uicontrol> aus, um die Verbindungsinformationen zu l��schen.</li> +</ul>Um ein Netz zu erstellen, klicken Sie auf das Symbol <uicontrol>Plus (+)</uicontrol> oben rechts in der Anzeige.</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="de-de"> +<title>Netz erstellen</title> +<shortdesc>Erstellen Sie ein Netz.</shortdesc> +<csbody> +<p> <ol> +<li>Geben Sie den Namen des Netzes ein.</li> +<li>Klicken Sie hier, um den Netztyp auszuw��hlen. <dl rev="rev1"><dlentry> +<dt><uicontrol>Isoliert</uicontrol></dt> +<dd>Isolierter Modus. G��ste k��nnen keine Kommunikation an externe Systeme senden oder von ihnen empfangen.</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>Network Address Translation-Modus. Bei der Kommunikation von G��sten mit externen Systemen wird die Host-IP-Adresse verwendet. Externe Systeme k��nnen keine Kommunikation mit G��sten initiieren.</dd> +</dlentry><dlentry> +<dt><uicontrol>��berbr��ckt</uicontrol></dt> +<dd>��berbr��ckt-Modus. G��ste k��nnen mit externen Systemen kommunizieren und von externen Systemen kontaktiert werden, als ob sie physische Systeme im Netz w��ren. F��r den ��berbr��ckt-Modus m��ssen Sie zus��tzliche Ziel- und VLAN-Informationen angeben.</dd> +</dlentry></dl></li> +<li>Klicken Sie auf <uicontrol>Erstellen</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 230 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/de_DE/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/de_DE/storage.dita new file mode 100644 index 0000000..7f89603 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/de_DE/storage.dita @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="de-de"> +<title>Speicher</title> +<shortdesc>Auf der Seite <wintitle>Speicher</wintitle> werden die verf��gbaren Speicherpools aufgelistet, einschlie��lich der sofort einsatzf��higen Speicherpools 'default' und 'ISO'. Wenn Sie ein eigenes ISO-Image verwenden m��chten, f��gen Sie es zum Speicherpoolpfad 'ISO' hinzu.</shortdesc> +<csbody> +<p>F��r jeden Speicherpool werden die folgenden Informationen angezeigt:<dl> +<dlentry> +<dt>Name</dt> +<dd>Name des Speicherpools und genutzter Prozentsatz.</dd> +</dlentry><dlentry> +<dt>Status</dt> +<dd>Status des Speicherpools, aktiv (gr��n) oder inaktiv (rot). </dd> +</dlentry><dlentry> +<dt>Position</dt> +<dd>Dateipfad zur Position des Speicherpools.</dd> +</dlentry><dlentry> +<dt>Typ</dt> +<dd>Typ des Speicherpools, zum Beispiel <uicontrol>dir</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Kapazit��t</dt> +<dd>Speicherkapazit��t im Speicherpool.</dd> +</dlentry><dlentry> +<dt>Zugeordnet</dt> +<dd>Speicherplatz, der bereits im Speicherpool zugeordnet ist.</dd> +</dlentry></dl></p> +<p>Die folgenden Aktionen k��nnen f��r jeden Speicherpool ausgew��hlt werden:<ul> +<li>W��hlen Sie <uicontrol>Aktivieren</uicontrol> aus, um den Speicherpool zu aktivieren, damit er genutzt werden kann.</li> +<li>W��hlen Sie <uicontrol>Inaktivieren</uicontrol> aus, um einen aktiven Speicherpool zu inaktivieren.</li> +<li>W��hlen Sie <uicontrol>Definition aufheben</uicontrol>, um einen inaktiven Speicherpool zu entfernen.</li> +</ul></p> +<p>Um Details zum Speicherdatentr��ger anzuzeigen, klicken Sie auf den Pfeil auf der rechten Seite der Speicherpoolzeile. Zu den Details geh��ren folgende Informationen:<dl><dlentry> +<dt>Typ</dt> +<dd>Typ des Datentr��gers, zum Beispiel <uicontrol>file</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Format</dt> +<dd>Das Format, variiert abh��ngig vom Typ.</dd> +</dlentry><dlentry> +<dt>Kapazit��t</dt> +<dd>Gr����e des Speicherdatentr��gers.</dd> +</dlentry><dlentry> +<dt>Zuordnung</dt> +<dd>Speicherplatz, der bereits im Speicherpool zugeordnet ist.</dd> +</dlentry></dl>Um einen Speicherpool zu definieren, klicken Sie auf das Symbol <uicontrol>Plus (+)</uicontrol> oben rechts in der Anzeige.</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="de-de"> +<title>Speicherpool definieren</title> +<shortdesc> Definieren Sie einen Speicherpool.</shortdesc> +<csbody> +<p> <ol> +<li>Geben Sie im Feld <uicontrol>Speicherpoolname</uicontrol> den Namen ein, mit dem der Speicherpool gekennzeichnet werden soll.</li> +<li>W��hlen Sie aus der Liste <uicontrol>Speicherpooltyp</uicontrol> den Typ aus: <dl><dlentry> +<dt><uicontrol>DIR</uicontrol></dt> +<dd>Gibt einen Verzeichnispool an. Wenn Sie <uicontrol>DIR</uicontrol> ausw��hlen, geben Sie den <uicontrol>Speicherpfad</uicontrol> ein (Dateipfad zum Speicherpool).</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>Gibt einen Netzdateisystempool an. Wenn Sie <uicontrol>NFS</uicontrol> ausw��hlen, +geben Sie <uicontrol>NFS-Server-IP</uicontrol> und <uicontrol>NFS-Pfad</uicontrol> an (Pfad des exportierten Verzeichnisses).</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>Gibt einen Pool an, der auf einem Ziel basiert, der auf einem iSCSI-Server zugeordnet ist. +Wenn Sie <uicontrol>iSCSI</uicontrol> ausw��hlen, geben Sie die IP-Adresse vom <uicontrol>iSCSI-Server</uicontrol> und das <uicontrol>Ziel</uicontrol> auf dem iSCSI-Server an. Sie k��nnen optional iSCSI-Authentifizierung hinzuf��gen.</dd> +</dlentry><dlentry> +<dt><uicontrol>Logisch</uicontrol></dt> +<dd>Gibt einen Speicherpool aus logischen Datentr��gern an. W��hlen Sie die Position zur Einheit im <uicontrol>Einheitenpfad</uicontrol> aus.</dd> +</dlentry><dlentry> +<dt><uicontrol>SCSI-Fibre Channel</uicontrol></dt> +<dd>Gibt einen Pool an, der auf einem SCSI-Fibre Channel basiert. W��hlen Sie aus, welcher Adapter verwendet werden soll.</dd> +</dlentry></dl></li> +<li>Klicken Sie auf <uicontrol>Erstellen</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 233 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/de_DE/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/de_DE/templates.dita new file mode 100644 index 0000000..5063930 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/de_DE/templates.dita @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="de-de"> +<title>Vorlagen</title> +<shortdesc>Die Seite <wintitle>Vorlagen</wintitle> zeigt die definierten Vorlagen der virtuellen Maschine an, die zum Erstellen von KVM-G��sten verwendet werden k��nnen.</shortdesc> +<csbody> +<p>F��r jede Vorlage werden die folgenden Informationen angezeigt:<dl> +<dlentry> +<dt>BS</dt> +<dd>Name des Betriebssystems oder der Verteilung.</dd> +</dlentry><dlentry> +<dt>Version</dt> +<dd>Version des Betriebssystems oder der Verteilung.</dd> +</dlentry><dlentry> +<dt>CPUs</dt> +<dd>Anzahl der Prozessoren, die f��r die Vorlage definiert sind.</dd> +</dlentry><dlentry> +<dt>Speicher</dt> +<dd>Gr����e des zuzuordnenden Arbeitsspeichers in MB.</dd> +</dlentry></dl></p> +<p>Die folgenden Aktionen k��nnen f��r jede Vorlage ausgew��hlt werden:<ul> +<li>W��hlen Sie <uicontrol>Bearbeiten</uicontrol> aus, um die Vorlage zu bearbeiten.</li> +<li>W��hlen Sie <uicontrol>L��schen</uicontrol> aus, um die Vorlage zu l��schen.</li> +</ul>Um eine Vorlage hinzuzuf��gen, klicken Sie auf das Symbol <uicontrol>Plus (+)</uicontrol> oben rechts in der Anzeige.</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="de-de"> +<title>Vorlage bearbeiten</title> +<shortdesc>Bearbeiten Sie eine bestehende Vorlage.</shortdesc> +<csbody> +<p>F��r jede Vorlage werden die folgenden Informationen angezeigt: <dl> +<dlentry> +<dt>Name</dt> +<dd>Name der Vorlage.</dd> +</dlentry><dlentry> +<dt>Anbieter</dt> +<dd>Der Name des Unternehmens, das das Betriebssystem oder die Verteilung erstellt hat, f��r die die Vorlage konfiguriert ist.</dd> +</dlentry><dlentry> +<dt>Version</dt> +<dd>Die Version des Betriebssystems oder der Verteilung, f��r die die Vorlage konfiguriert ist.</dd> +</dlentry><dlentry> +<dt>CPU-Anzahl</dt> +<dd>Anzahl der Prozessoren, die f��r die Vorlage definiert sind.</dd> +</dlentry><dlentry> +<dt>Speicher</dt> +<dd>Speicherkapazit��t in MB, die der virtuellen Maschine zugeordnet werden soll.</dd> +</dlentry><dlentry> +<dt>Platte</dt> +<dd>Plattengr����e in GB.</dd> +</dlentry><dlentry> +<dt>CD-ROM</dt> +<dd>Dateipfad zur Position der ISO-Datei an, die f��r die Installation des KVM-Gastes verwendet wird.</dd> +</dlentry><dlentry> +<dt>Speicherpool</dt> +<dd>Bestimmter Speicherpool oder der Standardspeicherpool.</dd> +</dlentry><dlentry> +<dt>Netz</dt> +<dd>Standardnetzschnittstelle, die f��r den KVM-Gast verf��gbar ist. Sie k��nnen mehrere Netze ausw��hlen.</dd> +</dlentry></dl> Felder, die nicht inaktiviert sind, k��nnen bearbeitet werden. Nachdem Sie ein Feld bearbeitet haben, klicken Sie auf <uicontrol>Speichern</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>Vorlage hinzuf��gen</title> +<shortdesc>F��gen Sie eine Vorlage vom Quellendatentr��ger hinzu. Sie k��nnen f��r eine nachfolgende Erkennung Ihr eigenes ISO-Image zum Speicherpool 'ISO' hinzuf��gen.</shortdesc> +<csbody> +<p>W��hlen Sie die Position des Quellendatentr��gers aus den folgenden Optionen aus:<dl> +<dlentry> +<dt>Lokales ISO-Image</dt> +<dd>W��hlen Sie diese Option aus, um Speicherpools nach Installations-ISO-Images zu durchsuchen, die im System verf��gbar sind.</dd> +</dlentry><dlentry> +<dt>Fernes ISO-Image</dt> +<dd>W��hlen Sie diese Option aus, um eine ferne Position f��r ein Installations-ISO-Image anzugeben.</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>Vorlage hinzuf��gen - lokales ISO-Image</title> +<shortdesc>F��gen Sie eine Vorlage aus einem lokalen ISO-Image hinzu.</shortdesc> +<csbody> +<p>Die im System verf��gbaren ISO-Images werden angezeigt.<dl><dlentry> +<dt>BS</dt> +<dd>Name des Betriebssystems oder der Verteilung.</dd> +</dlentry><dlentry> +<dt>Version</dt> +<dd>Version des Betriebssystems oder der Verteilung.</dd> +</dlentry><dlentry> +<dt>Gr����e</dt> +<dd>Gr����e des ISO-Image.</dd> +</dlentry></dl></p> +<p>Um eine Vorlage aus einem ISO-Image zu erstellen, w��hlen Sie aus den folgenden +Optionen aus:<ul> +<li>W��hlen Sie ein ISO-Image aus, aus dem Sie eine Vorlage erstellen m��chten, und klicken Sie dann auf <uicontrol>Vorlagen aus ausgew��hltem ISO erstellen</uicontrol>.</li> +<li>W��hlen Sie <uicontrol>Alle</uicontrol> aus, um eine Vorlage aus jedem aufgelisteten ISO-Image zu erstellen, und klicken Sie dann auf <uicontrol>Vorlagen aus ausgew��hltem ISO erstellen</uicontrol>.</li> +<li>Wenn das ISO-Image, das Sie verwenden m��chten, nicht in den Suchergebnissen angezeigt wird, k��nnen Sie aus den folgenden Optionen ausw��hlen:<ul> +<li>W��hlen Sie <uicontrol>Ich m��chte eine bestimmte ISO-Datei verwenden</uicontrol> aus, um einen Pfad zum ISO-Image anzugeben.</li> +<li>Klicken Sie auf <uicontrol>Weitere ISOs suchen</uicontrol>, um weitere ISO-Images zu suchen.</li> +</ul></li> +</ul></p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 229 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/dita-help.xsl b/src/wok/plugins/kimchi/ui/pages/help/dita-help.xsl new file mode 100644 index 0000000..45f0a3b --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/dita-help.xsl @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns="http://www.w3.org/1999/xhtml"> + <xsl:output method="xml" indent="yes" encoding="UTF-8" /> + + <xsl:template match="/"> + <html> + <head> + <title><xsl:value-of select="/cshelp/title" /></title> + <meta charset="UTF-8" /> + <link rel="shortcut icon" href="images/logo.ico" /> + <link rel="stylesheet" type="text/css" href="../kimchi.css" /> + </head> + <body> + <xsl:apply-templates select="//cshelp" /> + </body> + </html> + </xsl:template> + + <xsl:template match="cshelp"> + <h1><xsl:value-of select="title" /></h1> + <p class="shortdesc"><xsl:value-of select="shortdesc" /></p> + <p class="csbody"><xsl:copy-of select="csbody/node()" /></p> + </xsl:template> +</xsl:stylesheet> diff --git a/src/wok/plugins/kimchi/ui/pages/help/en_US/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/en_US/Makefile.am new file mode 100644 index 0000000..d37f03a --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/en_US/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +en_US_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/en_US + +dist_en_US_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/en_US/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/en_US/guests.dita new file mode 100644 index 0000000..1bb437a --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/en_US/guests.dita @@ -0,0 +1,136 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> +<?Pub Sty _display FontColor="red"?> +<?Pub Inc?> +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="en-us"> +<title>Guests</title> +<shortdesc>The <wintitle>Guests</wintitle> page lists the defined +KVM virtual machines.</shortdesc> +<csbody> +<p>For each guest, the following information is displayed:<dl><dlentry> +<dt>Name</dt> +<dd>Name of the virtual machine.</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>Percentage of processor utilization in the virtual machine.</dd> +</dlentry><dlentry> +<dt>Network I/O</dt> +<dd>Network input/output transmission rate in KB per seconds.</dd> +</dlentry><dlentry> +<dt>Disk I/O</dt> +<dd>Disk input/output transmission rate in KB per seconds.</dd> +</dlentry><dlentry> +<dt>Livetile</dt> +<dd>State of guest operating system console, or an icon that represents +the <tm tmtype="tm" trademark="Linux">Linux</tm> distribution if the +guest is not active.</dd> +</dlentry></dl></p> +<p>The following actions icons are displayed for each guest:<dl> +<dlentry> +<dt>Reset</dt> +<dd>Click to reset the guest. </dd> +</dlentry><dlentry> +<dt>Power (Start or Stop)</dt> +<dd>Click to power on or power off the guest. If the icon is red, +the power is off; if the icon is green, the power is on.</dd> +</dlentry></dl> </p> +<p>The following actions can be selected for each guest:<ul> +<li>Select <uicontrol>Connect</uicontrol> to connect to the remote +console for the guest operating system.</li> +<li>Select <uicontrol>Manage media</uicontrol> to change the path +to the installation media.</li> +<li>Select <uicontrol>Reset</uicontrol> to reset the guest.</li> +<li>Select <uicontrol>Edit</uicontrol> to edit the properties of an +existing guest. Guests can be edited only while stopped.</li> +<li>Select <uicontrol>Delete</uicontrol> to delete the guest.</li> +</ul>To create a guest, or virtual machine, click the <uicontrol>plus +(+)</uicontrol> icon in the upper right of the page.</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="en-us"> +<title>Create virtual machine</title> +<shortdesc>Create a virtual machine by using an existing template.</shortdesc> +<csbody> +<p> <ol> +<li>Type the name to be used to identify the virtual machine.</li> +<li rev="rev1">Select a template. <ul> +<li>If templates exist, select from displayed templates.</li> +<li>If no templates exist, click <uicontrol>Create a template</uicontrol> to +create a template.</li> +</ul></li> +<li>Click <uicontrol>Create</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="en-us"> +<title>Edit guest</title> +<shortdesc>Edit the properties of an existing virtual machine. Some properties +can be edited only while guest is stopped. Others will take effect in next boot.</shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>For each guest, the following information is displayed on the <wintitle>General</wintitle> tab:<dl> +<dlentry> +<dt>Name</dt> +<dd>Name of the virtual machine. (can only be edited while guest is stopped)</dd> +</dlentry><dlentry> +<dt>CPUs</dt> +<dd>Number of processors. (if guest is running, new amount will take effect +in next boot)</dd> +</dlentry><dlentry> +<dt>Memory</dt> +<dd>Amount of memory in MB. (if guest is running, new amount will take effect +in next boot)</dd> +</dlentry><dlentry> +<dt>Icon</dt> +<dd>Graphic image representing the Linux distribution to be displayed +in place of current status (Livetile) when the guest is not active.</dd> +</dlentry></dl></p> +<p>The following information is displayed on the <wintitle>Storage</wintitle> tab.</p> +<dl><dlentry> +<dt>Storage</dt> +<dd>Displays the location of the ISO file used for installation.</dd> +</dlentry></dl><?Pub Caret -2?> +<p> Fields that are not disabled can be edited. After you edit a field, +click <uicontrol>Save</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="en-us"> +<title>Add, replace, or detach a storage device</title> +<shortdesc rev="rev1">You can add, replace, or detach a storage device +to your virtual machine. The only supported device is CDROM. To edit +your storage devices, follow these steps:</shortdesc> +<csbody> +<ol> +<li>On the <wintitle>Edit Guest</wintitle> window, select <wintitle>Storage</wintitle>.</li> +<li>To replace a storage device, click the first icon with the <uicontrol>orange +slash (/)</uicontrol>. Enter the ISO file path and click <uicontrol>Replace</uicontrol>.</li> +<li>To detach a storage device, click the second icon with the <uicontrol>red +dash (-)</uicontrol>. Confirm the deletion and click <uicontrol>OK</uicontrol>.</li> +<li>To add a storage device, click the third icon with the green <uicontrol>plus +sign (+)</uicontrol>. Enter a device name and ISO file path and click <uicontrol>Attach</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="en-us"> +<title>Replace a CDROM of VM</title> +<shortdesc rev="rev1">You can replace the contents of the CDROM for +a virtual machine after the installation is complete.</shortdesc> +<csbody> +<ol> +<li>Ensure that the virtual machine is started.</li> +<li>From the Actions menu, select <uicontrol>Manage Media</uicontrol>.</li> +<li>To change what is currently loaded in the CDROM, click the <uicontrol>orange +slash (/)</uicontrol> icon next to the hdc field.</li> +<li>On the <wintitle>Replace a CDROM of VM</wintitle> page, enter +the ISO file path. The other two fields are read-only.</li> +<li>Click <uicontrol>Replace</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> +<?Pub *0000005541?> diff --git a/src/wok/plugins/kimchi/ui/pages/help/en_US/host.dita b/src/wok/plugins/kimchi/ui/pages/help/en_US/host.dita new file mode 100644 index 0000000..0dcb670 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/en_US/host.dita @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> +<?Pub Sty _display FontColor="red"?> +<?Pub Inc?> +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="en-us"> +<title>Host</title> +<shortdesc>The <wintitle>Host</wintitle> page shows information about +the host system, and allows you to shut down, restart, and connect +to the host.</shortdesc> +<csbody> +<p>You can perform the following actions on the host:<ul> +<li>Select <uicontrol>Shut down</uicontrol> to shut down the host +system.</li> +<li>Select <uicontrol>Restart</uicontrol> to restart the host system.</li> +<li>Select <uicontrol>Connect</uicontrol> to open a VNC connection +to the host system, if it is not already connected.</li> +</ul></p> +<p>Click the following sections to display information about the host:<dl> +<dlentry> +<dt>Basic information</dt> +<dd>This section displays the host operating system distribution, +version, and code name, as well as the processor type, the number of +online CPUs and amount of memory in GB.</dd> +</dlentry><dlentry> +<dt>System statistics</dt> +<dd>This section displays graphs to show statistics for CPU, memory, +disk I/O, and network I/O for the host. Select <uicontrol>Collecting +data after leaving this page</uicontrol> to continue collecting data +when the host tab is out of view.</dd> +</dlentry><dlentry> +<dt>Software Updates</dt> +<dd>This section displays information for all of the packages that +have updates available, including package name, version, architecture, +and repository. You can update all of the packages listed by selecting <uicontrol>Update +All</uicontrol>. You cannot select individual packages for updates.</dd> +</dlentry><dlentry> +<dt>Repositories</dt> +<dd>This section displays repositories that are associated with the +host system. You can add, enable, edit, or remove repositories. Adding +a repository associates it with the host system while enabling a repository +allows the host to access it. If your system is Red Hat Enterprise +Linux or Fedora, you can add <filepath>yum</filepath> repositories. +If your system is Ubuntu or Debian, then add <filepath>deb</filepath> repositories.<p>If +you are working with yum repositories, you can add a GPG check to +verify that a package from this repository have not been corrupted. +Select a repository and then <uicontrol>Edit</uicontrol>. Select <uicontrol>Yes</uicontrol> to +enable GPG Check and then enter a URL to the GPG key file for the +repository.</p><?Pub Caret 156?></dd> +</dlentry><dlentry> +<dt>Debug reports</dt> +<dd>This section displays debug reports, including name and file path. +You can select from options to generate a new report, or rename, remove, +or download an existing report.<p>The debug report is generated using +the <cmdname>sosreport</cmdname> command. It is available for Red +Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora, +and Ubuntu distributions. The command generates a .tar file that contains +configuration and diagnostic information, such as the running kernel +version, loaded modules, and system and service configuration files. +The command also runs external programs to collect further information +and stores this output in the resulting archive.</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> +<?Pub *0000003492?> diff --git a/src/wok/plugins/kimchi/ui/pages/help/en_US/network.dita b/src/wok/plugins/kimchi/ui/pages/help/en_US/network.dita new file mode 100644 index 0000000..25c05ff --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/en_US/network.dita @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> +<?Pub Sty _display FontColor="red"?> +<?Pub Inc?> +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="en-us"> +<title>Network</title> +<shortdesc>The <wintitle>Network</wintitle> page displays information +about the network connection.</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>Network Name</dt> +<dd>Name of the network, or <uicontrol>default</uicontrol>.</dd> +</dlentry><dlentry> +<dt>State</dt> +<dd>State of the network, active (green) or inactive (red). </dd> +</dlentry><dlentry> +<dt>Network type</dt> +<dd>Network type, for example, <uicontrol>NAT</uicontrol> (network +address translation).</dd> +</dlentry><dlentry> +<dt>Interface</dt> +<dd>Network interface, for example, <uicontrol>virbr0</uicontrol> (default).</dd> +</dlentry><dlentry> +<dt>Address space</dt> +<dd>IP address.</dd> +</dlentry></dl></p> +<p>The following actions can be selected:<ul> +<li rev="rev1">Select <uicontrol>Start</uicontrol> to begin the network +connection.</li> +<li>Select <uicontrol>Stop</uicontrol> to end the network connection.</li> +<li>Select <uicontrol>Delete</uicontrol> to delete the connection +information.</li> +</ul>To create a network, click the <uicontrol>plus (+)</uicontrol> icon +in the upper right of the display.</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="en-us"> +<title>Create a network</title> +<shortdesc>Create a network.</shortdesc> +<csbody> +<p> <ol> +<li>Type the name of the network.</li> +<li>Click to select the network type. <dl rev="rev1"><dlentry> +<dt><uicontrol>Isolated</uicontrol></dt> +<dd>Isolated mode. Guests cannot send or receive communication to +or from external systems.</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>Network Address Translation mode. Communication from guests to +external systems uses the host IP address. External systems cannot +initiate communication to guests.</dd> +</dlentry><dlentry> +<dt><uicontrol>Bridged</uicontrol></dt> +<dd>Bridged mode. Guests can communicate with external systems and +be contacted by external systems as if they were physical systems +on the network. For bridged mode, you must specify additional destination +and VLAN information.</dd> +</dlentry></dl><?Pub Caret 224?></li> +<li>Click <uicontrol>Create</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> +<?Pub *0000002571?> diff --git a/src/wok/plugins/kimchi/ui/pages/help/en_US/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/en_US/storage.dita new file mode 100644 index 0000000..d9a32f9 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/en_US/storage.dita @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> +<?Pub Sty _display FontColor="red"?> +<?Pub Inc?> +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="en-us"> +<title>Storage</title> +<shortdesc>The <wintitle>Storage</wintitle> page lists the available +storage pools, including the out of box 'default' and 'ISO' storage pool. +If you want to use your own ISO, please add it to 'ISO' storage pool path.</shortdesc> +<csbody> +<p>For each storage pool, the following information is displayed:<dl> +<dlentry> +<dt>Name</dt> +<dd>Name of the storage pool and percentage used.</dd> +</dlentry><dlentry> +<dt>State</dt> +<dd>State of the storage pool, active (green) or inactive (red). </dd> +</dlentry><dlentry> +<dt>Location</dt> +<dd>File path to the location of the storage pool.</dd> +</dlentry><dlentry> +<dt>Type</dt> +<dd>Type of storage pool, for example, <uicontrol>dir</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Capacity</dt> +<dd>Amount of space in the storage pool.</dd> +</dlentry><dlentry> +<dt>Allocated</dt> +<dd>Amount of space that is already allocated in the storage pool.</dd> +</dlentry></dl></p> +<p>The following actions can be selected for each storage pool:<ul> +<li>Select <uicontrol>Activate</uicontrol> to activate the storage +pool so that it can be used.</li> +<li>Select <uicontrol>Deactivate</uicontrol> to deactivate an active +storage pool.</li> +<li>Select <uicontrol>Undefine</uicontrol> to remove an inactive storage +pool.</li> +</ul></p> +<p>To display storage volume details for a storage pool, click the +arrow on the right side of the storage pool row. Details include +the following:<dl><dlentry> +<dt>Type</dt> +<dd>The type of volume, for example, <uicontrol>file</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Format</dt> +<dd>The format, varying dependent on the type.</dd> +</dlentry><dlentry> +<dt>Capacity</dt> +<dd>Size of the storage volume.</dd> +</dlentry><dlentry> +<dt>Allocation</dt> +<dd>Amount of space that is already allocated in the storage pool.</dd> +</dlentry></dl>To define a storage pool, click the <uicontrol>plus +(+)</uicontrol> icon in the upper right of the display.</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="en-us"> +<title>Define a storage pool</title> +<shortdesc> Define a storage pool.</shortdesc> +<csbody> +<p> <ol> +<li>In the <uicontrol>Storage pool name</uicontrol> field, type the +name to be used to identify the storage pool.</li> +<li>In the <uicontrol>Storage pool type</uicontrol> list, select the +type: <dl><dlentry> +<dt><uicontrol>DIR</uicontrol></dt> +<dd>Specifies a directory pool. When selecting <uicontrol>DIR</uicontrol>, +type the <uicontrol>Storage path</uicontrol> (file path to the storage +pool).</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>Specifies a network filesystem pool. When selecting <uicontrol>NFS</uicontrol>, +type the <uicontrol>NFS server IP</uicontrol> address and <uicontrol>NFS +path</uicontrol> (path of the exported directory).</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>Specifies a pool based on a target allocated on an iSCSI server. +When selecting <uicontrol>iSCSI</uicontrol>, type the <uicontrol>iSCSI +server</uicontrol> IP address and <uicontrol>Target</uicontrol> on +the iSCSI server. You can optionally select to add iSCSI authentication.</dd> +</dlentry><dlentry> +<dt><uicontrol>Logical</uicontrol></dt> +<dd>Specifies a logical volume storage pool. Select the location to +the device in <uicontrol>Device path</uicontrol>.</dd> +</dlentry><dlentry> +<dt><uicontrol>SCSI Fibre Channel</uicontrol></dt> +<dd>Specifies a pool based on an SCSI Fibre Channel. Select which +SCSI adapter to use.</dd> +</dlentry></dl><?Pub Caret 0?></li> +<li>Click <uicontrol>Create</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> +<?Pub *0000003914?> diff --git a/src/wok/plugins/kimchi/ui/pages/help/en_US/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/en_US/templates.dita new file mode 100644 index 0000000..57ee9b5 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/en_US/templates.dita @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> +<?Pub Sty _display FontColor="red"?> +<?Pub Inc?> +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="en-us"> +<title>Templates</title> +<shortdesc>The <wintitle>Templates</wintitle> page shows the defined +virtual machine templates that can be used to create KVM guests.</shortdesc> +<csbody> +<p>For each template, the following information is displayed:<dl> +<dlentry> +<dt>OS</dt> +<dd>Name of the operating system or distribution.</dd> +</dlentry><dlentry> +<dt>Version</dt> +<dd>Version of the operating system or distribution.</dd> +</dlentry><dlentry> +<dt>CPUs</dt> +<dd>Number of processors that are defined for the template.</dd> +</dlentry><dlentry> +<dt>Memory</dt> +<dd>Amount of random access memory to be allocated, in MB.</dd> +</dlentry></dl></p> +<p>The following actions can be selected for each template:<ul> +<li>Select <uicontrol>Edit</uicontrol> to edit the template.</li> +<li>Select <uicontrol>Delete</uicontrol> to delete the template.</li> +</ul>To add a template, click the <uicontrol>plus (+)</uicontrol> icon +in the upper right of the display.</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="en-us"> +<title>Edit template</title> +<shortdesc>Edit an existing template.</shortdesc> +<csbody> +<p>For each template, the following information is displayed: <dl> +<dlentry> +<dt>Name</dt> +<dd>Name of the template.</dd> +</dlentry><dlentry> +<dt>Vendor</dt> +<dd>The name of the company that created the operating system or distribution +that the template is configured to use.</dd> +</dlentry><dlentry> +<dt>Version</dt> +<dd>The version of the operating system or distribution that the template +is configured to use.</dd> +</dlentry><dlentry> +<dt>CPU number</dt> +<dd>Number of processors that are defined for the template.</dd> +</dlentry><dlentry> +<dt>Memory</dt> +<dd>Amount of memory in MB to be allocated to the virtual machine.</dd> +</dlentry><dlentry> +<dt>Disk</dt> +<dd>Disk size in GB.</dd> +</dlentry><dlentry> +<dt>CDROM</dt> +<dd>File path to the location of the ISO file used to install the +KVM guest.</dd> +</dlentry><dlentry> +<dt>Storage pool</dt> +<dd>Specific storage pool or the default storage pool.</dd> +</dlentry><dlentry> +<dt>Network</dt> +<dd>Default network interfaces available to the KVM guest. You can +select multiple networks.</dd> +</dlentry></dl> Fields that are not disabled can be edited. After +you edit a field, click <uicontrol>Save</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>Add template</title> +<shortdesc>Add a template from source media. +You can add your own ISO image to 'ISO' storage pool for following discovery.</shortdesc> +<csbody> +<p>Select the location of the source media from the following options:<dl> +<dlentry> +<dt>Local ISO image</dt> +<dd>Select to scan storage pools for installation ISO images available +on the system.</dd> +</dlentry><dlentry> +<dt>Remote ISO image</dt> +<dd>Select to specify a remote location for an installation ISO image.</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>Add template - local ISO image</title> +<shortdesc>Add a template from a local ISO image.</shortdesc> +<csbody> +<p>The ISO images available on the system are displayed.<dl><dlentry> +<dt>OS</dt> +<dd>Name of the operating system or distribution.</dd> +</dlentry><dlentry> +<dt>Version</dt> +<dd>Version of the operating system or distribution.</dd> +</dlentry><dlentry> +<dt>Size</dt> +<dd>Size of the ISO image.</dd> +</dlentry></dl></p> +<p>To create a template from an ISO image, choose from the following +options:<ul> +<li>Select an ISO image from which to create a template, then click <uicontrol>Create +Templates from Selected ISO</uicontrol>.</li> +<li>Select <uicontrol>All</uicontrol> to create a template from each + listed ISO image, then click <uicontrol>Create Templates from Selected +ISO</uicontrol>.</li> +<li>If the ISO image that you want to use does not appear in the scan +results, you can select from the following options:<ul> +<li>Select <uicontrol>I want to use a specific ISO file</uicontrol> to +specify a path to the ISO image.</li> +<li>Click <uicontrol>Search more ISOs</uicontrol> to search for more +ISO images.</li> +</ul></li><?Pub Caret 0?> +</ul></p> +</csbody> +</cshelp> +</cshelp> +<?Pub *0000004433?> diff --git a/src/wok/plugins/kimchi/ui/pages/help/es_ES/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/es_ES/Makefile.am new file mode 100644 index 0000000..29c596f --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/es_ES/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +es_ES_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/es_ES + +dist_es_ES_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/es_ES/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/es_ES/guests.dita new file mode 100644 index 0000000..88e77e0 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/es_ES/guests.dita @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="es-es"> +<title>Invitados</title> +<shortdesc>La p��gina <wintitle>Invitados</wintitle> lista las m��quinas virtuales KVM definidas.</shortdesc> +<csbody> +<p>Se visualiza la siguiente informaci��n para cada invitado:<dl><dlentry> +<dt>Nombre</dt> +<dd>Nombre de la m��quina virtual.</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>Porcentaje de utilizaci��n de procesador en la m��quina virtual.</dd> +</dlentry><dlentry> +<dt>E/S de red</dt> +<dd>Velocidad de transmisi��n de entrada/salida de red en KB por segundos.</dd> +</dlentry><dlentry> +<dt>E/S de disco</dt> +<dd>Velocidad de transmisi��n de entrada/salida de disco en KB por segundos.</dd> +</dlentry><dlentry> +<dt>Livetile</dt> +<dd>Estado de la consola del sistema operativo invitado, o un icono que representa la distribuci��n de <tm tmtype="tm" trademark="Linux">Linux</tm> si el invitado no est�� activo.</dd> +</dlentry></dl></p> +<p>Se visualizan los siguientes iconos de acciones para cada invitado:<dl> +<dlentry> +<dt>Restablecer</dt> +<dd>Pulse aqu�� para restablecer el invitado. </dd> +</dlentry><dlentry> +<dt>Alimentaci��n (Iniciar o Detener)</dt> +<dd>Pulse aqu�� para encender o apagar el invitado. Si el icono es de color rojo, la alimentaci��n est�� apagada; si el icono es de color verde, la alimentaci��n est�� encendida.</dd> +</dlentry></dl> </p> +<p>Se pueden seleccionar las siguientes acciones para cada invitado:<ul> +<li>Seleccione <uicontrol>Conectar</uicontrol> para conectarse a la consola remota para el sistema operativo invitado.</li> +<li>Seleccione <uicontrol>Gestionar soporte</uicontrol> para cambiar la v��a de acceso al soporte de instalaci��n.</li> +<li>Seleccione <uicontrol>Restablecer</uicontrol> para restablecer el invitado.</li> +<li>Seleccione <uicontrol>Editar</uicontrol> para editar las propiedades de un invitado existente. Los invitados s��lo pueden editarse mientras est��n detenidos.</li> +<li>Seleccione <uicontrol>Suprimir</uicontrol> para suprimir el invitado.</li> +</ul>Para crear un invitado o m��quina virtual, pulse el icono <uicontrol>m��s (+)</uicontrol> en la esquina superior derecha de la p��gina.</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="es-es"> +<title>Crear m��quina virtual</title> +<shortdesc>Crear una m��quina virtual utilizando una plantilla existente.</shortdesc> +<csbody> +<p> <ol> +<li>Escriba el nombre a utilizar para identificar la m��quina virtual.</li> +<li rev="rev1">Seleccione una plantilla. <ul> +<li>Si existen plantillas, seleccione entre las plantillas mostradas.</li> +<li>Si no existen plantillas, pulse <uicontrol>Crear una plantilla</uicontrol> para crear una plantilla.</li> +</ul></li> +<li>Pulse <uicontrol>Crear</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="es-es"> +<title>Editar invitado</title> +<shortdesc>Editar las propiedades de una m��quina virtual existente. Algunas propiedades pueden editarse s��lo cuando el invitado se ha detenido. Otras surtir��n efecto en el arranque siguiente.</shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>Se visualiza la siguiente informaci��n para cada invitado en la pesta��a <wintitle>General</wintitle>:<dl> +<dlentry> +<dt>Nombre</dt> +<dd>Nombre de la m��quina virtual.(s��lo puede editarse cuando el invitado se ha detenido)</dd> +</dlentry><dlentry> +<dt>CPUs</dt> +<dd>N��mero de procesadores.(si el invitado est�� en ejecuci��n, la nueva cantidad surtir�� efecto en el siguiente arranque) +</dd> +</dlentry><dlentry> +<dt>Memoria</dt> +<dd>Cantidad de memoria en MB.(si el invitado est�� en ejecuci��n, la nueva cantidad surtir�� efecto en el siguiente arranque) +</dd> +</dlentry><dlentry> +<dt>Icono</dt> +<dd>Imagen gr��fica que representa la distribuci��n de Linux a visualizar en lugar del estado actual (Livetile) cuando el invitado no est�� activo.</dd> +</dlentry></dl></p> +<p>Se visualiza la siguiente informaci��n en la pesta��a <wintitle>Almacenamiento</wintitle>.</p> +<dl><dlentry> +<dt>Almacenamiento</dt> +<dd>Muestra la ubicaci��n del archivo ISO utilizado para la instalaci��n.</dd> +</dlentry></dl> +<p> Los campos que no est��n inhabilitados pueden editarse. Despu��s de editar un campo, pulse <uicontrol>Guardar</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="es-es"> +<title>A��adir, sustituir o desconectar un dispositivo de almacenamiento</title> +<shortdesc rev="rev1">Puede a��adir, sustituir o desconectar un dispositivo de almacenamiento a la m��quina virtual. El ��nico dispositivo soportado es CDROM. Para editar los dispositivos de almacenamiento, siga estos pasos:</shortdesc> +<csbody> +<ol> +<li>En la ventana <wintitle>Editar invitado</wintitle>, seleccione <wintitle>Almacenamiento</wintitle>.</li> +<li>Para sustituir un dispositivo de almacenamiento, pulse el primer icono con la <uicontrol>barra inclinada naranja (/)</uicontrol>. Especifique la v��a de acceso del archivo ISO y pulse <uicontrol>Sustituir</uicontrol>.</li> +<li>Para desconectar un dispositivo de almacenamiento, pulse el segundo icono con el <uicontrol>gui��n rojo (-)</uicontrol>. Confirme la supresi��n y pulse <uicontrol>Aceptar</uicontrol>.</li> +<li>Para a��adir un dispositivo de almacenamiento, pulse el tercer icono con el <uicontrol>signo m��s (+)</uicontrol> verde. Especifique un nombre de dispositivo y la v��a de acceso del archivo ISO y pulse <uicontrol>Conectar</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="es-es"> +<title>Sustituir un CDROM de m��quina virtual</title> +<shortdesc rev="rev1">Puede sustituir el contenido del CDROM para una m��quina virtual despu��s de completarse la instalaci��n.</shortdesc> +<csbody> +<ol> +<li>Aseg��rese de que la m��quina virtual se ha iniciado.</li> +<li>En el men�� Acciones, seleccione <uicontrol>Gestionar soporte</uicontrol>.</li> +<li>Para cambiar lo que est�� cargado actualmente en el CDROM, pulse el icono <uicontrol>barra inclinada naranja (/)</uicontrol> junto al campo hdc.</li> +<li>En la p��gina <wintitle>Sustituir un CDROM de m��quina virtual</wintitle>, especifique la v��a de acceso del archivo ISO. Los otros dos campos son de s��lo lectura.</li> +<li>Pulse <uicontrol>Sustituir</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 231 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/es_ES/host.dita b/src/wok/plugins/kimchi/ui/pages/help/es_ES/host.dita new file mode 100644 index 0000000..7734244 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/es_ES/host.dita @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="es-es"> +<title>Host</title> +<shortdesc>La p��gina <wintitle>Host</wintitle> muestra informaci��n sobre el sistema host y le permite concluir, reiniciar y conectar con el sistema principal.</shortdesc> +<csbody> +<p>Puede realizar las acciones siguientes en el host:<ul> +<li>Seleccione <uicontrol>Concluir</uicontrol> para concluir el sistema host.</li> +<li>Seleccione <uicontrol>Reiniciar</uicontrol> para reiniciar el sistema host.</li> +<li>Seleccione <uicontrol>Conectar</uicontrol> para abrir una conexi��n VNC al sistema host, si no est�� conectado a��n.</li> +</ul></p> +<p>Pulse en las secciones siguientes para visualizar informaci��n acerca del host:<dl> +<dlentry> +<dt>Informaci��n b��sica</dt> +<dd>Esta secci��n muestra la distribuci��n del sistema operativo de host, la versi��n y el nombre de c��digo, as�� como el tipo de procesador y la cantidad de memoria en GB.</dd> +</dlentry><dlentry> +<dt>Estad��sticas del sistema</dt> +<dd>Esta secci��n muestra gr��ficos para mostrar estad��sticas para CPU, memoria, E/S de disco y E/S de red para el host. Seleccione <uicontrol>Recoger datos despu��s de salir de esta p��gina</uicontrol> para continuar la recogida de datos cuando la pesta��a principal ya no est�� a la vista.</dd> +</dlentry><dlentry> +<dt>Actualizaciones de software</dt> +<dd>En esta secci��n se muestra informaci��n para todos los paquetes que tienen actualizaciones disponibles, incluido el nombre de paquete, versi��n, arquitectura y repositorio. Puede actualizar todos los paquetes listados seleccionando <uicontrol>Actualizar todo</uicontrol>. No puede seleccionar paquetes individuales para las actualizaciones.</dd> +</dlentry><dlentry> +<dt>Repositorios</dt> +<dd>En esta secci��n se muestran los repositorios que est��n asociados con el sistema host. Puede a��adir, habilitar, editar o eliminar repositorios. A��adir un repositorio lo asocia con el sistema host mientras que habilitar un repositorio permite que el host acceda a ��l. Si el sistema es Red Hat Enterprise +Linux o Fedora, puede a��adir repositorios <filepath>yum</filepath>. +Si el sistema es Ubuntu o Debian, a��ada repositorios <filepath>deb</filepath>.<p>Si est�� trabajando con repositorios yum, puede a��adir una comprobaci��n GPG para verificar que un paquete de este repositorio no ha resultado da��ado. +Seleccione un repositorio y, a continuaci��n, <uicontrol>Editar</uicontrol>. Seleccione <uicontrol>S��</uicontrol> para habilitar la comprobaci��n GPG y, a continuaci��n, especifique un URL al archivo de claves GPG para el repositorio.</p></dd> +</dlentry><dlentry> +<dt>Informes de depuraci��n</dt> +<dd>En esta secci��n se muestran informes de depuraci��n, incluido el nombre y la ruta de archivo. +Puede seleccionar entre opciones para generar un informe nuevo, o bien redenominar, eliminar o descargar un informe existente.<p>El informe de depuraci��n se genera utilizando el mandato <cmdname>sosreport</cmdname>. Est�� disponible para distribuciones de Red +Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora y Ubuntu. El mandato genera un archivo .tar que contiene la informaci��n de configuraci��n y de diagn��stico, como la versi��n de kernel en ejecuci��n, los m��dulos de carga y los archivos de configuraci��n del sistema y servicio. +El mandato tambi��n ejecuta programas externos para recopilar informaci��n adicional y almacena esta salida en el archivo resultante.</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 232 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/es_ES/network.dita b/src/wok/plugins/kimchi/ui/pages/help/es_ES/network.dita new file mode 100644 index 0000000..3654531 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/es_ES/network.dita @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="es-es"> +<title>Red</title> +<shortdesc>La p��gina <wintitle>Red</wintitle> muestra informaci��n sobre la conexi��n de red.</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>Nombre de red</dt> +<dd>Nombre de la red, o <uicontrol>predeterminado</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Estado</dt> +<dd>Estado de la red, activa (verde) o inactiva (rojo). </dd> +</dlentry><dlentry> +<dt>Tipo de red</dt> +<dd>Tipo de red, por ejemplo, <uicontrol>NAT</uicontrol> (conversi��n de direcciones de red).</dd> +</dlentry><dlentry> +<dt>Interfaz</dt> +<dd>La interfaz de red, por ejemplo, <uicontrol>virbr0</uicontrol> (predeterminada).</dd> +</dlentry><dlentry> +<dt>Espacio de direcciones</dt> +<dd>Direcci��n IP.</dd> +</dlentry></dl></p> +<p>Se pueden seleccionar las siguientes acciones:<ul> +<li rev="rev1">Seleccione <uicontrol>Iniciar</uicontrol> para iniciar la conexi��n de red.</li> +<li>Seleccione <uicontrol>Detener</uicontrol> para finalizar la conexi��n de red.</li> +<li>Seleccione <uicontrol>Suprimir</uicontrol> para suprimir la informaci��n de conexi��n.</li> +</ul>Para crear una red, pulse en el icono <uicontrol>m��s (+)</uicontrol> en la esquina superior derecha de la pantalla.</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="es-es"> +<title>Crear una red</title> +<shortdesc>Crear una red.</shortdesc> +<csbody> +<p> <ol> +<li>Escriba el nombre de la red.</li> +<li>Pulse para seleccionar el tipo de red. <dl rev="rev1"><dlentry> +<dt><uicontrol>Aislada</uicontrol></dt> +<dd>Modalidad aislada. Los invitados no pueden enviar ni recibir comunicaci��n a sistemas externos o desde ellos.</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>Modalidad de Conversi��n de direcciones de red. La comunicaci��n de invitados a sistemas externos utiliza la direcci��n IP del host. Los sistemas externos no pueden iniciar la comunicaci��n con los invitados.</dd> +</dlentry><dlentry> +<dt><uicontrol>Puenteada</uicontrol></dt> +<dd>Modalidad puenteada. Los invitados pueden comunicarse con sistemas externos y ser contactados por sistemas externos como si fueran sistemas f��sicos en la red. Para la modalidad puenteada, debe especificar informaci��n de destino y VLAN adicional.</dd> +</dlentry></dl></li> +<li>Pulse <uicontrol>Crear</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 230 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/es_ES/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/es_ES/storage.dita new file mode 100644 index 0000000..0c68951 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/es_ES/storage.dita @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="es-es"> +<title>Almacenamiento</title> +<shortdesc>La p��gina <wintitle>Almacenamiento</wintitle> lista las agrupaciones de almacenamiento disponibles, incluyendo la agrupaci��n de almacenamiento predefinida 'default' e 'ISO'. +Si desea utilizar su propia ISO, a����dala a la v��a de acceso de la agrupaci��n de almacenamiento 'ISO'.</shortdesc> +<csbody> +<p>Se visualiza la siguiente informaci��n para cada agrupaci��n de almacenamiento:<dl> +<dlentry> +<dt>Nombre</dt> +<dd>Nombre de la agrupaci��n de almacenamiento y el porcentaje utilizado.</dd> +</dlentry><dlentry> +<dt>Estado</dt> +<dd>Estado de la agrupaci��n de almacenamiento, activa (verde) o inactiva (rojo). </dd> +</dlentry><dlentry> +<dt>Ubicaci��n</dt> +<dd>V��a de acceso de archivo a la ubicaci��n de la agrupaci��n de almacenamiento.</dd> +</dlentry><dlentry> +<dt>Tipo</dt> +<dd>Tipo de agrupaci��n de almacenamiento, por ejemplo, <uicontrol>dir</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Capacidad</dt> +<dd>Cantidad de espacio en la agrupaci��n de almacenamiento.</dd> +</dlentry><dlentry> +<dt>Asignado</dt> +<dd>Cantidad de espacio que ya est�� asignado en la agrupaci��n de almacenamiento.</dd> +</dlentry></dl></p> +<p>Se pueden seleccionar las siguientes acciones para cada agrupaci��n de almacenamiento:<ul> +<li>Seleccione <uicontrol>Activar</uicontrol> para activar la agrupaci��n de almacenamiento para que pueda utilizarse.</li> +<li>Seleccione <uicontrol>Desactivar</uicontrol> para desactivar una agrupaci��n de almacenamiento activa.</li> +<li>Seleccione <uicontrol>No definir</uicontrol> para eliminar una agrupaci��n de almacenamiento inactiva.</li> +</ul></p> +<p>Para visualizar detalles de volumen de almacenamiento para una agrupaci��n de almacenamiento, pulse la flecha situada en el lado derecho de la fila de agrupaci��n de almacenamiento. Los detalles incluyen lo siguiente:<dl><dlentry> +<dt>Tipo</dt> +<dd>El tipo de volumen, por ejemplo, <uicontrol>archivo</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Formato</dt> +<dd>El formato, variable dependiendo del tipo.</dd> +</dlentry><dlentry> +<dt>Capacidad</dt> +<dd>Tama��o del volumen de almacenamiento.</dd> +</dlentry><dlentry> +<dt>Asignaci��n</dt> +<dd>Cantidad de espacio que ya est�� asignado en la agrupaci��n de almacenamiento.</dd> +</dlentry></dl>Para definir una agrupaci��n de almacenamiento, pulse en el icono <uicontrol>m��s (+)</uicontrol> en la esquina superior derecha de la pantalla.</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="es-es"> +<title>Definir una agrupaci��n de almacenamiento</title> +<shortdesc> Definir una agrupaci��n de almacenamiento.</shortdesc> +<csbody> +<p> <ol> +<li>En el campo <uicontrol>Nombre de agrupaci��n de almacenamiento</uicontrol>, escriba el nombre que se utilizar�� para identificar la agrupaci��n de almacenamiento.</li> +<li>En la lista <uicontrol>Tipo de agrupaci��n almacenamiento</uicontrol>, seleccione el tipo: <dl><dlentry> +<dt><uicontrol>DIR</uicontrol></dt> +<dd>Especifica una agrupaci��n de directorio. Al seleccionar <uicontrol>DIR</uicontrol>, escriba la <uicontrol>V��a de acceso de almacenamiento</uicontrol> (v��a de acceso de archivo a la agrupaci��n de almacenamiento).</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>Especifica una agrupaci��n de sistema de archivos de red. Al seleccionar <uicontrol>NFS</uicontrol>, escriba la direcci��n <uicontrol>IP de servidor NFS</uicontrol> y <uicontrol>v��a de acceso de NFS</uicontrol> (v��a de acceso del directorio exportado).</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>Especifica una agrupaci��n basada en un destino asignado en un servidor iSCSI. +Al seleccionar <uicontrol>iSCSI</uicontrol>, escriba la direcci��n IP del <uicontrol>Servidor iSCSI</uicontrol> y el <uicontrol>Destino</uicontrol> en el servidor iSCSI. Opcionalmente puede seleccionar a��adir autenticaci��n iSCSI.</dd> +</dlentry><dlentry> +<dt><uicontrol>L��gico</uicontrol></dt> +<dd>Especifica una agrupaci��n de almacenamiento de volumen l��gico. Seleccione la ubicaci��n al dispositivo en <uicontrol>V��a de acceso de dispositivo</uicontrol>.</dd> +</dlentry><dlentry> +<dt><uicontrol>Canal de fibra de SCSI</uicontrol></dt> +<dd>Especifica una agrupaci��n basada en un Canal de fibra SCSI. Seleccione qu�� adaptador SCSI se utilizar��.</dd> +</dlentry></dl></li> +<li>Pulse <uicontrol>Crear</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 233 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/es_ES/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/es_ES/templates.dita new file mode 100644 index 0000000..8cceee7 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/es_ES/templates.dita @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="es-es"> +<title>Plantillas</title> +<shortdesc>La p��gina <wintitle>Plantillas</wintitle> muestra las plantillas de m��quina virtual definidas que se pueden utilizar para crear invitados KVM.</shortdesc> +<csbody> +<p>Se visualiza la siguiente informaci��n para cada plantilla:<dl> +<dlentry> +<dt>SO</dt> +<dd>Nombre del sistema operativo o distribuci��n.</dd> +</dlentry><dlentry> +<dt>Versi��n</dt> +<dd>Versi��n del sistema operativo o distribuci��n.</dd> +</dlentry><dlentry> +<dt>CPUs</dt> +<dd>N��mero de procesadores que est��n definidos para la plantilla.</dd> +</dlentry><dlentry> +<dt>Memoria</dt> +<dd>Cantidad de memoria de acceso aleatorio a asignar, en MB.</dd> +</dlentry></dl></p> +<p>Se pueden seleccionar las siguientes acciones para cada plantilla:<ul> +<li>Seleccione <uicontrol>Editar</uicontrol> para editar la plantilla.</li> +<li>Seleccione <uicontrol>Suprimir</uicontrol> para suprimir la plantilla.</li> +</ul>Para a��adir una plantilla, pulse en el icono <uicontrol>m��s (+)</uicontrol> en la esquina superior derecha de la pantalla.</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="es-es"> +<title>Editar plantilla</title> +<shortdesc>Editar una plantilla existente.</shortdesc> +<csbody> +<p>Se visualiza la siguiente informaci��n para cada plantilla: <dl> +<dlentry> +<dt>Nombre</dt> +<dd>Nombre de la plantilla.</dd> +</dlentry><dlentry> +<dt>Proveedor</dt> +<dd>El nombre de la empresa que cre�� el sistema operativo o distribuci��n que la plantilla est�� configurada para utilizar.</dd> +</dlentry><dlentry> +<dt>Versi��n</dt> +<dd>La versi��n del sistema operativo o distribuci��n que la plantilla est�� configurada para utilizar.</dd> +</dlentry><dlentry> +<dt>N��mero de CPU</dt> +<dd>N��mero de procesadores que est��n definidos para la plantilla.</dd> +</dlentry><dlentry> +<dt>Memoria</dt> +<dd>Cantidad de memoria en MB a asignar a la m��quina virtual.</dd> +</dlentry><dlentry> +<dt>Disco</dt> +<dd>Tama��o de disco en GB.</dd> +</dlentry><dlentry> +<dt>CDROM</dt> +<dd>V��a de acceso de archivo a la ubicaci��n del archivo ISO utilizado para instalar el invitado KVM.</dd> +</dlentry><dlentry> +<dt>Agrupaci��n de almacenamiento</dt> +<dd>Agrupaci��n de almacenamiento espec��fica o la agrupaci��n de almacenamiento predeterminada.</dd> +</dlentry><dlentry> +<dt>Red</dt> +<dd>Interfaces de red predeterminadas disponibles para el invitado KVM. Puede seleccionar varias redes.</dd> +</dlentry></dl> Los campos que no est��n inhabilitados pueden editarse. Despu��s de editar un campo, pulse <uicontrol>Guardar</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>A��adir plantilla</title> +<shortdesc>A��adir una plantilla desde el soporte de origen. Puede a��adir su propia imagen ISO a la agrupaci��n de almacenamiento 'ISO' para el siguiente descubrimiento.</shortdesc> +<csbody> +<p>Seleccione la ubicaci��n del soporte de origen entre una de las opciones siguientes:<dl> +<dlentry> +<dt>Imagen ISO local</dt> +<dd>Seleccione esta opci��n para explorar las agrupaciones de almacenamiento en busca de im��genes ISO de instalaci��n disponibles en el sistema.</dd> +</dlentry><dlentry> +<dt>Imagen ISO remota</dt> +<dd>Seleccione esta opci��n para especificar una ubicaci��n remota para una imagen ISO de instalaci��n.</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>A��adir plantilla ��� imagen ISO local</title> +<shortdesc>A��adir una plantilla desde una imagen ISO local.</shortdesc> +<csbody> +<p>Se visualizan las im��genes ISO disponibles en el sistema.<dl><dlentry> +<dt>SO</dt> +<dd>Nombre del sistema operativo o distribuci��n.</dd> +</dlentry><dlentry> +<dt>Versi��n</dt> +<dd>Versi��n del sistema operativo o distribuci��n.</dd> +</dlentry><dlentry> +<dt>Tama��o</dt> +<dd>Tama��o de la imagen ISO.</dd> +</dlentry></dl></p> +<p>Para crear una plantilla a partir de una imagen ISO, elija entre las opciones siguientes:<ul> +<li>Seleccione una imagen ISO desde la que desea crear una plantilla y, a continuaci��n, pulse <uicontrol>Crear plantillas desde ISO seleccionada</uicontrol>.</li> +<li>Seleccione <uicontrol>Todo</uicontrol> para crear una plantilla desde cada imagen ISO en la lista y, a continuaci��n, pulse <uicontrol>Crear plantillas desde ISO seleccionada</uicontrol>.</li> +<li>Si la imagen ISO que desea utilizar no aparece en los resultados de la exploraci��n, puede seleccionar entre las opciones siguientes:<ul> +<li>Seleccione <uicontrol>Deseo utilizar un archivo ISO espec��fico</uicontrol> para especificar una v��a de acceso a la imagen ISO.</li> +<li>Pulse <uicontrol>Buscar m��s ISO</uicontrol> para buscar m��s im��genes ISO.</li> +</ul></li> +</ul></p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 229 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/fr_FR/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/Makefile.am new file mode 100644 index 0000000..11ce394 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +fr_FR_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/fr_FR + +dist_fr_FR_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/fr_FR/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/guests.dita new file mode 100644 index 0000000..ad5b4e4 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/guests.dita @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="fr-fr"> +<title>Invit��s</title> +<shortdesc>La page <wintitle>Invit��s</wintitle> r��pertorie les machines virtuelles KVM d��finies.</shortdesc> +<csbody> +<p>Pour chaque invit��, les informations suivantes sont affich��es :<dl><dlentry> +<dt>Nom</dt> +<dd>Nom de la machine virtuelle.</dd> +</dlentry><dlentry> +<dt>UC</dt> +<dd>Pourcentage d'utilisation du processeur sur la machine virtuelle.</dd> +</dlentry><dlentry> +<dt>E-S r��seau</dt> +<dd>Vitesse de transmission d'entr��e-sortie du r��seau, exprim��e en ko par seconde.</dd> +</dlentry><dlentry> +<dt>E-S disque</dt> +<dd>Vitesse de transmission d'entr��e-sortie du disque, exprim��e en ko par seconde.</dd> +</dlentry><dlentry> +<dt>Livetile</dt> +<dd>Etat de la console du syst��me d'exploitation de l'h��te, ou +ic��ne repr��sentant la distribution <tm tmtype="tm" trademark="Linux">Linux</tm> +si l'invit�� n'est pas actif.</dd> +</dlentry></dl></p> +<p>Les ic��nes d'action suivantes sont affich��es pour chaque invit�� :<dl> +<dlentry> +<dt>R��initialiser</dt> +<dd>Cliquez pour r��initialiser l'invit��. </dd> +</dlentry><dlentry> +<dt>Alimentation (D��marrer ou Arr��ter)</dt> +<dd>Cliquez pour mettre sous ou hors tension l'invit��. Si l'ic��ne est rouge, +l'alimentation est d��marr��e ; si l'ic��ne est verte, l'alimentation est arr��t��e.</dd> +</dlentry></dl> </p> +<p>Les actions suivantes peuvent ��tre s��lectionn��es pour chaque invit�� :<ul> +<li>S��lectionnez <uicontrol>Connexion</uicontrol> pour vous connecter �� la console +distante du syst��me d'exploitation invit��.</li> +<li>S��lectionnez <uicontrol>G��rer le support</uicontrol> pour modifier le chemin +d'acc��s au support d'installation.</li> +<li>S��lectionnez <uicontrol>R��initialiser</uicontrol> pour r��initialiser l'invit��.</li> +<li>S��lectionnez <uicontrol>Editer</uicontrol> pour ��diter les propri��t��s d'un invit�� existant. Les invit��s peuvent ��tre ��dit��s uniquement lorsqu'ils sont �� l'arr��t.</li> +<li>S��lectionnez <uicontrol>Supprimer</uicontrol> pour supprimer l'invit��.</li> +</ul>Pour cr��er un invit��, cliquez sur l'ic��ne <uicontrol>plus (+)</uicontrol> +dans le coin sup��rieur droit de la page.</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="fr-fr"> +<title>Cr��er une machine virtuelle</title> +<shortdesc>Cr��ez une machine virtuelle en utilisant un mod��le existant.</shortdesc> +<csbody> +<p> <ol> +<li>Entrez le nom �� utiliser pour identifier la machine virtuelle.</li> +<li rev="rev1">S��lectionnez un mod��le. <ul> +<li>Si des mod��les existent, faites un choix parmi les mod��les affich��s.</li> +<li>Si aucun mod��le n'existe, cliquez sur <uicontrol>Cr��er un mod��le</uicontrol> pour cr��er un mod��le.</li> +</ul></li> +<li>Cliquez sur <uicontrol>Cr��er</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="fr-fr"> +<title>Editer l'invit��</title> +<shortdesc>Editez les propri��t��s d'une machine virtuelle existante. Certaines propri��t��s +peuvent ��tre ��dit��es uniquement lorsque l'invit�� est arr��t��. D'autres seront appliqu��es �� l'amor��age suivant.</shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>Pour chaque invit��, les informations suivantes sont affich��es dans l'onglet <wintitle>G��n��ral</wintitle> :<dl> +<dlentry> +<dt>Nom</dt> +<dd>Nom de la machine virtuelle. (Ne peut ��tre ��dit�� que lorsque l'invit�� est arr��t��)</dd> +</dlentry><dlentry> +<dt>UC</dt> +<dd>Nombre de processeurs. (Si l'invit�� est en cours d'ex��cution, la nouvelle quantit�� sera appliqu��e �� l'amor��age suivant)</dd> +</dlentry><dlentry> +<dt>M��moire</dt> +<dd>Quantit�� de m��moire en Mo. (Si l'invit�� est en cours d'ex��cution, la nouvelle quantit�� sera appliqu��e �� l'amor��age suivant)</dd> +</dlentry><dlentry> +<dt>Ic��ne</dt> +<dd>Image graphique repr��sentant la distribution Linux �� afficher �� la place +du statut en cours (Livetile) lorsque l'invit�� n'est pas actif.</dd> +</dlentry></dl></p> +<p>Les informations suivantes sont affich��es dans l'onglet <wintitle>Stockage</wintitle>.</p> +<dl><dlentry> +<dt>Stockage</dt> +<dd>Affiche l'emplacement du fichier ISO utilis�� pour l'installation.</dd> +</dlentry></dl> +<p> Les zones qui ne sont pas d��sactiv��es peuvent ��tre ��dit��es. Apr��s que vous avez ��dit�� une zone, cliquez sur <uicontrol>Sauvegarder</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="fr-fr"> +<title>Ajoutez, remplacez ou d��tachez une unit�� de stockage</title> +<shortdesc rev="rev1">Vous pouvez ajouter, remplacer ou d��tacher une unit�� de stockage +pour votre machine virtuelle. Seule une unit�� CD-ROM est prise en charge. Pour ��diter vos unit��s de stockage, proc��dez comme suit :</shortdesc> +<csbody> +<ol> +<li>Dans la fen��tre <wintitle>Editer l'invit��</wintitle>, s��lectionnez <wintitle>Stockage</wintitle>.</li> +<li>Pour remplacer une unit�� de stockage, cliquez sur la premi��re ic��ne avec la <uicontrol>barre oblique (/) orange</uicontrol>. Entrez le chemin d'acc��s au fichier ISO et cliquez sur <uicontrol>Remplacer</uicontrol>.</li> +<li>Pour d��tacher une unit�� de stockage, cliquez sur la deuxi��me ic��ne avec le <uicontrol>tiret (-) rouge</uicontrol>. Confirmer la suppression et cliquez sur <uicontrol>OK</uicontrol>.</li> +<li>Pour ajouter une unit�� de stockage, cliquez sur la troisi��me ic��ne avec le <uicontrol>signe plus (+) vert</uicontrol>. Entrez un nom d'unit�� et un chemin d'acc��s au fichier ISO puis cliquez sur <uicontrol>Attacher</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="fr-fr"> +<title>Remplacer l'unit�� CD-ROM d'une machine virtuelle</title> +<shortdesc rev="rev1">Vous pouvez remplacer le contenu du CD-ROM pour +une machine virtuelle une fois l'installation termin��e.</shortdesc> +<csbody> +<ol> +<li>V��rifiez que la machine virtuelle est d��marr��e.</li> +<li>Dans le menu Actions, s��lectionnez <uicontrol>G��rer le support</uicontrol>.</li> +<li>Pour modifier les donn��es actuellement charg��es dans l'unit�� de CD-ROM, cliquez sur l'ic��ne +<uicontrol>barre oblique (/) orange</uicontrol> en regard de la zone hdc.</li> +<li>Sur la page <wintitle>Remplacer une unit�� CD-ROM d'une machine virtuelle</wintitle>, +entrez le chemin d'acc��s au fichier ISO. Les deux autres zones sont en lecture seule.</li> +<li>Cliquez sur <uicontrol>Remplacer</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 231 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/fr_FR/host.dita b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/host.dita new file mode 100644 index 0000000..f4c330b --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/host.dita @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="fr-fr"> +<title>H��te</title> +<shortdesc>La page <wintitle>H��te</wintitle> affiche des informations +sur le syst��me h��te et vous permet d'arr��ter, de red��marrer et de vous +connecter �� l'h��te.</shortdesc> +<csbody> +<p>Vous pouvez effectuer les actions suivantes sur l'h��te :<ul> +<li>S��lectionnez <uicontrol>Arr��ter</uicontrol> pour arr��ter le syst��me h��te.</li> +<li>S��lectionnez <uicontrol>Red��marrer</uicontrol> pour red��marrer le syst��me h��te.</li> +<li>S��lectionnez <uicontrol>Connexion</uicontrol> pour ouvrir une connexion VNC +au syst��me h��te, si celui-ci n'est pas d��j�� connect��.</li> +</ul></p> +<p>Cliquez sur les sections suivantes pour afficher des informations sur l'h��te :<dl> +<dlentry> +<dt>Informations de base</dt> +<dd>Cette section affiche la distribution, la version et le nom de code +du syst��me d'exploitation h��te, ainsi que le type de processeur et la quantit�� +de m��moire en Go.</dd> +</dlentry><dlentry> +<dt>Statistiques syst��me</dt> +<dd>Cette section affiche les graphiques des statistiques pour l'UC, m��moire, ainsi que +les E-S disque et E-S r��seau pour l'h��te. S��lectionnez <uicontrol>Collecte des donn��es une fois la page quitt��e</uicontrol> +pour continuer la collecte de donn��es lorsque l'onglet h��te n'est plus visible.</dd> +</dlentry><dlentry> +<dt>Mises �� jour logicielles</dt> +<dd>Cette section affiche des informations pour tous les modules qui +disposent de mises �� jour disponibles, y compris le nom de module, la version, l'architecture +et le r��f��rentiel. Vous pouvez mettre �� jour toutes les modules r��pertori��s en s��lectionnant <uicontrol>Tout +mettre �� jour</uicontrol>. Vous ne pouvez pas s��lectionner des modules individuels pour les mises �� jour.</dd> +</dlentry><dlentry> +<dt>R��f��rentiels</dt> +<dd>Cette section affiche les r��f��rentiels associ��s au syst��me h��te. Vous pouvez ajouter, activer, ��diter ou retirer des r��f��rentiels. L'ajout d'un r��f��rentiel associe celui-ci au syst��me h��te, +tandis que l'activation d'un r��f��rentiel permet �� l'h��te d'y acc��der. Si votre syst��me est Red Hat Enterprise Linux ou Fedora, +vous pouvez ajouter des r��f��rentiels <filepath>yum</filepath>. +Si votre syst��me est de type Ubuntu ou Debian, ajoutez des r��f��rentiels +<filepath>deb</filepath>.<p>Si vous travaillez avec des r��f��rentiels yum, vous pouvez ajouter un contr��le GPG +afin de v��rifier qu'un module provenant de ce r��f��rentiel n'a pas ��t�� endommag��. +S��lectionnez un r��f��rentiel puis cliquez sur <uicontrol>Editer</uicontrol>. S��lectionnez <uicontrol>Oui</uicontrol> pour activer le contr��le GPG, +puis entrez une URL pour le fichier de cl��s GPG du r��f��rentiel.</p></dd> +</dlentry><dlentry> +<dt>Rapports de d��bogage</dt> +<dd>Cette section affiche les rapports de d��bogage, y compris le nom et le chemin du fichier. +Vous pouvez faire un choix parmi les options afin de g��n��rer un nouveau rapport, ou renommer, supprimer, +ou t��l��charger un rapport existant.<p>Le rapport de d��bogage est g��n��r�� �� +l'aide de la commande <cmdname>sosreport</cmdname>. Cette option est disponible pour les distributions +Red Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora et Ubuntu. La commande g��n��re un fichier .tar contenant la configuration et des informations de diagnostic, +telles que la version du noyau d'ex��cution, les modules charg��s, ainsi que les fichiers de configuration +du syst��me et de la maintenance. +La commande ex��cute ��galement des programmes externes pour collecter des informations +suppl��mentaires et stocke cette sortie dans l'archive r��sultante.</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 232 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/fr_FR/network.dita b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/network.dita new file mode 100644 index 0000000..5c2e9dd --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/network.dita @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="fr-fr"> +<title>R��seau</title> +<shortdesc>La page <wintitle>R��seau</wintitle> affiche des informations sur la connexion r��seau.</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>Nom du r��seau</dt> +<dd>Nom du r��seau, ou <uicontrol>par d��faut</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Etat</dt> +<dd>Etat du r��seau, actif (vert) ou inactif (rouge). </dd> +</dlentry><dlentry> +<dt>Type de r��seau</dt> +<dd>Type du r��seau, par exemple <uicontrol>NAT</uicontrol> (conversion d'adresses r��seau).</dd> +</dlentry><dlentry> +<dt>Interface</dt> +<dd>Interface r��seau, par exemple <uicontrol>virbr0</uicontrol> (par d��faut).</dd> +</dlentry><dlentry> +<dt>Espace adresse</dt> +<dd>Adresse IP.</dd> +</dlentry></dl></p> +<p>Les actions suivantes peuvent ��tre s��lectionn��es :<ul> +<li rev="rev1">S��lectionnez <uicontrol>D��marrer</uicontrol> pour d��marrer la connexion au r��seau.</li> +<li>S��lectionnez <uicontrol>Arr��ter</uicontrol> pour mettre fin �� la connexion au r��seau.</li> +<li>S��lectionnez <uicontrol>Supprimer</uicontrol> pour supprimer les informations de connexion.</li> +</ul>Pour cr��er un r��seau, cliquez sur l'ic��ne <uicontrol>plus (+)</uicontrol> +dans le coin sup��rieur droit de l'��cran.</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="fr-fr"> +<title>Cr��er un r��seau</title> +<shortdesc>Cr��ez un r��seau.</shortdesc> +<csbody> +<p> <ol> +<li>Entrez le nom du r��seau.</li> +<li>Cliquez pour s��lectionner le type de r��seau. <dl rev="rev1"><dlentry> +<dt><uicontrol>Isol��</uicontrol></dt> +<dd>Mode isol��. Les invit��s ne peuvent pas envoyer ni recevoir de communication avec des syst��mes externes.</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>Mode de conversion d'adresses r��seau. La communication �� partir d'invit��s +vers des syst��mes externes utilise l'adresse IP h��te. Les syst��mes externes ne +peuvent pas initier de communication vers les invit��s.</dd> +</dlentry><dlentry> +<dt><uicontrol>Rout��</uicontrol></dt> +<dd>Mode rout��. Les invit��s peuvent communiquer avec des syst��mes externes et +��tre contact��s par des syst��mes externes comme s'il s'agissait de syst��mes physiques +sur le r��seau. Pour le mode rout��, vous devez sp��cifier des informations suppl��mentaires +sur la destination et le r��seau local virtuel.</dd> +</dlentry></dl></li> +<li>Cliquez sur <uicontrol>Cr��er</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 230 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/fr_FR/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/storage.dita new file mode 100644 index 0000000..eebf2bb --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/storage.dita @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="fr-fr"> +<title>Stockage</title> +<shortdesc>La page <wintitle>Stockage</wintitle> r��pertorie les pools de stockage disponibles, +y compris les pools de stockage 'default' et 'ISO' pr��ts �� l'emploi. +Si vous souhaitez utiliser votre propre pool de stockage ISO, ajoutez-le dans le chemin du pool de stockage 'ISO'.</shortdesc> +<csbody> +<p>Pour chaque pool de stockage, les informations suivantes sont affich��es :<dl> +<dlentry> +<dt>Nom</dt> +<dd>Nom du pool de stockage et pourcentage d'utilisation.</dd> +</dlentry><dlentry> +<dt>Etat</dt> +<dd>Etat du pool de stockage, actif (vert) ou inactif (rouge). </dd> +</dlentry><dlentry> +<dt>Emplacement</dt> +<dd>chemin d'acc��s au fichier pour l'emplacement du pool de stockage.</dd> +</dlentry><dlentry> +<dt>Type</dt> +<dd>Type de pool de stockage, par exemple <uicontrol>dir</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Capacit��</dt> +<dd>Quantit�� d'espace dans le pool de stockage.</dd> +</dlentry><dlentry> +<dt>Allou��</dt> +<dd>Quantit�� d'espace d��j�� allou��e dans le pool de stockage.</dd> +</dlentry></dl></p> +<p>Les actions suivantes peuvent ��tre s��lectionn��es pour chaque pool de stockage :<ul> +<li>S��lectionnez <uicontrol>Activer</uicontrol> pour activer le pool de stockage pour utilisation.</li> +<li>S��lectionnez <uicontrol>D��sactiver</uicontrol> pour d��sactiver un pool de stockage actif.</li> +<li>S��lectionnez <uicontrol>Annuler d��finition</uicontrol> pour retirer un pool de stockage inactif.</li> +</ul></p> +<p>Pour afficher les d��tails de volume de stockage pour un pool de stockage, cliquez sur la +fl��che situ��e �� droite de la ligne du pool de stockage. D��tails inclus :<dl><dlentry> +<dt>Type</dt> +<dd>Type de volume, par exemple <uicontrol>file</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Format</dt> +<dd>Format, variable selon le type.</dd> +</dlentry><dlentry> +<dt>Capacit��</dt> +<dd>Taille du volume de stockage.</dd> +</dlentry><dlentry> +<dt>Allocation</dt> +<dd>Quantit�� d'espace d��j�� allou��e dans le pool de stockage.</dd> +</dlentry></dl>Pour d��finir un pool de stockage, cliquez sur l'ic��ne <uicontrol>plus (+)</uicontrol> +dans le coin sup��rieur droit de l'��cran.</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="fr-fr"> +<title>D��finir un pool de stockage</title> +<shortdesc> D��finissez un pool de stockage.</shortdesc> +<csbody> +<p> <ol> +<li>Dans la zone <uicontrol>Nom du pool de stockage</uicontrol>, entrez le nom �� utiliser pour identifier le pool de stockage.</li> +<li>Dans la zone <uicontrol>Type de pool de stockage</uicontrol>, s��lectionnez le type : <dl><dlentry> +<dt><uicontrol>DIR</uicontrol></dt> +<dd>Indique un pool de r��pertoires. Lorsque vous s��lectionnez <uicontrol>DIR</uicontrol>, +indiquez le <uicontrol>Chemin de stockage</uicontrol> (chemin d'acc��s au fichier +du pool de stockage).</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>indique un pool de syst��mes de fichiers r��seau. Lorsque vous s��lectionnez <uicontrol>NFS</uicontrol>, +indiquez l'adresse <uicontrol>IP du serveur NFS</uicontrol> et le <uicontrol>Chemin NFS</uicontrol> (chemin d'acc��s au r��pertoire d'exportation).</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>Indique un pool bas�� sur une cible allou��e sur un serveur iSCSI. +Lorsque vous s��lectionnez <uicontrol>iSCSI</uicontrol>, indiquez l'adresse IP du <uicontrol>Serveur iSCSI</uicontrol> +et la <uicontrol>Cible</uicontrol> sur le serveur iSCSI. Vous avez la possibilit�� d'ajouter l'authentification iSCSI.</dd> +</dlentry><dlentry> +<dt><uicontrol>Logique</uicontrol></dt> +<dd>Indique un pool de stockage de volumes logiques. S��lectionnez l'emplacement de l'unit�� dans <uicontrol>Chemin d'unit��</uicontrol>.</dd> +</dlentry><dlentry> +<dt><uicontrol>Fibre Channel SCSI</uicontrol></dt> +<dd>Indique un pool bas��e sur une connexion Fibre Channel SCSI. S��lectionnez l'adaptateur SCSI �� utiliser.</dd> +</dlentry></dl></li> +<li>Cliquez sur <uicontrol>Cr��er</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 233 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/fr_FR/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/templates.dita new file mode 100644 index 0000000..a517e33 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/fr_FR/templates.dita @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="fr-fr"> +<title>Mod��les</title> +<shortdesc>La page <wintitle>Mod��les</wintitle> affiche les mod��les de machine virtuelle d��finis +pouvant ��tre utilis��s pour cr��er des h��tes KVM.</shortdesc> +<csbody> +<p>Pour chaque mod��le, les informations suivantes sont affich��es :<dl> +<dlentry> +<dt>SE</dt> +<dd>Nom du syst��me d'exploitation ou de la distribution.</dd> +</dlentry><dlentry> +<dt>Version</dt> +<dd>Version du syst��me d'exploitation ou de la distribution.</dd> +</dlentry><dlentry> +<dt>UC</dt> +<dd>Nombre de processeurs d��finis pour le mod��le.</dd> +</dlentry><dlentry> +<dt>M��moire</dt> +<dd>Quantit�� de m��moire vive �� allouer, en Mo.</dd> +</dlentry></dl></p> +<p>Les actions suivantes peuvent ��tre s��lectionn��es pour chaque mod��le :<ul> +<li>S��lectionnez <uicontrol>Editer</uicontrol> pour ��diter le mod��le.</li> +<li>S��lectionnez <uicontrol>Supprimer</uicontrol> pour supprimer le mod��le.</li> +</ul>Pour ajouter un mod��le, cliquez sur l'ic��ne <uicontrol>plus (+)</uicontrol> +dans le coin sup��rieur droit de l'��cran.</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="fr-fr"> +<title>Editer un mod��le</title> +<shortdesc>Editez un mod��le existant.</shortdesc> +<csbody> +<p>Pour chaque mod��le, les informations suivantes sont affich��es : <dl> +<dlentry> +<dt>Nom</dt> +<dd>Nom du mod��le.</dd> +</dlentry><dlentry> +<dt>Fournisseur</dt> +<dd>Nom de la soci��t�� qui a cr���� le syst��me d'exploitation ou la distribution +pour lequel/laquelle le mod��le est configur��.</dd> +</dlentry><dlentry> +<dt>Version</dt> +<dd>Version du syst��me d'exploitation ou de la distribution +pour lequel/laquelle le mod��le est configur��.</dd> +</dlentry><dlentry> +<dt>Nombre d'UC</dt> +<dd>Nombre de processeurs d��finis pour le mod��le.</dd> +</dlentry><dlentry> +<dt>M��moire</dt> +<dd>Quantit�� de m��moire en Mo �� allouer �� la machine virtuelle.</dd> +</dlentry><dlentry> +<dt>Disque</dt> +<dd>Taille du disque en Go.</dd> +</dlentry><dlentry> +<dt>CD-ROM</dt> +<dd>chemin d'acc��s au fichier pour l'emplacement du fichier ISO utilis�� pour l'installation de l'invit�� KVM.</dd> +</dlentry><dlentry> +<dt>Pool de stockage</dt> +<dd>Pool de stockage sp��cifique ou pool de stockage par d��faut.</dd> +</dlentry><dlentry> +<dt>R��seau</dt> +<dd>Interfaces r��seau par d��faut disponibles pour l'invit�� KVM. Vous pouvez +s��lectionner plusieurs r��seaux.</dd> +</dlentry></dl> Les zones qui ne sont pas d��sactiv��es peuvent ��tre ��dit��es. Apr��s que vous avez ��dit�� une zone, cliquez sur <uicontrol>Sauvegarder</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>Ajouter un mod��le</title> +<shortdesc>Ajoutez un mod��le �� partir du support source. +Vous pouvez ajouter votre propre image ISO au pool de stockage 'ISO' pour la reconnaissance suivante.</shortdesc> +<csbody> +<p>S��lectionnez l'emplacement du support source �� partir des options suivantes :<dl> +<dlentry> +<dt>Image ISO locale</dt> +<dd>S��lectionnez cette option pour rechercher dans les pools de stockage l'image d'installation ISO disponible sur le syst��me.</dd> +</dlentry><dlentry> +<dt>Image ISO distante</dt> +<dd>S��lectionnez cette option pour indiquer un emplacement distant pour une image d'installation ISO.</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>Ajouter un mod��le - Image ISO locale</title> +<shortdesc>Ajoutez un mod��le �� partir d'une image ISO locale.</shortdesc> +<csbody> +<p>Les images ISO disponibles sur le syst��me sont affich��es.<dl><dlentry> +<dt>SE</dt> +<dd>Nom du syst��me d'exploitation ou de la distribution.</dd> +</dlentry><dlentry> +<dt>Version</dt> +<dd>Version du syst��me d'exploitation ou de la distribution.</dd> +</dlentry><dlentry> +<dt>Taille</dt> +<dd>Taille de l'image ISO.</dd> +</dlentry></dl></p> +<p>Pour cr��er un mod��le �� partir d'une image ISO, choisissez parmi les options suivantes :<ul> +<li>S��lectionnez une image ISO �� partir de laquelle cr��er un mod��le, puis cliquez sur <uicontrol>Cr��er des mod��les �� partir de l'ISO s��lectionn�� </uicontrol>.</li> +<li>S��lectionnez <uicontrol>Tout</uicontrol> pour cr��er un mod��le �� partir de chaque +image ISO r��pertori��e, puis cliquez sur <uicontrol>Cr��er des mod��les �� partir de l'ISO s��lectionn��</uicontrol>.</li> +<li>Si l'image ISO que vous souhaitez utiliser ne figure pas dans les r��sultats +d'analyse, vous pouvez faire un choix parmi les options suivantes :<ul> +<li>S��lectionnez <uicontrol>Je souhaite utiliser un fichier ISO sp��cifique</uicontrol> pour +sp��cifier un chemin d'acc��s �� l'image ISO.</li> +<li>Cliquez sur <uicontrol>Rechercher d'autres images ISO</uicontrol> pour rechercher des images ISO suppl��mentaires.</li> +</ul></li> +</ul></p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 229 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/it_IT/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/it_IT/Makefile.am new file mode 100644 index 0000000..62e2f29 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/it_IT/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +it_IT_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/it_IT + +dist_it_IT_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/it_IT/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/it_IT/guests.dita new file mode 100644 index 0000000..e05db7e --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/it_IT/guests.dita @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="it-it"> +<title>Guest</title> +<shortdesc>La pagina <wintitle>Guest</wintitle> elenca le macchine virtuali +KVM definite.</shortdesc> +<csbody> +<p>Per ciascuna macchina guest vengono visualizzate le seguenti informazioni:<dl><dlentry> +<dt>Nome</dt> +<dd>Il nome della macchina virtuale.</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>La percentuale di utilizzo del processore nella macchina virtuale.</dd> +</dlentry><dlentry> +<dt>I/O di rete</dt> +<dd>La velocit�� di trasmissione dell'input/output di rete in KB al secondo.</dd> +</dlentry><dlentry> +<dt>I/O disco</dt> +<dd>La velocit�� di trasmissione dell'input/output disco in KB al secondo.</dd> +</dlentry><dlentry> +<dt>Riquadro animato</dt> +<dd>Lo stato della console del sistema operativo della macchina guest o un'icona che rappresenta la distribuzione <tm tmtype="tm" trademark="Linux">Linux</tm> se la macchina guest non �� attiva.</dd> +</dlentry></dl></p> +<p>Per ciascuna macchina guest vengono visualizzate le icone di azioni indicate di seguito:<dl> +<dlentry> +<dt>Reimposta</dt> +<dd>Fare clic qui per reimpostare la macchina guest. </dd> +</dlentry><dlentry> +<dt>Alimentazione (Avvia o Arresta)</dt> +<dd>Fare clic qui per accendere o spegnere la macchina guest. Se l'icona �� rossa, la macchina �� spenta, se �� verde �� accesa.</dd> +</dlentry></dl> </p> +<p>Per ciascuna macchina guest �� possibile selezionare le azioni indicate di seguito:<ul> +<li>Selezionare <uicontrol>Connetti</uicontrol> per effettuare la connessione alla console remota per il sistema operativo della macchina guest.</li> +<li>Selezionare <uicontrol>Gestisci supporti</uicontrol> per modificare il percorso al supporto di installazione.</li> +<li>Selezionare <uicontrol>Reimposta</uicontrol> per reimpostare la macchina guest.</li> +<li>Selezionare <uicontrol>Modifica</uicontrol> per modificare le propriet����di una macchina guest esistente. �� possibile modificare le macchine guest solo se sono arrestate.</li> +<li>Selezionare <uicontrol>Elimina</uicontrol> per eliminare la macchina guest.</li> +</ul>Per creare una macchina guest, o macchina virtuale, fare clic sull'icona <uicontrol>pi�� +(+)</uicontrol> nella parte in alto a destra della pagina.</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="it-it"> +<title>Creare una macchina virtuale</title> +<shortdesc>Creare una macchina virtuale utilizzando un modello esistente.</shortdesc> +<csbody> +<p> <ol> +<li>Immettere il nome da utilizzare per identificare la macchina virtuale.</li> +<li rev="rev1">Selezionare un modello. <ul> +<li>Se il modello esiste, selezionarlo dai modelli visualizzati.</li> +<li>Se non esiste alcun modello, fare clic su <uicontrol>Crea un modello</uicontrol> per crearne uno.</li> +</ul></li> +<li>Fare clic su <uicontrol>Crea</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="it-it"> +<title>Modifica macchina guest</title> +<shortdesc>Modificare le propriet�� di una macchina virtuale esistente. Alcune propriet�� possono essere +modificate solo mentre la macchina guest �� arrestata. Altre diventeranno effettive al prossimo avvio.</shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>Per ciascuna macchina guest vengono visualizzate le seguenti informazioni sulla scheda <wintitle>Generale</wintitle>:<dl> +<dlentry> +<dt>Nome</dt> +<dd>Il nome della macchina virtuale. (Pu�� essere modificato solo mentre la macchina guest �� arrestata)</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>Il numero di processori. (Se la macchina guest �� in esecuzione, la nuova quantit�� diventer�� effettiva +al prossimo avvio)</dd> +</dlentry><dlentry> +<dt>Memoria</dt> +<dd>La quantit�� di memoria in MB. (Se la macchina guest �� in esecuzione, la nuova quantit�� diventer�� effettiva +al prossimo avvio)</dd> +</dlentry><dlentry> +<dt>Icona</dt> +<dd>L'immagine grafica che rappresenta la distribuzione Linux da visualizzare al posto dello stato corrente (Riquadro animato) quando la macchina guest non �� attiva.</dd> +</dlentry></dl></p> +<p>Sulla scheda <wintitle>Memoria</wintitle> vengono visualizzate le seguenti informazioni.</p> +<dl><dlentry> +<dt>Memoria</dt> +<dd>Visualizza l'ubicazione del file ISO utilizzato per l'installazione.</dd> +</dlentry></dl> +<p> I campi non disabilitati possono essere modificati. Dopo aver modificato un campo, fare clic su <uicontrol>Salva</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="it-it"> +<title>Aggiungere, sostituire o scollegare un dispositivo di memoria.</title> +<shortdesc rev="rev1">�� possibile aggiungere, sostituire o scollegare un dispositivo di memoria per la macchina virtuale. L'unico dispositivo supportato �� CDROM. Per modificare i dispositivi di memoria, attenersi alla seguente procedura:</shortdesc> +<csbody> +<ol> +<li>Nella finestra <wintitle>Modifica macchina guest</wintitle>, selezionare <wintitle>Memoria</wintitle>.</li> +<li>Per sostituire un dispositivo di memoria, fare clic sulla prima icona con la <uicontrol>barra (/) arancione</uicontrol>. Immettere il percorso del file ISO e fare clic su <uicontrol>Sostituisci</uicontrol>.</li> +<li>Per scollegare un dispositivo di memoria, fare clic sulla seconda icona con il <uicontrol>trattino (-) rosso</uicontrol>. Confermare l'eliminazione facendo clic su <uicontrol>OK</uicontrol>.</li> +<li>Per aggiungere un dispositivo di memoria, fare clic sulla terza icona con il <uicontrol>segno pi�� (+)</uicontrol> verde. Immettere un nome dispositivo e percorso file ISO e fare clic su <uicontrol>Collega</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="it-it"> +<title>Sostituisci un CDROM della macchina virtuale</title> +<shortdesc rev="rev1">�� possibile sostituire il contenuto del CDROM per una macchina virtuale dopo il completamento dell'installazione.</shortdesc> +<csbody> +<ol> +<li>Assicurarsi che la macchina virtuale sia avviata.</li> +<li>Dal menu Azioni, selezionare <uicontrol>Gestisci supporti</uicontrol>.</li> +<li>Per modificare il contenuto correntemente caricato sul CDROM, fare clic sull'icona della <uicontrol>barra (/) arancione</uicontrol> accanto al campo hdc.</li> +<li>Sulla pagina <wintitle>Sostituisci un CDROM della macchina virtuale</wintitle>, immettere il percorso del file ISO. Gli altri due campi sono di sola lettura.</li> +<li>Fare clic su <uicontrol>Sostituisci</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 231 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/it_IT/host.dita b/src/wok/plugins/kimchi/ui/pages/help/it_IT/host.dita new file mode 100644 index 0000000..63d3367 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/it_IT/host.dita @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="it-it"> +<title>Host</title> +<shortdesc>La pagina <wintitle>Host</wintitle> visualizza le informazioni sul sistema host e consente di arrestarlo, riavviarlo e connettersi ad esso.</shortdesc> +<csbody> +<p>�� possibile effettuare le seguenti operazioni sull'host:<ul> +<li>Selezionare <uicontrol>Arresta</uicontrol> per arrestare il sistema host.</li> +<li>Selezionare <uicontrol>Riavvia</uicontrol> per riavviare il sistema host.</li> +<li>Selezionare <uicontrol>Connetti</uicontrol> per aprire una connessione VNC al sistema host, se non �� gi�� connesso.</li> +</ul></p> +<p>Fare clic sulle seguenti sezioni per visualizzare le informazioni sull'host:<dl> +<dlentry> +<dt>Informazioni di base</dt> +<dd>Questa sezione visualizza il nome codice, la versione e la distribuzione del sistema operativo, come pure il tipo di processore e la quantit�� di memoria in GB.</dd> +</dlentry><dlentry> +<dt>Statistiche di sistema</dt> +<dd>Questa sezione visualizza i grafici che mostrano le statistiche per la CPU, la memoria, l'I/O disco e di rete per l'host. Selezionare <uicontrol>Raccolta dati all'uscita dalla pagina</uicontrol> per continuare la raccolta dei dati quando la scheda host non �� pi�� visibile.</dd> +</dlentry><dlentry> +<dt>Aggiornamenti del software</dt> +<dd>Questa sezione visualizza le informazioni per tutti i pacchetti per cui sono disponibili gli aggiornamenti, incluso il nome, la versione, l'architettura e il repository del pacchetto. �� possibile aggiornare tutti i pacchetti elencati, selezionando <uicontrol>Aggiorna tutto</uicontrol>. Non �� possibile selezionare singoli pacchetti per gli aggiornamenti.</dd> +</dlentry><dlentry> +<dt>Repository</dt> +<dd>Questa sezione visualizza i repository associati al sistema host. �� possibile aggiungere, abilitare, modificare o rimuovere i repository. L'aggiunta di un repository lo associa al sistema host, mentre l'abilitazione di un repository +consente all'host di accedervi. Se il sistema �� Red Hat Enterprise +Linux o Fedora, �� possibile aggiungere i repository <filepath>yum</filepath>. +Se il sistema �� Ubuntu o Debian, aggiungere i repository <filepath>deb</filepath>.<p>Se si stanno utilizzando i repository yum, �� possibile aggiungere un controllo GPG per verificare che un pacchetto da questo repository non sia stato corrotto. +Selezionare un repository, quindi <uicontrol>Modifica</uicontrol>. Selezionare <uicontrol>S��</uicontrol> per abilitare il controllo GPG, quindi immettere un URL al file di chiavi GPG per il +repository.</p></dd> +</dlentry><dlentry> +<dt>Report di debug</dt> +<dd>Questa sezione visualizza i report di debug, incluso il nome e il percorso file. +Le opzioni disponibili consentono di generare un nuovo report oppure ridenominare, rimuovere o scaricare un report esistente.<p>Il report di debug viene generato utilizzando il comando <cmdname>sosreport</cmdname>. �� disponibile per le distribuzioni Red +Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora e Ubuntu. Il comando genera un file .tar che contiene informazioni di diagnostica e configurazione, come la versione del kernel in esecuzione, i moduli caricati e i file di configurazione del servizio e del sistema. +Il comando esegue anche programmi esterni per raccogliere ulteriori informazioni e memorizza l'output nell'archivio risultante.</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 232 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/it_IT/network.dita b/src/wok/plugins/kimchi/ui/pages/help/it_IT/network.dita new file mode 100644 index 0000000..a396d58 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/it_IT/network.dita @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="it-it"> +<title>Rete</title> +<shortdesc>La pagina <wintitle>Rete</wintitle> visualizza le informazioni sulla connessione di rete.</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>Nome rete</dt> +<dd>Il nome della rete o il <uicontrol>valore predefinito</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Stato</dt> +<dd>Lo stato della rete, attivo (verde) o non attivo (rosso). </dd> +</dlentry><dlentry> +<dt>Tipo di rete</dt> +<dd>I tipo di rete, ad esempio, <uicontrol>NAT</uicontrol> (network +address translation).</dd> +</dlentry><dlentry> +<dt>Interfaccia</dt> +<dd>L'interfaccia di rete, ad esempio, <uicontrol>virbr0</uicontrol> (valore predefinito).</dd> +</dlentry><dlentry> +<dt>Spazio indirizzo</dt> +<dd>L'indirizzo IP.</dd> +</dlentry></dl></p> +<p>�� possibile selezionare le seguenti azioni:<ul> +<li rev="rev1">Selezionare <uicontrol>Avvia</uicontrol> per iniziare la connessione di rete.</li> +<li>Selezionare <uicontrol>Arresta</uicontrol> per terminare la connessione di rete.</li> +<li>Selezionare <uicontrol>Elimina</uicontrol> per eliminare le informazioni di connessione.</li> +</ul>Per creare una rete fare clic sull'icona <uicontrol>pi�� +(+)</uicontrol> nella parte in alto a destra del pannello.</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="it-it"> +<title>Crea una rete</title> +<shortdesc>Creare una rete.</shortdesc> +<csbody> +<p> <ol> +<li>Immettere il nome della rete.</li> +<li>Fare clic per selezionare il tipo di rete. <dl rev="rev1"><dlentry> +<dt><uicontrol>Isolata</uicontrol></dt> +<dd>La modalit�� isolata. Le macchine guest non possono inviare o ricevere comunicazioni verso o da i sistemi esterni.</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>La modalit�� NAT (Network Address Translation). La comunicazione dalle macchine guest ai sistemi esterni utilizza l'indirizzo IP host. I sistemi esterni non possono iniziare la comunicazione con le macchine guest.</dd> +</dlentry><dlentry> +<dt><uicontrol>Con bridge</uicontrol></dt> +<dd>La modalit�� con bridge. Le macchine guest possono comunicare con i sistemi esterni ed essere contattate dai sistemi esterni come se fossero sistemi fisici sulla rete. Per la modalit�� con bridge, �� necessario specificare informazioni aggiuntive su destinazione e VLAN.</dd> +</dlentry></dl></li> +<li>Fare clic su <uicontrol>Crea</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 230 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/it_IT/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/it_IT/storage.dita new file mode 100644 index 0000000..5a9bc25 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/it_IT/storage.dita @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="it-it"> +<title>Memoria</title> +<shortdesc>La pagina <wintitle>Memoria</wintitle> elenca i pool di memoria +disponibili, compresi i pool di memoria pronti per l'uso 'default' e 'ISO'. +Se si desidera utilizzare un proprio ISO, aggiungerlo al percorso del pool di memoria 'ISO'.</shortdesc> +<csbody> +<p>Per ciascun pool di memoria vengono visualizzate le seguenti informazioni:<dl> +<dlentry> +<dt>Nome</dt> +<dd>Il nome del pool di memoria e la percentuale utilizzata.</dd> +</dlentry><dlentry> +<dt>Stato</dt> +<dd>Lo stato del pool di memoria, attivo (verde) o non attivo (rosso). </dd> +</dlentry><dlentry> +<dt>Ubicazione</dt> +<dd>Il percorso file all'ubicazione del pool di memoria.</dd> +</dlentry><dlentry> +<dt>Tipo</dt> +<dd>Il tipo di pool di memoria, ad esempio, <uicontrol>dir</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Capacit��</dt> +<dd>La quantit�� di spazio nel pool di memoria.</dd> +</dlentry><dlentry> +<dt>Assegnato</dt> +<dd>La quantit�� di spazio gi�� assegnato nel pool di memoria.</dd> +</dlentry></dl></p> +<p>Per ciascun pool di memoria �� possibile selezionare le azioni indicate di seguito:<ul> +<li>Selezionare <uicontrol>Attiva</uicontrol> per attivare il pool di memoria in modo da poterlo utilizzare.</li> +<li>Selezionare <uicontrol>Disattiva</uicontrol> per disattivare un pool di memoria attivo.</li> +<li>Selezionare <uicontrol>Rimuovi definizione</uicontrol> per rimuovere un pool di memoria non attivo.</li> +</ul></p> +<p>Per visualizzare i dettagli del volume di memoria per un pool di memoria, fare clic sulla freccia sul lato destro della riga del pool di memoria. I dettagli includono:<dl><dlentry> +<dt>Tipo</dt> +<dd>Il tipo di volume, ad esempio, <uicontrol>file</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Formato</dt> +<dd>Il formato, che varia in base al tipo.</dd> +</dlentry><dlentry> +<dt>Capacit��</dt> +<dd>La dimensione del volume di memoria.</dd> +</dlentry><dlentry> +<dt>Assegnazione</dt> +<dd>La quantit�� di spazio gi�� assegnato nel pool di memoria.</dd> +</dlentry></dl>Per definire un pool di memoria fare clic sull'icona <uicontrol>pi�� +(+)</uicontrol> nella parte in alto a destra del pannello.</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="it-it"> +<title>Definire un pool di memoria</title> +<shortdesc> Definire un pool di memoria.</shortdesc> +<csbody> +<p> <ol> +<li>Nel campo <uicontrol>Nome pool di memoria</uicontrol>, immettere i l nome da utilizzare per definire il pool di memoria.</li> +<li>Nell'elenco <uicontrol>Tipo pool di memoria</uicontrol>, selezionare il tipo: <dl><dlentry> +<dt><uicontrol>DIR</uicontrol></dt> +<dd>Specifica un pool directory. Quando si seleziona <uicontrol>DIR</uicontrol>, +immettere il <uicontrol>Percorso di memoria</uicontrol> (percorso file al pool di memoria).</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>Specifica un pool NFS (Network File System). Quando si seleziona <uicontrol>NFS</uicontrol>, +immettere l'indirizzo <uicontrol>IP del server NFS</uicontrol> e il <uicontrol>Percorso NFS</uicontrol> (percorso alla directory esportata).</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>Specifica un pool basato su una destinazione assegnata su un server iSCSI. +Quando si seleziona <uicontrol>iSCSI</uicontrol>, immettere l'indirizzo IP del <uicontrol>Server iSCSI</uicontrol> e la <uicontrol>Destinazione</uicontrol> sul server iSCSI. �� possibile, facoltativamente, selezionare di aggiungere l'autenticazione iSCSI.</dd> +</dlentry><dlentry> +<dt><uicontrol>Logico</uicontrol></dt> +<dd>Specifica un pool di memoria di tipo volume logico. Selezionare l'ubicazione del dispositivo in <uicontrol>Percorso dispositivo</uicontrol>.</dd> +</dlentry><dlentry> +<dt><uicontrol>Canale a fibre ottiche SCSI</uicontrol></dt> +<dd>Specifica un pool basato su un canale a fibre ottiche SCSI. Selezionare quale adattatore +SCSI utilizzare.</dd> +</dlentry></dl></li> +<li>Fare clic su <uicontrol>Crea</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 233 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/it_IT/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/it_IT/templates.dita new file mode 100644 index 0000000..9b84b16 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/it_IT/templates.dita @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="it-it"> +<title>Modelli</title> +<shortdesc>La pagina <wintitle>Modelli</wintitle> visualizza i modelli di macchina virtuale definiti che �� possibile utilizzare per creare macchine guest KVM.</shortdesc> +<csbody> +<p>Per ciascun modello vengono visualizzate le seguenti informazioni:<dl> +<dlentry> +<dt>SO</dt> +<dd>Il nome del sistema operativo o della distribuzione.</dd> +</dlentry><dlentry> +<dt>Versione</dt> +<dd>La versione del sistema operativo o della distribuzione.</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>Il numero di processori definiti per il modello.</dd> +</dlentry><dlentry> +<dt>Memoria</dt> +<dd>La quantit�� di memoria ad accesso casuale da assegnare, in MB.</dd> +</dlentry></dl></p> +<p>Per ciascun modello �� possibile selezionare le azioni indicate di seguito:<ul> +<li>Selezionare <uicontrol>Modifica</uicontrol> per modificare il modello.</li> +<li>Selezionare <uicontrol>Elimina</uicontrol> per eliminare il modello.</li> +</ul>Per aggiungere un modello fare clic sull'icona <uicontrol>pi�� +(+)</uicontrol> nella parte in alto a destra del pannello.</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="it-it"> +<title>Modifica modello</title> +<shortdesc>Modificare un modello esistente.</shortdesc> +<csbody> +<p>Per ciascun modello vengono visualizzate le seguenti informazioni: <dl> +<dlentry> +<dt>Nome</dt> +<dd>Il nome del modello.</dd> +</dlentry><dlentry> +<dt>Fornitore</dt> +<dd>Il nome della societ�� che ha creato il sistema operativo o la distribuzione per il cui utilizzo �� configurato il modello.</dd> +</dlentry><dlentry> +<dt>Versione</dt> +<dd>La versione del sistema operativo o della distribuzione per il cui utilizzo �� configurato il modello.</dd> +</dlentry><dlentry> +<dt>Numero CPU</dt> +<dd>Il numero di processori definiti per il modello.</dd> +</dlentry><dlentry> +<dt>Memoria</dt> +<dd>La quantit�� di memoria in MB da assegnare alla macchina virtuale.</dd> +</dlentry><dlentry> +<dt>Disco</dt> +<dd>La dimensione del disco in GB.</dd> +</dlentry><dlentry> +<dt>CDROM</dt> +<dd>Il percorso file all'ubicazione del file ISO utilizzato per installare la macchina guest +KVM.</dd> +</dlentry><dlentry> +<dt>Pool di memoria</dt> +<dd>Un pool di memoria specifico o quello predefinito.</dd> +</dlentry><dlentry> +<dt>Rete</dt> +<dd>Le interfacce di rete predefinite disponibili per la macchina guest KVM. �� possibile selezionare pi�� reti.</dd> +</dlentry></dl> I campi non disabilitati possono essere modificati. Dopo aver modificato un campo, fare clic su <uicontrol>Salva</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>Aggiungi modello</title> +<shortdesc>Aggiungere un modello dal supporto di origine. +�� possibile aggiungere una propria immagine ISO al pool di memoria 'ISO' per la seguente individuazione.</shortdesc> +<csbody> +<p>Selezionare l'ubicazione del supporto di origine dalle seguenti opzioni:<dl> +<dlentry> +<dt>Immagine ISO locale</dt> +<dd>Selezionare questa opzione per eseguire la scansione dei pool di memoria alla ricerca di immagini ISO di installazione disponibili sul sistema.</dd> +</dlentry><dlentry> +<dt>Immagine ISO remota</dt> +<dd>Selezionare questa opzione per specificare un'ubicazione remota per un'immagine ISO di installazione.</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>Aggiungi modello - Immagine ISO locale</title> +<shortdesc>Aggiungere un modello da un'immagine ISO locale.</shortdesc> +<csbody> +<p>Vengono visualizzate le immagini ISO disponibili sul sistema.<dl><dlentry> +<dt>SO</dt> +<dd>Il nome del sistema operativo o della distribuzione.</dd> +</dlentry><dlentry> +<dt>Versione</dt> +<dd>La versione del sistema operativo o della distribuzione.</dd> +</dlentry><dlentry> +<dt>Dimensione</dt> +<dd>La dimensione dell'immagine ISO.</dd> +</dlentry></dl></p> +<p>Per creare un modello da un'immagine ISO scegliere tra le seguenti opzioni:<ul> +<li>Selezionare un'immagine ISO da cui creare un modello, quindi fare clic su <uicontrol>Crea modelli da ISO selezionato</uicontrol>.</li> +<li>Selezionare <uicontrol>Tutti</uicontrol> per creare un modello da ciascuna immagine ISO elencata, quindi fare clic su <uicontrol>Crea modelli da ISO selezionato</uicontrol>.</li> +<li>Se nei risultati della scansione non viene visualizzata l'immagine ISO che si desidera utilizzare, �� possibile selezionare dalle seguenti opzioni:<ul> +<li>Selezionare <uicontrol>Utilizzare un file ISO specifico</uicontrol> per specificare un percorso all'immagine ISO.</li> +<li>Fare clic su <uicontrol>Ricerca pi�� ISO</uicontrol> per ricercare pi�� immagini +ISO.</li> +</ul></li> +</ul></p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 229 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ja_JP/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/Makefile.am new file mode 100644 index 0000000..f9c2f33 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +ja_JP_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/ja_JP + +dist_ja_JP_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/ja_JP/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/guests.dita new file mode 100644 index 0000000..5dade49 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/guests.dita @@ -0,0 +1,172 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="ja-jp"> +<title>���������</title> +<shortdesc><wintitle>���������������</wintitle>������������������������������ KVM ������������������������������������������ +</shortdesc> +<csbody> +<p>������������������������������������������������������������ +<dl><dlentry> +<dt>������</dt> +<dd>��������������������������� +</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>��������������������������������������������������������� +</dd> +</dlentry><dlentry> +<dt>���������������������������</dt> +<dd>������������������������������������ (KB/���)��� +</dd> +</dlentry><dlentry> +<dt>���������������������</dt> +<dd>������������������������������ (KB/���)��� +</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>������������������������������������������������������������������������������������������������������������������������������������������<tm tmtype="tm" trademark="Linux">Linux</tm> +��������������������������������������������������������� +</dd> +</dlentry></dl></p> +<p>������������������������������������������������������������������������������������ +<dl> +<dlentry> +<dt>������������</dt> +<dd>������������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt>������ (���������������������)</dt> +<dd>��������������������������������������������������������������������������� +������������������������������������������������������������������������������������������������������������������������ +</dd> +</dlentry></dl> </p> +<p>��������������������������������������������������������������������� +<ul> +<li>������������������������������������������������������������������������������������������������������������<uicontrol>������������</uicontrol>��������������������� +</li> +<li>������������������������������������������������������������������<uicontrol>���������������������������</uicontrol>��������������������� +</li> +<li>������������������������������������<uicontrol>������������������</uicontrol>��������������������� +</li> +<li>���������������������������������������������������������������<uicontrol>������������</uicontrol>��������������������� +��������������������������������������������������������������� +</li> +<li>������������������������������<uicontrol>������������</uicontrol>��������������������� +</li> +</ul>��������� (���������������) ���������������������������������������������������<uicontrol>��������� (+)</uicontrol> ������������������������������������������������ +</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="ja-jp"> +<title>������������������������</title> +<shortdesc>��������������������������������������������������������������������������������������������������� +</shortdesc> +<csbody> +<p> <ol> +<li>������������������������������������������������������������������ +</li> +<li rev="rev1">��������������������������������������� +<ul> +<li>������������������������������������������������������������������������������������������������������������ +</li> +<li>������������������������������������������������<uicontrol>���������������������������������</uicontrol>������������������������������������������������������������ +</li> +</ul></li> +<li><uicontrol>������������</uicontrol>������������������������������������ +</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="ja-jp"> +<title>������������������</title> +<shortdesc>������������������������������������������������������������������ +������������������������������������������������������������������������������������������������ +������������������������������������������������������������������������������������������</shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>���������������������������������������<wintitle>������������</wintitle>������������������������������ +<dl> +<dlentry> +<dt>������</dt> +<dd>��������������������������� +(������������������������������������������������������)</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>��������������������������� +(���������������������������������������������������������������������������������������)</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������������ (MB ������)��� +(���������������������������������������������������������������������������������������)</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>��������������������������������������������������������������� (������������������) ���������������������������Linux ������������������������������������������������������������������������������ +</dd> +</dlentry></dl></p> +<p>���������������<wintitle>���������������������</wintitle>������������������������������ +</p> +<dl><dlentry> +<dt>���������������</dt> +<dd>������������������������������������ ISO ������������������������������������������������������ +</dd> +</dlentry></dl> +<p> ������������������������������������������������������������������������ +������������������������������������<uicontrol>������������</uicontrol>������������������������������������ +</p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="ja-jp"> +<title>������������������������������������������������������������������������</title> +<shortdesc rev="rev1">������������������������������������������������������������������������������������������������������������������������������������������������������ +������������������������������������������ CDROM ��������������� +������������������������������������������������������������������������������������������������ +</shortdesc> +<csbody> +<ol> +<li><wintitle>������������������������</wintitle>������������������<wintitle>���������������������</wintitle>��������������������� +</li> +<li>������������������������������������������������������<uicontrol>������������������������������ (/)</uicontrol> ��������������������������������������������������������������������� +ISO ������������������������������������<uicontrol>������������</uicontrol>��������������������������� +</li> +<li>������������������������������������������������������<uicontrol>������������������ (-)</uicontrol> ������������ 2 ��������������������������������������������������������� +���������������������<uicontrol>���OK���</uicontrol>��������������������������� +</li> +<li>������������������������������������������������������<uicontrol>��������������� (+)</uicontrol> ������������ 3 ��������������������������������������������������������� +������������������ ISO ������������������������������������<uicontrol>������������</uicontrol>��������������������������� +</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="ja-jp"> +<title>VM ��� CDROM ���������</title> +<shortdesc rev="rev1">������������������������������������������������������������ CDROM ������������������������������������������������ +</shortdesc> +<csbody> +<ol> +<li>��������������������������������������������������������������� +</li> +<li>���������������������������������������<uicontrol>���������������������������</uicontrol>��������������������� +</li> +<li>CDROM ���������������������������������������������������������hdc ������������������������������<uicontrol>������������������������������ (/)</uicontrol> ��������������������������������������� +</li> +<li><wintitle>���VM ��� CDROM ������������</wintitle>���������������ISO ������������������������������������������ +��������������� 2 ��������������������������������������������������� +</li> +<li><uicontrol>������������</uicontrol>������������������������������������ +</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 231 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ja_JP/host.dita b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/host.dita new file mode 100644 index 0000000..3a0141c --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/host.dita @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="ja-jp"> +<title>���������</title> +<shortdesc><wintitle>���������������</wintitle>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ +</shortdesc> +<csbody> +<p>��������������������������������������������������������������������� +<ul> +<li>������������������������������������������������������������<uicontrol>���������������������������</uicontrol>��������������������� +</li> +<li>������������������������������������������������<uicontrol>���������������</uicontrol>��������������������� +</li> +<li>������������������������������ VNC ��������� (���������������������������������������) ���������������������������<uicontrol>������������</uicontrol>��������������������� +</li> +</ul></p> +<p>������������������������������������������������������������������������������������������������������������ +<dl> +<dlentry> +<dt>������������</dt> +<dd>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ (GB ������) ������������������������ +</dd> +</dlentry><dlentry> +<dt>������������������������</dt> +<dd>������������������������������������������ CPU��������������������������������������������������������������������������������������������������������������������������������������� +���������������������������������������������������������������������������������<uicontrol>���������������������������������������������������������������</uicontrol>������������������������������ +</dd> +</dlentry><dlentry> +<dt>������������������������</dt> +<dd>��������������������������������������������������������������������������������������������� +(������������������������������������������������������������������������������������������) ������������������������ +<uicontrol>���������������������</uicontrol>��������������������������������������������������������������������������������������������� +��������������������������������������������������������������������������������������������� +</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>������������������������������������������������������������������������������������������������������������������������������ +������������������������������������������������������������������������������������������������������������������ +������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ +��������������� Red Hat Enterprise Linux ��������� Fedora ���������������<filepath>yum</filepath> ������������������������������������������ +��������������� Ubuntu ��������� Debian ���������������<filepath>deb</filepath> ������������������������������������������������ +<p>yum ������������������������������������������������������������������������������������������������������������������������������������������������������������GPG ������������������������������������ +���������������������������������<uicontrol>������������</uicontrol>������������������������������������ +<uicontrol>������������</uicontrol>��������������� GPG ������������������������������������������������������������������ GPG ������������������ URL ������������������������������ +</p></dd> +</dlentry><dlentry> +<dt>���������������������������</dt> +<dd>��������������������������������������������������������� (������������������������������������) ������������������������ +������������������������������������������������������������������������������������������������������������������������������������������������������������������ +<p>���������������������������������<cmdname>sosreport</cmdname> ������������������������������������ +������������Red Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>���Fedora������������ Ubuntu ��������������������������������������������������������������� +��������������������������������������������������� (������������������������������������������������������������������������������������������������������������������������������������������������) ������������ .tar ��������������������������������� +������������������������������������������������������������������������������������������������������������������������������������������������������������ +</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 227 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ja_JP/network.dita b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/network.dita new file mode 100644 index 0000000..5d9ce05 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/network.dita @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="ja-jp"> +<title> ������������������</title> +<shortdesc><wintitle>������������������������</wintitle>������������������������������������������������������������������������������������ +</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>���������������������</dt> +<dd>��������������������������� (��������� <uicontrol>default</uicontrol>) ��������� +</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������������������ (���) ��������������������������� (���) ��������� +</dd> +</dlentry><dlentry> +<dt>������������������������������</dt> +<dd>��������������������������������������������� <uicontrol>NAT</uicontrol> (���������������������������������������) ��������� +</dd> +</dlentry><dlentry> +<dt>������������������������</dt> +<dd>������������������������������������������������������������ <uicontrol>virbr0</uicontrol> (���������������) ��������� +</dd> +</dlentry><dlentry> +<dt>���������������������������</dt> +<dd>IP ���������������</dd> +</dlentry></dl></p> +<p>������������������������������������������������ +<ul> +<li rev="rev1">���������������������������������������������<uicontrol>������������</uicontrol>��������������������� +</li> +<li>���������������������������������������������<uicontrol>������������</uicontrol>��������������������� +</li> +<li>���������������������������������<uicontrol>������������</uicontrol>��������������������� +</li> +</ul>������������������������������������������������������������������<uicontrol>��������� (+)</uicontrol> ������������������������������������������������ +</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="ja-jp"> +<title>���������������������������</title> +<shortdesc>��������������������������������������� +</shortdesc> +<csbody> +<p> <ol> +<li>������������������������������������������������ +</li> +<li>��������������������������������������������������������������������� +<dl rev="rev1"><dlentry> +<dt><uicontrol>������</uicontrol></dt> +<dd>������������������ +��������������������������������������������������������������������������������������� +</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>��������������������������������������������������� +������������������������������������������������������������ IP ������������������������������������ +������������������������������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt><uicontrol>������������</uicontrol></dt> +<dd>��������������������������� +������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ +������������������������������������������������ VLAN ������������������������������������������������������ +</dd> +</dlentry></dl></li> +<li><uicontrol>������������</uicontrol>������������������������������������ +</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 230 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ja_JP/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/storage.dita new file mode 100644 index 0000000..f975e7a --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/storage.dita @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="ja-jp"> +<title>���������������</title> +<shortdesc><wintitle>���������������������</wintitle>��������������������������������� +��������������������������� (������������������������default������������������������������������ISO���������������������������������������) ��������������������������� +��������� ISO ���������������������������������������ISO���������������������������������������������������������������������</shortdesc> +<csbody> +<p>������������������������������������������������������������������������������ +<dl> +<dlentry> +<dt>������</dt> +<dd>��������������������������������������������������������� +</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>��������������������������������������������������������� (���) ��������������������������� (���) ��������� +</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>��������������������������������������������������������������������������� +</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������������������������������������������������������ <uicontrol>dir</uicontrol> ��������� +</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>������������������������������������������������������������������������������������ +</dd> +</dlentry></dl></p> +<p>��������������������������������������������������������������������������������������� +<ul> +<li>������������������������������������������������������������������������������������<uicontrol>������������������������������</uicontrol>��������������������� +</li> +<li>������������������������������������������������������������������������������������<uicontrol>���������������������������������</uicontrol>��������������������� +</li> +<li>������������������������������������������������������������������������<uicontrol>���������������������������</uicontrol>��������������������� +</li> +</ul></p> +<p>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� +������������������������������������ +<dl><dlentry> +<dt>���������</dt> +<dd>������������������������������������������ <uicontrol>file</uicontrol> ��������� +</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>��������������������������������������������������� +</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������������������������������������������������������������������������������ +</dd> +</dlentry></dl>���������������������������������������������������������������������������<uicontrol>��������� (+)</uicontrol> ������������������������������������������������ +</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="ja-jp"> +<title>������������������������������������</title> +<shortdesc> ������������������������������������������������ +</shortdesc> +<csbody> +<p> <ol> +<li><uicontrol>������������������������������������</uicontrol>��������������������������������������������������������������������������������������������������� +</li> +<li><uicontrol>���������������������������������������������</uicontrol>��������������������������������������������������������� +<dl><dlentry> +<dt><uicontrol>DIR</uicontrol></dt> +<dd>������������������������������������������������������ +<uicontrol>DIR</uicontrol> ������������������������<uicontrol>������������������������</uicontrol> (���������������������������������������������������) ������������������������������ +</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>������������������������������������������������������������������������������ +<uicontrol>NFS</uicontrol> ������������������������<uicontrol>NFS ������������ IP</uicontrol> ��������������������� <uicontrol>NFS ������</uicontrol> +(���������������������������������������������������������) ������������������������������ +</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>iSCSI ��������������������������������������������������������������������������������������������������������� +<uicontrol>iSCSI</uicontrol> ������������������������<uicontrol>iSCSI ������������</uicontrol> IP ������������������������ iSCSI ������������������<uicontrol>���������������</uicontrol>������������������������������ +���������������������iSCSI ������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt><uicontrol>������</uicontrol></dt> +<dd>������������������������������������������������������������������������ +������������������������������������<uicontrol>���������������������������</uicontrol>������������������������������ +</dd> +</dlentry><dlentry> +<dt><uicontrol>SCSI ������������������������������</uicontrol></dt> +<dd>SCSI ��������������������������������������������������������������������������� +������������ SCSI ��������������������������������������������� +</dd> +</dlentry></dl></li> +<li><uicontrol>������������</uicontrol>������������������������������������ +</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 233 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ja_JP/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/templates.dita new file mode 100644 index 0000000..24dc2ab --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ja_JP/templates.dita @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="ja-jp"> +<title>������������������</title> +<shortdesc><wintitle>������������������������</wintitle>������������������KVM ��������������������������������������������������������������������������������������������������������������������������� +</shortdesc> +<csbody> +<p>��������������������������������������������������������������������� +<dl> +<dlentry> +<dt>OS</dt> +<dd>��������������������������������������������������������������������������������������������� +</dd> +</dlentry><dlentry> +<dt>���������������</dt> +<dd>������������������������������������������������������������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>��������������������������������������������������������������������� +</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>��������������������������������������������������������������������� (MB ������)��� +</dd> +</dlentry></dl></p> +<p>������������������������������������������������������������������������������ +<ul> +<li>���������������������������������������<uicontrol>������������</uicontrol>��������������������� +</li> +<li>���������������������������������������<uicontrol>������������</uicontrol>��������������������� +</li> +</ul>������������������������������������������������������������������<uicontrol>��������� (+)</uicontrol> ������������������������������������������������ +</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="ja-jp"> +<title>���������������������������</title> +<shortdesc>������������������������������������������������ +</shortdesc> +<csbody> +<p>��������������������������������������������������������������������� +<dl> +<dlentry> +<dt>������</dt> +<dd>������������������������������ +</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt>���������������</dt> +<dd>������������������������������������������������������������������������������������������������������������������������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt>CPU ���</dt> +<dd>��������������������������������������������������������������������� +</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>��������������������������������������������������������� (MB ������)��� +</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������������������ (GB ������)��� +</dd> +</dlentry><dlentry> +<dt>CDROM</dt> +<dd>KVM ������������������������������������������������������������ ISO ������������������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt>���������������������������</dt> +<dd>������������������������������������������������������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt> ������������������</dt> +<dd>KVM ��������������������������������������������������������������������������������������������� +������������������������������������������������������������������ +</dd> +</dlentry></dl> ������������������������������������������������������������������������ +������������������������������������<uicontrol>������������</uicontrol>������������������������������������ +</p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>���������������������������</title> +<shortdesc>��������������������������������������������������������������������� +������������������������������������������������������ ISO ������������������ISO������������������������������������������������������</shortdesc> +<csbody> +<p>��������������������������������������������������������������������������������������������������������� +<dl> +<dlentry> +<dt>������������ ISO ������������</dt> +<dd>������������������������������������������������������������������������ ISO ������������������������������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt>������������ ISO ������������</dt> +<dd>������������������������������������������ ISO ��������������������������������������������������������������������� +</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>��������������������������� - ������������ ISO ������������</title> +<shortdesc>��������������������������������� ISO ������������������������������������ +</shortdesc> +<csbody> +<p>������������������������������ ISO ������������������������������������ +<dl><dlentry> +<dt>OS</dt> +<dd>��������������������������������������������������������������������������������������������� +</dd> +</dlentry><dlentry> +<dt>���������������</dt> +<dd>������������������������������������������������������������������������������������������������������ +</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>ISO ��������������������������� +</dd> +</dlentry></dl></p> +<p>��������������������� ISO ��������������������������������������������������������������������������������������������� +<ul> +<li>��������������������������������������������� ISO ������������������������������<uicontrol>��������������� ISO ������������������������������������</uicontrol>��������������������������� +</li> +<li>������������������������ ISO ������������������������������������������������������������������������<uicontrol>���������������</uicontrol>���������������������<uicontrol>��������������� ISO ������������������������������������</uicontrol>��������������������������� +</li> +<li>��������������� ISO ��������������������������������������������������������������������������������������������������������������� +<ul> +<li>ISO ���������������������������������������������<uicontrol>������������ ISO ������������������������������</uicontrol>��������������������� +</li> +<li>��������������� ISO ������������������������������������<uicontrol>���ISO ���������������������</uicontrol>��������������������������� +</li> +</ul></li> +</ul></p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 229 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/kimchi.css b/src/wok/plugins/kimchi/ui/pages/help/kimchi.css new file mode 100644 index 0000000..32fae4a --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/kimchi.css @@ -0,0 +1,208 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +BODY { + background: #FFFFFF; + margin-bottom: 1em; + margin-left: .5em; +} + +bold { + font-weight: bold; +} + +boldItalic { + font-weight: bold; + font-style: italic; +} + +italic { + font-style: italic; +} + +underlined { + text-decoration: underline; +} + +uicontrol { + font-weight: bold; +} + +filepath { + font-family: monospace, monospace; +}.option { + font-family: monospace, monospace; +} + +cmdname { + font-weight: bold; + font-family: monospace, monospace; +} + +.defparmname { + font-weight: bold; + text-decoration: underline; + font-family: monospace, monospace; +} + +.kwd { + font-weight: bold; +} + +.defkwd { + font-weight: bold; + text-decoration: underline; +} + +var { + font-style : italic; +} + +strongwintitle { + font-weight : bold; +} + +parmname { + font-weight: bold; + font-family: monospace, monospace; + white-space: nowrap; +} + +code { + font-family: monospace, monospace; +} + +pre { + font-family: monospace, monospace; +} + +CITE { + font-style: italic; +} + +EM { + font-style: italic; +} + +STRONG { + font-weight: bold; +} + +VAR { + font-style: italic; +} + +dt { + font-weight: bold; +} + +/*********************************************************** + * Basic fonts + ***********************************************************/ +body, +td, +th, +caption { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 10pt; +} + +pre, code { + font-family: MS Courier New, Courier, monospace; +} + +h1, h2, h3 { + font-size: 12pt; + font-weight: bold; + color: #336699; +} + +h4 { + font-size: 10pt; + font-weight: bold; + color: #336699; +} + +/*********************************************************** + * Basic indents, padding, and margin + ***********************************************************/ +body { + color: black; + background-color: white; + margin: 0; + padding-top: 0.2em; + padding-left: 0.6em; + padding-right: 0.2em; + padding-bottom: 1em; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + padding: 0; + margin-top: 1em; + margin-bottom: 0.75em; + margin-left: 0; + margin-right: 0; +} + +address, +dl, +li, +p { + padding: 0; + margin-top: 0.75em; + margin-bottom: 0.75em; + margin-left: 0; + margin-right: 0; + line-height: 125%; +} + +td dl { + margin-left: 2em; +} + +pre { + padding: 0; + margin-top: 0.75em; + margin-bottom: 0.75em; + margin-left: 2em; + margin-right: 0; +} + +ol, +ul { + padding: 0; + margin-top: 0.75em; + margin-bottom: 0.75em; + margin-left: 2.00em; + margin-right: 0; +} + +dd { + margin-left: 3.00em; + margin-top: 0.75em; + margin-bottom: 0.75em; +} + +dt { + margin-left: 1.00em; + margin-top: 0.75em; +} diff --git a/src/wok/plugins/kimchi/ui/pages/help/ko_KR/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/Makefile.am new file mode 100644 index 0000000..e441955 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +ko_KR_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/ko_KR + +dist_ko_KR_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/ko_KR/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/guests.dita new file mode 100644 index 0000000..2d9f32b --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/guests.dita @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="ko-kr"> +<title>���������</title> +<shortdesc><wintitle>���������</wintitle> ��������������� ��������� KVM ������ ��������� ���������������.</shortdesc> +<csbody> +<p>��� ������������ ������ ������ ��������� ���������������.<dl><dlentry> +<dt>������</dt> +<dd>������ ��������� ���������������.</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>������ ��������� ������������ ������������������.</dd> +</dlentry><dlentry> +<dt>������������ I/O</dt> +<dd>������ ������������ ���/������(I/O) ������ ������(KB)���������.</dd> +</dlentry><dlentry> +<dt>��������� I/O</dt> +<dd>������ ��������� ���/������(I/O) ������ ������(KB)���������.</dd> +</dlentry><dlentry> +<dt>���������������</dt> +<dd>��������� ������ ��������� ���������������, ������������ ��������� ������ ������ <tm tmtype="tm" trademark="Linux">Linux</tm> ��������� ������������ ������������������.</dd> +</dlentry></dl></p> +<p>������ ������ ������������ ��� ��������������� ���������������.<dl> +<dlentry> +<dt>������ ������</dt> +<dd>������������ ������ ��������������� ���������������. </dd> +</dlentry><dlentry> +<dt>������(������ ������ ������)</dt> +<dd>������������ ��������� ��������� ��������� ���������������. ������������ ��������������� ��������� ������ ��������� ������������ ������������ ��������� ������ ������������.</dd> +</dlentry></dl> </p> +<p>��� ��������������� ������ ��������� ��������� ��� ������������.<ul> +<li>��������� ������ ��������� ������ ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> +<li>��������� ������ ��������� ��������������� <uicontrol>������ ������</uicontrol>��� ���������������.</li> +<li>������������ ������ ��������������� <uicontrol>������ ������</uicontrol>��� ���������������.</li> +<li>������ ������������ ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������. ������������ ������ ��������� ������ ��������� ��� ������������.</li> +<li>������������ ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> +</ul>��������� ������ ������ ��������� ��������������� ��������� ��������� ��������� ������ <uicontrol>���������(+)</uicontrol> ������������ ���������������.</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="ko-kr"> +<title>������ ������ ������</title> +<shortdesc>������ ��������������� ������������ ������ ��������� ���������������.</shortdesc> +<csbody> +<p> <ol> +<li>������ ��������� ������������ ��� ��������� ��������� ������������������.</li> +<li rev="rev1">��������������� ������������������. <ul> +<li>��������������� ������������ ������, ��������� ������������ ��������� ������������������.</li> +<li>��������������� ������ ������, <uicontrol>������������ ������</uicontrol>��� ������������ ��������������� ������������������.</li> +</ul></li> +<li><uicontrol>������</uicontrol>��� ������������������.</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="ko-kr"> +<title>��������� ������</title> +<shortdesc>������ ������ ��������� ��������� ���������������. ������ ��������� ������������ ��������� ������������ ��������� ��� ������������. +������ ��������� ������ ������������ ���������������. </shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>��� ������������ ������ ������ ��������� <wintitle>������</wintitle> ������ ���������������.<dl> +<dlentry> +<dt>������</dt> +<dd>������ ��������� ���������������(������������ ��������� ������������ ��������� ��� ������).</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>������������ ������������(������������ ������ ������ ������ ��� ��������� ������ ������������ ���������).</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>��������� ������(MB)���������(������������ ������ ������ ������ ��� ��������� ������ ������������ ���������).</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������������ ��������� ������ ��� ������ ������(���������������) ��������� ��������� Linux ��������� ������������ ��������� ������������������.</dd> +</dlentry></dl></p> +<p>������ ��������� <wintitle>������������</wintitle> ������ ���������������.</p> +<dl><dlentry> +<dt>������������</dt> +<dd>��������� ��������� ISO ��������� ��������� ���������������.</dd> +</dlentry></dl> +<p> ������ ������������ ������������ ������ ��������� ��������� ��� ������������. ��������� ��������� ������ <uicontrol>������</uicontrol>��� ���������������. </p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="ko-kr"> +<title>������������ ������ ������, ������ ������ ������</title> +<shortdesc rev="rev1">������ ��������� ������ ������������ ��������� ������, ������ ������ ��������� ��� ������������. ������������ ��������� CDROM������������. ������������ ��������� ��������������� ������ ��������� ������������������.</shortdesc> +<csbody> +<ol> +<li><wintitle>��������� ������</wintitle> ��������� <wintitle>������������</wintitle>��� ������������������.</li> +<li>������������ ��������� ��������������� <uicontrol>��������� ���������(/)</uicontrol>��� ������ ��� ������ ������������ ������������������. ISO ������ ��������� ������������ <uicontrol>������</uicontrol>��� ������������������.</li> +<li>������������ ��������� ��������������� <uicontrol>��������� ������(-)</uicontrol>��� ������ ��� ������ ������������ ������������������. ������ ��������� ������������ <uicontrol>������</uicontrol>��� ������������������.</li> +<li>������������ ��������� ��������������� ������ <uicontrol>��������� ������(+)</uicontrol>��� ������ ��� ������ ������������ ������������������. ������ ������ ��� ISO ������ ��������� ������������ <uicontrol>������</uicontrol>��� ������������������.</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="ko-kr"> +<title>VM��� CDROM ������</title> +<shortdesc rev="rev1">��������� ��������� ������ ������ ��������� ������ CDROM��� ������������ ������ ��� ������������.</shortdesc> +<csbody> +<ol> +<li>������ ��������� ������������������ ������������������.</li> +<li>������ ������������ <uicontrol>������ ������</uicontrol>��� ������������������.</li> +<li>CDROM��� ������ ��������� ��������� ������������ ������ hdc ������ ������ ������ <uicontrol>��������� ���������(/)</uicontrol> ������������ ������������������.</li> +<li><wintitle>VM��� CDROM ������</wintitle> ��������������� ISO ������ ��������� ������������������. ������ ��� ��������� ������ ���������������.</li> +<li><uicontrol>������</uicontrol>��� ������������������.</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 231 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ko_KR/host.dita b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/host.dita new file mode 100644 index 0000000..ee4a9c3 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/host.dita @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="ko-kr"> +<title>���������</title> +<shortdesc><wintitle>���������</wintitle> ��������������� ��������� ������������ ������ ��������� ������������ ��� ������������ ������������ ������������ ������ ��� ������ ��������������� ������������ ��������� ��� ������������.</shortdesc> +<csbody> +<p>������������ ������ ������ ��������� ��������� ��� ������������.<ul> +<li>��������� ������������ ��������������� <uicontrol>��������� ������</uicontrol>��� ���������������.</li> +<li>��������� ������������ ������ ��������������� <uicontrol>������ ������</uicontrol>��� ���������������.</li> +<li>������ ������������ ������ ������ ������, ��������� ������������ ������ VNC ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> +</ul></p> +<p>������������ ������ ��������� ��������������� ������ ��������� ������������������.<dl> +<dlentry> +<dt>������ ������</dt> +<dd>��� ������������ ��������� ������ ������ ������, ������, ������ ������, ������������ ������, ��������� ������(GB) ������ ���������������.</dd> +</dlentry><dlentry> +<dt>��������� ������</dt> +<dd>��� ������������ ������������ CPU, ���������, ��������� I/O, ������������ I/O��� ������ ��������� ������������ ������������ ���������������. ��������� ������ ��������� ��� ��������� ��������� ��������������� <uicontrol>��� ������������ ������ ������ ��������� ������</uicontrol>��� ���������������.</dd> +</dlentry><dlentry> +<dt>��������������� ������������</dt> +<dd>��� ������������ ��������� ������, ������, ������������, ������������ ������������ ������ ��������� ��������������� ������ ������ ������������ ������ ��������� ���������������. <uicontrol>������ ������������</uicontrol>��� ������������ ��������� ������ ������������ ��������������� ��� ������������. ��������������� ������ ������ ������������ ��������� ������ ������������.</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>��� ������������ ��������� ������������ ��������� ������������ ���������������. ������������ ���������������, ������������ ���������������, ���������������, ��������� ��� ������������. ������������ ������������ ������������ ��������� ������������ ������������, ������������ ������������ ������������ ������������ ������������ ������������ ��� ������������. ������ ������������ Red Hat Enterprise Linux ������ Fedora��� ������, <filepath>yum</filepath> ������������ ��������� ��� ������������. +������ ������������ Ubuntu ������ Debian��� ������, <filepath>deb</filepath> ������������ ������������������.<p>yum ������������ ������������ ������, GPG ��������� ������������ ��� ������������ ������������ ������������ ������������ ��������� ��� ������������. +������������ ��������� ��� <uicontrol>������</uicontrol>��� ������������������. <uicontrol>���</uicontrol>��� ������������ GPG ��������� ������������ ��������� ��� ������������ ������ GPG ��� ��������� URL��� ������������������.</p></dd> +</dlentry><dlentry> +<dt>��������� ���������</dt> +<dd>��� ������������ ������ ��� ������ ��������� ��������� ��������� ������������ ���������������. +��� ��������� ������, ������ ��������� ������ ���������, ������, ������������ ������ ������ ��������� ��������� ��� ������������.<p>��������� ������������ <cmdname>sosreport</cmdname> ��������� ������������ ���������������. ������ Red Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora ��� Ubuntu ������������ ������ ���������������. ��� ��������� ������ ��� ������ ������(���: ������ ������ ������ ������, ��������� ������, ��������� ��� ��������� ������ ������)��� ������������ .tar ��������� ���������������. +������ ��� ��������� ������ ��������������� ������������ ������ ��������� ������������ ������ ��������������� ��� ��������� ���������������.</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 232 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ko_KR/network.dita b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/network.dita new file mode 100644 index 0000000..451510f --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/network.dita @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="ko-kr"> +<title>������������</title> +<shortdesc><wintitle>������������</wintitle> ��������������� ������������ ��������� ������ ��������� ���������������.</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>������������ ������</dt> +<dd>��������������� ������ ������ <uicontrol>���������</uicontrol>���������.</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>��������������� ������(��������� ������ ������, ������������ ������ ���������)���������. </dd> +</dlentry><dlentry> +<dt>������������ ������</dt> +<dd>������������ ���������������. ���: <uicontrol>NAT</uicontrol>(Network Address Translation)</dd> +</dlentry><dlentry> +<dt>���������������</dt> +<dd>������������ ������������������������. ���: <uicontrol>virbr0</uicontrol>(���������)</dd> +</dlentry><dlentry> +<dt>������ ������</dt> +<dd>IP ���������������.</dd> +</dlentry></dl></p> +<p>������ ��������� ��������� ��� ������������.<ul> +<li rev="rev1">������������ ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> +<li>������������ ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> +<li>������ ��������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> +</ul>��������������� ��������������� ������ ��������� ��������� ������ <uicontrol>���������(+)</uicontrol> ������������ ���������������.</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="ko-kr"> +<title>������������ ������</title> +<shortdesc>��������������� ���������������.</shortdesc> +<csbody> +<p> <ol> +<li>��������������� ��������� ������������������.</li> +<li>������������ ��������� ��������������� ������������������. <dl rev="rev1"><dlentry> +<dt><uicontrol>���������</uicontrol></dt> +<dd>������ ���������������. ������������ ������ ������������ ������ ��������� ������������ ������ ��� ������������.</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>Network Address Translation ���������������. ������������ ������ ��������������� ��������� ������������ ��������� IP ��������� ���������������. ������ ������������ ��������������� ��������� ��������� ��� ������������.</dd> +</dlentry><dlentry> +<dt><uicontrol>������������</uicontrol></dt> +<dd>��������� ���������������. ������������ ������ ������������ ��������� ��� ������ ������ ������������ ������������������ ��������� ��������������� ������������ ��������� ��� ������������. ��������� ��������� ������, ������ ��������� ��� VLAN ��������� ������������ ���������.</dd> +</dlentry></dl></li> +<li><uicontrol>������</uicontrol>��� ������������������.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 230 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ko_KR/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/storage.dita new file mode 100644 index 0000000..2e6f5e8 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/storage.dita @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="ko-kr"> +<title>������������</title> +<shortdesc><wintitle>������������</wintitle> ��������������� ������ ��������� ��� ������ '������' ��� 'ISO' ������������ ������ ������������ ������ ��������� ������������ ������ ���������������. +��������� ������ ISO��� ��������������� ������ 'ISO' ������������ ��� ��������� ������������������.</shortdesc> +<csbody> +<p>��� ������������ ������ ������ ������ ��������� ���������������.<dl> +<dlentry> +<dt>������</dt> +<dd>������������ ������ ������ ��� ������������������.</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������ ������ ������(��������� ������ ������, ������������ ������ ���������)���������. </dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������ ������ ��������� ������ ������ ���������������.</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������ ������ ���������������. ���: <uicontrol>dir</uicontrol></dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������ ��������� ��������� ������������.</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������������ ������ ������ ��������� ��������� ������������.</dd> +</dlentry></dl></p> +<p>��� ������������ ��������� ������ ��������� ��������� ��� ������������.<ul> +<li>������ ��������������� ������������ ������ ������������������ <uicontrol>���������</uicontrol>��� ���������������.</li> +<li>������������ ������ ��������������������� <uicontrol>������������</uicontrol>��� ���������������.</li> +<li>��������� ������������ ������ ��������������� <uicontrol>������ ������</uicontrol>��� ���������������.</li> +</ul></p> +<p>������������ ������ ������ ������������ ������ ��������������� ��������������� ������������ ��� ������ ������������ ������ ������������ ������������������. ������������������ ��������� ���������������.<dl><dlentry> +<dt>������</dt> +<dd>��������� ���������������. ���: <uicontrol>������</uicontrol></dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>��������� ��������� ������ ���������������.</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������ ��������� ���������������.</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������ ������ ������ ��������� ��������� ������������.</dd> +</dlentry></dl>������������ ������ ��������������� ������ ��������� ��������� ������ <uicontrol>���������(+)</uicontrol> ������������ ���������������.</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="ko-kr"> +<title>������������ ��� ������</title> +<shortdesc> ������������ ������ ���������������.</shortdesc> +<csbody> +<p> <ol> +<li><uicontrol>������������ ��� ������</uicontrol> ������������, ������������ ������ ������������ ��� ��������� ��������� ������������������.</li> +<li><uicontrol>������������ ��� ������</uicontrol> ������������ ������ ��������� ������������������. <dl><dlentry> +<dt><uicontrol>DIR</uicontrol></dt> +<dd>������������ ������ ���������������. <uicontrol>DIR</uicontrol> ��������� ��������� ������, <uicontrol>������������ ������</uicontrol>(������������ ������ ������ ������)��� ���������������.</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>������������ ������ ��������� ������ ���������������. <uicontrol>NFS</uicontrol>��� ��������� ������, <uicontrol>NFS ������ IP ������</uicontrol> ��� <uicontrol>NFS ������</uicontrol>(������ ��������������� ������)��� ���������������.</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>iSCSI ��������� ��������� ��������� ������������ ������ ���������������. +<uicontrol>iSCSI</uicontrol>��� ��������� ������, iSCSI ��������� ������ <uicontrol>iSCSI ������ IP ������</uicontrol> ��� <uicontrol>������</uicontrol>��� ���������������. ���������������, iSCSI ��������� ��������������� ��������� ��� ������������.</dd> +</dlentry><dlentry> +<dt><uicontrol>���������</uicontrol></dt> +<dd>��������� ������ ������������ ������ ���������������. <uicontrol>������ ������</uicontrol>������ ��������� ������ ��������� ���������������.</dd> +</dlentry><dlentry> +<dt><uicontrol>SCSI ��������� ������</uicontrol></dt> +<dd>SCSI ��������� ��������� ������������ ������ ���������������. ��������� SCSI ������������ ���������������.</dd> +</dlentry></dl></li> +<li><uicontrol>������</uicontrol>��� ������������������.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 233 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ko_KR/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/templates.dita new file mode 100644 index 0000000..de16d6e --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ko_KR/templates.dita @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="ko-kr"> +<title>������������</title> +<shortdesc><wintitle>������������</wintitle> ��������������� KVM ������������ ������������ ��� ��������� ��� ������ ��������� ������ ������ ��������������� ���������������.</shortdesc> +<csbody> +<p>��� ��������������� ������ ������ ��������� ���������������.<dl> +<dlentry> +<dt>OS</dt> +<dd>������ ������ ������ ��������� ���������������.</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������ ������ ������ ��������� ���������������.</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>��������������� ������ ��������� ��������������� ������������.</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>��������� RAM(Random Access Memory)��� ���(MB)���������.</dd> +</dlentry></dl></p> +<p>��� ������������������ ������ ��������� ��������� ��� ������������.<ul> +<li>��������������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> +<li>��������������� ��������������� <uicontrol>������</uicontrol>��� ���������������.</li> +</ul>��������������� ��������������� ������ ��������� ��������� ������ <uicontrol>���������(+)</uicontrol> ������������ ���������������.</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="ko-kr"> +<title>������������ ������</title> +<shortdesc>������ ��������������� ���������������.</shortdesc> +<csbody> +<p>��� ��������������� ������ ������ ��������� ���������������. <dl> +<dlentry> +<dt>������</dt> +<dd>��������������� ���������������.</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>��������������� ��������������� ��������� ������ ������ ������ ��������� ��������� ��������� ���������������.</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>��������������� ��������������� ��������� ������ ������ ������ ��������� ���������������.</dd> +</dlentry><dlentry> +<dt>CPU ���</dt> +<dd>��������������� ������ ��������� ��������������� ������������.</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������ ��������� ��������� ��������� ������(MB)���������.</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>��������� ������(GB)���������.</dd> +</dlentry><dlentry> +<dt>CDROM</dt> +<dd>KVM ������������ ������������ ��� ��������� ISO ��������� ��������� ������ ������ ���������������.</dd> +</dlentry><dlentry> +<dt>������������ ���</dt> +<dd>������ ������������ ��� ������ ������ ������������ ������������.</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>KVM ������������ ������ ��������� ������ ������������ ������������������������. ������ ��������������� ��������� ��� ������������.</dd> +</dlentry></dl> ������ ������������ ������������ ������ ��������� ��������� ��� ������������. ��������� ��������� ������ <uicontrol>������</uicontrol>��� ���������������. </p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>������������ ������</title> +<shortdesc>������ ��������������� ��������������� ���������������. ������ ��������� ������ 'ISO' ������������ ������ ��������� ������ ISO ������������ ��������� ��� ������������. </shortdesc> +<csbody> +<p>������ ������ ��������� ������ ��������� ��������� ������������������.<dl> +<dlentry> +<dt>������ ISO ���������</dt> +<dd>��������������� ������ ��������� ������ ISO ������������ ������������ ������ ��������������� ���������������.</dd> +</dlentry><dlentry> +<dt>������ ISO ���������</dt> +<dd>������ ISO ������������ ������ ��������� ��������������� ���������������.</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>������������ ������ - ������ ISO ���������</title> +<shortdesc>������ ISO ������������������ ��������������� ���������������.</shortdesc> +<csbody> +<p>��������������� ������ ��������� ISO ������������ ���������������.<dl><dlentry> +<dt>OS</dt> +<dd>������ ������ ������ ��������� ���������������.</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������ ������ ������ ��������� ���������������.</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>ISO ������������ ���������������.</dd> +</dlentry></dl></p> +<p>ISO ������������������ ��������������� ��������������� ������ ������ ��������� ������������������.<ul> +<li>��������������� ������������ ������ ISO ������������ ��������� ��� <uicontrol>��������� ISO��������� ������������ ������</uicontrol>��� ���������������.</li> +<li>��������� ��� ISO ������������������ ��������������� ��������������� <uicontrol>������</uicontrol>��� ��������� ��� <uicontrol>��������� ISO��������� ������������ ������</uicontrol>��� ���������������.</li> +<li>��������������� ISO ������������ ������ ��������� ������������ ������ ������, ������ ������ ��������� ��������� ��� ������������.<ul> +<li>ISO ������������ ��������� ��������������� <uicontrol>������ ISO ��������� ��������������� ���������.</uicontrol>��� ���������������.</li> +<li>������ ISO ������������ ��������������� <uicontrol>������ ISO ������</uicontrol>��� ���������������.</li> +</ul></li> +</ul></p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 229 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/pt_BR/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/Makefile.am new file mode 100644 index 0000000..7fc2cb0 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +pt_BR_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/pt_BR + +dist_pt_BR_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/pt_BR/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/guests.dita new file mode 100644 index 0000000..ac58d5c --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/guests.dita @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="pt-br"> +<title>M��quinas Virtuais</title> +<shortdesc>A p��gina <wintitle>M��quinas Virtuais</wintitle> lista as m��quinas virtuais +KVM definidas.</shortdesc> +<csbody> +<p>Para cada convidado, as informa����es a seguir s��o exibidas:<dl><dlentry> +<dt>Nome</dt> +<dd>Nome da m��quina virtual.</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>Porcentagem de utiliza����o do processador na m��quina virtual.</dd> +</dlentry><dlentry> +<dt>E/S de rede</dt> +<dd>Taxa de transmiss��o de entrada/sa��da de rede em KB por segundo.</dd> +</dlentry><dlentry> +<dt>E/S de disco</dt> +<dd>Taxa de transmiss��o de entrada/sa��da de disco em KB por segundo.</dd> +</dlentry><dlentry> +<dt>Livetile</dt> +<dd>Estado do console do sistema operacional guest ou um ��cone que representa +a distribui����o <tm tmtype="tm" trademark="Linux">Linux</tm> se o +convidado n��o estiver ativo.</dd> +</dlentry></dl></p> +<p>Os ��cones de a����es a seguir s��o exibidos para cada convidado:<dl> +<dlentry> +<dt>Reiniciar</dt> +<dd>Clique para Reiniciar o convidado. </dd> +</dlentry><dlentry> +<dt>Energia (iniciar ou parar)</dt> +<dd>Clique para ligar ou desligar o convidado. Se o ��cone estiver vermelho, +a energia est�� desligada; se o ��cone estiver verde, a energia est�� ligada.</dd> +</dlentry></dl> </p> +<p>As a����es a seguir podem ser selecionadas para cada convidado:<ul> +<li>Selecione <uicontrol>Conectar</uicontrol> para conectar-se ao console +remoto para o sistema operacional guest.</li> +<li>Selecione <uicontrol>Gerenciar m��dia</uicontrol> para alterar o caminho +para a m��dia de instala����o.</li> +<li>Selecione <uicontrol>Reiniciar</uicontrol> para Reiniciar o convidado.</li> +<li>Selecione <uicontrol>Editar</uicontrol> para editar as propriedades de um +convidado existente. Os M��quinas Virtuais podem ser editados somente quando interrompidos.</li> +<li>Selecione <uicontrol>Excluir</uicontrol> para excluir o convidado.</li> +</ul>Para criar um convidado, ou m��quina virtual, clique no ��cone <uicontrol>mais +(+)</uicontrol> na parte superior direita da p��gina.</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="en-us"> +<title>Criar m��quina virtual</title> +<shortdesc>Crie uma m��quina virtual usando um modelo existente.</shortdesc> +<csbody> +<p> <ol> +<li>Digite o nome a ser usado para identificar a m��quina virtual.</li> +<li rev="rev1">Selecione um modelo. <ul> +<li>Se existirem modelos, selecione a partir dos modelos exibidos.</li> +<li>Se n��o existir nenhum modelo, clique em <uicontrol>Criar um modelo</uicontrol> para +criar um modelo.</li> +</ul></li> +<li>Clique em <uicontrol>Criar</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="en-us"> +<title>Editar convidado</title> +<shortdesc>Edite as propriedades de uma m��quina virtual existente. Algumas propriedades podem ser editadas enquanto o convidado est�� interrompido. Outras entrar��o em vigor na pr��xima inicializa����o.</shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>Para cada convidado, as informa����es a seguir s��o exibidas na guia <wintitle>Geral</wintitle>:<dl> +<dlentry> +<dt>Nome</dt> +<dd>Nome da m��quina virtual. (somente pode ser editado enquanto o convidado est�� interrompido)</dd> +</dlentry><dlentry> +<dt>CPUs</dt> +<dd>N��mero de processadores. (se o convidado estiver em execu����o, uma nova quantia entrar�� em vigor na pr��xima inicializa����o)</dd> +</dlentry><dlentry> +<dt>Mem��ria</dt> +<dd>Quantia de mem��ria em MB. (se o convidado estiver em execu����o, uma nova quantia entrar�� em vigor na pr��xima inicializa����o)</dd> +</dlentry><dlentry> +<dt>��cone</dt> +<dd>Imagem gr��fica representando a distribui����o Linux a ser exibida +no lugar do status atual (Livetile) quando o convidado n��o est�� ativo.</dd> +</dlentry></dl></p> +<p>As informa����es a seguir s��o exibidas na guia <wintitle>Armazenamento</wintitle>.</p> +<dl><dlentry> +<dt>Armazenamento</dt> +<dd>Exibe o local do arquivo ISO usado para instala����o.</dd> +</dlentry></dl> +<p> Os campos que n��o est��o desativados podem ser editados. Depois de editar um campo, +clique em <uicontrol>Salvar</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="en-us"> +<title>Incluir, substituir ou remover um dispositivo de armazenamento</title> +<shortdesc rev="rev1">�� poss��vel incluir, substituir ou remover um dispositivo de armazenamento +para sua m��quina virtual. O ��nico dispositivo suportado �� CD-ROM. Para editar +seus dispositivos de armazenamento, siga estas etapas:</shortdesc> +<csbody> +<ol> +<li>Na janela <wintitle>Editar convidado</wintitle>, selecione <wintitle>Armazenamento</wintitle>.</li> +<li>Para substituir um dispositivo de armazenamento, clique no primeiro ��cone com a <uicontrol>barra +laranja (/)</uicontrol>. Insira o caminho do arquivo ISO e clique em <uicontrol>Substituir</uicontrol>.</li> +<li>Para remover um dispositivo de armazenamento, clique no segundo ��cone com o <uicontrol>tra��o +vermelho (-)</uicontrol>. Confirme a exclus��o e clique em <uicontrol>OK</uicontrol>.</li> +<li>Para incluir um dispositivo de armazenamento, clique no terceiro ��cone com o <uicontrol>sinal de +mais (+)</uicontrol> verde. Insira um nome de dispositivo e um caminho de arquivo ISO e clique em <uicontrol>Conectar</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="en-us"> +<title>Substituir um CD-ROM da VM</title> +<shortdesc rev="rev1">�� poss��vel substituir o conte��do do CD-ROM para +uma m��quina virtual ap��s a instala����o ser conclu��da.</shortdesc> +<csbody> +<ol> +<li>Assegure-se de que a m��quina virtual esteja iniciada.</li> +<li>No menu A����es, selecione <uicontrol>Gerenciar m��dia</uicontrol>.</li> +<li>Para alterar o que est�� atualmente carregado no CD-ROM, clique no ��cone <uicontrol>barra +laranja (/)</uicontrol> pr��ximo ao campo hdc.</li> +<li>Na p��gina <wintitle>Substituir um CD-ROM da VM</wintitle>, insira +o caminho do arquivo ISO. Os outros dois campos s��o somente leitura.</li> +<li>Clique em <uicontrol>Substituir</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 231 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/pt_BR/host.dita b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/host.dita new file mode 100644 index 0000000..88f7eb2 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/host.dita @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="pt-br"> +<title>Host</title> +<shortdesc>A p��gina <wintitle>Host</wintitle> mostra informa����es sobre +o sistema host e permite encerrar, reiniciar e conectar +ao host.</shortdesc> +<csbody> +<p>�� poss��vel executar as a����es a segur no host:<ul> +<li>Selecione <uicontrol>Encerrar</uicontrol> para encerrar o sistema +host.</li> +<li>Selecione <uicontrol>Reiniciar</uicontrol> para reiniciar o sistema host.</li> +<li>Selecione <uicontrol>Conectar</uicontrol> para abrir uma conex��o VNC +para o sistema host, se ele j�� n��o estiver conectado.</li> +</ul></p> +<p>Clique nas se����es a seguir para exibir informa����es sobre o host:<dl> +<dlentry> +<dt>Informa����es b��sicas</dt> +<dd>Esta se����o exibe a distribui����o do sistema operacional do host, +a vers��o e o nome do c��digo, bem como o tipo de processador e quantia de +mem��ria em GB.</dd> +</dlentry><dlentry> +<dt>Estat��sticas do sistema</dt> +<dd>Esta se����o exibe gr��ficos para mostrar estat��sticas para CPU, mem��ria, +E/S de disco e E/S de rede para o host. Selecione <uicontrol>Coletando +dados depois de sair desta p��gina</uicontrol> para continuar a coletar dados +quando a guia do host estiver fora de visualiza����o.</dd> +</dlentry><dlentry> +<dt>Atualiza����es de software</dt> +<dd>Esta se����o exibe informa����es de todos os pacotes que +possuem atualiza����es dispon��veis, incluindo nome do pacote, vers��o, arquitetura +e reposit��rio. �� poss��vel atualizar todos os pacotes listados selecionando <uicontrol>Atualizar +todos</uicontrol>. N��o �� poss��vel selecionar pacotes individuais para atualiza����es.</dd> +</dlentry><dlentry> +<dt>Reposit��rios</dt> +<dd>Esta se����o exibe reposit��rios que est��o associados ao +sistema host. �� poss��vel incluir, ativar, editar ou remover reposit��rios. Incluir +um reposit��rio o associa com o sistema host enquanto ativar um reposit��rio +permite que o host o acesse. Se o seu sistema for Red Hat Enterprise +Linux ou Fedora, ser�� poss��vel incluir reposit��rios <filepath>yum</filepath>. +Se o seu sistema for Ubuntu ou Debian, inclua reposit��rios <filepath>deb</filepath>.<p>Se +voc�� estiver trabalhando com reposit��rios yum, ser�� poss��vel incluir uma verifica����o de GPG para +verificar se um pacote desse reposit��rio n��o foi corrompido. +Selecione um reposit��rio e, em seguida, <uicontrol>Editar</uicontrol>. Selecione <uicontrol>Sim</uicontrol> para +ativar a Verifica����o de GPG e, em seguida, insira uma URL no arquivo-chave de GPG para o +reposit��rio.</p></dd> +</dlentry><dlentry> +<dt>Relat��rios de depura����o</dt> +<dd>Esta se����o exibe relat��rios de depura����o, incluindo nome e caminho do arquivo. +�� poss��vel selecionar a partir das op����es para gerar um novo relat��rio ou renomear, remover +ou fazer o download de um relat��rio existente.<p>O relat��rio de depura����o �� gerado usando +o comando <cmdname>sosreport</cmdname>. Ele est�� dispon��vel para distribui����es +Red Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora +e Ubuntu. O comando gera um arquivo .tar que cont��m +informa����es de configura����o e de diagn��stico, como vers��o do kernel +em execu����o, m��dulos carregados e arquivos de configura����o de sistema e de servi��o. +O comando tamb��m executa programas externos para coletar informa����es adicionais +e armazena essa sa��da no archive resultante.</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 232 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/pt_BR/network.dita b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/network.dita new file mode 100644 index 0000000..1585298 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/network.dita @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="pt-br"> +<title>Rede</title> +<shortdesc>A p��gina <wintitle>Rede</wintitle> exibe informa����es +sobre a conex��o de rede.</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>Nome da rede</dt> +<dd>Nome da rede ou <uicontrol>padr��o</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Estado</dt> +<dd>Estado da rede, ativo (verde) ou inativo (vermelho). </dd> +</dlentry><dlentry> +<dt>Tipo de rede</dt> +<dd>Tipo de rede, por exemplo, <uicontrol>NAT</uicontrol> (convers��o +de endere��o de rede).</dd> +</dlentry><dlentry> +<dt>Interface</dt> +<dd>Interface de rede, por exemplo, <uicontrol>virbr0</uicontrol> (padr��o).</dd> +</dlentry><dlentry> +<dt>Espa��o de endere��o</dt> +<dd>Endere��o IP.</dd> +</dlentry></dl></p> +<p>As a����es a seguir podem ser selecionadas:<ul> +<li rev="rev1">Selecione <uicontrol>Iniciar</uicontrol> para iniciar a conex��o +de rede.</li> +<li>Selecione <uicontrol>Parar</uicontrol> para terminar a conex��o de rede.</li> +<li>Selecione <uicontrol>Excluir</uicontrol> para excluir as informa����es +de conex��o.</li> +</ul>Para criar uma rede, clique no ��cone <uicontrol>mais (+)</uicontrol> na +parte superior direita da exibi����o.</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="en-us"> +<title>Criar uma rede</title> +<shortdesc>Crie uma rede.</shortdesc> +<csbody> +<p> <ol> +<li>Digite o nome da rede.</li> +<li>Clique para selecionar o tipo de rede. <dl rev="rev1"><dlentry> +<dt><uicontrol>Isolado</uicontrol></dt> +<dd>Modo isolado. Os M��quinas Virtuais n��o podem enviar ou receber comunica����o para +ou de sistemas externos.</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>Modo de Convers��o de Endere��o de Rede. A comunica����o de M��quinas Virtuais com +sistemas externos usa o endere��o IP do host. Os sistemas externos n��o podem +iniciar a comunica����o com os M��quinas Virtuais.</dd> +</dlentry><dlentry> +<dt><uicontrol>bridged</uicontrol></dt> +<dd>Modo bridged. Os M��quinas Virtuais podem se comunicar com os sistemas externos e +ser contatados por sistemas externos como se fossem sistemas f��sicos +na rede. Para o modo bridged, devem-se especificar informa����es adicionais +de destino e de VLAN.</dd> +</dlentry></dl></li> +<li>Clique em <uicontrol>Criar</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 230 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/pt_BR/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/storage.dita new file mode 100644 index 0000000..03c8cab --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/storage.dita @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="pt-br"> +<title>Armazenamento</title> +<shortdesc>A p��gina <wintitle>Armazenamento</wintitle> lista os conjuntos de armazenamentos dispon��veis, inclusive o conjunto de armazenamentos 'padr��o' e 'ISO' integrado. +Se desejar usar seu pr��prio ISO, inclua-o em seu caminho do conjunto de armazenamentos 'ISO'.</shortdesc> +<csbody> +<p>Para cada storage pool, as informa����es a seguir s��o exibidas:<dl> +<dlentry> +<dt>Nome</dt> +<dd>Nome do storage pool e porcentagem usada.</dd> +</dlentry><dlentry> +<dt>Estado</dt> +<dd>Estado do storage pool, ativo (verde) ou inativo (vermelho). </dd> +</dlentry><dlentry> +<dt>Local</dt> +<dd>Caminho do arquivo para o local do storage pool.</dd> +</dlentry><dlentry> +<dt>Tipo</dt> +<dd>Tipo de storage pool, por exemplo, <uicontrol>dir</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Capacidade</dt> +<dd>Quantia de espa��o no storage pool.</dd> +</dlentry><dlentry> +<dt>Alocado</dt> +<dd>Quantia de espa��o j�� alocado no storage pool.</dd> +</dlentry></dl></p> +<p>As a����es a seguir podem ser selecionadas para cada storage pool:<ul> +<li>Selecione <uicontrol>Ativar</uicontrol> para ativar o storage pool +para que ele possa ser usado.</li> +<li>Selecione <uicontrol>Desativar</uicontrol> para desativar um storage pool +ativo.</li> +<li>Selecione <uicontrol>Indefinir</uicontrol> para remover um storage pool +inativo.</li> +</ul></p> +<p>Para exibir detalhes do volume de armazenamento para um storage pool, clique na +seta no lado direito da linha do storage pool. Os detalhes incluem +os seguintes:<dl><dlentry> +<dt>Tipo</dt> +<dd>O tipo de volume, por exemplo, <uicontrol>arquivo</uicontrol>.</dd> +</dlentry><dlentry> +<dt>Formato</dt> +<dd>O formato, que varia dependendo do tipo.</dd> +</dlentry><dlentry> +<dt>Capacidade</dt> +<dd>Tamanho do volume de armazenamento.</dd> +</dlentry><dlentry> +<dt>Aloca����o</dt> +<dd>Quantia de espa��o j�� alocado no storage pool.</dd> +</dlentry></dl>Para definir um storage pool, clique no ��cone <uicontrol>mais +(+)</uicontrol> na parte superior direita da exibi����o.</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="en-us"> +<title>Definir um storage pool</title> +<shortdesc> Defina um storage pool.</shortdesc> +<csbody> +<p> <ol> +<li>No campo <uicontrol>Nome do storage pool</uicontrol>, digite o +nome a ser usado para identificar o storage pool.</li> +<li>Na lista <uicontrol>Tipo de storage pool</uicontrol>, selecione o +tipo: <dl><dlentry> +<dt><uicontrol>DIR</uicontrol></dt> +<dd>Especifica um conjunto de diret��rios. Ao selecionar <uicontrol>DIR</uicontrol>, +digite o <uicontrol>Caminho do armazenamento</uicontrol> (caminho do arquivo para o +storage pool).</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>Especifica um conjunto de sistema de arquivos de rede. Ao selecionar <uicontrol>NFS</uicontrol>, +digite o endere��o <uicontrol>IP do servidor NFS</uicontrol> e o <uicontrol>Caminho +do NFS</uicontrol> (caminho do diret��rio exportado).</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>Especifica um conjunto com base em um destino alocado em um servidor iSCSI. +Ao selecionar <uicontrol>iSCSI</uicontrol>, digite o endere��o IP do <uicontrol>Servidor +iSCSI</uicontrol> e o <uicontrol>Destino</uicontrol> no +servidor iSCSI. Opcionalmente, �� poss��vel selecionar para incluir a autentica����o iSCSI.</dd> +</dlentry><dlentry> +<dt><uicontrol>L��gico</uicontrol></dt> +<dd>Especifica um storage pool do volume l��gico. Selecione o local para +o dispositivo em <uicontrol>Caminho do dispositivo</uicontrol>.</dd> +</dlentry><dlentry> +<dt><uicontrol>Fibre Channel SCSI</uicontrol></dt> +<dd>Especifica um conjunto com base em um Fibre Channel SCSI. Selecione qual +adaptador SCSI deve ser usado.</dd> +</dlentry></dl></li> +<li>Clique em <uicontrol>Criar</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 233 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/pt_BR/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/templates.dita new file mode 100644 index 0000000..f3c6515 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/pt_BR/templates.dita @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="pt-br"> +<title>Modelos</title> +<shortdesc>A p��gina <wintitle>Modelos</wintitle> mostra os modelos de +m��quina virtual definidos que podem ser usados para criar M��quinas Virtuais do KVM.</shortdesc> +<csbody> +<p>Para cada modelo, as informa����es a seguir s��o exibidas:<dl> +<dlentry> +<dt>S.O.</dt> +<dd>Nome do sistema operacional ou distribui����o.</dd> +</dlentry><dlentry> +<dt>Vers��o</dt> +<dd>Vers��o do sistema operacional ou distribui����o.</dd> +</dlentry><dlentry> +<dt>CPUs</dt> +<dd>N��mero de processadores que est��o definidos para o modelo.</dd> +</dlentry><dlentry> +<dt>Mem��ria</dt> +<dd>Quantia de mem��ria de acesso aleat��rio a ser alocada, em MB.</dd> +</dlentry></dl></p> +<p>As a����es a seguir podem ser selecionadas para cada modelo:<ul> +<li>Selecione <uicontrol>Editar</uicontrol> para editar o modelo.</li> +<li>Selecione <uicontrol>Excluir</uicontrol> para excluir o modelo.</li> +</ul>Para incluir um modelo, clique no ��cone <uicontrol>mais (+)</uicontrol> na +parte superior direita da exibi����o.</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="en-us"> +<title>Editar modelo</title> +<shortdesc>Edite um modelo existente.</shortdesc> +<csbody> +<p>Para cada modelo, as informa����es a seguir s��o exibidas: <dl> +<dlentry> +<dt>Nome</dt> +<dd>Nome do modelo.</dd> +</dlentry><dlentry> +<dt>Fornecedor</dt> +<dd>O nome da empresa que criou o sistema operacional ou a distribui����o +que o modelo est�� configurado para usar.</dd> +</dlentry><dlentry> +<dt>Vers��o</dt> +<dd>A vers��o do sistema operacional ou distribui����o que o modelo +est�� configurado para usar.</dd> +</dlentry><dlentry> +<dt>N��mero de CPU</dt> +<dd>N��mero de processadores que est��o definidos para o modelo.</dd> +</dlentry><dlentry> +<dt>Mem��ria</dt> +<dd>Quantia de mem��ria em MB a ser alocada para a m��quina virtual.</dd> +</dlentry><dlentry> +<dt>Disco</dt> +<dd>O tamanho do disco em GB.</dd> +</dlentry><dlentry> +<dt>CD-ROM</dt> +<dd>O caminho do arquivo para o local do arquivo ISO usado para instalar o +convidado do KVM.</dd> +</dlentry><dlentry> +<dt>storage pool</dt> +<dd>storage pool espec��fico ou storage pool padr��o.</dd> +</dlentry><dlentry> +<dt>Rede</dt> +<dd>As interfaces de rede padr��o dispon��veis para o convidado do KVM. �� poss��vel +selecionar diversas redes.</dd> +</dlentry></dl> Os campos que n��o est��o desativados podem ser editados. Depois +de editar um campo, clique em <uicontrol>Salvar</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>Incluir modelo</title> +<shortdesc>Inclua um modelo a partir da m��dia de origem. +�� poss��vel incluir sua pr��pria imagem ISO em seu conjunto de armazenamentos 'ISO' para a descoberta a seguir.</shortdesc> +<csbody> +<p>Selecione o local da m��dia de origem a partir das op����es a seguir:<dl> +<dlentry> +<dt>Imagem ISO local</dt> +<dd>Selecione para varrer conjuntos de armazenamentos para imagens ISO de instala����o dispon��veis +no sistema.</dd> +</dlentry><dlentry> +<dt>Imagem ISO remota</dt> +<dd>Selecione para especificar um local remoto para uma imagem ISO de instala����o.</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>Incluir modelo - imagem ISO local</title> +<shortdesc>Inclua um modelo a partir de uma imagem ISO local.</shortdesc> +<csbody> +<p>As imagens ISO dispon��veis no sistema s��o exibidas.<dl><dlentry> +<dt>S.O.</dt> +<dd>Nome do sistema operacional ou distribui����o.</dd> +</dlentry><dlentry> +<dt>Vers��o</dt> +<dd>Vers��o do sistema operacional ou distribui����o.</dd> +</dlentry><dlentry> +<dt>Tamanho</dt> +<dd>Tamanho da imagem ISO.</dd> +</dlentry></dl></p> +<p>Para criar um modelo a partir de uma imagem ISO, escolha a partir das op����es +a seguir:<ul> +<li>Selecione uma imagem ISO para criar um modelo a partir dela, em seguida, clique em <uicontrol>Criar +modelos a partir do ISO selecionado</uicontrol>.</li> +<li>Selecione <uicontrol>Todos</uicontrol> para criar um modelo a partir de cada +imagem ISO listada, em seguida, clique em <uicontrol>Criar modelos a partir do +ISO selecionado</uicontrol>.</li> +<li>Se a imagem ISO que voc�� deseja usar n��o aparecer nos resultados de +varredura, ser�� poss��vel selecionar a partir das op����es a seguir:<ul> +<li>Selecione <uicontrol>Eu desejo usar um arquivo ISO espec��fico</uicontrol> para +especificar um caminho para a imagem ISO.</li> +<li>Clique em <uicontrol>Procurar mais ISOs</uicontrol> para procurar mais +imagens ISO.</li> +</ul></li> +</ul></p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 229 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ru_RU/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/Makefile.am new file mode 100644 index 0000000..85ca27a --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +ru_RU_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/ru_RU + +dist_ru_RU_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/ru_RU/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/guests.dita new file mode 100644 index 0000000..701dd7e --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/guests.dita @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="ru-ru"> +<title>���������������� ��������������</title> +<shortdesc>���� ���������������� <wintitle>���������������� ��������������</wintitle> ������������������������ ������������ ������������������ ���������������������� ���������� KVM.</shortdesc> +<csbody> +<p>������ ������������ ���������������� �������������� ������������������������ ������������������ ��������������������:<dl><dlentry> +<dt>������</dt> +<dd>������ ���������������������� ������������.</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>�������������� �������������������������� �������������������� �� ���������������������� ������������.</dd> +</dlentry><dlentry> +<dt>�������������� ��������-����������</dt> +<dd>���������������� ���������������� ����������-������������ �� ����/��.</dd> +</dlentry><dlentry> +<dt>���������������� ��������-����������</dt> +<dd>���������������� ������������������ ����������-������������ �� ����/��.</dd> +</dlentry><dlentry> +<dt>Livetile</dt> +<dd>������������������ �������������� ���������������� ������������������������ �������������� ������ ������������, ���������������������������� �������������� ���� <tm tmtype="tm" trademark="Linux">Linux</tm>, �������� ���������������� �������������� ���� ��������������.</dd> +</dlentry></dl></p> +<p>������ ������������ ���������������� �������������� ������������������������ ������������������ ������������ ����������������:<dl> +<dlentry> +<dt>����������</dt> +<dd>���������� ���������������� ��������������. </dd> +</dlentry><dlentry> +<dt>�������������� (������������/������������������)</dt> +<dd>������������������/�������������������� �������������� ���������������� ��������������. �������� ������������ ��������������, �������������� ������������������. �������� ������������ ��������������, �������������� ����������������.</dd> +</dlentry></dl> </p> +<p>������ ������������ ���������������� �������������� ���������������� ������������������ ����������������:<ul> +<li><uicontrol>������������������������</uicontrol> - ������������������������ �� ������������������ �������������� ���������������� ������������������������ ��������������.</li> +<li><uicontrol>�������������������� ��������������������</uicontrol> - ������������������ �������� �� �������������������������� ����������������.</li> +<li><uicontrol>����������</uicontrol> - ���������� ���������������� ��������������.</li> +<li><uicontrol>����������������</uicontrol> - ������������������ �������������� ���������������� ��������������. ���������������� ���������������� �������������� ���������� ����������������, ������������ ���������� �������������� ����������������������.</li> +<li><uicontrol>��������������</uicontrol> - �������������� ���������������� ��������������.</li> +</ul>������ ���������������� ���������������� �������������� (���������������������� ������������) ���������������� ���� ������������ <uicontrol>�������� +(+)</uicontrol> �� ������������ �������������� �������� ����������������.</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="ru-ru"> +<title>���������������� ���������������������� ������������</title> +<shortdesc>���������������� ���������������������� ������������ �� �������������� ��������������.</shortdesc> +<csbody> +<p> <ol> +<li>�������������� ������ ������ �������������������������� ���������������������� ������������.</li> +<li rev="rev1">���������������� ������������. <ul> +<li>�������� �������� ��������������, ���������������� ������������ �� ������������.</li> +<li>�������� ���������������� ������, ���������������� ���� <uicontrol>�������������� ������������</uicontrol>, ���������� �������������� ������������.</li> +</ul></li> +<li>���������������� ���� <uicontrol>��������������</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="ru-ru"> +<title>������������������ ���������������� ��������������</title> +<shortdesc>������������������ �������������� ������������������������ ���������������������� ������������. ������������������ ���������������� ���������� ���������������� ������������ �������� ���������������������� ���������������� ����������. ������������ ���������������� �� �������� ���������� ������������������ ������������������������.</shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>������ ������������ ���������������� �������������� ������������������������ ������������������ �������������������� ���� �������������� <wintitle>����������</wintitle>:<dl> +<dlentry> +<dt>������</dt> +<dd>������ ���������������������� ������������. (���������� �������������������������� �������� ���������������������� ���������������� ����������)</dd> +</dlentry><dlentry> +<dt>��������������������</dt> +<dd>���������� ����������������������. (�������� ���������������� ���������� ����������������, ���������� ���������� �������������� �� �������� ���������� ������������������������)</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>���������� ������������ �� ����. (�������� ���������������� ���������� ����������������, ���������� ���������� �������������� �� �������� ���������� ������������������������)</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>���������������������� ����������������������, ���������������������������� �������������� ���� Linux. ������ ������������������������ ������������ ���������������� ������������������ +(Livetile), ���������� ���������������� �������������� ���� ��������������.</dd> +</dlentry></dl></p> +<p>���� �������������� <wintitle>���������������� ������������</wintitle> ������������������������ ������������������ ��������������������.</p> +<dl><dlentry> +<dt>���������������� ������������</dt> +<dd>�������������������� ������������������������ ���������� ISO ������ ������������������.</dd> +</dlentry></dl> +<p> ���������������� �������� ���������� ����������������. ���������� ������������������ �������� ���������������� ���� <uicontrol>������������������</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="ru-ru"> +<title>��������������������, ������������ �� �������������������� ������������������ ����������������</title> +<shortdesc rev="rev1">�� ���������������������� ������������ ���������� ������������������, ���������������� �� ������������������ �������������������� ����������������. ������������������������ ���������������������������� �������������������� - CDROM. ������ ������������������ ������������������ ���������������� ������������������ ������������������ ����������������:</shortdesc> +<csbody> +<ol> +<li>�� �������� <wintitle>���������������� ���������������� ��������������</wintitle> ���������������� <wintitle>���������������� ������������</wintitle>.</li> +<li>������ ������������ �������������������� ���������������� ���������������� ���� ������������ ������������ �� <uicontrol>������������������ ���������� ������������ (/)</uicontrol>. �������������� �������� �� ���������� ISO �� ���������������� ���� <uicontrol>����������������</uicontrol>.</li> +<li>������ �������������������� �������������������� ���������������� ���������������� ���� ������������ ������������ �� <uicontrol>�������������� ���������������������������� ������������ (-)</uicontrol>. ���������������������� ���������������� �� �������������� ������������ <uicontrol>OK</uicontrol>.</li> +<li>������ �������������������� �������������������� ���������������� ���������������� ���� �������������� ������������ �� <uicontrol>�������������� ������������ +(+)</uicontrol>. �������������� ������ �������������������� �� �������� �� ���������� ISO �� ���������������� ���� <uicontrol>��������������������</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="ru-ru"> +<title>������������ CDROM ���������������������� ������������</title> +<shortdesc rev="rev1">���� ������������������ ������������������ ���������� ���������������� �������������������� CDROM ������ ���������������������� ������������.</shortdesc> +<csbody> +<ol> +<li>������������������ ���������������������� ������������.</li> +<li>�� �������� ���������������� ���������������� <uicontrol>�������������������� ��������������������</uicontrol>.</li> +<li>������ ������������ ����������������, ������������������������ �� CDROM, ���������������� ���� ������������ �� <uicontrol>������������������ ���������� ������������ +(/)</uicontrol> ���������� �� ���������� hdc.</li> +<li>���� ���������������� <wintitle>������������ CDROM ���������������������� ������������</wintitle> �������������� �������� �� ���������� ISO. ������ ������������ �������� ���������������� ������������ ������ ������������.</li> +<li>���������������� ���������� <uicontrol>����������������</uicontrol>.</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 231 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ru_RU/host.dita b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/host.dita new file mode 100644 index 0000000..fb72c21 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/host.dita @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="ru-ru"> +<title>��������</title> +<shortdesc>���������������� <wintitle>��������</wintitle> �������������������� �������������������� �� �������������� ���������� �� ������������������ �������������������������� ��������, �������������������������� �������� �� ������������������������ �� ��������.</shortdesc> +<csbody> +<p>���� ���������� ���������� ������������������ ������������������ ����������������:<ul> +<li><uicontrol>������������������ ������������</uicontrol> - �������������������� �������������� ����������.</li> +<li><uicontrol>��������������������������</uicontrol> - �������������������������� �������������� ����������.</li> +<li><uicontrol>������������������������</uicontrol> - �������������� �������������������� VNC �� ���������������� ����������, �������� ������ ������ ���� ����������������������.</li> +</ul></p> +<p>���������������� ���� ������������������ ���������������� ������ ������������������ �������������������� �� ����������:<dl> +<dlentry> +<dt>�������������� ��������������������</dt> +<dd>�� �������� �������������� ������������������������ �������������� ������������������������ ��������������, ������ ������������ �� �������������� ������, �� ���������� ������ �������������������� �� ���������� ������������ �� ����.</dd> +</dlentry><dlentry> +<dt>������������������ ��������������������</dt> +<dd>�� �������� �������������� ������������������������ ��������������, �������������������� ���������������������������� �������������������� �� ��������������������, ������������, ���������������� ����������-������������ �� �������������� ����������-������������ ������ ����������. ���������������� <uicontrol>�������� ������������ ���������� ���������������� �������� ����������������</uicontrol>, ���������� �������� ������������ ���������������������� ���������� ���������������� �������������� ��������.</dd> +</dlentry><dlentry> +<dt>�������������������� ������������������������ ����������������������</dt> +<dd>�� �������� �������������� ������������������������ �������������������� ������ �������� ��������������, ������ �������������� ���������������� ��������������������, �������������� ������ ������������, ������������, ���������������������� �� ������������������. ���������� ���������������� ������ ������������ �� ������������ �������������� ���� <uicontrol>���������������� ������</uicontrol>. ������������������ ������������ ������ �������������������� �������������� ������������.</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>�� �������� �������������� ������������������������ ������������������, ������������������ �� ���������������� ����������. ������������������ ���������� ������������������, ������������������������, ���������������� �� ��������������. ������ �������������������� ������������������ ���������������������� �� ���������������� ����������, ������ ������������������ ������������������ �������������������� ������������������ ������ ����������. �������� �������������� - Red Hat Enterprise Linux ������ Fedora, ���������� ���������������� ������������������ <filepath>yum</filepath>. +�������� �������������� - Ubuntu ������ Debian, ���������������� ������������������ <filepath>deb</filepath>.<p>������ ������������ �� ���������������������� yum ���������� ���������������� ���������������� GPG ������ ���������������� ���������������������� �������������� ���� �������������� ������������������. +���������������� ������������������ �� ���������������� ���� <uicontrol>����������������</uicontrol>. ���������������� <uicontrol>����</uicontrol>, ���������� ���������������� ���������������� GPG, �� �������������� URL ���������� ������������ GPG ������ ������������������.</p></dd> +</dlentry><dlentry> +<dt>�������������������� ������������</dt> +<dd>�� �������� �������������� ������������������������ �������������������� ������������, �������������� ������ �� ��������. +���������������� �������������� ������ ����������������, ����������������������������, ���������������� �� ���������������� ��������������.<p>�������������������� ���������� ������������������ ���������������� <cmdname>sosreport</cmdname>. ���� ���������������� ������ Red +Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>, Fedora �� Ubuntu. �������������� �������������� �������� .tar �� �������������������������������� �� ������������������������������ ����������������������, ���������� ������ ������������ ��������, ���������������������� ������������ �� ���������� ������������������������ �������������� �� ����������. +�������������� ���������� ������������������ �������������� ������������������ ������ ���������� ���������������������������� �������������������� �� ������������������ ���� ���������� �� ���������������������������� ������������.</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 232 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ru_RU/network.dita b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/network.dita new file mode 100644 index 0000000..9cdcdd1 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/network.dita @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="ru-ru"> +<title>��������</title> +<shortdesc>���� ���������������� <wintitle>��������</wintitle> ������������������������ �������������������� �� �������������� ��������������������.</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>������ ��������</dt> +<dd>������ �������� ������ <uicontrol>���� ������������������</uicontrol>.</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>������������������ �������� - ���������������� (��������������) ������ �������������������� (��������������). </dd> +</dlentry><dlentry> +<dt>������ ��������</dt> +<dd>������ ��������, ���������������� <uicontrol>NAT</uicontrol> (���������������������������� �������������� ��������������).</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>�������������� ������������������, ���������������� <uicontrol>virbr0</uicontrol> (���� ������������������).</dd> +</dlentry><dlentry> +<dt>���������������� ������������������������</dt> +<dd>IP-����������.</dd> +</dlentry></dl></p> +<p>���������������� ������������������ ����������������:<ul> +<li rev="rev1"><uicontrol>������������������</uicontrol> - �������������� �������������� ��������������������.</li> +<li><uicontrol>��������������������</uicontrol> - �������������� �������������� ��������������������.</li> +<li><uicontrol>��������������</uicontrol> - �������������� �������������������� �� ��������������������.</li> +</ul>������ ���������������� �������� ���������������� ���� ������������ <uicontrol>���������� (+)</uicontrol> �� ������������ �������������� �������� ����������������.</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="ru-ru"> +<title>���������������� ��������</title> +<shortdesc>���������������� ��������.</shortdesc> +<csbody> +<p> <ol> +<li>�������������� ������ ��������.</li> +<li>���������������� ������ ��������. <dl rev="rev1"><dlentry> +<dt><uicontrol>��������������������������</uicontrol></dt> +<dd>�������������������������� ����������. ���������������� �������������� ���� ���������� ������������������������ �������������� �� ���������������� ������������������.</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>���������� ���������������������������� �������������� ��������������. ���������� �������������� ���������� ������������������ �� ���������������� ������������������ ���������������������������� ���������� IP-���������� ����������. �������������� �������������� ���� ���������� ������������������������ �� ����������������.</dd> +</dlentry><dlentry> +<dt><uicontrol>���������� ��������</uicontrol></dt> +<dd>���������� ������������ ���������� ��������. ���������������� �������������� ���������� ������������������������ �������������� �� ���������������� ������������������, �� �������������� �������������� ���������� ������������������������ �� ����������������, ������ �������� ���� ���� �������� ���������������������� ������������������ �� ��������. �� ������������ ������������ ���������� �������� �������������������� �������������� ���������������������������� �������������������� �� �������������� ������������������������ �� VLAN.</dd> +</dlentry></dl></li> +<li>���������������� ���� <uicontrol>��������������</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 230 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ru_RU/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/storage.dita new file mode 100644 index 0000000..fa37edc --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/storage.dita @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="ru-ru"> +<title>���������������� ������������</title> +<shortdesc>���� ���������������� <wintitle>���������������� ������������</wintitle> ������������������������ ������������ ������������������ ���������� ������������, �������������� �������� ������������ '���� ������������������' �� 'ISO'. +�������� ���� ������������ ������������������������ ���������������������� ISO, ���������������� ������ �� �������� ���������������� ������������ 'ISO'.</shortdesc> +<csbody> +<p>������ �������������� �������� ������������ ������������������������ ������������������ ��������������������:<dl> +<dlentry> +<dt>������</dt> +<dd>������ �������� ������������ �� �������������� ��������������������������.</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>������������������ �������� ������������ - ���������������� (��������������) ������ �������������������� (��������������). </dd> +</dlentry><dlentry> +<dt>������������������������</dt> +<dd>�������� �� ������������������������ �������� ������������.</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������ �������� ������������, ���������������� <uicontrol>��������������</uicontrol>.</dd> +</dlentry><dlentry> +<dt>��������������</dt> +<dd>���������� �������� ������������.</dd> +</dlentry><dlentry> +<dt>����������������</dt> +<dd>���������� �������������������� ������������ �� ��������.</dd> +</dlentry></dl></p> +<p>������ �������������� �������� ������������ ���������� ���������������� ������������������ ����������������:<ul> +<li><uicontrol>������������������������</uicontrol> - ������������������������ ������ ������������, ���������� ������ ���������� �������� ������������������������.</li> +<li><uicontrol>����������������������������</uicontrol> - ���������������������������� ���������������� ������ ������������.</li> +<li><uicontrol>��������������</uicontrol> - �������������� �������������������� ������ ������������.</li> +</ul></p> +<p>������ ������������������ ���������������� �� ���������� �������� ������������ ���������������� ���� �������������� �� ������������ ���������� ������������ �������� ������������. ���������������� ����������������:<dl><dlentry> +<dt>������</dt> +<dd>������ ��������, ���������������� <uicontrol>��������</uicontrol>.</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������ (�������������� ���� ��������).</dd> +</dlentry><dlentry> +<dt>��������������</dt> +<dd>������������ ��������.</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>���������� �������������������� ������������ �� ��������.</dd> +</dlentry></dl>������ ���������������� �������� ������������ ���������������� ���� ������������ <uicontrol>���������� (+)</uicontrol> �� ������������ �������������� �������� ����������������.</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="ru-ru"> +<title>���������������� �������� ������������</title> +<shortdesc> ���������������� �������� ������������.</shortdesc> +<csbody> +<p> <ol> +<li>�� �������� <uicontrol>������ �������� ������������</uicontrol> �������������� ������ ������ �������������������������� �������� ������������.</li> +<li>�� ������������ <uicontrol>������ �������� ������������</uicontrol> ���������������� ������: <dl><dlentry> +<dt><uicontrol>��������������</uicontrol></dt> +<dd>������������ ������-��������������. ������ ������������ �������� <uicontrol>��������������</uicontrol> ������������������ �������� +<uicontrol>�������� �� �������� ������������</uicontrol> (�������� �� �������� ������������ �� ���������������� ��������������).</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>������������ ������ ���� ������������ �������������� ���������������� ��������������. ������ ������������ <uicontrol>NFS</uicontrol> �������������� ���������� �� +�������� <uicontrol>IP-���������� �������������� NFS</uicontrol> �� �������� �� ���������������������������������� ���������������� �� �������� <uicontrol>�������� NFS</uicontrol>.</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>������������ ������ ���� ������������ ���������������� ��������������, ���������������������� ���� �������������� iSCSI. +������ ������������ �������� <uicontrol>iSCSI</uicontrol> �������������� IP-���������� �� �������� <uicontrol>������������ iSCSI</uicontrol> �� �������������� ������������ ���� �������������� iSCSI �� �������� <uicontrol>�������������� ������������</uicontrol>. ���������� ���������� ���������������� �������������������������� iSCSI.</dd> +</dlentry><dlentry> +<dt><uicontrol>��������������������</uicontrol></dt> +<dd>������������ ������ ������������ ���� ������������ ���������������������� ��������. ���������������� ������������������������ �������������������� �� �������� <uicontrol>�������� �� ��������������������</uicontrol>.</dd> +</dlentry><dlentry> +<dt><uicontrol>SCSI Fibre Channel</uicontrol></dt> +<dd>������������ ������ ���� ������������ SCSI Fibre Channel. ���������������� �������������� SCSI.</dd> +</dlentry></dl></li> +<li>���������������� ���� <uicontrol>��������������</uicontrol>.</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 233 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/ru_RU/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/templates.dita new file mode 100644 index 0000000..27ce4ae --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/ru_RU/templates.dita @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="ru-ru"> +<title>��������������</title> +<shortdesc>���� ���������������� <wintitle>��������������</wintitle> ������������������������ ������������������ �������������� ���������������������� ����������, �������������� ���������� ������������������������ ������ ���������������� ���������������� ������������ KVM.</shortdesc> +<csbody> +<p>������ �������������� �������������� ������������������������ ������������������ ��������������������:<dl> +<dlentry> +<dt>����</dt> +<dd>������ ������������������������ �������������� ������ ���������������� ������������������������ ��������������.</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������ ������������������������ �������������� ������ ���������������� ������������������������ ��������������.</dd> +</dlentry><dlentry> +<dt>��������������������</dt> +<dd>�������������������� ���������������������� ������ ��������������.</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>�������������������� ���������� ���������������������� ������������ �� ����.</dd> +</dlentry></dl></p> +<p>������ �������������� �������������� ���������� ���������������� ������������������ ����������������:<ul> +<li><uicontrol>����������������</uicontrol> - ���������������� ������������.</li> +<li><uicontrol>��������������</uicontrol> - �������������� ������������.</li> +</ul>������ �������������������� �������������� ���������������� ���� ������������ <uicontrol>���������� (+)</uicontrol> �� ������������ �������������� �������� ����������������.</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="ru-ru"> +<title>���������������� ������������</title> +<shortdesc>���������������� ������������������������ ������������.</shortdesc> +<csbody> +<p>������ �������������� �������������� ������������������������ ������������������ ��������������������: <dl> +<dlentry> +<dt>������</dt> +<dd>������ ��������������.</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������ ����������������, ������������������ ������������������������ �������������� ������ �������������� ������������������������ ��������������, ������ �������������������������� �������������� �������������������������� ������������.</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������ ������������������������ �������������� ������ ���������������� ������������������������ ��������������, ������ �������������������������� �������������� �������������������������� ������������.</dd> +</dlentry><dlentry> +<dt>�������������������� ����������������������</dt> +<dd>�������������������� ���������������������� ������ ��������������.</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>���������� ������������ �� ����, �������������������� ���������������������� ������������.</dd> +</dlentry><dlentry> +<dt>��������</dt> +<dd>������������ ���������� �� ����.</dd> +</dlentry><dlentry> +<dt>CDROM</dt> +<dd>�������� �� ���������� ISO ������ ������������������ ���������������� �������������� KVM.</dd> +</dlentry><dlentry> +<dt>������ ������������</dt> +<dd>������������������������ ������ ������������ ������ ������ ������������ ���� ������������������.</dd> +</dlentry><dlentry> +<dt>��������</dt> +<dd>�������������� �������������������� ���� ������������������, ������������������ ������ ���������������� �������������� KVM. ���������� �������������� ������������������ ����������.</dd> +</dlentry></dl> ���������������� �������� ���������� ����������������. ���������� ������������������ �������� ���������������� ���� <uicontrol>������������������</uicontrol>. </p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>�������������������� ��������������</title> +<shortdesc>�������������������� �������������� �� ������������������ ����������������. ���������������� ���������������������� ���������� ISO �� ���������������� ������������ ISO ������ ���������������������� ������������.</shortdesc> +<csbody> +<p>���������������� �������� ���� ������������������ ������������������ ������������������������ ������������������ ����������������:<dl> +<dlentry> +<dt>������������������ ���������� ISO</dt> +<dd>���������������� �������� �������������� ������ ������������ ������������������������ �������������� ISO �� ������������������ ���������� ������������ ��������������.</dd> +</dlentry><dlentry> +<dt>������������������ ���������� ISO</dt> +<dd>���������������� �������� ��������������, ���������� �������������� ������������������ ������������������������ �������������������������� ������������ ISO.</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>�������������������� �������������� (������������������ ���������� ISO)</title> +<shortdesc>�������������������� �������������� ���� �������������������� ������������ ISO.</shortdesc> +<csbody> +<p>���������� ���������������� ������������ ISO, ������������������ �� ��������������.<dl><dlentry> +<dt>����</dt> +<dd>������ ������������������������ �������������� ������ ���������������� ������������������������ ��������������.</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������ ������������������������ �������������� ������ ���������������� ������������������������ ��������������.</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������ ������������ ISO.</dd> +</dlentry></dl></p> +<p>������ ���������������� �������������� ���� ������������ ISO ���������������� �������� ���� ������������������ ������������������:<ul> +<li>���������������� ���������� ISO, ���� ���������������� ���������� �������������� ������������, ���������� ���������������� ���� <uicontrol>�������������� �������������� ���� ������������������ �������������� ISO</uicontrol>.</li> +<li>���������������� <uicontrol>������</uicontrol>, ���������� �������������� ������������ ���� �������������� ������������ ISO �� ������������, ���������� ���������������� ���� <uicontrol>�������������� �������������� ���� ������������������ �������������� ISO</uicontrol>.</li> +<li>�������� ������������������ ���������� ISO ���������������������� �� ���������������������� ������������, ���������������� �������� ���� ������������������ ������������������:<ul> +<li>���������������� <uicontrol>������������������������ �������������������� �������� ISO</uicontrol>, ���������� �������������� �������� �� ������������ ISO.</li> +<li>���������������� ���� <uicontrol>���������� ���������������������������� �������������� ISO</uicontrol> ������ ������������ ���������������������������� �������������� ISO.</li> +</ul></li> +</ul></p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 229 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_CN/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/Makefile.am new file mode 100644 index 0000000..e785048 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +zh_CN_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/zh_CN + +dist_zh_CN_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_CN/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/guests.dita new file mode 100644 index 0000000..d684af2 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/guests.dita @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="zh-cn"> +<title>������</title> +<shortdesc>���<wintitle>������</wintitle>��������������������������� KVM ������������</shortdesc> +<csbody> +<p>���������������������������������������������<dl><dlentry> +<dt>������</dt> +<dd>���������������������</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>���������������������������������������</dd> +</dlentry><dlentry> +<dt>������ I/O</dt> +<dd>������������/������������������������ KB/������������</dd> +</dlentry><dlentry> +<dt>������ I/O</dt> +<dd>������������/������������������������ KB/������������</dd> +</dlentry><dlentry> +<dt>Livetile</dt> +<dd>������������������������������������������������������������������������������������ <tm tmtype="tm" trademark="Linux">Linux</tm> ���������������������</dd> +</dlentry></dl></p> +<p>���������������������������������������������<dl> +<dlentry> +<dt>������</dt> +<dd>������������������������������</dd> +</dlentry><dlentry> +<dt>���������������������������</dt> +<dd>������������������������������������������������������������������������������������������������������������������������������������������������������</dd> +</dlentry></dl> </p> +<p>���������������������������������������<ul> +<li>������<uicontrol>������</uicontrol>���������������������������������������������������</li> +<li>������<uicontrol>������������</uicontrol>���������������������������������</li> +<li>������<uicontrol>������</uicontrol>������������������</li> +<li>������<uicontrol>������</uicontrol>���������������������������������������������������������������������</li> +<li>������<uicontrol>������</uicontrol>������������������</li> +</ul>���������������������������������������������������������<uicontrol>��������� (+) </uicontrol> ���������</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="zh-cn"> +<title>���������������</title> +<shortdesc>������������������������������������������</shortdesc> +<csbody> +<p> <ol> +<li>���������������������������������������</li> +<li rev="rev1">���������������<ul> +<li>���������������������������������������������������������������</li> +<li>���������������������������������������<uicontrol>������������</uicontrol>������������������</li> +</ul></li> +<li>������<uicontrol>������</uicontrol>���</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="zh-cn"> +<title>������������</title> +<shortdesc>���������������������������������������������������������������������������������������������������������������������������������������</shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>������������������������������<wintitle>������</wintitle>������������������������������������<dl> +<dlentry> +<dt>������</dt> +<dd>���������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>CPU ���</dt> +<dd>���������������������������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>��������������� MB ���������������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>��������������������������������������������������� Linux ������������������������������ (Livetile) ������������������</dd> +</dlentry></dl></p> +<p>���������<wintitle>���������</wintitle>������������������������������������</p> +<dl><dlentry> +<dt>���������</dt> +<dd>��������������������� ISO ������������������������</dd> +</dlentry></dl> +<p> ���������������������������������������������������������������������<uicontrol>������</uicontrol>���</p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="zh-cn"> +<title>������������������������������������</title> +<shortdesc rev="rev1">��������������������������������������������������������������������������������������� CDROM���������������������������������������������������</shortdesc> +<csbody> +<ol> +<li>������<wintitle>������������</wintitle>������������������������<wintitle>���������</wintitle>������</li> +<li>���������������������������������������������������������<uicontrol>������������ (/)</uicontrol>��������� ISO ���������������������<uicontrol>������</uicontrol>���</li> +<li>���������������������������������������������������������<uicontrol>��������������� (-)</uicontrol>������������������������������������<uicontrol>������</uicontrol>���</li> +<li>���������������������������������������������������������<uicontrol>��������������� (+)</uicontrol>��������������������� ISO ���������������������<uicontrol>������</uicontrol>���</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="zh-cn"> +<title>������ VM ��� CDROM</title> +<shortdesc rev="rev1">������������������������������������������������ CDROM ������������</shortdesc> +<csbody> +<ol> +<li>������������������������������</li> +<li>���������������������������������<uicontrol>������������</uicontrol>���</li> +<li>������������������������ CDROM ������������������������ hdc ���������������<uicontrol>������������ (/)</uicontrol> ���������</li> +<li>������<wintitle>������ VM ��� CDROM</wintitle>��������������������� ISO ���������������������������������������������</li> +<li>������<uicontrol>������</uicontrol>���</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 231 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_CN/host.dita b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/host.dita new file mode 100644 index 0000000..78a89c3 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/host.dita @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="zh-cn"> +<title>������</title> +<shortdesc>���<wintitle>������</wintitle>������������������������������������������������������������������������������������������������������</shortdesc> +<csbody> +<p>���������������������������������<ul> +<li>������<uicontrol>������</uicontrol>������������������������</li> +<li>������<uicontrol>������������</uicontrol>������������������������������</li> +<li>������<uicontrol>������</uicontrol>��������������������������� VNC ���������������������������������</li> +</ul></p> +<p>���������������������������������������������������<dl> +<dlentry> +<dt>������������</dt> +<dd>��������������������������������������������������������������������������������������������������������� GB ���������</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>��������������������������������������������� CPU������������������ I/O ��������� I/O ������������������������<uicontrol>���������������������������������</uicontrol>������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>���������������������������������������������������������������������������������������������������������������������������������������������<uicontrol>������������</uicontrol>���������������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� Red Hat Enterprise Linux ��� Fedora������������������ <filepath>yum</filepath> ��������������������������������� Ubuntu ��� Debian������������������ <filepath>deb</filepath> ������������<p>��������������� Yum ��������������������������� GPG ������������������������������������������������������������������������������������������������<uicontrol>������</uicontrol>���������<uicontrol>���</uicontrol>��������� GPG ��������������������������������� GPG ��������������� URL���</p></dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<p>��������������������� +<cmdname>sosreport</cmdname> ��������������������������������� Red +Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>���Fedora ��� Ubuntu ������������������������������������������������������������ .tar ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 232 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_CN/network.dita b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/network.dita new file mode 100644 index 0000000..f6aa532 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/network.dita @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="zh-cn"> +<title>������</title> +<shortdesc>���<wintitle>������</wintitle>���������������������������������������������</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>���������</dt> +<dd>������������������<uicontrol>���������</uicontrol>���</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>���������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������������������<uicontrol>NAT</uicontrol>���������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������<uicontrol>virbr0</uicontrol>������������������</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>IP ���������</dd> +</dlentry></dl></p> +<p>���������������������������<ul> +<li rev="rev1">������<uicontrol>������</uicontrol>������������������������</li> +<li>������<uicontrol>������</uicontrol>������������������������</li> +<li>������<uicontrol>������</uicontrol>������������������������</li> +</ul>������������������������������������������������<uicontrol>��������� (+)</uicontrol> ���������</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="zh-cn"> +<title>������������</title> +<shortdesc>���������������</shortdesc> +<csbody> +<p> <ol> +<li>������������������������</li> +<li>������������������������������������<dl rev="rev1"><dlentry> +<dt><uicontrol>������</uicontrol></dt> +<dd>������������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>��������������������������������������������������������������������������� IP ������������������������������������������������������</dd> +</dlentry><dlentry> +<dt><uicontrol>������</uicontrol></dt> +<dd>������������������������������������������������������������������������������������������������������������������������������������������������������������������ VLAN ���������</dd> +</dlentry></dl></li> +<li>������<uicontrol>������</uicontrol>���</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 230 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_CN/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/storage.dita new file mode 100644 index 0000000..cfb09f5 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/storage.dita @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="zh-cn"> +<title>���������</title> +<shortdesc>���<wintitle>���������</wintitle>���������������������������������������������������������������������ISO��������������������������������������������� ISO������������������������ISO���������������������</shortdesc> +<csbody> +<p>������������������������������������������������<dl> +<dlentry> +<dt>������</dt> +<dd>������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������ </dt> +<dd>���������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������<uicontrol>dir</uicontrol>���</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>���������������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������������������������������������</dd> +</dlentry></dl></p> +<p>������������������������������������������<ul> +<li>������<uicontrol>������</uicontrol>���������������������������������������</li> +<li>������<uicontrol>������������</uicontrol>���������������������������������</li> +<li>������<uicontrol>������������</uicontrol>������������������������������</li> +</ul></p> +<p>���������������������������������������������������������������������������������������������������������������������<dl><dlentry> +<dt>������</dt> +<dd>������������������������<uicontrol>������</uicontrol>���</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>���������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>���������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������</dd> +</dlentry></dl>���������������������������������������������������<uicontrol>��������� (+)</uicontrol> ���������</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="zh-cn"> +<title>���������������</title> +<shortdesc> ������������������</shortdesc> +<csbody> +<p> <ol> +<li>���<uicontrol>���������������</uicontrol>���������������������������������������������������</li> +<li>���<uicontrol>���������������</uicontrol>���������������������������<dl><dlentry> +<dt><uicontrol>DIR</uicontrol></dt> +<dd>��������������������������� <uicontrol>DIR</uicontrol> ������������<uicontrol>������������</uicontrol>���������������������������������</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>��������������������������������������� <uicontrol>NFS</uicontrol> ������������ <uicontrol>NFS ��������� IP ������</uicontrol>��� <uicontrol>NFS ������</uicontrol>���������������������������������</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>������ iSCSI ������������������������������������������������ <uicontrol>iSCSI</uicontrol> ��������� iSCSI ������������������ <uicontrol>iSCSI ��������� IP ������</uicontrol>���<uicontrol>������</uicontrol>������������������������������������ iSCSI ���������</dd> +</dlentry><dlentry> +<dt><uicontrol>������</uicontrol></dt> +<dd>������������������������������<uicontrol>������������</uicontrol>���������������������������</dd> +</dlentry><dlentry> +<dt><uicontrol>SCSI ������������</uicontrol></dt> +<dd>������ SCSI ������������������������������������������ SCSI ������������</dd> +</dlentry></dl></li> +<li>������<uicontrol>������</uicontrol>���</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 233 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_CN/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/templates.dita new file mode 100644 index 0000000..ca50119 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_CN/templates.dita @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="zh-cn"> +<title>������</title> +<shortdesc>���<wintitle>������</wintitle>������������������������������ KVM ������������������������������������</shortdesc> +<csbody> +<p>���������������������������������������������<dl> +<dlentry> +<dt>������������</dt> +<dd>������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������</dd> +</dlentry><dlentry> +<dt>CPU ���</dt> +<dd>���������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>��������������������������������������� MB ���������</dd> +</dlentry></dl></p> +<p>���������������������������������������<ul> +<li>������<uicontrol>������</uicontrol>������������������</li> +<li>������<uicontrol>������</uicontrol>������������������</li> +</ul>������������������������������������������������<uicontrol>��������� (+)</uicontrol> ���������</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="zh-cn"> +<title>������������</title> +<shortdesc>���������������������</shortdesc> +<csbody> +<p>���������������������������������������������<dl> +<dlentry> +<dt>������</dt> +<dd>������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������������������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>CPU ������</dt> +<dd>���������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>��������������������������������������� MB ���������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������ GB ���������</dd> +</dlentry><dlentry> +<dt>CDROM</dt> +<dd>������������ KVM ��������� ISO ������������������������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������ KVM ������������������������������������������������������������������</dd> +</dlentry></dl> ���������������������������������������������������������������������<uicontrol>������</uicontrol>���</p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>������������</title> +<shortdesc>������������������������������������������������������ ISO ������������������ISO������������������������������������</shortdesc> +<csbody> +<p>������������������������������������������������<dl> +<dlentry> +<dt>������ ISO ������</dt> +<dd>������������������������������������������ ISO ���������������������������������</dd> +</dlentry><dlentry> +<dt>������ ISO ������</dt> +<dd>��������������������������� ISO ������������������������</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>������������ - ������ ISO ������</title> +<shortdesc>��������� ISO ���������������������</shortdesc> +<csbody> +<p>��������������������������� ISO ���������<dl><dlentry> +<dt>������������</dt> +<dd>������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>ISO ������������������</dd> +</dlentry></dl></p> +<p>������ ISO ���������������������������������������������������<ul> +<li>������������������������������ ISO ���������������������<uicontrol>��������� ISO ������������</uicontrol>���</li> +<li>������<uicontrol>������</uicontrol>������������������������ ISO ���������������������������������<uicontrol>��������� ISO ������������</uicontrol>���</li> +<li>��������������������� ISO ������������������������������������������������������������������������<ul> +<li>������<uicontrol>������������������ ISO ������</uicontrol>��������� ISO ������������������</li> +<li>������<uicontrol>������������ ISO</uicontrol> ��������������� ISO ���������</li> +</ul></li> +</ul></p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 229 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_TW/Makefile.am b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/Makefile.am new file mode 100644 index 0000000..9c8ac26 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/Makefile.am @@ -0,0 +1,23 @@ +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +zh_TW_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/zh_TW + +dist_zh_TW_help_DATA = $(wildcard *.html) $(NULL) + +EXTRA_DIST = $(wildcard *.dita) + +CLEANFILES = $(wildcard *.html) diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_TW/guests.dita b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/guests.dita new file mode 100644 index 0000000..cf73785 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/guests.dita @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhvirtm" xml:lang="zh-tw"> +<title>������</title> +<shortdesc>���<wintitle>������</wintitle>������������������������������ KVM ���������������</shortdesc> +<csbody> +<p>���������������������������������������������������<dl><dlentry> +<dt>������</dt> +<dd>������������������������</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������ I/O</dt> +<dd>������������/������������������ (KB/s)���</dd> +</dlentry><dlentry> +<dt>������ I/O</dt> +<dd>������������/������������������ (KB/s)���</dd> +</dlentry><dlentry> +<dt>Livetile</dt> +<dd>��������������������������������������������������� <tm tmtype="tm" trademark="Linux">Linux</tm> ������������������������������������������������������������������</dd> +</dlentry></dl></p> +<p>���������������������������������������������������������<dl> +<dlentry> +<dt>������</dt> +<dd>���������������������������</dd> +</dlentry><dlentry> +<dt>���������������������������</dt> +<dd>���������������������������������������������������������������������������������������������������������������������������������������������������</dd> +</dlentry></dl> </p> +<p>���������������������������������������������<ul> +<li>������<uicontrol>������</uicontrol>���������������������������������������������������</li> +<li>������<uicontrol>������������</uicontrol>���������������������������������</li> +<li>������<uicontrol>������</uicontrol>������������������</li> +<li>������<uicontrol>������</uicontrol>������������������������������������������������������������������������</li> +<li>������<uicontrol>������</uicontrol>������������������</li> +</ul>������������������������������������������������������������������������<uicontrol>������ (+)</uicontrol> ���������</p> +</csbody> +<cshelp id="kimhvirtmcrt" xml:lang="zh-tw"> +<title>������������������</title> +<shortdesc>���������������������������������������</shortdesc> +<csbody> +<p> <ol> +<li>������������������������������������������</li> +<li rev="rev1">���������������<ul> +<li>������������������������������������������������������</li> +<li>���������������������������������<uicontrol>������������</uicontrol>������������������</li> +</ul></li> +<li>���������<uicontrol>������</uicontrol>���</li> +</ol> </p> +</csbody> +</cshelp> +<cshelp id="kimhvirtmedit" xml:lang="zh-tw"> +<title>������������</title> +<shortdesc>������������������������������������������������������������������������������������������������������������������������������������</shortdesc> +<csprolog><csmetadata></csmetadata></csprolog> +<csbody> +<p>������������������������������������<wintitle>������</wintitle>���������������������������������<dl> +<dlentry> +<dt>������</dt> +<dd>������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>���������������������������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>��������������� (MB)������������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������������������������������ (Livetile) ��������������� Linux ������������������������������</dd> +</dlentry></dl></p> +<p>���������������������������<wintitle>������</wintitle>���������������</p> +<dl><dlentry> +<dt>���������</dt> +<dd>��������������������� ISO ������������������</dd> +</dlentry></dl> +<p> ���������������������������������������������������������������<uicontrol>������</uicontrol>���</p> +</csbody> +</cshelp> +<cshelp id="kimstoragedevice" xml:lang="zh-tw"> +<title>������������������������������������</title> +<shortdesc rev="rev1">������������������������������������������������������������������������������������������ CDROM������������������������������������������������������</shortdesc> +<csbody> +<ol> +<li>������<wintitle>������������</wintitle>������������������������<wintitle>���������</wintitle>������</li> +<li>���������������������������������������������<uicontrol>������������ (/)</uicontrol> ��������������������������� +ISO ������������������������������<uicontrol>������</uicontrol>���</li> +<li>���������������������������������������������<uicontrol>������������ (/)</uicontrol> ���������������������������������������������������<uicontrol>������</uicontrol>���</li> +<li>���������������������������������������������������<uicontrol>������ (+)</uicontrol> ������������������������������������������ +ISO ������������������������������<uicontrol>������</uicontrol>���</li> +</ol> +</csbody> +</cshelp> +<cshelp id="kimreplacemedia" xml:lang="zh-tw"> +<title>��������������������� CDROM</title> +<shortdesc rev="rev1">��������������������������������������������������� CDROM ������������</shortdesc> +<csbody> +<ol> +<li>������������������������������</li> +<li>������������������������������������<uicontrol>������������</uicontrol>���</li> +<li>��������������������� CDROM ��������������������������������� hdc ���������������<uicontrol>������������ (/)</uicontrol> ���������</li> +<li>������<wintitle>��������������������� CDROM</wintitle>��������������������� ISO ������������������������������������������������</li> +<li>���������<uicontrol>������</uicontrol>���</li> +</ol> +</csbody> +</cshelp> +<?tm 1391540919 3?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 45645_6 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 231 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_TW/host.dita b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/host.dita new file mode 100644 index 0000000..a55aae4 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/host.dita @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhhost" xml:lang="zh-tw"> +<title>������</title> +<shortdesc>���<wintitle>������</wintitle>���������������������������������������������������������������������������������������������������������</shortdesc> +<csbody> +<p>������������������������������������������<ul> +<li>������<uicontrol>������</uicontrol>������������������������</li> +<li>������<uicontrol>������������</uicontrol>������������������������������</li> +<li>������<uicontrol>������</uicontrol>��������������������������� VNC ������������������������������������������������</li> +</ul></p> +<p>������������������������������������������������������<dl> +<dlentry> +<dt>������������</dt> +<dd>������������������������������������������������������������������������������������������������������������������ (GB)���</dd> +</dlentry><dlentry> +<dt>������������������</dt> +<dd>��������������������������������������������������� CPU��������������������� I/O ��������� I/O ������������������������<uicontrol>���������������������������������</uicontrol>���������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>���������������������������������������������������������������������������������������������������������������������������������������������<uicontrol>������������</uicontrol>���������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ +Red Hat Enterprise Linux ��� Fedora������������������ <filepath>yum</filepath> ��������������������������������� +Ubuntu ��� Debian������������������ <filepath>deb</filepath> ������������<p>��������������������� +yum ��������������������������� GPG ���������������������������������������������������������������������������������������������<uicontrol>������</uicontrol>���������<uicontrol>���</uicontrol>��������� +GPG ��������������������������������� GPG ������������ URL���</p></dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>���������������������������������������������������������������������������������������������������������������������������������������������������������<p>��������������������� +<cmdname>sosreport</cmdname> ������������������������������������ Red +Hat Enterprise <tm tmtype="tm" trademark="Linux">Linux</tm>���Fedora +��� Ubuntu ��������������������������������� .tar ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������</p> </dd> +</dlentry></dl></p> +</csbody> +<?tm 1392659967 1?> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47930_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 232 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_TW/network.dita b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/network.dita new file mode 100644 index 0000000..f392060 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/network.dita @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhnetw" xml:lang="zh-tw"> +<title>������</title> +<shortdesc>���<wintitle>������</wintitle>������������������������������������������������</shortdesc> +<csbody> +<p><dl><dlentry> +<dt>������������</dt> +<dd>������������������������<uicontrol>���������</uicontrol>���</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>���������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>������������������������<uicontrol>NAT</uicontrol>���������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������<uicontrol>virbr0</uicontrol>������������������</dd> +</dlentry><dlentry> +<dt>������������</dt> +<dd>IP ���������</dd> +</dlentry></dl></p> +<p>������������������������<ul> +<li rev="rev1">������<uicontrol>������</uicontrol>������������������������</li> +<li>������<uicontrol>������</uicontrol>������������������������</li> +<li>������<uicontrol>������</uicontrol>������������������������</li> +</ul>���������������������������������������������������������<uicontrol>������ (+)</uicontrol> ���������</p> +</csbody> +<cshelp id="kimhnetwcrt" xml:lang="zh-tw"> +<title>������������</title> +<shortdesc>������������</shortdesc> +<csbody> +<p> <ol> +<li>������������������������</li> +<li>���������������������������������<dl rev="rev1"><dlentry> +<dt><uicontrol>���������</uicontrol></dt> +<dd>������������������������������������������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt><uicontrol>NAT</uicontrol></dt> +<dd>������������������������������������������������������������������ IP ������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt><uicontrol>���������</uicontrol></dt> +<dd>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� VLAN ���������</dd> +</dlentry></dl></li> +<li>���������<uicontrol>������</uicontrol>���</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 47050_3 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 230 --> +<!-- T9N_SH1P_STR1NG KVM21AAP001 3 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_TW/storage.dita b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/storage.dita new file mode 100644 index 0000000..971619c --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/storage.dita @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhstor" xml:lang="zh-tw"> +<title>���������</title> +<shortdesc>���<wintitle>���������</wintitle>������������������������������������������������������������������������������������ 'ISO' ��������������������������������������� ISO��������������������� 'ISO' ������������������</shortdesc> +<csbody> +<p>������������������������������������������������������<dl> +<dlentry> +<dt>������</dt> +<dd>������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>���������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������<uicontrol>dir</uicontrol>���</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>���������������������������������������</dd> +</dlentry></dl></p> +<p>������������������������������������������������<ul> +<li>������<uicontrol>������</uicontrol>������������������������������������������</li> +<li>������<uicontrol>������������</uicontrol>���������������������������������������</li> +<li>������<uicontrol>������������</uicontrol>������������������������������������</li> +</ul></p> +<p>������������������������������������������������������������������������������������������������������������������������������<dl><dlentry> +<dt>������</dt> +<dd>���������������������������<uicontrol>������</uicontrol>���</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>���������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>���������������������������������������</dd> +</dlentry></dl>������������������������������������������������������������<uicontrol>������ (+)</uicontrol> ���������</p> +</csbody> +<cshelp id="kimhdefstor" xml:lang="zh-tw"> +<title>���������������</title> +<shortdesc> ������������������</shortdesc> +<csbody> +<p> <ol> +<li>���<uicontrol>���������������</uicontrol>���������������������������������������������������</li> +<li>���<uicontrol>���������������</uicontrol>���������������������������<dl><dlentry> +<dt><uicontrol>DIR</uicontrol></dt> +<dd>��������������������������������� <uicontrol>DIR</uicontrol> ���������������<uicontrol>���������������</uicontrol>���������������������������</dd> +</dlentry><dlentry> +<dt><uicontrol>NFS</uicontrol></dt> +<dd>��������������������������������������������� <uicontrol>NFS</uicontrol> ��������������� +<uicontrol>NFS ��������� IP</uicontrol> ��������� <uicontrol>NFS +������</uicontrol>���������������������������������</dd> +</dlentry><dlentry> +<dt><uicontrol>iSCSI</uicontrol></dt> +<dd>��������� iSCSI ��������������������������������������������������������� +<uicontrol>iSCSI</uicontrol> ��������������� <uicontrol>iSCSI +���������</uicontrol> IP ��������� iSCSI ���������������<uicontrol>������</uicontrol>������������������������������������ iSCSI ���������</dd> +</dlentry><dlentry> +<dt><uicontrol>������</uicontrol></dt> +<dd>���������������������������������<uicontrol>������������</uicontrol>���������������������������</dd> +</dlentry><dlentry> +<dt><uicontrol>SCSI ������������</uicontrol></dt> +<dd>������ SCSI ������������������������������������������������ SCSI ������������</dd> +</dlentry></dl></li> +<li>���������<uicontrol>������</uicontrol>���</li> +</ol> </p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 22336_4 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 233 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/help/zh_TW/templates.dita b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/templates.dita new file mode 100644 index 0000000..4b3a6a6 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/help/zh_TW/templates.dita @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--Arbortext, Inc., 1988-2011, v.4002--> +<!DOCTYPE cshelp PUBLIC "-//IBM//DTD DITA CSHelp//EN" + "..\dtd\cshelp.dtd"> + + +<!--This DITA specialized document type is not supported by the Authoring Tools development team. +For support please see: +https://w3.opensource.ibm.com/projects/dita-cshelp/--> +<cshelp id="kimhtempl" xml:lang="zh-tw"> +<title>������</title> +<shortdesc>���<wintitle>������</wintitle>��������������������������������� +KVM ���������������������������������������</shortdesc> +<csbody> +<p>���������������������������������������������������<dl> +<dlentry> +<dt>OS</dt> +<dd>������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������������������</dd> +</dlentry><dlentry> +<dt>CPU</dt> +<dd>������������������������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>��������������������������������������� (MB)���</dd> +</dlentry></dl></p> +<p>���������������������������������������������<ul> +<li>������<uicontrol>������</uicontrol>������������������</li> +<li>������<uicontrol>������</uicontrol>������������������</li> +</ul>���������������������������������������������������������<uicontrol>������ (+)</uicontrol> ���������</p> +</csbody> +<cshelp id="kimhedittempl" xml:lang="zh-tw"> +<title>������������</title> +<shortdesc>���������������������</shortdesc> +<csbody> +<p>���������������������������������������������������<dl> +<dlentry> +<dt>������</dt> +<dd>������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������������������������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>���������������������������������������������������������������</dd> +</dlentry><dlentry> +<dt>CPU ������</dt> +<dd>������������������������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������������������������������������������ (MB)���</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������ (GB)���</dd> +</dlentry><dlentry> +<dt>CDROM</dt> +<dd>������������ KVM ��������� ISO ������������������������������</dd> +</dlentry><dlentry> +<dt>���������</dt> +<dd>������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>KVM ���������������������������������������������������������������������</dd> +</dlentry></dl> ���������������������������������������������������������������<uicontrol>������</uicontrol>���</p> +</csbody> +</cshelp> +<cshelp id="kimhaddtempl"> +<title>������������</title> +<shortdesc>������������������������������������������������������ ISO ������������������ 'ISO' ������������������������������������</shortdesc> +<csbody> +<p>������������������������������������������������<dl> +<dlentry> +<dt>������ ISO ���������</dt> +<dd>��������������������������������������������������������������� ISO ������������</dd> +</dlentry><dlentry> +<dt>������ ISO ���������</dt> +<dd>��������������������������� ISO ���������������������������</dd> +</dlentry></dl></p> +</csbody> +</cshelp> +<cshelp id="kimhaddloct"> +<title>������������ - ������ ISO ���������</title> +<shortdesc>��������� ISO ������������������������</shortdesc> +<csbody> +<p>������������������������������ ISO ������������<dl><dlentry> +<dt>OS</dt> +<dd>������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>������������������������������������������������</dd> +</dlentry><dlentry> +<dt>������</dt> +<dd>ISO ���������������������</dd> +</dlentry></dl></p> +<p>��������� ISO ������������������������������������������������������<ul> +<li>������������������������������ ISO ���������������������������<uicontrol>��������� ISO ������������</uicontrol>���</li> +<li>������<uicontrol>������</uicontrol>������������������������ ISO ���������������������������������������<uicontrol>��������� ISO ������������</uicontrol>���</li> +<li>������������������ ISO ���������������������������������������������������������������������������<ul> +<li>������<uicontrol>��������������������� ISO ������</uicontrol>��������� ISO ���������������������</li> +<li>���������<uicontrol>������������ ISO</uicontrol> ��������������� ISO ������������</li> +</ul></li> +</ul></p> +</csbody> +</cshelp> +</cshelp> + + +<!-- ENGL1SH_VERS10N 61085_5 DO NOT REMOVE OR CHANGE THIS LINE --> +<!-- T9N_SRC_ID 229 --> +<!-- T9N_SH1P_STR1NG KV211AAP001 1 --> diff --git a/src/wok/plugins/kimchi/ui/pages/host.html.tmpl b/src/wok/plugins/kimchi/ui/pages/host.html.tmpl new file mode 100644 index 0000000..d87debc --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/host.html.tmpl @@ -0,0 +1,177 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# + +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<html> +<head> +<link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> +<script src="plugins/kimchi/js/kimchi.min.js"></script> +</head> +<body> +<div id="host-root-container"> + <div class="toolbar"> + <div class="tools"> + </div> + </div> + <div id="host-content-container" class="empty-when-logged-off"></div> +</div> + +<script id="host-tmpl" type="kimchi/template"> + <div class="host-panel"> + <div class="logo-container"> + <div class="logo" style="background-image: url({logo});"></div> + </div> + <div id="host-info-container" class="info-container"> + <h2 class="hostname">{hostname}</h2> + <div class="action-panel"> + <button id="host-button-shutdown" class="btn-normal-1 stop"> + <div class="button-icon action-icon-stop"></div> + $_("Shut down") + </button> + <button id="host-button-restart" class="btn-normal-1 restart"> + <div class="button-icon action-icon-restart"></div> + $_("Restart") + </button> + <button class="btn-normal-1 connect" disabled="disabled"> + <div class="button-icon action-icon-connect"></div> + $_("Connect") + </button> + </div> + <div class="host-section"> + <h3 class="section-header" + aria-expanded="false" + aria-controls="content-sys-info"> + $_("Basic Information") + </h3> + <div id="content-sys-info" class="section-content"> + <div class="section-row"> + <div class="section-label">$_("OS Distro")</div> + <div class="section-value">{os_distro}</div> + </div> + <div class="section-row"> + <div class="section-label">$_("OS Version")</div> + <div class="section-value">{os_version}</div> + </div> + <div class="section-row"> + <div class="section-label">$_("OS Code Name")</div> + <div class="section-value">{os_codename}</div> + </div> + <div class="section-row"> + <div class="section-label">$_("Processor")</div> + <div class="section-value">{cpu_model}</div> + </div> + <div class="section-row"> + <div class="section-label">$_("CPU(s)")</div> + <div class="section-value">{cpus}</div> + </div> + <div class="section-row"> + <div class="section-label">$_("Memory")</div> + <div class="section-value">{memory}</div> + </div> + </div> + </div> + <div class="host-section"> + <h3 class="section-header" + aria-controls="content-sys-statistics"> + $_("System Statistics") + </h3> + <div id="content-sys-statistics" class="section-content"> + <div class="section-row"> + <div class="section-label">$_("CPU")</div> + <div class="section-value"> + <div id="container-chart-cpu" class="inline-block"></div> + </div> + </div> + <div class="section-row"> + <div class="section-label">$_("Memory")</div> + <div class="section-value"> + <div id="container-chart-memory" class="inline-block"></div> + </div> + </div> + <div class="section-row"> + <div class="section-label">$_("Disk I/O")</div> + <div class="section-value"> + <div id="container-chart-disk-io" class="inline-block"></div> + </div> + </div> + <div class="section-row"> + <div class="section-label">$_("Network I/O")</div> + <div class="section-value"> + <div id="container-chart-network-io" class="inline-block"></div> + </div> + </div> + </div> + </div> + <div id="software-update-section" class="host-section hidden"> + <h3 class="section-header" + aria-controls="content-software-update"> + $_("Software Updates") + </h3> + <div id="content-software-update" class="section-content"> + <div class="section-row"> + <div class="section-value"> + <div id="software-updates-grid-container"></div> + <div id="software-updates-progress-container" class="hidden"> + <label for="software-updates-progress-textarea">$_("Update Progress")</label> + <textarea id="software-updates-progress-textarea" readonly></textarea> + </div> + </div> + </div> + </div> + </div> + <div id="repositories-section" class="host-section hidden"> + <h3 class="section-header" + aria-controls="content-repositories"> + $_("Repositories") + </h3> + <div id="content-repositories" class="section-content"> + <div class="section-row"> + <div class="section-value"> + <div id="repositories-grid-container"></div> + </div> + </div> + </div> + </div> + <div id="debug-report-section" class="host-section hidden"> + <h3 class="section-header" + aria-controls="content-sys-reports"> + $_("Debug Reports") + </h3> + <div id="content-sys-reports" class="section-content"> + <div class="section-row"> + <div class="section-value"> + <div id="available-reports-grid-container"></div> + </div> + </div> + </div> + </div> + </div> + </div> +</script> + +<script type="text/javascript"> + kimchi.host_main(); +</script> +</body> +</html> diff --git a/src/wok/plugins/kimchi/ui/pages/i18n.json.tmpl b/src/wok/plugins/kimchi/ui/pages/i18n.json.tmpl new file mode 100644 index 0000000..cd320e0 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/i18n.json.tmpl @@ -0,0 +1,187 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2014-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +{ + "KCHAUTH6001E": "$_("The username or password you entered is incorrect. Please try again.")", + "KCHAUTH6002E": "$_("This field is required.")", + + "KCHAUTH6001M": "$_("Log in")", + "KCHAUTH6002M": "$_("Logging in...")", + + "Host": "$_("Host")", + "Guests": "$_("Guests")", + "Templates": "$_("Templates")", + "Storage": "$_("Storage")", + "Network": "$_("Network")", + + "KCHAPI6002E": "$_("Failed to get application configuration")", + "KCHAPI6003E": "$_("This is not a valid Linux path")", + "KCHAPI6004E": "$_("This is not a valid URL.")", + "KCHAPI6005E": "$_("No such data available.")", + "KCHAPI6007E": "$_("Can not contact the host system. Verify the host system is up and that you have network connectivity to it. HTTP request response %1. ")", + "KCHAPI6008E": "$_("Unable to read file.")", + "KCHAPI6009E": "$_("Error while uploading file.")", + + "KCHAPI6001M": "$_("Delete Confirmation")", + "KCHAPI6002M": "$_("OK")", + "KCHAPI6003M": "$_("Cancel")", + "KCHAPI6004M": "$_("Confirm")", + "KCHAPI6005M": "$_("Create")", + "KCHAPI6006M": "$_("Warning")", + "KCHAPI6007M": "$_("Save")", + "KCHAPI6008M": "$_("Creating...")", + "KCHAPI6009M": "$_("Cloning...")", + + "KCHGRD6001M": "$_("Loading...")", + "KCHGRD6002M": "$_("An error occurred while retrieving system information.")", + "KCHGRD6003M": "$_("Retry")", + "KCHGRD6004M": "$_("Detailed message:")", + + "KCHTMPL6001W": "$_("No ISO found")", + + "KCHTMPL6002E": "$_("This is not a valid ISO file.")", + + "KCHTMPL6002M": "$_("This may take a long time. Do you want to continue?")", + "KCHTMPL6003M": "$_("This will permanently delete the template. Would you like to continue?")", + + "KCHHOST6001E": "$_("Unable to shut down system as there are some virtual machines running!")", + + "KCHHOST6001M": "$_("Max:")", + "KCHHOST6002M": "$_("Utilization")", + "KCHHOST6003M": "$_("Available")", + "KCHHOST6004M": "$_("Read Rate")", + "KCHHOST6005M": "$_("Write Rate")", + "KCHHOST6006M": "$_("Received")", + "KCHHOST6007M": "$_("Sent")", + "KCHHOST6008M": "$_("Shutting down or restarting host will cause unsaved work lost. Continue to shut down/restarting?")", + + + "KCHREPO6001M": "$_("Confirm")", + "KCHREPO6002M": "$_("Repository will be removed permanently and can't be recovered. Do you want to continue?")", + "KCHREPO6003M": "$_("Repositories")", + "KCHREPO6004M": "$_("ID")", + "KCHREPO6005M": "$_("Name")", + "KCHREPO6006M": "$_("Base URL")", + "KCHREPO6007M": "$_("Is Mirror")", + "KCHREPO6008M": "$_("URL Args")", + "KCHREPO6009M": "$_("Enabled")", + "KCHREPO6010M": "$_("GPG Check")", + "KCHREPO6011M": "$_("GPG Key")", + "KCHREPO6012M": "$_("Add")", + "KCHREPO6013M": "$_("Edit")", + "KCHREPO6014M": "$_("Remove")", + "KCHREPO6016M": "$_("Enable")", + "KCHREPO6017M": "$_("Disable")", + + + "KCHUPD6001M": "$_("Software Updates")", + "KCHUPD6002M": "$_("Package Name")", + "KCHUPD6003M": "$_("Version")", + "KCHUPD6004M": "$_("Architecture")", + "KCHUPD6005M": "$_("Repository")", + "KCHUPD6006M": "$_("Update All")", + "KCHUPD6007M": "$_("Updating...")", + "KCHUPD6008M": "$_("Failed to retrieve packages update information.")", + "KCHUPD6009M": "$_("Failed to update package(s).")", + + + "KCHDR6001M": "$_("Debug report will be removed permanently and can't be recovered. Do you want to continue?")", + "KCHDR6002M": "$_("Debug Reports")", + "KCHDR6003M": "$_("Name")", + "KCHDR6005M": "$_("Generated Time")", + "KCHDR6006M": "$_("Generate")", + "KCHDR6007M": "$_("Generating...")", + "KCHDR6008M": "$_("Rename")", + "KCHDR6009M": "$_("Remove")", + "KCHDR6010M": "$_("Download")", + "KCHDR6011M": "$_("Report name should contain only letters, digits, underscore ('_') and/or hyphen ('-').")", + "KCHDR6012M": "$_("Pending...")", + "KCHDR6013M": "$_("Report name is the same as the original one.")", + + "KCHVM6001M": "$_("This will delete the virtual machine and its virtual disks. This operation cannot be undone. Would you like to continue?")", + "KCHVM6002M": "$_("Power off Confirmation")", + "KCHVM6003M": "$_("This action may produce undesirable results, " + "for example unflushed disk cache in the guest. " + "Would you like to continue?")", + "KCHVM6004M": "$_("Reset Confirmation")", + "KCHVM6005M": "$_("There is a risk of data loss caused by reset without" + " the guest OS shutdown. Would you like to continue?")", + "KCHVM6006M": "$_("Shut Down Confirmation")", + "KCHVM6007M": "$_("Note the guest OS may ignore this request. Would you like to continue?")", + "KCHVM6008M": "$_("Virtual Machine delete Confirmation")", + "KCHVM6009M": "$_("This virtual machine is not persistent. Power Off will delete it. Continue?")", + "KCHVM6010M": "$_("When the target guest has SCSI or iSCSI volumes, they will be cloned on default storage pool. The same will happen when the target pool does not have enough space to clone the volumes. Do you want to continue?")", + + "KCHVMCD6001M": "$_("This CDROM will be detached permanently and you can re-attach it. Continue to detach it?")", + "KCHVMCD6002M": "$_("Attach")", + "KCHVMCD6003M": "$_("Attaching...")", + "KCHVMCD6004M": "$_("Replace")", + "KCHVMCD6005M": "$_("Replacing...")", + "KCHVMCD6006M": "$_("Successfully attached!")", + "KCHVMCD6007M": "$_("Successfully replaced!")", + "KCHVMCD6008M": "$_("Successfully detached!")", + "KCHVMCD6009M": "$_("This disk will be detached permanently and you can re-attach it. Continue to detach it?")", + + "KCHVMED6001M": "$_("interface:")", + "KCHVMED6002M": "$_("address:")", + "KCHVMED6003M": "$_("link_type:")", + "KCHVMED6004M": "$_("block:")", + "KCHVMED6005M": "$_("drive_type:")", + "KCHVMED6006M": "$_("model:")", + "KCHVMED6007M": "$_("Affected devices:")", + + "KCHNET6001E": "$_("The VLAN id must be between 1 and 4094.")", + + "KCHNET6001M": "$_("unavailable")", + "KCHNET6002M": "$_("This action will interrupt network connectivity for any virtual machine that depend on this network.")", + "KCHNET6003M": "$_("Create a network")", + "KCHNET6004M": "$_("This network is not persistent. Instead of stop, this action will permanently delete it. Would you like to continue?")", + "KCHNET6001W": "$_("The bridged VLAN tag may not work well with NetworkManager enabled. You should consider disabling it.")", + + "KCHPOOL6001M": "$_("This will permanently delete the storage pool. Would you like to continue?")", + "KCHPOOL6002M": "$_("This storage pool is empty.")", + "KCHPOOL6003M": "$_("It will format your disk and you will loose any data in there, are you sure to continue? ")", + "KCHPOOL6004M": "$_("SCSI Fibre Channel")", + "KCHPOOL6005M": "$_("No SCSI adapters found.")", + "KCHPOOL6006M": "$_("Loading iSCSI targets...")", + "KCHPOOL6007M": "$_("No iSCSI found. Please input one.")", + "KCHPOOL6008M": "$_("Failed to load iSCSI targets.")", + + "KCHPOOL6001E": "$_("The storage pool name can not be blank.")", + "KCHPOOL6002E": "$_("The storage pool path can not be blank.")", + "KCHPOOL6003E": "$_("NFS server mount path can not be blank.")", + "KCHPOOL6005E": "$_("Invalid NFS mount path.")", + "KCHPOOL6006E": "$_("No logical device selected.")", + "KCHPOOL6007E": "$_("The iSCSI target can not be blank.")", + "KCHPOOL6008E": "$_("Server name can not be blank.")", + "KCHPOOL6009E": "$_("This is not a valid Server Name or IP. Please, modify it.")", + "KCHPOOL6010M": "$_("Looking for available partitions ...")", + "KCHPOOL6011M": "$_("No available partitions found.")", + "KCHPOOL6012M": "$_("This storage pool is not persistent. Instead of deactivate, this action will permanently delete it. Would you like to continue?")", + "KCHPOOL6013M": "$_("Unable to retrieve partitions information.")", + "KCHPOOL6014M": "$_("In progress...")", + "KCHPOOL6015M": "$_("Failed!")", + + "KCHVMSTOR0001E": "$_("CDROM path needs to be a valid local/remote path and cannot be blank.")", + "KCHVMSTOR0002E": "$_("Disk pool or volume cannot be blank.")" +} diff --git a/src/wok/plugins/kimchi/ui/pages/network.html.tmpl b/src/wok/plugins/kimchi/ui/pages/network.html.tmpl new file mode 100644 index 0000000..915feac --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/network.html.tmpl @@ -0,0 +1,133 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# + +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<html> +<head> +<link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> +<script src="plugins/kimchi/js/kimchi.min.js"></script> +</head> +<body> +<div class="toolbar"> + <div class="tools" style="display:none"> + <a id="networkAdd" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> + </div> +</div> +<div id="network-content" class="network"> + <div class="grid-control"><input type="text" class="filter" placeholder="$_("Filter")"></div> + <div id="networkGrid" class="list"> + <div> + <span class="column-name">$_("Network Name")</span><!-- + --><span class="column-state">$_("State")</span><!-- + --><span class="column-type">$_("Network Type")</span><!-- + --><span class="column-interface">$_("Interface")</span><!-- + --><span class="column-space">$_("Address Space")</span><!-- + --><span style="display:none">$_("Actions")</span> + </div> + <div id="networkBody" class="empty-when-logged-off"></div> + </div> + <div id="networkConfig" class="network-config"> + <div class="section-container"> + <div class="section-header">1. $_("Network Name")</div> + <div class="section-content"> + <input type="text" id="networkName" /> + <div class="input-hint"> + <span class="icon-info-circled light-grey c1 help-inline"></span> + <span class="input-hint-text help-inline">$_("Name should not contain '/' and '\"'.")</span> + </div> + </div> + </div> + <div class="section-container"> + <div class="section-header">2. $_("Network Type")</div> + <div class="section-content"> + <div class="input-container"> + <input type="radio" id="networkTypeIso" name="networkType" value="isolated" /> + <label for="networkTypeIso">$_("Isolated: no external network connection")</label> + </div> + <div class="input-container"> + <input type="radio" id="networkTypeNat" name="networkType" value="nat" /> + <label for="networkTypeNat">$_("NAT: outbound physical network connection only")</label> + </div> + <div class="input-container"> + <div class="bridged-inline"> + <input type="radio" id="networkTypeBri" name="networkType" value="bridged" /> + </div> + <div class="bridged-inline"> + <label for="networkTypeBri">$_("Bridged: Virtual machines are connected to physical network directly")</label><br /> + <label id="networkBriDisabledLabel" style="display:none">$_("(No interfaces found)")</label> + </div> + </div> + <div id="bridgeOptions"> + <div> + <div class="bridge-option-column"> + <label for="networkInterface">$_("Destination"): </label> + </div> + <div class="bridge-option-column"> + <div class="network-type-wrapper-controls"> + <div id ="networkDestinationID"> + <input id="networkDestinationInputId" name="type" type="hidden"/> + <span id="networkDestinationLabel" type="text"></span><span class="arrow"></span> + <div> + <ul id="networkInterface"></ul> + </div> + </div> + </div> + </div> + </div> + <div> + <input id="enableVlan" type="checkbox" value="" /> + <label for="enableVlan" id="labelEnableVlan">$_("Enable VLAN") </label> + </div> + <label for="networkVlanID" id="labelNetworkVlanID">$_("VLAN ID"): </label> + <input type="text" id="networkVlanID" class="network-label"/> + </div> + </div> + </div> + </div> + </div> +</div> +<script id="networkItem" type="text/html"> + <div id='{name}' class='remove-when-logged-off'> + <span class='column-name' title="{name}" val="{name}">{name}</span><!-- + --><span class='column-state' val="{state}"><span class='network-state {state}'></span></span><!-- + --><span class='column-type' val="{type}">{type}</span><!-- + --><span class='column-interface' val="{interface}">{interface}</span><!-- + --><span class='column-space' val="{addrSpace}">{addrSpace}</span><!-- + --><span class='column-action' style="display:none"> + <span class="ui-button-secondary dropdown popable action-button"> + $_("Actions") + <ul class='popover actionsheet right-side menu-container'> + <li nwAct="start" class='{startClass}'><a class='button-big'>$_("Start")</a></li> + <li nwAct="stop" class='{stopClass}'><a {stopDisabled} class='button-big'>$_("Stop")</a></li> + <li nwAct="delete" class='{deleteClass}'><a {deleteDisabled} class='red'>$_("Delete")</a></li> + </ul> + </span> + </span> + </div> +</script> +<script> + kimchi.initNetwork(); +</script> +</body> +</html> diff --git a/src/wok/plugins/kimchi/ui/pages/report-add.html.tmpl b/src/wok/plugins/kimchi/ui/pages/report-add.html.tmpl new file mode 100644 index 0000000..25bf0a9 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/report-add.html.tmpl @@ -0,0 +1,56 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<div id="report-add-window" class="window"> + <header> + <h1 class="title h1 grey">$_("Generate a New Debug Report")</h1> + </header> + <div class="content"> + <form id="form-report-add"> + <section class="form-section"> + <h2> + <label for="report-name-textbox">$_("Report Name")</label> + </h2> + <div class="field"> + <input type="text" class="text" id="report-name-textbox" name="name" /> + <span class="icon-info-circled light-grey c1"></span> + <span class="info-add-debug-report"> + $_("The name used to identify the report. If omitted, a name will be chosen based on current time. Name can contain: letters, digits, underscore (\"_\") and hyphen (\"-\").") + </span> + </div> + </section> + </form> + </div> + <footer> + <div class="btn-group"> + <button id="button-report-add" class="btn-normal"><span class="text">$_("Generate")</span></button> + <button id="button-report-cancel" class="btn-normal close" type="button"> + <span calss="text">$_("Cancel")</span> + </button> + </div> + </footer> +</div> +<script> + kimchi.report_add_main(); +</script> diff --git a/src/wok/plugins/kimchi/ui/pages/report-rename.html.tmpl b/src/wok/plugins/kimchi/ui/pages/report-rename.html.tmpl new file mode 100644 index 0000000..90a0a80 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/report-rename.html.tmpl @@ -0,0 +1,56 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2014-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<div id="report-rename-window" class="window"> + <header> + <h1 class="title h1 grey">$_("Rename a Debug Report")</h1> + </header> + <div class="content"> + <form id="form-report-rename"> + <section class="form-section"> + <h2> + <label for="report-name-textbox">$_("Report Name")</label> + </h2> + <div class="field"> + <input type="text" class="text" id="report-name-textbox" name="name" /> + <span class="icon-info-circled light-grey c1"></span> + <span class="info-debug-report-rename"> + $_("The name used to identify the report. Name can contain: letters, digits and hyphen (\"-\").") + </span> + </div> + </section> + </form> + </div> + <footer> + <div class="btn-group"> + <button id="button-report-rename" class="btn-normal"><span class="text">$_("Submit")</span></button> + <button id-"button-report-rename-cancel" class="btn-normal close" type="button"> + <span class="text">$_("Cancel")</span> + </button> + </div> + </footer> +</div> +<script> + kimchi.report_rename_main(); +</script> diff --git a/src/wok/plugins/kimchi/ui/pages/repository-add.html.tmpl b/src/wok/plugins/kimchi/ui/pages/repository-add.html.tmpl new file mode 100644 index 0000000..950252a --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/repository-add.html.tmpl @@ -0,0 +1,113 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2014-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<div id="repository-add-window" class="window"> + <form id="form-repository-add"> + <header class="window-header"> + <h1 class="title h1 grey">$_("Add a Repository")</h1> + </header> + <section> + <div class="content"> + <div class="form-section yum"> + <h2>$_("Identifier")</h2> + <div class="field"> + <div class="textbox-wrapper"> + <input type="text" class="text" name="repo_id" /> + </div> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("Single word, unique identifier for the repository.") + </p> + </div> + </div> + <section class="form-section yum"> + <h2>$_("Name")</h2> + <div class="field"> + <div class="textbox-wrapper"> + <input type="text" class="text" name="config[repo_name]" /> + </div> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("Textual name for the repository.") + </p> + </div> + </section> + <section class="form-section"> + <h2>$_("URL")<span class="required" role="presentation" title='$_("Required Field")'>*</span></h2> + <div class="field"> + <div class="textbox-wrapper"> + <input type="text" class="text required" name="baseurl" /> + </div> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("URL to the repository. Supported protocols are http, ftp, and file.") + </p> + </div> + <div class="field yum"> + <p class="yum"> + <input type="checkbox" name="isMirror" value="true" id="isMirror" /> + <label id="isMirrorLabel" for="isMirror">$_("Repository is a mirror")</label> + </p> + </div> + </section> + <section class="form-section repository-dist deb"> + <h2>$_("Distribution")</h2> + <div class="field"> + <div class="textbox-wrapper"> + <input type="text" class="text" name="config[dist]" /> + </div> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("Distribution of the DEB repository.") + </p> + </div> + </section> + <section class="form-section repository-comps deb"> + <h2>$_("Components")</h2> + <div class="field"> + <div class="textbox-wrapper"> + <input type="text" class="text" name="config[comps]" /> + </div> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("List of components in DEB repository.") + </p> + </div> + </section> + </div> + </section> + <footer> + <div class="btn-group"> + <button type="submit" id="button-repository-add" class="btn-normal" disabled="disabled"> + <span class="text">$_("Add")</span> + </button> + <button type="button" id="button-repository-close" class="btn-normal close"> + <span class="text">$("Cancel")</span> + </button> + </div> + </footer> + </form> +</div> +<script> + kimchi.repository_add_main(); +</script> diff --git a/src/wok/plugins/kimchi/ui/pages/repository-edit.html.tmpl b/src/wok/plugins/kimchi/ui/pages/repository-edit.html.tmpl new file mode 100644 index 0000000..e5a3cfb --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/repository-edit.html.tmpl @@ -0,0 +1,117 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2014-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext + +<div id="repository-edit-window" class="window"> + <form id="form-repository-edit"> + <header> + <h1 class="title h1 grey">$_("Edit Repository")</h1> + </header> + <div class="content"> + <section id="form-repository-edit"> + <fieldset class="repository-edit-fieldset"> + <div class="repository-id yum"> + <div class="repository-edit-wrapper-label"> + <label for="repository-edit-id-textbox">$_("ID")</label> + </div> + <div class="repository-edit-wrapper-controls"> + <input id="repository-edit-id-textbox" name="repo_id" type="text" disabled="disabled" readonly="readonly"/> + </div> + </div> + <div class="repository-name yum"> + <div class="repository-edit-wrapper-label"> + <label for="repository-edit-name-textbox">$_("Name")</label> + </div> + <div class="repository-edit-wrapper-controls"> + <input id="repository-edit-name-textbox" class="yum" name="config[repo_name]" type="text" /> + </div> + </div> + <div class="repository-url"> + <div class="repository-edit-wrapper-label"> + <label for="repository-edit-baseurl-textbox">$_("URL")</label> + </div> + <div class="repository-edit-wrapper-controls"> + <input id="repository-edit-baseurl-textbox" name="baseurl" type="text" /> + </div> + </div> + <div class="repository-dist deb"> + <div class="repository-edit-wrapper-label"> + <label for="repository-edit-urlargs-textbox">$_("Distribution")</label> + </div> + <div class="repository-edit-wrapper-controls"> + <input id="repository-edit-urlargs-textbox" class="deb" name="config[dist]" type="text" /> + </div> + </div> + <div class="repository-mirrorlist yum"> + <div class="repository-edit-wrapper-label"> + <label for="repository-edit-urlargs-textbox">$_("Mirror List URL")</label> + </div> + <div class="repository-edit-wrapper-controls"> + <input id="repository-edit-urlargs-textbox" class="yum" name="config[mirrorlist]" type="text" /> + </div> + </div> + <div class="repository-comps deb"> + <div class="repository-edit-wrapper-label"> + <label for="repository-edit-urlargs-textbox">$_("Components")</label> + </div> + <div class="repository-edit-wrapper-controls"> + <input id="repository-edit-urlargs-textbox" class="deb" name="config[comps]" type="text" /> + </div> + </div> + <div class="repository-gpgkey yum"> + <div class="repository-edit-wrapper-label"> + <label for="repository-edit-gpgkey-textbox">$_("GPG Key")</label> + </div> + <div class="repository-edit-wrapper-controls"> + <input id="repository-edit-gpgkey-textbox" class="yum" name="config[gpgkey]" type="text" /> + </div> + </div> + <div class="repository-gpgcheck yum"> + <div class="repository-edit-wrapper-label"> + <label>$_("GPG Check")</label> + </div> + <div class="repository-edit-wrapper-controls"> + <input id="repository-edit-gpgcheck-radio-true" class="yum" name="config[gpgcheck]" type="radio" value="true" /> + <label for="repository-edit-gpgcheck-radio-true">$_("Yes")</label> + <input id="repository-edit-gpgcheck-radio-false" class="yum" name="config[gpgcheck]" type="radio" value="false" /> + <label for="repository-edit-gpgcheck-radio-false">$_("No")</label> + </div> + </div> + </fieldset> + </section> + </div> + <footer> + <div class="btn-group"> + <button type="submit" id="repository-edit-button-save" class="btn-normal"> + <span class="text">$_("Save")</span> + </button> + <button type="button" id="repository-edit-button-cancel" class="close btn-normal"> + <span class="text">$_("Cancel")</span> + </button> + </div> + </footer> + </form> +</div> +<script type="text/javascript"> + kimchi.repository_edit_main(); +</script> diff --git a/src/wok/plugins/kimchi/ui/pages/storage.html.tmpl b/src/wok/plugins/kimchi/ui/pages/storage.html.tmpl new file mode 100644 index 0000000..7b51a8b --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/storage.html.tmpl @@ -0,0 +1,143 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# + +#unicode UTF-8 +#import gettext +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<html> +<head> +<link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> +<script src="plugins/kimchi/js/kimchi.min.js"></script> +</head> +<body> +<div class="toolbar"> + <div class="tools" style="display:none"> + <a id="storage-pool-add" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> + </div> +</div> +<div class='storage'> +<div class="grid-control"><input type="text" class="filter" placeholder="$_("Filter")"></div> +<div id='storageGrid'> + <div> + <span class="storage-name">$_("Name")</span> + <span class="storage-state" >$_("State")</span> + <span class="storage-type">$_("Type")</span> + <span class="storage-capacity">$_("Capacity")</span> + <span class="storage-allocate">$_("Allocated")</span> + <span class="storage-location">$_("Location")</span> + </div> + <div id="storagepoolsList" class="list-storage empty-when-logged-off"></div> +</div> +</div> +<div id="logicalPoolExtend" title="$_("Device path")"> + <p id="loading-info" class="text-help"> + <img src = "plugins/kimchi/images/theme-default/loading.gif" /> + $_("Looking for available partitions ...") + </p> + <div class="host-partition"> + </div> +</div> +<script id="storageTmpl" type="html/text"> + <div id="{name}" class="storage-li in" data-name="{name}" data-stat="{state}"> + <span class="storage-name" val="{name}{usage}%"> + <span title="{name}">{name}</span> + <span class="usage">{usage}%</span> + </span> + <span class="storage-state"> + <div class="status-dot toolable active" data-state="{state}"> + <label class="tooltip">$_("active")</label> + </div> + <div class="status-dot toolable inactive" data-state="{state}"> + <label class="tooltip">$_("inactive")</label> + </div> + </span> + <span class="storage-type" val="{type}"> + <div>{type}</div> + </span> + <span class="storage-capacity" val="{capacity}"> + <div data-type="{type}">{capacity}</div> + </span> + <span class="storage-allocate" val="{allocated}"> + <div data-type="{type}">{allocated}</div> + </span> + <span class="storage-location" val="{path}"> + <div>{path}</div> + </span> + <span class="bottom storage-button" style="display:none"> + <div class="btn dropdown popable storage-action" data-state="{state}" data-type="{type}" data-name="{name}"> + <span class="text">$_("Actions")</span><span class="arrow"></span> + <div class="popover actionsheet right-side" style="width: 250px"> + <button class="button-big pool-deactivate" data-stat="{state}" data-name="{name}" data-persistent="{persistent}"><span class="text">$_("Deactivate")</span></button> + <button class="button-big pool-activate" data-stat="{state}" data-name="{name}"><span class="text">$_("Activate")</span></button> + <button class="button-big pool-add-volume" data-stat="{state}" data-name="{name}" data-type="{type}"><span class="text">$_("Add Volume")</span></button> + <button class="button-big pool-extend {enableExt}" data-stat="{state}" data-name="{name}"><span class="text">$_("Extend")</span></button> + <button class="button-big red pool-delete" data-stat="{state}" data-name="{name}"><span class="text">$_("Undefine")</span></button> + </div> + </div> + </span> + <span class="handle"> + <div class="arrow-down"></div> + </span> + <div class="volumes"> + <div id="volume{name}" class="volumeslist" data-name="{name}" ></div> + <div class="clear"></div> + </div> + </div> +</script> +<script id="volumeTmpl" type="html/text"> + <div class="volume-box white-box" data-volume-name="{name}"> + <div class="storage-icon volume-default icon-{format} "> + </div> + <div class="volume-title"> + <div class="volume-name" title="{name}">{name}</div> + <div class="volume-progress hidden"> + <div class="progress-bar-outer"> + <div class="progress-bar-inner"></div> + </div> + <div class="progress-label"> + <span class="progress-status"></span> + <span class="progress-transferred"></span> + </div> + </div> + </div> + <div class="volume-setting"> + </div> + <div class="volume-type-position"> + <div title="{type}" class="volume-text">$_("Type"): {type}</div> + <div title="{format}" class="volume-text">$_("Format"): {format}</div> + </div> + <div class="volume-quota-position"> + <div title="{capacity}" class="volume-textquota">$_("Capacity"): {capacity}</div> + <div title="{allocation}"class="volume-textquota">$_("Allocation"): {allocation}</div> + </div> + </div> +</script> +<script id="logicalPoolExtendTmpl" type="html/text"> + <div> + <input type="checkbox" value="{path}" name="devices"> + <label for="{name}">{path}</label> + </div> +</script> +<script> + kimchi.storage_main(); +</script> +</body> +</html> diff --git a/src/wok/plugins/kimchi/ui/pages/storagepool-add-volume.html.tmpl b/src/wok/plugins/kimchi/ui/pages/storagepool-add-volume.html.tmpl new file mode 100644 index 0000000..ab10939 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/storagepool-add-volume.html.tmpl @@ -0,0 +1,79 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2014-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<div id="sp-add-volume-window" class="window"> + <form id="form-sp-add-volume"> + <header class="window-header"> + <h1 class="title h1 grey">$_("Add a Volume to Storage Pool")</h1> + </header> + <section> + <div class="content"> + <div class="form-section"> + <h2> + <input type="radio" id="volume-type-download" class="volume-type" name="volumeType" value="download" checked="checked" /> + <label for="volume-type-download"> + $_("Fetch from remote URL") + </label> + </h2> + <div class="field"> + <div class="textbox-wrapper"> + <input type="text" id="volume-remote-url" class="text volume-input download" name="volumeRemoteURL" /> + </div><br> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("Enter the remote URL here.") + </p> + </div> + </div> + <div class="form-section"> + <h2> + <input type="radio" id="volume-type-upload" class="volume-type" name="volumeType" value="upload"/> + <label for="volume-type-upload"> + $_("Upload a file") + </label> + </h2> + <div class="field"> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("Choose the file you want to upload.") + </p> + <div class="textbox-wrapper"> + <input type="file" class="volume-input upload" id="volume-input-file" name="volumeLocalFile" disabled="disabled" /> + </div> + </div> + </div> + </div> + </section> + <footer> + <div class="btn-group"> + <button type="submit" id="sp-add-volume-button" class="btn-normal" disabled="disabled"> + <span class="text">$_("Add")</span> + </button> + <button type="button" class="btn-normal close"><span class="text">$_("Cancel")</span></button> + </div> + </footer> + </form> +</div> +<script type="text/javascript"> + kimchi.sp_add_volume_main(); +</script> diff --git a/src/wok/plugins/kimchi/ui/pages/storagepool-add.html.tmpl b/src/wok/plugins/kimchi/ui/pages/storagepool-add.html.tmpl new file mode 100644 index 0000000..a697af5 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/storagepool-add.html.tmpl @@ -0,0 +1,186 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<html> +<body> + <div class="window storage-window storage-admin"> + <header> + <h1 class="title h1 grey">$_("Define a New Storage Pool")</h1> + </header> + <div class="content"> + <form id="form-pool-add"> + <section class="form-section"> + <h2>1. $_("Storage Pool Name")</h2> + <div class="field"> + <input id="poolId" required="required" type="text" class="text storage-base-input-width" name="name"><br> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("The name used to identify the storage pools, and it should not be empty.") + </p> + </div> + </section> + <section class="form-section"> + <h2>2. $_("Storage Pool Type")</h2> + <div class="storage-type-wrapper-controls"> + <div id="poolTypeId"> + <input id="poolTypeInputId" name="type" type="hidden" value="dir"/> + <span id="pool-type-label" class="text"></span><span class="arrow"></span> + <div> + <ul id="storagePool-list"> + </ul> + </div> + </div> + </div> + </section> + <div class="path-section"> + <section class="form-section"> + <h2>3. $_("Storage Path")</h2> + <div class="field"> + <input id="pathId" type="text" class="text storage-base-input-width"><br> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("The path of the Storage Pool. Each Storage Pool must have a unique path.")</p><br> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("Kimchi will try to create the directory when it does not already exist in your system.")</p> + </div> + <div class="clear"></div> + </section> + </div> + <div class="nfs-section tmpl-html"> + <section class="form-section"> + <h2>3. $_("NFS Server IP")</h2> + <div class="field storage-field"> + <div id="serverComboboxId" class="storage-add-input-width"> + <input id="nfsserverId"/> + <div> + <ul id="nfs-server-used"> + </ul> + </div> + </div><br> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("NFS server IP or hostname. It can be input or chosen from history.")</p> + </div> + </section> + <section class="form-section"> + <h2>4. $_("NFS Path")</h2> + <div class="field storage-field"> + <div id="targetFilterSelectId" class="storage-add-input-width"> + <input id="nfspathId" class="input" disabled/> + <div> + <ul id="nfs-server-target"> + </ul> + </div> + </div><br> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline">$_("The NFS exported path on NFS server.")</p> + </div> + </section> + </div> + <div class="logical-section tmpl-html"> + <section class="form-section storageType"> + <h2>3. $_("Device path")</h2> + <div class="host-partition"> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("Looking for available partitions ...") + <img src = "plugins/kimchi/images/theme-default/loading.gif" /> + </p> + </div> + </section> + </div> + <div class="iscsi-section tmpl-html"> + <section class="form-section"> + <h2>3. $_("iSCSI Server")</h2> + <div class="field"> + <span class="filter-select popable" id="iSCSIServer"> + <input id="iscsiserverId" type="text" placeholder="$_("Server")"> + <div class="popover"><ul class="option select-list"></ul></div> + </span> + <input id="iscsiportId" placeholder="$_("Port")" type="text" class="text storage-port-width" maxlength="4"><br> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline"> + $_("iSCSI server IP or hostname. It should not be empty.")</p> + </div> + </section> + <section class="form-section"> + <h2>4. $_("Target")</h2> + <div class="field"> + <span class="filter-select popable" id="iSCSITarget"> + <input id="iscsiTargetId" type="text"> + <div class="popover"><ul class="option select-list"></ul></div> + </span><br> + <div class="icon-info-circled light-grey c1 help-inline"></div> + <p class="text-help help-inline">$_("The iSCSI target on iSCSI server")</p> + </div> + </section> + <section class="form-section"> + <div class="field"> + <input type="checkbox" id="authId" name="authname"> + <label for="authId">$_("Add iSCSI Authentication")</label> + </div> + </section> + <section class="authenticationfield form-section tmpl-html"> + <h2>5. $_("iSCSI Authentication")</h2> + <div class="field"> + <input id="usernameId" placeholder="$_("User Name")" type="text" class="text storage-auth-width"> + <input id="passwordId" placeholder="$_("Password")" type="password" class="text storage-auth-width"> + </div> + </section> + </div> + <div class="scsi-section tmpl-html"> + <section class="form-section"> + <h2>3. $_("SCSI Adapter")</h2> + <div class="storage-type-wrapper-controls"> + <div id="scsiAdapter"> + <input type="hidden"/> + <span class="text"></span><span class="arrow"></span> + <div><ul></ul></div> + </div> + </div> + </section> + </div> + </form> + </div> + <footer> + <div class="btn-group"> + <button id="pool-doAdd" class="btn-normal"> + <span class="text">$_("Create")</span> + </button> + <button class="btn-normal" id="pool-loading" style="display: none"><span class="text">$_("Please, wait...")</span></button> + <button class="btn-normal close" type="button"><span class="text">$_("Cancel")</span></button> + </div> + </footer> + </div> + <script> + kimchi.storagepool_add_main(); + </script> + <script id="partitionTmpl" type="html/text"> + <div> + <input type="checkbox" id="{name}" value="{path}" name="devices"> + <label for="{name}">{path}</label> + </div> + </script> +</body> +</html> diff --git a/src/wok/plugins/kimchi/ui/pages/template-add.html.tmpl b/src/wok/plugins/kimchi/ui/pages/template-add.html.tmpl new file mode 100644 index 0000000..b44db79 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/template-add.html.tmpl @@ -0,0 +1,233 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<html> +<body> +<div class="window" style="width: 992px;height: 660px;"> + <header> + <h1 class="title h1 grey">$_("Add Template")</h1> + </header> + <div class="content" style="margin-bottom: 0"> + <div class="page-list"> + <!-- 1 --> + <div class="page" id="iso-type-box" style="left:0"> + <h2 class="step-title">$_("Where is the source media for this template? ")</h2> + <ul class="step-choose"> + <li> + <a id="iso-local" class="local">$_("Local ISO Image")</a> + </li> + <li> + <a id="vm-image-local" class="local">$_("Local Image File")</a> + </li> + <li> + <a id="iso-remote" class="remote">$_("Remote ISO Image")</a> + </li> + </ul> + </div> + + <!-- 1-1 --> + <div class="page" id="iso-local-box"> + <header> + <a class="back" id="iso-local-box-back"></a> + <h2 class="step-title">$_("Local ISO Image")</h2> + </header> + + <button class="btn-normal" id="iso-search" style="display: none"><span class="text">$_("Search ISOs")</span></button> + <button class="btn-normal" id="iso-search-loading" style="display: none"><span class="text">$_("Please, wait...")</span></button> + <!-- 1-1-1 --> + <div id="local-iso-field" class="iso-field" style="display: none;"> + <h3 class="step-subtitle"> + $_("The following ISOs are available:") + </h3> + <div class="toolbar"> + <label class="check-all"> + <input type="checkbox" id="select-all-local-iso">$_("All") + </label> + </div> + <div> + <form id="form-local-iso"> + <ul id="list-local-iso" class="list-iso"> + </ul> + </form> + <script id="tmpl-list-local-iso" type="text/html"> + <li> + <label> + <input type="checkbox" name="iso" value="{isoId}"> + <div class="box box-iso"> + <div class="iso-icon {os_distro}"> + </div> + <h3 class="iso-title" title="{name}"> + {name} + </h3> + <div class="iso-info"> + <div class="iso-info-col"> + <div class="iso-info-item" title="{os_distro}"> + $_("OS: "){os_distro} + </div> + <div class="iso-info-item" title="{os_version}"> + $_("Version: "){os_version} + </div> + </div> + <div class="iso-info-col"> + <div class="iso-info-item" title="{capacity}"> + $_("Size: "){capacity} + </div> + </div> + </div> + </div> + </label> + </li> + </script> + </div> + <div class="button-field"> + <button class="btn-normal" id="iso-more" style="display: none"><span class="text">$_("Search more ISOs")</span></button> + <button class="btn-normal" id="iso-more-loading" style="display: none"><span class="text">$_("Please, wait...")</span></button> + <button class="btn-normal" id="btn-template-local-iso-create" disabled="disabled"><span class="text">$_("Create Templates from Selected ISO")</span></button> + </div> + </div> + + <!-- 1-1-2 --> + <div id="iso-file-field"> + <h3 class="step-subtitle"> + <label> + <input type="checkbox" id="iso-file-check"> + $_("I want to use a specific ISO file") + </label> + </h3> + <div id="iso-file-box" class="custom-iso-field"> + <div class="input-wrapper"><input type="text" class="text" id="iso-file" name="iso-file"></div> + <button class="btn-normal" id="btn-template-file-create" disabled="disabled"><span class="text">$_("Create")</span></button> + </div> + </div> + + </div> + + <div class="page" id="vm-image-local-box"> + <header> + <a class="back" id="vm-image-local-box-back"></a> + <h2 class="step-title">$_("Local Image File")</h2> + </header> + <div class="body"> + <label for="vm-image-local-text">File Path:</label> + <input type="text" id="vm-image-local-text" /> + <button class="ui-button-primary">$_("Create")</button> + </div> + </div> + + <!-- 1-2 --> + <div class="page" id="iso-remote-box"> + <header> + <a class="back" id="iso-remote-box-back"></a> + <h2 class="step-title">$_("Remote ISO Image")</h2> + </header> + + <!-- 1-2-0 --> + <div id="load-remote-iso"> + <h3 class="step-subtitle"> + <label> + <img src = "plugins/kimchi/images/theme-default/loading.gif" /> + $_("Loading default remote ISOs ...") + </label> + </h3> + </div> + + <!-- 1-2-1 --> + <div id="remote-iso-field" class="iso-field" style="display: none;"> + <h3 class="step-subtitle"> + $_("The following ISOs are available:") + </h3> + <div class="toolbar"> + <label class="check-all"> + <input type="checkbox" id="select-all-remote-iso">$_("All") + </label> + </div> + <div> + <form id="form-remote-iso"> + <ul id="list-remote-iso" class="list-iso"> + </ul> + </form> + <script id="tmpl-list-remote-iso" type="text/html"> + <li> + <label> + <input type="checkbox" name="iso" value="{isoId}"> + <div class="box box-iso"> + <div class="iso-icon {os_distro}"> + </div> + <h3 class="iso-title" title="{name}"> + {name} + </h3> + <div class="iso-info"> + <div class="iso-info-col"> + <div class="iso-info-item" title="{os_distro}"> + $_("OS: "){os_distro} + </div> + <div class="iso-info-item" title="{os_version}"> + $_("Version: "){os_version} + </div> + + </div> + <div class="iso-info-col"> + <div class="iso-info-item" title="{os_arch}"> + $_("Arch: "){os_arch} + </div> + </div> + </div> + </div> + </label> + </li> + </script> + </div> + <div class="button-field"> + <button class="btn-normal" id="btn-template-remote-iso-create" disabled="disabled"><span class="text">$_("Create Templates from Selected ISO")</span></button> + </div> + </div> + + <!-- 1-2-2 --> + <div id="iso-url-field" style="display: none;"> + <h3 class="step-subtitle"> + <label> + <input type="checkbox" id="iso-url-check"> + $_("I want to use a custom URL") + </label> + </h3> + <div id="iso-url-box" class="custom-iso-field"> + <div class="input-wrapper"><input type="text" class="text" id="iso-url" name="iso-url"></div> + <button class="btn-normal" id="btn-template-url-create" disabled="disabled"><span class="text">$_("Create")</span></button> + </div> + </div> + + </div> + </div> + </div> + <footer> + <div class="button-group"> + <button class="btn-normal close" type="button"><span type="text">$_("Cancel")</span></button> + </div> + </footer> +</div> +<script> +kimchi.template_add_main(); +</script> +</body> +</html> diff --git a/src/wok/plugins/kimchi/ui/pages/template-edit.html.tmpl b/src/wok/plugins/kimchi/ui/pages/template-edit.html.tmpl new file mode 100644 index 0000000..0588294 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/template-edit.html.tmpl @@ -0,0 +1,193 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext + +<div id="template-edit-window" class="window"> + <header> + <h1 class="title h1 grey">$_("Edit Template")</h1> + </header> + <div class="content"> + <div id="edit-template-tabs"> + <input type="hidden" id="template-name" name="templateName" /> + <ul> + <li> + <a href="#form-template-general">$_("General")</a> + </li> + <li> + <a href="#form-template-storage">$_("Storage")</a> + </li> + <li> + <a href="#form-template-interface">$_("Interface")</a> + </li> + <li> + <a href="#form-template-processor">$_("Processor")</a> + </li> + </ul> + <form id="form-template-general"> + <div class="form-template-inline-wrapper"> + <div class="template-edit-wrapper-label"> + <label for="template-edit-id-textbox">$_("Name")</label> + </div> + <div class="template-edit-wrapper-label"> + <label for="template-edit-vendor-textbox">$_("Vendor")</label> + </div> + <div class="template-edit-wrapper-label"> + <label for="template-edit-version-textbox">$_("Version")</label> + </div> + <div class="template-edit-wrapper-label"> + <label for="template-edit-memory-textbox">$_("Memory (MB)")</label> + </div> + <div class="template-edit-wrapper-label templ-edit-cdrom"> + <label for="template-edit-cdrom-textbox">$_("CDROM")</label> + </div> + <div class="template-edit-wrapper-label templ-edit-vm-image hide"> + <label for="template-edit-vmimage-textbox">$_("Image File")</label> + </div> + <div class="template-edit-wrapper-label"> + <label>$_("Graphics")</label> + </div> + </div> + <div class="form-template-inline-wrapper"> + <div class="template-edit-wrapper-controls"> + <input id="template-edit-id-textbox" name="name" type="text" /> + </div> + <div class="template-edit-wrapper-controls"> + <input id="template-edit-vendor-textbox" name="os_distro" type="text" disabled="disabled" /> + </div> + <div class="template-edit-wrapper-controls"> + <input id="template-edit-version-textbox" name="os_version" type="text" disabled="disabled" /> + </div> + <div class="template-edit-wrapper-controls"> + <input id="template-edit-memory-textbox" name="memory" type="text" /> + </div> + <div class="template-edit-wrapper-controls templ-edit-cdrom"> + <input id="template-edit-cdrom-textbox" name="cdrom" type="text" disabled="disabled" /> + </div> + <div class="template-edit-wrapper-controls templ-edit-vm-image hide"> + <input id="template-edit-vmimage-textbox" name="vm-image" type="text" disabled="disabled" /> + </div> + <div class="template-edit-wrapper-controls"> + <div class="btn dropdown popable"> + <input id="template-edit-graphics" name="graphics" type="hidden" /> + <span class="text" id="template-edit-graphics-label"></span><span class="arrow"></span> + <div class="popover" style="width: 100%"> + <ul class="select-list" id="template-edit-graphics-list" data-target="template-edit-graphics" data-label="template-edit-graphics-label"> + </ul> + </div> + </div> + </div> + </div> + </form> + <form id="form-template-storage"> + <div class="template-tab-header"> + <span class="template-storage-cell">$_("Storage Pool")</span> + <span class="template-storage-cell">$_("Type")</span> + <span class="template-storage-cell">$_("Disk(GB)")</span> + <span class="template-storage-cell">$_("Disk Format")</span> + <button type="button" id="template-edit-storage-add-button" class="action-area"></button> + </div> + <div class="template-tab-body"> + </div> + </form> + <form id="form-template-interface"> + <div class="template-tab-header"> + <span class="template-interface-cell">$_("Network")</span> + <span class="template-interface-cell">$_("Type")</span> + <button type="button" id="template-edit-interface-add-button" class="action-area"></button> + </div> + <div class="template-tab-body"></div> + </form> + <form id="form-template-processor"> + <div> + <label for="cpus">$_("CPU Number"):</label> + <input type="text" value="1" id="cpus" /> + </div> + <div class="manual"> + <input type="checkbox" id="cpus-check" /> + <label for="cpus-check">$_("Manually set CPU topology")</label> + </div> + <div class="topology hide"> + <div> + <label for="cores">$_("Cores"):</label> + <input type="text" value="1" id="cores" /> + </div> + <div> + <label for="threads">$_("Threads"):</label> + <select id="threads"></select> + </div> + </div> + </form> + </div> + </div> + <footer> + <div class="btn-group"> + <a id="tmpl-edit-button-save" class="btn-normal" href="javascript:void(0);"><span class="text">$_("Save")</span></a> + <button class="btn-normal close" type="button"><span class="text">$_("Cancel")</span></button> + </div> + </footer> +</div> +<script> + kimchi.template_edit_main(); +</script> +<script id="template-storage-pool-tmpl" type="text/html"> + <div class='item'> + <span class="template-storage-cell"> + <input class="template-storage-name" value={storageName} type="text" style="display:none" /> + <select id="selectStorageName"></select> + </span> + <span class="template-storage-cell"> + <input class="template-storage-type" value={storageType} readonly=true type="text" /> + </span> + <span class="template-storage-cell"> + <input class="template-storage-disk" value={storageDisk} type="text" /> + </span> + <span class="template-storage-cell"> + <input class="template-storage-disk-format" value={storageDiskFormat} type="text" style="display:none" /> + <select id="diskFormat"> + <option value="qcow2">qcow2</option> + <option value="raw">raw</option> + <option value="bochs">bochs</option> + <option value="cloop">cloop</option> + <option value="cow">cow</option> + <option value="dmg">dmg</option> + <option value="qcow">qcow</option> + <option value="qed">qed</option> + <option value="vmdk">vmdk</option> + <option value="vpc">vpc</option> + </select> + </span> + </div> +</script> +<script id="template-interface-tmpl" type="text/html"> + <div class="item" id={networkID}> + <span class="template-interface-cell"> + <select></select> + </span> + <span class="template-interface-cell"> + <input value={type} readonly=true type="text" /> + </span> + <span class="action-area"> + <button class="delete"></button> + </span> + </div> +</script> diff --git a/src/wok/plugins/kimchi/ui/pages/templates.html.tmpl b/src/wok/plugins/kimchi/ui/pages/templates.html.tmpl new file mode 100644 index 0000000..af1cf3f --- /dev/null +++ b/src/wok/plugins/kimchi/ui/pages/templates.html.tmpl @@ -0,0 +1,77 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<html> +<head> +<link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> +<script src="plugins/kimchi/js/kimchi.min.js"></script> +</head> +<body> +<div class="toolbar"> + <div class="tools" style="display:none"> + <a id="template-add" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> + </div> +</div> +<div> + <div id="noTemplates" class="list-no-result" style="display: none;"> + $_("No templates found.") + </div> + + <ul id="templateList" class="empty-when-logged-off"></ul> + + <script id="templateTmpl" type="html/text"> + + <div class="template-box white-box template-border"> + <div class="btn dropdown popable" style="width: 70px"> + <span class="text">$_("Actions")</span><span class="arrow"></span> + <div class="popover actionsheet right-side" style="width: 250px"> + <a class="button-big template-edit" data-template='{name}'>$_("Edit")</a> + <a class="button-big template-clone" data-template='{name}'>$_("Clone")</a> + <a class="button-big red template-delete" data-template='{name}'>$_("Delete")</a> + </div> + </div> + + <div class="template-icon template-icon-position"> + <img alt="" src="{icon}"> + <img alt="" src="{location}" class="template-type-icon-position"> + </div> + <div class="template-general template-title template-title-position"> + <h2 class="title" title="{name}">{name}</h2> + </div> + <div class="template-os-position"> + <div class="template-text">$_("OS"): {os_distro}</div> + <div class="template-text">$_("Version"): {os_version}</div> + </div> + <div class="template-cpu-position"> + <div class="template-text">$_("CPUs"): {cpus}</div> + <div class="template-text">$_("Memory"): {memory}M</div> + </div> + </div> + </script> +</div> +<script> + kimchi.template_main(); +</script> +</body> +</html> diff --git a/src/wok/plugins/kimchi/ui/robots.txt b/src/wok/plugins/kimchi/ui/robots.txt new file mode 100644 index 0000000..1f53798 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/src/wok/plugins/kimchi/ui/spice-html5/Makefile.am b/src/wok/plugins/kimchi/ui/spice-html5/Makefile.am new file mode 100644 index 0000000..c43f1ef --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/Makefile.am @@ -0,0 +1,25 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2014 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SUBDIRS = pages + +if WITH_SPICE +SUBDIRS += css thirdparty + +spicehtml5dir = $(datadir)/wok/plugins/kimchi/ui/spice-html5 +dist_spicehtml5_DATA = $(wildcard *.js) $(NULL) +endif diff --git a/src/wok/plugins/kimchi/ui/spice-html5/atKeynames.js b/src/wok/plugins/kimchi/ui/spice-html5/atKeynames.js new file mode 100644 index 0000000..e1e27fd --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/atKeynames.js @@ -0,0 +1,183 @@ +"use strict"; +/* + Copyright (C) 2012 by Aric Stewart <aric@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ +/* + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + */ +/* + * Copyright (c) 1994-2003 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +/* + * NOTE: The AT/MF keyboards can generate (via the 8042) two (MF: three) + * sets of scancodes. Set3 can only be generated by a MF keyboard. + * Set2 sends a makecode for keypress, and the same code prefixed by a + * F0 for keyrelease. This is a little bit ugly to handle. Thus we use + * here for X386 the PC/XT compatible Set1. This set uses 8bit scancodes. + * Bit 7 ist set if the key is released. The code E0 switches to a + * different meaning to add the new MF cursorkeys, while not breaking old + * applications. E1 is another special prefix. Since I assume that there + * will be further versions of PC/XT scancode compatible keyboards, we + * may be in trouble one day. + * + * IDEA: 1) Use Set2 on AT84 keyboards and translate it to MF Set3. + * 2) Use the keyboards native set and translate it to common keysyms. + */ + +/* + * definition of the AT84/MF101/MF102 Keyboard: + * ============================================================ + * Defined Key Cap Glyphs Pressed value + * Key Name Main Also (hex) (dec) + * ---------------- ---------- ------- ------ ------ + */ + +var KEY_Escape =/* Escape 0x01 */ 1 +var KEY_1 =/* 1 ! 0x02 */ 2 +var KEY_2 =/* 2 @ 0x03 */ 3 +var KEY_3 =/* 3 # 0x04 */ 4 +var KEY_4 =/* 4 $ 0x05 */ 5 +var KEY_5 =/* 5 % 0x06 */ 6 +var KEY_6 =/* 6 ^ 0x07 */ 7 +var KEY_7 =/* 7 & 0x08 */ 8 +var KEY_8 =/* 8 * 0x09 */ 9 +var KEY_9 =/* 9 ( 0x0a */ 10 +var KEY_0 =/* 0 ) 0x0b */ 11 +var KEY_Minus =/* - (Minus) _ (Under) 0x0c */ 12 +var KEY_Equal =/* = (Equal) + 0x0d */ 13 +var KEY_BackSpace =/* Back Space 0x0e */ 14 +var KEY_Tab =/* Tab 0x0f */ 15 +var KEY_Q =/* Q 0x10 */ 16 +var KEY_W =/* W 0x11 */ 17 +var KEY_E =/* E 0x12 */ 18 +var KEY_R =/* R 0x13 */ 19 +var KEY_T =/* T 0x14 */ 20 +var KEY_Y =/* Y 0x15 */ 21 +var KEY_U =/* U 0x16 */ 22 +var KEY_I =/* I 0x17 */ 23 +var KEY_O =/* O 0x18 */ 24 +var KEY_P =/* P 0x19 */ 25 +var KEY_LBrace =/* [ { 0x1a */ 26 +var KEY_RBrace =/* ] } 0x1b */ 27 +var KEY_Enter =/* Enter 0x1c */ 28 +var KEY_LCtrl =/* Ctrl(left) 0x1d */ 29 +var KEY_A =/* A 0x1e */ 30 +var KEY_S =/* S 0x1f */ 31 +var KEY_D =/* D 0x20 */ 32 +var KEY_F =/* F 0x21 */ 33 +var KEY_G =/* G 0x22 */ 34 +var KEY_H =/* H 0x23 */ 35 +var KEY_J =/* J 0x24 */ 36 +var KEY_K =/* K 0x25 */ 37 +var KEY_L =/* L 0x26 */ 38 +var KEY_SemiColon =/* ;(SemiColon) :(Colon) 0x27 */ 39 +var KEY_Quote =/* ' (Apostr) " (Quote) 0x28 */ 40 +var KEY_Tilde =/* ` (Accent) ~ (Tilde) 0x29 */ 41 +var KEY_ShiftL =/* Shift(left) 0x2a */ 42 +var KEY_BSlash =/* \(BckSlash) |(VertBar)0x2b */ 43 +var KEY_Z =/* Z 0x2c */ 44 +var KEY_X =/* X 0x2d */ 45 +var KEY_C =/* C 0x2e */ 46 +var KEY_V =/* V 0x2f */ 47 +var KEY_B =/* B 0x30 */ 48 +var KEY_N =/* N 0x31 */ 49 +var KEY_M =/* M 0x32 */ 50 +var KEY_Comma =/* , (Comma) < (Less) 0x33 */ 51 +var KEY_Period =/* . (Period) >(Greater)0x34 */ 52 +var KEY_Slash =/* / (Slash) ? 0x35 */ 53 +var KEY_ShiftR =/* Shift(right) 0x36 */ 54 +var KEY_KP_Multiply =/* * 0x37 */ 55 +var KEY_Alt =/* Alt(left) 0x38 */ 56 +var KEY_Space =/* (SpaceBar) 0x39 */ 57 +var KEY_CapsLock =/* CapsLock 0x3a */ 58 +var KEY_F1 =/* F1 0x3b */ 59 +var KEY_F2 =/* F2 0x3c */ 60 +var KEY_F3 =/* F3 0x3d */ 61 +var KEY_F4 =/* F4 0x3e */ 62 +var KEY_F5 =/* F5 0x3f */ 63 +var KEY_F6 =/* F6 0x40 */ 64 +var KEY_F7 =/* F7 0x41 */ 65 +var KEY_F8 =/* F8 0x42 */ 66 +var KEY_F9 =/* F9 0x43 */ 67 +var KEY_F10 =/* F10 0x44 */ 68 +var KEY_NumLock =/* NumLock 0x45 */ 69 +var KEY_ScrollLock =/* ScrollLock 0x46 */ 70 +var KEY_KP_7 =/* 7 Home 0x47 */ 71 +var KEY_KP_8 =/* 8 Up 0x48 */ 72 +var KEY_KP_9 =/* 9 PgUp 0x49 */ 73 +var KEY_KP_Minus =/* - (Minus) 0x4a */ 74 +var KEY_KP_4 =/* 4 Left 0x4b */ 75 +var KEY_KP_5 =/* 5 0x4c */ 76 +var KEY_KP_6 =/* 6 Right 0x4d */ 77 +var KEY_KP_Plus =/* + (Plus) 0x4e */ 78 +var KEY_KP_1 =/* 1 End 0x4f */ 79 +var KEY_KP_2 =/* 2 Down 0x50 */ 80 +var KEY_KP_3 =/* 3 PgDown 0x51 */ 81 +var KEY_KP_0 =/* 0 Insert 0x52 */ 82 +var KEY_KP_Decimal =/* . (Decimal) Delete 0x53 */ 83 +var KEY_SysReqest =/* SysReqest 0x54 */ 84 + /* NOTUSED 0x55 */ +var KEY_Less =/* < (Less) >(Greater) 0x56 */ 86 +var KEY_F11 =/* F11 0x57 */ 87 +var KEY_F12 =/* F12 0x58 */ 88 + +var KEY_Prefix0 =/* special 0x60 */ 96 +var KEY_Prefix1 =/* specail 0x61 */ 97 diff --git a/src/wok/plugins/kimchi/ui/spice-html5/bitmap.js b/src/wok/plugins/kimchi/ui/spice-html5/bitmap.js new file mode 100644 index 0000000..03f5127 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/bitmap.js @@ -0,0 +1,51 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + + +/*---------------------------------------------------------------------------- +** bitmap.js +** Handle SPICE_IMAGE_TYPE_BITMAP +**--------------------------------------------------------------------------*/ +function convert_spice_bitmap_to_web(context, spice_bitmap) +{ + var ret; + var offset, x; + var u8 = new Uint8Array(spice_bitmap.data); + if (spice_bitmap.format != SPICE_BITMAP_FMT_32BIT && + spice_bitmap.format != SPICE_BITMAP_FMT_RGBA) + return undefined; + + ret = context.createImageData(spice_bitmap.x, spice_bitmap.y); + for (offset = 0; offset < (spice_bitmap.y * spice_bitmap.stride); ) + for (x = 0; x < spice_bitmap.x; x++, offset += 4) + { + ret.data[offset + 0 ] = u8[offset + 2]; + ret.data[offset + 1 ] = u8[offset + 1]; + ret.data[offset + 2 ] = u8[offset + 0]; + + // FIXME - We effectively treat all images as having SPICE_IMAGE_FLAGS_HIGH_BITS_SET + if (spice_bitmap.format == SPICE_BITMAP_FMT_32BIT) + ret.data[offset + 3] = 255; + else + ret.data[offset + 3] = u8[offset]; + } + + return ret; +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/css/Makefile.am b/src/wok/plugins/kimchi/ui/spice-html5/css/Makefile.am new file mode 100644 index 0000000..ed51972 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/css/Makefile.am @@ -0,0 +1,20 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2014 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +spicecssdir = $(datadir)/wok/plugins/kimchi/ui/spice-html5 + +dist_spicecss_DATA = $(wildcard *.css) $(NULL) diff --git a/src/wok/plugins/kimchi/ui/spice-html5/css/spice.css b/src/wok/plugins/kimchi/ui/spice-html5/css/spice.css new file mode 100644 index 0000000..5d092ba --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/css/spice.css @@ -0,0 +1,118 @@ +body +{ + background-color: #999999; + color: #000000; margin: 0; padding: 0; + font-family: "Lucida Grande", "Lucida Sans Unicode", "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif; + font-size: 12pt; + line-height: 1.5em; +} + +* { margin: 0; } + +#login +{ + width: 95%; + margin-left: auto; + margin-right: auto; + border: 1px solid #999999; + background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#24414e)); + background: -moz-linear-gradient(top, #fff, #24414e); + background-color: #24414e; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + border-radius: 10px; +} +#login span.logo +{ + display: inline-block; + margin-right: 5px; + padding: 2px 10px 2px 20px; + border-right: 1px solid #999999; + font-size: 20px; + font-weight: bolder; + text-shadow: #efefef 1px 1px 0px; +} +#login label { color: #ffffff; text-shadow: 1px 1px 0px rgba(175, 210, 220, 0.8); } +#login input +{ + padding: 5px; + background-color: #fAfAfA; + border: 1px inset #999999; + outline: none; + -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} +#login input#host { width: 200px; } +#login input#port { width: 75px; } +#login input#password { width: 100px; } +#login button +{ + padding: 5px 10px 5px 10px; + margin-left: 5px; + text-shadow: #efefef 1px 1px 0px; + border: 1px outset #999999; + cursor: pointer; + -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; +} +#login button:hover +{ + background-color: #666666; + color: #ffffff; +} + +#spice-area +{ + height: 100%; + width: 95%; + padding: 0; + margin-left: auto; + margin-right: auto; + border: solid #222222 1px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + border-radius: 10px; +} +.spice-screen +{ + min-height: 600px; + height: 100%; + margin: 10px; + padding: 0; + background-color: #333333; +} +.spice-message { + width: 700px; + height: 50px; + overflow: auto; + margin-top: 5px; + margin-left: auto; + margin-right: auto; + padding: 10px; + background-color: #efefef; + border: solid #c3c3c3 2px; + font-size: 8pt; + line-height: 1.1em; + font-family: 'Andale Mono', monospace; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + border-radius: 10px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); +} +.spice-message p { + margin-bottom: 0em; + margin-top: 0em; +} +.spice-message-warning { + color: orange; +} +.spice-message-error { + color: red; +} + diff --git a/src/wok/plugins/kimchi/ui/spice-html5/cursor.js b/src/wok/plugins/kimchi/ui/spice-html5/cursor.js new file mode 100644 index 0000000..71e941d --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/cursor.js @@ -0,0 +1,110 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + + +/*---------------------------------------------------------------------------- +** SpiceCursorConn +** Drive the Spice Cursor Channel +**--------------------------------------------------------------------------*/ +function SpiceCursorConn() +{ + SpiceConn.apply(this, arguments); +} + +SpiceCursorConn.prototype = Object.create(SpiceConn.prototype); +SpiceCursorConn.prototype.process_channel_message = function(msg) +{ + if (msg.type == SPICE_MSG_CURSOR_INIT) + { + var cursor_init = new SpiceMsgCursorInit(msg.data); + DEBUG > 1 && console.log("SpiceMsgCursorInit"); + if (this.parent && this.parent.inputs && + this.parent.inputs.mouse_mode == SPICE_MOUSE_MODE_SERVER) + { + // FIXME - this imagines that the server actually + // provides the current cursor position, + // instead of 0,0. As of May 11, 2012, + // that assumption was false :-(. + this.parent.inputs.mousex = cursor_init.position.x; + this.parent.inputs.mousey = cursor_init.position.y; + } + // FIXME - We don't handle most of the parameters here... + return true; + } + + if (msg.type == SPICE_MSG_CURSOR_SET) + { + var cursor_set = new SpiceMsgCursorSet(msg.data); + DEBUG > 1 && console.log("SpiceMsgCursorSet"); + if (cursor_set.flags & SPICE_CURSOR_FLAGS_NONE) + { + document.getElementById(this.parent.screen_id).style.cursor = "none"; + return true; + } + + if (cursor_set.flags > 0) + this.log_warn("FIXME: No support for cursor flags " + cursor_set.flags); + + if (cursor_set.cursor.header.type != SPICE_CURSOR_TYPE_ALPHA) + { + this.log_warn("FIXME: No support for cursor type " + cursor_set.cursor.header.type); + return false; + } + + this.set_cursor(cursor_set.cursor); + + return true; + } + + if (msg.type == SPICE_MSG_CURSOR_HIDE) + { + DEBUG > 1 && console.log("SpiceMsgCursorHide"); + document.getElementById(this.parent.screen_id).style.cursor = "none"; + return true; + } + + if (msg.type == SPICE_MSG_CURSOR_RESET) + { + DEBUG > 1 && console.log("SpiceMsgCursorReset"); + document.getElementById(this.parent.screen_id).style.cursor = "auto"; + return true; + } + + if (msg.type == SPICE_MSG_CURSOR_INVAL_ALL) + { + DEBUG > 1 && console.log("SpiceMsgCursorInvalAll"); + // FIXME - There may be something useful to do here... + return true; + } + + return false; +} + +SpiceCursorConn.prototype.set_cursor = function(cursor) +{ + var pngstr = create_rgba_png(cursor.header.height, cursor.header.width, cursor.data); + var curstr = 'url(data:image/png,' + pngstr + ') ' + + cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y + ", default"; + var screen = document.getElementById(this.parent.screen_id); + screen.style.cursor = 'auto'; + screen.style.cursor = curstr; + if (window.getComputedStyle(screen, null).cursor == 'auto') + SpiceSimulateCursor.simulate_cursor(this, cursor, screen, pngstr); +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/display.js b/src/wok/plugins/kimchi/ui/spice-html5/display.js new file mode 100644 index 0000000..2aa5985 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/display.js @@ -0,0 +1,823 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + + +/*---------------------------------------------------------------------------- +** FIXME: putImageData does not support Alpha blending +** or compositing. So if we have data in an ImageData +** format, we have to draw it onto a context, +** and then use drawImage to put it onto the target, +** as drawImage does alpha. +**--------------------------------------------------------------------------*/ +function putImageDataWithAlpha(context, d, x, y) +{ + var c = document.createElement("canvas"); + var t = c.getContext("2d"); + c.setAttribute('width', d.width); + c.setAttribute('height', d.height); + t.putImageData(d, 0, 0); + context.drawImage(c, x, y, d.width, d.height); +} + +/*---------------------------------------------------------------------------- +** FIXME: Spice will send an image with '0' alpha when it is intended to +** go on a surface w/no alpha. So in that case, we have to strip +** out the alpha. The test case for this was flux box; in a Xspice +** server, right click on the desktop to get the menu; the top bar +** doesn't paint/highlight correctly w/out this change. +**--------------------------------------------------------------------------*/ +function stripAlpha(d) +{ + var i; + for (i = 0; i < (d.width * d.height * 4); i += 4) + d.data[i + 3] = 255; +} + +/*---------------------------------------------------------------------------- +** SpiceDisplayConn +** Drive the Spice Display Channel +**--------------------------------------------------------------------------*/ +function SpiceDisplayConn() +{ + SpiceConn.apply(this, arguments); +} + +SpiceDisplayConn.prototype = Object.create(SpiceConn.prototype); +SpiceDisplayConn.prototype.process_channel_message = function(msg) +{ + if (msg.type == SPICE_MSG_DISPLAY_MARK) + { + // FIXME - DISPLAY_MARK not implemented (may be hard or impossible) + this.known_unimplemented(msg.type, "Display Mark"); + return true; + } + + if (msg.type == SPICE_MSG_DISPLAY_RESET) + { + DEBUG > 2 && console.log("Display reset"); + this.surfaces[this.primary_surface].canvas.context.restore(); + return true; + } + + if (msg.type == SPICE_MSG_DISPLAY_DRAW_COPY) + { + var draw_copy = new SpiceMsgDisplayDrawCopy(msg.data); + + DEBUG > 1 && this.log_draw("DrawCopy", draw_copy); + + if (! draw_copy.base.box.is_same_size(draw_copy.data.src_area)) + this.log_warn("FIXME: DrawCopy src_area is a different size than base.box; we do not handle that yet."); + if (draw_copy.base.clip.type != SPICE_CLIP_TYPE_NONE) + this.log_warn("FIXME: DrawCopy we don't handle clipping yet"); + if (draw_copy.data.rop_descriptor != SPICE_ROPD_OP_PUT) + this.log_warn("FIXME: DrawCopy we don't handle ropd type: " + draw_copy.data.rop_descriptor); + if (draw_copy.data.mask.flags) + this.log_warn("FIXME: DrawCopy we don't handle mask flag: " + draw_copy.data.mask.flags); + if (draw_copy.data.mask.bitmap) + this.log_warn("FIXME: DrawCopy we don't handle mask"); + + if (draw_copy.data && draw_copy.data.src_bitmap) + { + if (draw_copy.data.src_bitmap.descriptor.flags && + draw_copy.data.src_bitmap.descriptor.flags != SPICE_IMAGE_FLAGS_CACHE_ME && + draw_copy.data.src_bitmap.descriptor.flags != SPICE_IMAGE_FLAGS_HIGH_BITS_SET) + { + this.log_warn("FIXME: DrawCopy unhandled image flags: " + draw_copy.data.src_bitmap.descriptor.flags); + DEBUG <= 1 && this.log_draw("DrawCopy", draw_copy); + } + + if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_QUIC) + { + var canvas = this.surfaces[draw_copy.base.surface_id].canvas; + if (! draw_copy.data.src_bitmap.quic) + { + this.log_warn("FIXME: DrawCopy could not handle this QUIC file."); + return false; + } + var source_img = convert_spice_quic_to_web(canvas.context, + draw_copy.data.src_bitmap.quic); + + return this.draw_copy_helper( + { base: draw_copy.base, + src_area: draw_copy.data.src_area, + image_data: source_img, + tag: "copyquic." + draw_copy.data.src_bitmap.quic.type, + has_alpha: (draw_copy.data.src_bitmap.quic.type == QUIC_IMAGE_TYPE_RGBA ? true : false) , + descriptor : draw_copy.data.src_bitmap.descriptor + }); + } + else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_FROM_CACHE || + draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS) + { + if (! this.cache || ! this.cache[draw_copy.data.src_bitmap.descriptor.id]) + { + this.log_warn("FIXME: DrawCopy did not find image id " + draw_copy.data.src_bitmap.descriptor.id + " in cache."); + return false; + } + + return this.draw_copy_helper( + { base: draw_copy.base, + src_area: draw_copy.data.src_area, + image_data: this.cache[draw_copy.data.src_bitmap.descriptor.id], + tag: "copycache." + draw_copy.data.src_bitmap.descriptor.id, + has_alpha: true, /* FIXME - may want this to be false... */ + descriptor : draw_copy.data.src_bitmap.descriptor + }); + + /* FIXME - LOSSLESS CACHE ramifications not understood or handled */ + } + else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_SURFACE) + { + var source_context = this.surfaces[draw_copy.data.src_bitmap.surface_id].canvas.context; + var target_context = this.surfaces[draw_copy.base.surface_id].canvas.context; + + var source_img = source_context.getImageData( + draw_copy.data.src_area.left, draw_copy.data.src_area.top, + draw_copy.data.src_area.right - draw_copy.data.src_area.left, + draw_copy.data.src_area.bottom - draw_copy.data.src_area.top); + var computed_src_area = new SpiceRect; + computed_src_area.top = computed_src_area.left = 0; + computed_src_area.right = source_img.width; + computed_src_area.bottom = source_img.height; + + /* FIXME - there is a potential optimization here. + That is, if the surface is from 0,0, and + both surfaces are alpha surfaces, you should + be able to just do a drawImage, which should + save time. */ + + return this.draw_copy_helper( + { base: draw_copy.base, + src_area: computed_src_area, + image_data: source_img, + tag: "copysurf." + draw_copy.data.src_bitmap.surface_id, + has_alpha: this.surfaces[draw_copy.data.src_bitmap.surface_id].format == SPICE_SURFACE_FMT_32_xRGB ? false : true, + descriptor : draw_copy.data.src_bitmap.descriptor + }); + + return true; + } + else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_JPEG) + { + if (! draw_copy.data.src_bitmap.jpeg) + { + this.log_warn("FIXME: DrawCopy could not handle this JPEG file."); + return false; + } + + // FIXME - how lame is this. Be have it in binary format, and we have + // to put it into string to get it back into jpeg. Blech. + var tmpstr = "data:image/jpeg,"; + var img = new Image; + var i; + var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg.data); + for (i = 0; i < qdv.length; i++) + { + tmpstr += '%'; + if (qdv[i] < 16) + tmpstr += '0'; + tmpstr += qdv[i].toString(16); + } + + img.o = + { base: draw_copy.base, + tag: "jpeg." + draw_copy.data.src_bitmap.surface_id, + descriptor : draw_copy.data.src_bitmap.descriptor, + sc : this, + }; + img.onload = handle_draw_jpeg_onload; + img.src = tmpstr; + + return true; + } + else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_JPEG_ALPHA) + { + if (! draw_copy.data.src_bitmap.jpeg_alpha) + { + this.log_warn("FIXME: DrawCopy could not handle this JPEG ALPHA file."); + return false; + } + + // FIXME - how lame is this. Be have it in binary format, and we have + // to put it into string to get it back into jpeg. Blech. + var tmpstr = "data:image/jpeg,"; + var img = new Image; + var i; + var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg_alpha.data); + for (i = 0; i < qdv.length; i++) + { + tmpstr += '%'; + if (qdv[i] < 16) + tmpstr += '0'; + tmpstr += qdv[i].toString(16); + } + + img.o = + { base: draw_copy.base, + tag: "jpeg." + draw_copy.data.src_bitmap.surface_id, + descriptor : draw_copy.data.src_bitmap.descriptor, + sc : this, + }; + + if (this.surfaces[draw_copy.base.surface_id].format == SPICE_SURFACE_FMT_32_ARGB) + { + + var canvas = this.surfaces[draw_copy.base.surface_id].canvas; + img.alpha_img = convert_spice_lz_to_web(canvas.context, + draw_copy.data.src_bitmap.jpeg_alpha.alpha); + } + img.onload = handle_draw_jpeg_onload; + img.src = tmpstr; + + return true; + } + else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_BITMAP) + { + var canvas = this.surfaces[draw_copy.base.surface_id].canvas; + if (! draw_copy.data.src_bitmap.bitmap) + { + this.log_err("null bitmap"); + return false; + } + + var source_img = convert_spice_bitmap_to_web(canvas.context, + draw_copy.data.src_bitmap.bitmap); + if (! source_img) + { + this.log_warn("FIXME: Unable to interpret bitmap of format: " + + draw_copy.data.src_bitmap.bitmap.format); + return false; + } + + return this.draw_copy_helper( + { base: draw_copy.base, + src_area: draw_copy.data.src_area, + image_data: source_img, + tag: "bitmap." + draw_copy.data.src_bitmap.bitmap.format, + has_alpha: draw_copy.data.src_bitmap.bitmap == SPICE_BITMAP_FMT_32BIT ? false : true, + descriptor : draw_copy.data.src_bitmap.descriptor + }); + } + else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_LZ_RGB) + { + var canvas = this.surfaces[draw_copy.base.surface_id].canvas; + if (! draw_copy.data.src_bitmap.lz_rgb) + { + this.log_err("null lz_rgb "); + return false; + } + + if (draw_copy.data.src_bitmap.lz_rgb.top_down != 1) + this.log_warn("FIXME: Implement non top down support for lz_rgb"); + + var source_img = convert_spice_lz_to_web(canvas.context, + draw_copy.data.src_bitmap.lz_rgb); + if (! source_img) + { + this.log_warn("FIXME: Unable to interpret bitmap of type: " + + draw_copy.data.src_bitmap.lz_rgb.type); + return false; + } + + return this.draw_copy_helper( + { base: draw_copy.base, + src_area: draw_copy.data.src_area, + image_data: source_img, + tag: "lz_rgb." + draw_copy.data.src_bitmap.lz_rgb.type, + has_alpha: draw_copy.data.src_bitmap.lz_rgb.type == LZ_IMAGE_TYPE_RGBA ? true : false , + descriptor : draw_copy.data.src_bitmap.descriptor + }); + } + else + { + this.log_warn("FIXME: DrawCopy unhandled image type: " + draw_copy.data.src_bitmap.descriptor.type); + this.log_draw("DrawCopy", draw_copy); + return false; + } + } + + this.log_warn("FIXME: DrawCopy no src_bitmap."); + return false; + } + + if (msg.type == SPICE_MSG_DISPLAY_DRAW_FILL) + { + var draw_fill = new SpiceMsgDisplayDrawFill(msg.data); + + DEBUG > 1 && this.log_draw("DrawFill", draw_fill); + + if (draw_fill.data.rop_descriptor != SPICE_ROPD_OP_PUT) + this.log_warn("FIXME: DrawFill we don't handle ropd type: " + draw_fill.data.rop_descriptor); + if (draw_fill.data.mask.flags) + this.log_warn("FIXME: DrawFill we don't handle mask flag: " + draw_fill.data.mask.flags); + if (draw_fill.data.mask.bitmap) + this.log_warn("FIXME: DrawFill we don't handle mask"); + + if (draw_fill.data.brush.type == SPICE_BRUSH_TYPE_SOLID) + { + // FIXME - do brushes ever have alpha? + var color = draw_fill.data.brush.color & 0xffffff; + var color_str = "rgb(" + (color >> 16) + ", " + ((color >> 8) & 0xff) + ", " + (color & 0xff) + ")"; + this.surfaces[draw_fill.base.surface_id].canvas.context.fillStyle = color_str; + + this.surfaces[draw_fill.base.surface_id].canvas.context.fillRect( + draw_fill.base.box.left, draw_fill.base.box.top, + draw_fill.base.box.right - draw_fill.base.box.left, + draw_fill.base.box.bottom - draw_fill.base.box.top); + + if (DUMP_DRAWS && this.parent.dump_id) + { + var debug_canvas = document.createElement("canvas"); + debug_canvas.setAttribute('width', this.surfaces[draw_fill.base.surface_id].canvas.width); + debug_canvas.setAttribute('height', this.surfaces[draw_fill.base.surface_id].canvas.height); + debug_canvas.setAttribute('id', "fillbrush." + draw_fill.base.surface_id + "." + this.surfaces[draw_fill.base.surface_id].draw_count); + debug_canvas.getContext("2d").fillStyle = color_str; + debug_canvas.getContext("2d").fillRect( + draw_fill.base.box.left, draw_fill.base.box.top, + draw_fill.base.box.right - draw_fill.base.box.left, + draw_fill.base.box.bottom - draw_fill.base.box.top); + document.getElementById(this.parent.dump_id).appendChild(debug_canvas); + } + + this.surfaces[draw_fill.base.surface_id].draw_count++; + + } + else + { + this.log_warn("FIXME: DrawFill can't handle brush type: " + draw_fill.data.brush.type); + } + return true; + } + + if (msg.type == SPICE_MSG_DISPLAY_COPY_BITS) + { + var copy_bits = new SpiceMsgDisplayCopyBits(msg.data); + + DEBUG > 1 && this.log_draw("CopyBits", copy_bits); + + var source_canvas = this.surfaces[copy_bits.base.surface_id].canvas; + var source_context = source_canvas.context; + + var width = source_canvas.width - copy_bits.src_pos.x; + var height = source_canvas.height - copy_bits.src_pos.y; + if (width > (copy_bits.base.box.right - copy_bits.base.box.left)) + width = copy_bits.base.box.right - copy_bits.base.box.left; + if (height > (copy_bits.base.box.bottom - copy_bits.base.box.top)) + height = copy_bits.base.box.bottom - copy_bits.base.box.top; + + var source_img = source_context.getImageData( + copy_bits.src_pos.x, copy_bits.src_pos.y, width, height); + //source_context.putImageData(source_img, copy_bits.base.box.left, copy_bits.base.box.top); + putImageDataWithAlpha(source_context, source_img, copy_bits.base.box.left, copy_bits.base.box.top); + + if (DUMP_DRAWS && this.parent.dump_id) + { + var debug_canvas = document.createElement("canvas"); + debug_canvas.setAttribute('width', width); + debug_canvas.setAttribute('height', height); + debug_canvas.setAttribute('id', "copybits" + copy_bits.base.surface_id + "." + this.surfaces[copy_bits.base.surface_id].draw_count); + debug_canvas.getContext("2d").putImageData(source_img, 0, 0); + document.getElementById(this.parent.dump_id).appendChild(debug_canvas); + } + + + this.surfaces[copy_bits.base.surface_id].draw_count++; + return true; + } + + if (msg.type == SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES) + { + this.known_unimplemented(msg.type, "Inval All Palettes"); + return true; + } + + if (msg.type == SPICE_MSG_DISPLAY_SURFACE_CREATE) + { + if (! ("surfaces" in this)) + this.surfaces = []; + + var m = new SpiceMsgSurfaceCreate(msg.data); + DEBUG > 1 && console.log(this.type + ": MsgSurfaceCreate id " + m.surface.surface_id + + "; " + m.surface.width + "x" + m.surface.height + + "; format " + m.surface.format + + "; flags " + m.surface.flags); + if (m.surface.format != SPICE_SURFACE_FMT_32_xRGB && + m.surface.format != SPICE_SURFACE_FMT_32_ARGB) + { + this.log_warn("FIXME: cannot handle surface format " + m.surface.format + " yet."); + return false; + } + + var canvas = document.createElement("canvas"); + canvas.setAttribute('width', m.surface.width); + canvas.setAttribute('height', m.surface.height); + canvas.setAttribute('id', "spice_surface_" + m.surface.surface_id); + canvas.setAttribute('tabindex', m.surface.surface_id); + canvas.context = canvas.getContext("2d"); + + if (DUMP_CANVASES && this.parent.dump_id) + document.getElementById(this.parent.dump_id).appendChild(canvas); + + m.surface.canvas = canvas; + m.surface.draw_count = 0; + this.surfaces[m.surface.surface_id] = m.surface; + + if (m.surface.flags & SPICE_SURFACE_FLAGS_PRIMARY) + { + this.primary_surface = m.surface.surface_id; + + /* This .save() is done entirely to enable SPICE_MSG_DISPLAY_RESET */ + canvas.context.save(); + document.getElementById(this.parent.screen_id).appendChild(canvas); + + /* We're going to leave width dynamic, but correctly set the height */ + document.getElementById(this.parent.screen_id).style.height = m.surface.height + "px"; + this.hook_events(); + } + return true; + } + + if (msg.type == SPICE_MSG_DISPLAY_SURFACE_DESTROY) + { + var m = new SpiceMsgSurfaceDestroy(msg.data); + DEBUG > 1 && console.log(this.type + ": MsgSurfaceDestroy id " + m.surface_id); + this.delete_surface(m.surface_id); + return true; + } + + if (msg.type == SPICE_MSG_DISPLAY_STREAM_CREATE) + { + var m = new SpiceMsgDisplayStreamCreate(msg.data); + DEBUG > 1 && console.log(this.type + ": MsgStreamCreate id" + m.id); + if (!this.streams) + this.streams = new Array(); + if (this.streams[m.id]) + console.log("Stream already exists"); + else + this.streams[m.id] = m; + if (m.codec_type != SPICE_VIDEO_CODEC_TYPE_MJPEG) + console.log("Unhandled stream codec: "+m.codec_type); + return true; + } + + if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA) + { + var m = new SpiceMsgDisplayStreamData(msg.data); + if (!this.streams[m.base.id]) + { + console.log("no stream for data"); + return false; + } + if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_MJPEG) + { + var tmpstr = "data:image/jpeg,"; + var img = new Image; + var i; + for (i = 0; i < m.data.length; i++) + { + tmpstr += '%'; + if (m.data[i] < 16) + tmpstr += '0'; + tmpstr += m.data[i].toString(16); + } + var strm_base = new SpiceMsgDisplayBase(); + strm_base.surface_id = this.streams[m.base.id].surface_id; + strm_base.box = this.streams[m.base.id].dest; + strm_base.clip = this.streams[m.base.id].clip; + img.o = + { base: strm_base, + tag: "mjpeg." + m.base.id, + descriptor: null, + sc : this, + }; + img.onload = handle_draw_jpeg_onload; + img.src = tmpstr; + } + return true; + } + + if (msg.type == SPICE_MSG_DISPLAY_STREAM_CLIP) + { + var m = new SpiceMsgDisplayStreamClip(msg.data); + DEBUG > 1 && console.log(this.type + ": MsgStreamClip id" + m.id); + this.streams[m.id].clip = m.clip; + return true; + } + + if (msg.type == SPICE_MSG_DISPLAY_STREAM_DESTROY) + { + var m = new SpiceMsgDisplayStreamDestroy(msg.data); + DEBUG > 1 && console.log(this.type + ": MsgStreamDestroy id" + m.id); + this.streams[m.id] = undefined; + return true; + } + if (msg.type == SPICE_MSG_DISPLAY_INVAL_LIST) + { + var m = new SpiceMsgDisplayInvalList(msg.data); + var i; + DEBUG > 1 && console.log(this.type + ": MsgInvalList " + m.count + " items"); + for (i = 0; i < m.count; i++) + if (this.cache[m.resources[i].id] != undefined) + delete this.cache[m.resources[i].id]; + return true; + } + + return false; +} + +SpiceDisplayConn.prototype.delete_surface = function(surface_id) +{ + var canvas = document.getElementById("spice_surface_" + surface_id); + if (DUMP_CANVASES && this.parent.dump_id) + document.getElementById(this.parent.dump_id).removeChild(canvas); + if (this.primary_surface == surface_id) + { + this.unhook_events(); + this.primary_surface = undefined; + document.getElementById(this.parent.screen_id).removeChild(canvas); + } + + delete this.surfaces[surface_id]; +} + + +SpiceDisplayConn.prototype.draw_copy_helper = function(o) +{ + + var canvas = this.surfaces[o.base.surface_id].canvas; + if (o.has_alpha) + { + /* FIXME - This is based on trial + error, not a serious thoughtful + analysis of what Spice requires. See display.js for more. */ + if (this.surfaces[o.base.surface_id].format == SPICE_SURFACE_FMT_32_xRGB) + { + stripAlpha(o.image_data); + canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top); + } + else + putImageDataWithAlpha(canvas.context, o.image_data, + o.base.box.left, o.base.box.top); + } + else + canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top); + + if (o.src_area.left > 0 || o.src_area.top > 0) + { + this.log_warn("FIXME: DrawCopy not shifting draw copies just yet..."); + } + + if (o.descriptor && (o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) + { + if (! ("cache" in this)) + this.cache = {}; + this.cache[o.descriptor.id] = o.image_data; + } + + if (DUMP_DRAWS && this.parent.dump_id) + { + var debug_canvas = document.createElement("canvas"); + debug_canvas.setAttribute('width', o.image_data.width); + debug_canvas.setAttribute('height', o.image_data.height); + debug_canvas.setAttribute('id', o.tag + "." + + this.surfaces[o.base.surface_id].draw_count + "." + + o.base.surface_id + "@" + o.base.box.left + "x" + o.base.box.top); + debug_canvas.getContext("2d").putImageData(o.image_data, 0, 0); + document.getElementById(this.parent.dump_id).appendChild(debug_canvas); + } + + this.surfaces[o.base.surface_id].draw_count++; + + return true; +} + + +SpiceDisplayConn.prototype.log_draw = function(prefix, draw) +{ + var str = prefix + "." + draw.base.surface_id + "." + this.surfaces[draw.base.surface_id].draw_count + ": "; + str += "base.box " + draw.base.box.left + ", " + draw.base.box.top + " to " + + draw.base.box.right + ", " + draw.base.box.bottom; + str += "; clip.type " + draw.base.clip.type; + + if (draw.data) + { + if (draw.data.src_area) + str += "; src_area " + draw.data.src_area.left + ", " + draw.data.src_area.top + " to " + + draw.data.src_area.right + ", " + draw.data.src_area.bottom; + + if (draw.data.src_bitmap && draw.data.src_bitmap != null) + { + str += "; src_bitmap id: " + draw.data.src_bitmap.descriptor.id; + str += "; src_bitmap width " + draw.data.src_bitmap.descriptor.width + ", height " + draw.data.src_bitmap.descriptor.height; + str += "; src_bitmap type " + draw.data.src_bitmap.descriptor.type + ", flags " + draw.data.src_bitmap.descriptor.flags; + if (draw.data.src_bitmap.surface_id !== undefined) + str += "; src_bitmap surface_id " + draw.data.src_bitmap.surface_id; + if (draw.data.src_bitmap.quic) + str += "; QUIC type " + draw.data.src_bitmap.quic.type + + "; width " + draw.data.src_bitmap.quic.width + + "; height " + draw.data.src_bitmap.quic.height ; + if (draw.data.src_bitmap.lz_rgb) + str += "; LZ_RGB length " + draw.data.src_bitmap.lz_rgb.length + + "; magic " + draw.data.src_bitmap.lz_rgb.magic + + "; version 0x" + draw.data.src_bitmap.lz_rgb.version.toString(16) + + "; type " + draw.data.src_bitmap.lz_rgb.type + + "; width " + draw.data.src_bitmap.lz_rgb.width + + "; height " + draw.data.src_bitmap.lz_rgb.height + + "; stride " + draw.data.src_bitmap.lz_rgb.stride + + "; top down " + draw.data.src_bitmap.lz_rgb.top_down; + } + else + str += "; src_bitmap is null"; + + if (draw.data.brush) + { + if (draw.data.brush.type == SPICE_BRUSH_TYPE_SOLID) + str += "; brush.color 0x" + draw.data.brush.color.toString(16); + if (draw.data.brush.type == SPICE_BRUSH_TYPE_PATTERN) + { + str += "; brush.pat "; + if (draw.data.brush.pattern.pat != null) + str += "[SpiceImage]"; + else + str += "[null]"; + str += " at " + draw.data.brush.pattern.pos.x + ", " + draw.data.brush.pattern.pos.y; + } + } + + str += "; rop_descriptor " + draw.data.rop_descriptor; + if (draw.data.scale_mode !== undefined) + str += "; scale_mode " + draw.data.scale_mode; + str += "; mask.flags " + draw.data.mask.flags; + str += "; mask.pos " + draw.data.mask.pos.x + ", " + draw.data.mask.pos.y; + if (draw.data.mask.bitmap != null) + { + str += "; mask.bitmap width " + draw.data.mask.bitmap.descriptor.width + ", height " + draw.data.mask.bitmap.descriptor.height; + str += "; mask.bitmap type " + draw.data.mask.bitmap.descriptor.type + ", flags " + draw.data.mask.bitmap.descriptor.flags; + } + else + str += "; mask.bitmap is null"; + } + + console.log(str); +} + +SpiceDisplayConn.prototype.hook_events = function() +{ + if (this.primary_surface !== undefined) + { + var canvas = this.surfaces[this.primary_surface].canvas; + canvas.sc = this.parent; + canvas.addEventListener('mousemove', handle_mousemove); + canvas.addEventListener('mousedown', handle_mousedown); + canvas.addEventListener('contextmenu', handle_contextmenu); + canvas.addEventListener('mouseup', handle_mouseup); + canvas.addEventListener('keydown', handle_keydown); + canvas.addEventListener('keyup', handle_keyup); + canvas.addEventListener('mouseout', handle_mouseout); + canvas.addEventListener('mouseover', handle_mouseover); + canvas.addEventListener('mousewheel', handle_mousewheel); + canvas.focus(); + } +} + +SpiceDisplayConn.prototype.unhook_events = function() +{ + if (this.primary_surface !== undefined) + { + var canvas = this.surfaces[this.primary_surface].canvas; + canvas.removeEventListener('mousemove', handle_mousemove); + canvas.removeEventListener('mousedown', handle_mousedown); + canvas.removeEventListener('contextmenu', handle_contextmenu); + canvas.removeEventListener('mouseup', handle_mouseup); + canvas.removeEventListener('keydown', handle_keydown); + canvas.removeEventListener('keyup', handle_keyup); + canvas.removeEventListener('mouseout', handle_mouseout); + canvas.removeEventListener('mouseover', handle_mouseover); + canvas.removeEventListener('mousewheel', handle_mousewheel); + } +} + + +SpiceDisplayConn.prototype.destroy_surfaces = function() +{ + for (var s in this.surfaces) + { + this.delete_surface(this.surfaces[s].surface_id); + } + + this.surfaces = undefined; +} + + +function handle_mouseover(e) +{ + this.focus(); +} + +function handle_mouseout(e) +{ + if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor) + this.sc.cursor.spice_simulated_cursor.style.display = 'none'; + this.blur(); +} + +function handle_draw_jpeg_onload() +{ + var temp_canvas = null; + var context; + + /*------------------------------------------------------------ + ** FIXME: + ** The helper should be extended to be able to handle actual HtmlImageElements + ** ...and the cache should be modified to do so as well + **----------------------------------------------------------*/ + if (this.o.sc.surfaces[this.o.base.surface_id] === undefined) + { + // This can happen; if the jpeg image loads after our surface + // has been destroyed (e.g. open a menu, close it quickly), + // we'll find we have no surface. + DEBUG > 2 && this.o.sc.log_info("Discarding jpeg; presumed lost surface " + this.o.base.surface_id); + temp_canvas = document.createElement("canvas"); + temp_canvas.setAttribute('width', this.o.base.box.right); + temp_canvas.setAttribute('height', this.o.base.box.bottom); + context = temp_canvas.getContext("2d"); + } + else + context = this.o.sc.surfaces[this.o.base.surface_id].canvas.context; + + if (this.alpha_img) + { + var c = document.createElement("canvas"); + var t = c.getContext("2d"); + c.setAttribute('width', this.alpha_img.width); + c.setAttribute('height', this.alpha_img.height); + t.putImageData(this.alpha_img, 0, 0); + t.globalCompositeOperation = 'source-in'; + t.drawImage(this, 0, 0); + + context.drawImage(c, this.o.base.box.left, this.o.base.box.top); + + if (this.o.descriptor && + (this.o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) + { + if (! ("cache" in this.o.sc)) + this.o.sc.cache = {}; + + this.o.sc.cache[this.o.descriptor.id] = + t.getImageData(0, 0, + this.alpha_img.width, + this.alpha_img.height); + } + } + else + { + context.drawImage(this, this.o.base.box.left, this.o.base.box.top); + + // Give the Garbage collector a clue to recycle this; avoids + // fairly massive memory leaks during video playback + this.src = null; + + if (this.o.descriptor && + (this.o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) + { + if (! ("cache" in this.o.sc)) + this.o.sc.cache = {}; + + this.o.sc.cache[this.o.descriptor.id] = + context.getImageData(this.o.base.box.left, this.o.base.box.top, + this.o.base.box.right - this.o.base.box.left, + this.o.base.box.bottom - this.o.base.box.top); + } + } + + if (temp_canvas == null) + { + if (DUMP_DRAWS && this.o.sc.parent.dump_id) + { + var debug_canvas = document.createElement("canvas"); + debug_canvas.setAttribute('id', this.o.tag + "." + + this.o.sc.surfaces[this.o.base.surface_id].draw_count + "." + + this.o.base.surface_id + "@" + this.o.base.box.left + "x" + this.o.base.box.top); + debug_canvas.getContext("2d").drawImage(this, 0, 0); + document.getElementById(this.o.sc.parent.dump_id).appendChild(debug_canvas); + } + + this.o.sc.surfaces[this.o.base.surface_id].draw_count++; + } +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/enums.js b/src/wok/plugins/kimchi/ui/spice-html5/enums.js new file mode 100644 index 0000000..d99b38e --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/enums.js @@ -0,0 +1,324 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + + +/*---------------------------------------------------------------------------- +** enums.js +** 'constants' for Spice +**--------------------------------------------------------------------------*/ +var SPICE_MAGIC = "REDQ"; +var SPICE_VERSION_MAJOR = 2; +var SPICE_VERSION_MINOR = 2; + +var SPICE_CONNECT_TIMEOUT = (30 * 1000); + +var SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION = 0; +var SPICE_COMMON_CAP_AUTH_SPICE = 1; +var SPICE_COMMON_CAP_AUTH_SASL = 2; +var SPICE_COMMON_CAP_MINI_HEADER = 3; + +var SPICE_TICKET_KEY_PAIR_LENGTH = 1024; +var SPICE_TICKET_PUBKEY_BYTES = (SPICE_TICKET_KEY_PAIR_LENGTH / 8 + 34); + +var SPICE_LINK_ERR_OK = 0, + SPICE_LINK_ERR_ERROR = 1, + SPICE_LINK_ERR_INVALID_MAGIC = 2, + SPICE_LINK_ERR_INVALID_DATA = 3, + SPICE_LINK_ERR_VERSION_MISMATCH = 4, + SPICE_LINK_ERR_NEED_SECURED = 5, + SPICE_LINK_ERR_NEED_UNSECURED = 6, + SPICE_LINK_ERR_PERMISSION_DENIED = 7, + SPICE_LINK_ERR_BAD_CONNECTION_ID = 8, + SPICE_LINK_ERR_CHANNEL_NOT_AVAILABLE = 9; + +var SPICE_MSG_MIGRATE = 1; +var SPICE_MSG_MIGRATE_DATA = 2; +var SPICE_MSG_SET_ACK = 3; +var SPICE_MSG_PING = 4; +var SPICE_MSG_WAIT_FOR_CHANNELS = 5; +var SPICE_MSG_DISCONNECTING = 6; +var SPICE_MSG_NOTIFY = 7; +var SPICE_MSG_LIST = 8; + +var SPICE_MSG_MAIN_MIGRATE_BEGIN = 101; +var SPICE_MSG_MAIN_MIGRATE_CANCEL = 102; +var SPICE_MSG_MAIN_INIT = 103; +var SPICE_MSG_MAIN_CHANNELS_LIST = 104; +var SPICE_MSG_MAIN_MOUSE_MODE = 105; +var SPICE_MSG_MAIN_MULTI_MEDIA_TIME = 106; +var SPICE_MSG_MAIN_AGENT_CONNECTED = 107; +var SPICE_MSG_MAIN_AGENT_DISCONNECTED = 108; +var SPICE_MSG_MAIN_AGENT_DATA = 109; +var SPICE_MSG_MAIN_AGENT_TOKEN = 110; +var SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST = 111; +var SPICE_MSG_MAIN_MIGRATE_END = 112; +var SPICE_MSG_MAIN_NAME = 113; +var SPICE_MSG_MAIN_UUID = 114; +var SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS = 115; +var SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS = 116; +var SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK = 117; +var SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK = 118; +var SPICE_MSG_END_MAIN = 119; + + + +var SPICE_MSGC_ACK_SYNC = 1; +var SPICE_MSGC_ACK = 2; +var SPICE_MSGC_PONG = 3; +var SPICE_MSGC_MIGRATE_FLUSH_MARK = 4; +var SPICE_MSGC_MIGRATE_DATA = 5; +var SPICE_MSGC_DISCONNECTING = 6; + + +var SPICE_MSGC_MAIN_CLIENT_INFO = 101; +var SPICE_MSGC_MAIN_MIGRATE_CONNECTED = 102; +var SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR = 103; +var SPICE_MSGC_MAIN_ATTACH_CHANNELS = 104; +var SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST = 105; +var SPICE_MSGC_MAIN_AGENT_START = 106; +var SPICE_MSGC_MAIN_AGENT_DATA = 107; +var SPICE_MSGC_MAIN_AGENT_TOKEN = 108; +var SPICE_MSGC_MAIN_MIGRATE_END = 109; +var SPICE_MSGC_END_MAIN = 110; + +var SPICE_MSG_DISPLAY_MODE = 101; +var SPICE_MSG_DISPLAY_MARK = 102; +var SPICE_MSG_DISPLAY_RESET = 103; +var SPICE_MSG_DISPLAY_COPY_BITS = 104; +var SPICE_MSG_DISPLAY_INVAL_LIST = 105; +var SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS = 106; +var SPICE_MSG_DISPLAY_INVAL_PALETTE = 107; +var SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES= 108; + +var SPICE_MSG_DISPLAY_STREAM_CREATE = 122; +var SPICE_MSG_DISPLAY_STREAM_DATA = 123; +var SPICE_MSG_DISPLAY_STREAM_CLIP = 124; +var SPICE_MSG_DISPLAY_STREAM_DESTROY = 125; +var SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL= 126; + +var SPICE_MSG_DISPLAY_DRAW_FILL = 302; +var SPICE_MSG_DISPLAY_DRAW_OPAQUE = 303; +var SPICE_MSG_DISPLAY_DRAW_COPY = 304; +var SPICE_MSG_DISPLAY_DRAW_BLEND = 305; +var SPICE_MSG_DISPLAY_DRAW_BLACKNESS = 306; +var SPICE_MSG_DISPLAY_DRAW_WHITENESS = 307; +var SPICE_MSG_DISPLAY_DRAW_INVERS = 308; +var SPICE_MSG_DISPLAY_DRAW_ROP3 = 309; +var SPICE_MSG_DISPLAY_DRAW_STROKE = 310; +var SPICE_MSG_DISPLAY_DRAW_TEXT = 311; +var SPICE_MSG_DISPLAY_DRAW_TRANSPARENT = 312; +var SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND = 313; +var SPICE_MSG_DISPLAY_SURFACE_CREATE = 314; +var SPICE_MSG_DISPLAY_SURFACE_DESTROY = 315; + +var SPICE_MSGC_DISPLAY_INIT = 101; + +var SPICE_MSG_INPUTS_INIT = 101; +var SPICE_MSG_INPUTS_KEY_MODIFIERS = 102; + +var SPICE_MSG_INPUTS_MOUSE_MOTION_ACK = 111; + +var SPICE_MSGC_INPUTS_KEY_DOWN = 101; +var SPICE_MSGC_INPUTS_KEY_UP = 102; +var SPICE_MSGC_INPUTS_KEY_MODIFIERS = 103; + +var SPICE_MSGC_INPUTS_MOUSE_MOTION = 111; +var SPICE_MSGC_INPUTS_MOUSE_POSITION = 112; +var SPICE_MSGC_INPUTS_MOUSE_PRESS = 113; +var SPICE_MSGC_INPUTS_MOUSE_RELEASE = 114; + +var SPICE_MSG_CURSOR_INIT = 101; +var SPICE_MSG_CURSOR_RESET = 102; +var SPICE_MSG_CURSOR_SET = 103; +var SPICE_MSG_CURSOR_MOVE = 104; +var SPICE_MSG_CURSOR_HIDE = 105; +var SPICE_MSG_CURSOR_TRAIL = 106; +var SPICE_MSG_CURSOR_INVAL_ONE = 107; +var SPICE_MSG_CURSOR_INVAL_ALL = 108; + +var SPICE_MSG_PLAYBACK_DATA = 101; +var SPICE_MSG_PLAYBACK_MODE = 102; +var SPICE_MSG_PLAYBACK_START = 103; +var SPICE_MSG_PLAYBACK_STOP = 104; +var SPICE_MSG_PLAYBACK_VOLUME = 105; +var SPICE_MSG_PLAYBACK_MUTE = 106; +var SPICE_MSG_PLAYBACK_LATENCY = 107; + +var SPICE_PLAYBACK_CAP_CELT_0_5_1 = 0; +var SPICE_PLAYBACK_CAP_VOLUME = 1; +var SPICE_PLAYBACK_CAP_LATENCY = 2; +var SPICE_PLAYBACK_CAP_OPUS = 3; + +var SPICE_AUDIO_DATA_MODE_INVALID = 0; +var SPICE_AUDIO_DATA_MODE_RAW = 1; +var SPICE_AUDIO_DATA_MODE_CELT_0_5_1 = 2; +var SPICE_AUDIO_DATA_MODE_OPUS = 3; + +var SPICE_AUDIO_FMT_INVALID = 0; +var SPICE_AUDIO_FMT_S16 = 1; + +var SPICE_CHANNEL_MAIN = 1; +var SPICE_CHANNEL_DISPLAY = 2; +var SPICE_CHANNEL_INPUTS = 3; +var SPICE_CHANNEL_CURSOR = 4; +var SPICE_CHANNEL_PLAYBACK = 5; +var SPICE_CHANNEL_RECORD = 6; +var SPICE_CHANNEL_TUNNEL = 7; +var SPICE_CHANNEL_SMARTCARD = 8; +var SPICE_CHANNEL_USBREDIR = 9; + +var SPICE_SURFACE_FLAGS_PRIMARY = (1 << 0); + +var SPICE_NOTIFY_SEVERITY_INFO = 0; +var SPICE_NOTIFY_SEVERITY_WARN = 1; +var SPICE_NOTIFY_SEVERITY_ERROR = 2; + +var SPICE_MOUSE_MODE_SERVER = (1 << 0), + SPICE_MOUSE_MODE_CLIENT = (1 << 1), + SPICE_MOUSE_MODE_MASK = 0x3; + +var SPICE_CLIP_TYPE_NONE = 0; +var SPICE_CLIP_TYPE_RECTS = 1; + +var SPICE_IMAGE_TYPE_BITMAP = 0; +var SPICE_IMAGE_TYPE_QUIC = 1; +var SPICE_IMAGE_TYPE_RESERVED = 2; +var SPICE_IMAGE_TYPE_LZ_PLT = 100; +var SPICE_IMAGE_TYPE_LZ_RGB = 101; +var SPICE_IMAGE_TYPE_GLZ_RGB = 102; +var SPICE_IMAGE_TYPE_FROM_CACHE = 103; +var SPICE_IMAGE_TYPE_SURFACE = 104; +var SPICE_IMAGE_TYPE_JPEG = 105; +var SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS = 106; +var SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB = 107; +var SPICE_IMAGE_TYPE_JPEG_ALPHA = 108; + +var SPICE_IMAGE_FLAGS_CACHE_ME = (1 << 0), + SPICE_IMAGE_FLAGS_HIGH_BITS_SET = (1 << 1), + SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME = (1 << 2); + +var SPICE_BITMAP_FLAGS_PAL_CACHE_ME = (1 << 0), + SPICE_BITMAP_FLAGS_PAL_FROM_CACHE = (1 << 1), + SPICE_BITMAP_FLAGS_TOP_DOWN = (1 << 2), + SPICE_BITMAP_FLAGS_MASK = 0x7; + +var SPICE_BITMAP_FMT_INVALID = 0, + SPICE_BITMAP_FMT_1BIT_LE = 1, + SPICE_BITMAP_FMT_1BIT_BE = 2, + SPICE_BITMAP_FMT_4BIT_LE = 3, + SPICE_BITMAP_FMT_4BIT_BE = 4, + SPICE_BITMAP_FMT_8BIT = 5, + SPICE_BITMAP_FMT_16BIT = 6, + SPICE_BITMAP_FMT_24BIT = 7, + SPICE_BITMAP_FMT_32BIT = 8, + SPICE_BITMAP_FMT_RGBA = 9; + + +var SPICE_CURSOR_FLAGS_NONE = (1 << 0), + SPICE_CURSOR_FLAGS_CACHE_ME = (1 << 1), + SPICE_CURSOR_FLAGS_FROM_CACHE = (1 << 2), + SPICE_CURSOR_FLAGS_MASK = 0x7; + +var SPICE_MOUSE_BUTTON_MASK_LEFT = (1 << 0), + SPICE_MOUSE_BUTTON_MASK_MIDDLE = (1 << 1), + SPICE_MOUSE_BUTTON_MASK_RIGHT = (1 << 2), + SPICE_MOUSE_BUTTON_MASK_MASK = 0x7; + +var SPICE_MOUSE_BUTTON_INVALID = 0; +var SPICE_MOUSE_BUTTON_LEFT = 1; +var SPICE_MOUSE_BUTTON_MIDDLE = 2; +var SPICE_MOUSE_BUTTON_RIGHT = 3; +var SPICE_MOUSE_BUTTON_UP = 4; +var SPICE_MOUSE_BUTTON_DOWN = 5; + +var SPICE_BRUSH_TYPE_NONE = 0, + SPICE_BRUSH_TYPE_SOLID = 1, + SPICE_BRUSH_TYPE_PATTERN = 2; + +var SPICE_SURFACE_FMT_INVALID = 0, + SPICE_SURFACE_FMT_1_A = 1, + SPICE_SURFACE_FMT_8_A = 8, + SPICE_SURFACE_FMT_16_555 = 16, + SPICE_SURFACE_FMT_32_xRGB = 32, + SPICE_SURFACE_FMT_16_565 = 80, + SPICE_SURFACE_FMT_32_ARGB = 96; + +var SPICE_ROPD_INVERS_SRC = (1 << 0), + SPICE_ROPD_INVERS_BRUSH = (1 << 1), + SPICE_ROPD_INVERS_DEST = (1 << 2), + SPICE_ROPD_OP_PUT = (1 << 3), + SPICE_ROPD_OP_OR = (1 << 4), + SPICE_ROPD_OP_AND = (1 << 5), + SPICE_ROPD_OP_XOR = (1 << 6), + SPICE_ROPD_OP_BLACKNESS = (1 << 7), + SPICE_ROPD_OP_WHITENESS = (1 << 8), + SPICE_ROPD_OP_INVERS = (1 << 9), + SPICE_ROPD_INVERS_RES = (1 << 10), + SPICE_ROPD_MASK = 0x7ff; + +var LZ_IMAGE_TYPE_INVALID = 0, + LZ_IMAGE_TYPE_PLT1_LE = 1, + LZ_IMAGE_TYPE_PLT1_BE = 2, // PLT stands for palette + LZ_IMAGE_TYPE_PLT4_LE = 3, + LZ_IMAGE_TYPE_PLT4_BE = 4, + LZ_IMAGE_TYPE_PLT8 = 5, + LZ_IMAGE_TYPE_RGB16 = 6, + LZ_IMAGE_TYPE_RGB24 = 7, + LZ_IMAGE_TYPE_RGB32 = 8, + LZ_IMAGE_TYPE_RGBA = 9, + LZ_IMAGE_TYPE_XXXA = 10; + + +var QUIC_IMAGE_TYPE_INVALID = 0, + QUIC_IMAGE_TYPE_GRAY = 1, + QUIC_IMAGE_TYPE_RGB16 = 2, + QUIC_IMAGE_TYPE_RGB24 = 3, + QUIC_IMAGE_TYPE_RGB32 = 4, + QUIC_IMAGE_TYPE_RGBA = 5; + +var SPICE_INPUT_MOTION_ACK_BUNCH = 4; + + +var SPICE_CURSOR_TYPE_ALPHA = 0, + SPICE_CURSOR_TYPE_MONO = 1, + SPICE_CURSOR_TYPE_COLOR4 = 2, + SPICE_CURSOR_TYPE_COLOR8 = 3, + SPICE_CURSOR_TYPE_COLOR16 = 4, + SPICE_CURSOR_TYPE_COLOR24 = 5, + SPICE_CURSOR_TYPE_COLOR32 = 6; + +var SPICE_VIDEO_CODEC_TYPE_MJPEG = 1; + +var VD_AGENT_PROTOCOL = 1; + +var VD_AGENT_MOUSE_STATE = 1, + VD_AGENT_MONITORS_CONFIG = 2, + VD_AGENT_REPLY = 3, + VD_AGENT_CLIPBOARD = 4, + VD_AGENT_DISPLAY_CONFIG = 5, + VD_AGENT_ANNOUNCE_CAPABILITIES = 6, + VD_AGENT_CLIPBOARD_GRAB = 7, + VD_AGENT_CLIPBOARD_REQUEST = 8, + VD_AGENT_CLIPBOARD_RELEASE = 9, + VD_AGENT_FILE_XFER_START =10, + VD_AGENT_FILE_XFER_STATUS =11, + VD_AGENT_FILE_XFER_DATA =12, + VD_AGENT_CLIENT_DISCONNECTED =13, + VD_AGENT_MAX_CLIPBOARD =14; diff --git a/src/wok/plugins/kimchi/ui/spice-html5/inputs.js b/src/wok/plugins/kimchi/ui/spice-html5/inputs.js new file mode 100644 index 0000000..c904eda --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/inputs.js @@ -0,0 +1,280 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- + ** Modifier Keystates + ** These need to be tracked because focus in and out can get the keyboard + ** out of sync. + **------------------------------------------------------------------------*/ +var Shift_state = -1; +var Ctrl_state = -1; +var Alt_state = -1; +var Meta_state = -1; + +/*---------------------------------------------------------------------------- +** SpiceInputsConn +** Drive the Spice Inputs channel (e.g. mouse + keyboard) +**--------------------------------------------------------------------------*/ +function SpiceInputsConn() +{ + SpiceConn.apply(this, arguments); + + this.mousex = undefined; + this.mousey = undefined; + this.button_state = 0; + this.waiting_for_ack = 0; +} + +SpiceInputsConn.prototype = Object.create(SpiceConn.prototype); +SpiceInputsConn.prototype.process_channel_message = function(msg) +{ + if (msg.type == SPICE_MSG_INPUTS_INIT) + { + var inputs_init = new SpiceMsgInputsInit(msg.data); + this.keyboard_modifiers = inputs_init.keyboard_modifiers; + DEBUG > 1 && console.log("MsgInputsInit - modifier " + this.keyboard_modifiers); + // FIXME - We don't do anything with the keyboard modifiers... + return true; + } + if (msg.type == SPICE_MSG_INPUTS_KEY_MODIFIERS) + { + var key = new SpiceMsgInputsKeyModifiers(msg.data); + this.keyboard_modifiers = key.keyboard_modifiers; + DEBUG > 1 && console.log("MsgInputsKeyModifiers - modifier " + this.keyboard_modifiers); + // FIXME - We don't do anything with the keyboard modifiers... + return true; + } + if (msg.type == SPICE_MSG_INPUTS_MOUSE_MOTION_ACK) + { + DEBUG > 1 && console.log("mouse motion ack"); + this.waiting_for_ack -= SPICE_INPUT_MOTION_ACK_BUNCH; + return true; + } + return false; +} + + + +function handle_mousemove(e) +{ + var msg = new SpiceMiniData(); + var move; + if (this.sc.mouse_mode == SPICE_MOUSE_MODE_CLIENT) + { + move = new SpiceMsgcMousePosition(this.sc, e) + msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_POSITION, move); + } + else + { + move = new SpiceMsgcMouseMotion(this.sc, e) + msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_MOTION, move); + } + if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") + { + if (this.sc.inputs.waiting_for_ack < (2 * SPICE_INPUT_MOTION_ACK_BUNCH)) + { + this.sc.inputs.send_msg(msg); + this.sc.inputs.waiting_for_ack++; + } + else + { + DEBUG > 0 && this.sc.log_info("Discarding mouse motion"); + } + } + + if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor) + { + this.sc.cursor.spice_simulated_cursor.style.display = 'block'; + this.sc.cursor.spice_simulated_cursor.style.left = e.pageX - this.sc.cursor.spice_simulated_cursor.spice_hot_x + 'px'; + this.sc.cursor.spice_simulated_cursor.style.top = e.pageY - this.sc.cursor.spice_simulated_cursor.spice_hot_y + 'px'; + e.preventDefault(); + } + +} + +function handle_mousedown(e) +{ + var press = new SpiceMsgcMousePress(this.sc, e) + var msg = new SpiceMiniData(); + msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_PRESS, press); + if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") + this.sc.inputs.send_msg(msg); + + e.preventDefault(); +} + +function handle_contextmenu(e) +{ + e.preventDefault(); + return false; +} + +function handle_mouseup(e) +{ + var release = new SpiceMsgcMouseRelease(this.sc, e) + var msg = new SpiceMiniData(); + msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_RELEASE, release); + if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") + this.sc.inputs.send_msg(msg); + + e.preventDefault(); +} + +function handle_mousewheel(e) +{ + var press = new SpiceMsgcMousePress; + var release = new SpiceMsgcMouseRelease; + if (e.wheelDelta > 0) + press.button = release.button = SPICE_MOUSE_BUTTON_UP; + else + press.button = release.button = SPICE_MOUSE_BUTTON_DOWN; + press.buttons_state = 0; + release.buttons_state = 0; + + var msg = new SpiceMiniData(); + msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_PRESS, press); + if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") + this.sc.inputs.send_msg(msg); + + msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_RELEASE, release); + if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") + this.sc.inputs.send_msg(msg); + + e.preventDefault(); +} + +function handle_keydown(e) +{ + var key = new SpiceMsgcKeyDown(e) + var msg = new SpiceMiniData(); + check_and_update_modifiers(e, key.code, this.sc); + msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key); + if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") + this.sc.inputs.send_msg(msg); + + e.preventDefault(); +} + +function handle_keyup(e) +{ + var key = new SpiceMsgcKeyUp(e) + var msg = new SpiceMiniData(); + check_and_update_modifiers(e, key.code, this.sc); + msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key); + if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") + this.sc.inputs.send_msg(msg); + + e.preventDefault(); +} + +function sendCtrlAltDel() +{ + if (sc && sc.inputs && sc.inputs.state === "ready"){ + var key = new SpiceMsgcKeyDown(); + var msg = new SpiceMiniData(); + + update_modifier(true, KEY_LCtrl, sc); + update_modifier(true, KEY_Alt, sc); + + key.code = KEY_KP_Decimal; + msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key); + sc.inputs.send_msg(msg); + msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key); + sc.inputs.send_msg(msg); + + if(Ctrl_state == false) update_modifier(false, KEY_LCtrl, sc); + if(Alt_state == false) update_modifier(false, KEY_Alt, sc); + } +} + +function update_modifier(state, code, sc) +{ + var msg = new SpiceMiniData(); + if (!state) + { + var key = new SpiceMsgcKeyUp() + key.code =(0x80|code); + msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key); + } + else + { + var key = new SpiceMsgcKeyDown() + key.code = code; + msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key); + } + + sc.inputs.send_msg(msg); +} + +function check_and_update_modifiers(e, code, sc) +{ + if (Shift_state === -1) + { + Shift_state = e.shiftKey; + Ctrl_state = e.ctrlKey; + Alt_state = e.altKey; + Meta_state = e.metaKey; + } + + if (code === KEY_ShiftL) + Shift_state = true; + else if (code === KEY_Alt) + Alt_state = true; + else if (code === KEY_LCtrl) + Ctrl_state = true; + else if (code === 0xE0B5) + Meta_state = true; + else if (code === (0x80|KEY_ShiftL)) + Shift_state = false; + else if (code === (0x80|KEY_Alt)) + Alt_state = false; + else if (code === (0x80|KEY_LCtrl)) + Ctrl_state = false; + else if (code === (0x80|0xE0B5)) + Meta_state = false; + + if (sc && sc.inputs && sc.inputs.state === "ready") + { + if (Shift_state != e.shiftKey) + { + console.log("Shift state out of sync"); + update_modifier(e.shiftKey, KEY_ShiftL, sc); + Shift_state = e.shiftKey; + } + if (Alt_state != e.altKey) + { + console.log("Alt state out of sync"); + update_modifier(e.altKey, KEY_Alt, sc); + Alt_state = e.altKey; + } + if (Ctrl_state != e.ctrlKey) + { + console.log("Ctrl state out of sync"); + update_modifier(e.ctrlKey, KEY_LCtrl, sc); + Ctrl_state = e.ctrlKey; + } + if (Meta_state != e.metaKey) + { + console.log("Meta state out of sync"); + update_modifier(e.metaKey, 0xE0B5, sc); + Meta_state = e.metaKey; + } + } +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/lz.js b/src/wok/plugins/kimchi/ui/spice-html5/lz.js new file mode 100644 index 0000000..4292eac --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/lz.js @@ -0,0 +1,166 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + + +/*---------------------------------------------------------------------------- +** lz.js +** Functions for handling SPICE_IMAGE_TYPE_LZ_RGB +** Adapted from lz.c . +**--------------------------------------------------------------------------*/ +function lz_rgb32_decompress(in_buf, at, out_buf, type, default_alpha) +{ + var encoder = at; + var op = 0; + var ctrl; + var ctr = 0; + + for (ctrl = in_buf[encoder++]; (op * 4) < out_buf.length; ctrl = in_buf[encoder++]) + { + var ref = op; + var len = ctrl >> 5; + var ofs = (ctrl & 31) << 8; + +//if (type == LZ_IMAGE_TYPE_RGBA) +//console.log(ctr++ + ": from " + (encoder + 28) + ", ctrl " + ctrl + ", len " + len + ", ofs " + ofs + ", op " + op); + if (ctrl >= 32) { + + var code; + len--; + + if (len == 7 - 1) { + do { + code = in_buf[encoder++]; + len += code; + } while (code == 255); + } + code = in_buf[encoder++]; + ofs += code; + + + if (code == 255) { + if ((ofs - code) == (31 << 8)) { + ofs = in_buf[encoder++] << 8; + ofs += in_buf[encoder++]; + ofs += 8191; + } + } + len += 1; + if (type == LZ_IMAGE_TYPE_RGBA) + len += 2; + + ofs += 1; + + ref -= ofs; + if (ref == (op - 1)) { + var b = ref; +//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha " + out_buf[(b*4)+3] + " dupped into pixel " + op + " through pixel " + (op + len)); + for (; len; --len) { + if (type == LZ_IMAGE_TYPE_RGBA) + { + out_buf[(op*4) + 3] = out_buf[(b*4)+3]; + } + else + { + for (i = 0; i < 4; i++) + out_buf[(op*4) + i] = out_buf[(b*4)+i]; + } + op++; + } + } else { +//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha copied to pixel " + op + " through " + (op + len) + " from " + ref); + for (; len; --len) { + if (type == LZ_IMAGE_TYPE_RGBA) + { + out_buf[(op*4) + 3] = out_buf[(ref*4)+3]; + } + else + { + for (i = 0; i < 4; i++) + out_buf[(op*4) + i] = out_buf[(ref*4)+i]; + } + op++; ref++; + } + } + } else { + ctrl++; + + if (type == LZ_IMAGE_TYPE_RGBA) + { +//console.log("alpha " + in_buf[encoder] + " set into pixel " + op); + out_buf[(op*4) + 3] = in_buf[encoder++]; + } + else + { + out_buf[(op*4) + 0] = in_buf[encoder + 2]; + out_buf[(op*4) + 1] = in_buf[encoder + 1]; + out_buf[(op*4) + 2] = in_buf[encoder + 0]; + if (default_alpha) + out_buf[(op*4) + 3] = 255; + encoder += 3; + } + op++; + + + for (--ctrl; ctrl; ctrl--) { + if (type == LZ_IMAGE_TYPE_RGBA) + { +//console.log("alpha " + in_buf[encoder] + " set into pixel " + op); + out_buf[(op*4) + 3] = in_buf[encoder++]; + } + else + { + out_buf[(op*4) + 0] = in_buf[encoder + 2]; + out_buf[(op*4) + 1] = in_buf[encoder + 1]; + out_buf[(op*4) + 2] = in_buf[encoder + 0]; + if (default_alpha) + out_buf[(op*4) + 3] = 255; + encoder += 3; + } + op++; + } + } + + } + return encoder - 1; +} + +function convert_spice_lz_to_web(context, lz_image) +{ + var at; + if (lz_image.type === LZ_IMAGE_TYPE_RGB32 || lz_image.type === LZ_IMAGE_TYPE_RGBA) + { + var u8 = new Uint8Array(lz_image.data); + var ret = context.createImageData(lz_image.width, lz_image.height); + + at = lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGB32, lz_image.type != LZ_IMAGE_TYPE_RGBA); + if (lz_image.type == LZ_IMAGE_TYPE_RGBA) + lz_rgb32_decompress(u8, at, ret.data, LZ_IMAGE_TYPE_RGBA, false); + } + else if (lz_image.type === LZ_IMAGE_TYPE_XXXA) + { + var u8 = new Uint8Array(lz_image.data); + var ret = context.createImageData(lz_image.width, lz_image.height); + lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGBA, false); + } + else + return undefined; + + return ret; +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/main.js b/src/wok/plugins/kimchi/ui/spice-html5/main.js new file mode 100644 index 0000000..91f1963 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/main.js @@ -0,0 +1,231 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** SpiceMainConn +** This is the master Javascript class for establishing and +** managing a connection to a Spice Server. +** +** Invocation: You must pass an object with properties as follows: +** uri (required) Uri of a WebSocket listener that is +** connected to a spice server. +** password (required) Password to send to the spice server +** message_id (optional) Identifier of an element in the DOM +** where SpiceConn will write messages. +** It will use classes spice-messages-x, +** where x is one of info, warning, or error. +** screen_id (optional) Identifier of an element in the DOM +** where SpiceConn will create any new +** client screens. This is the main UI. +** dump_id (optional) If given, an element to use for +** dumping every single image + canvas drawn. +** Sometimes useful for debugging. +** onerror (optional) If given, a function to receive async +** errors. Note that you should also catch +** errors for ones that occur inline +** onagent (optional) If given, a function to be called when +** a VD agent is connected; a good opportunity +** to request a resize +** +** Throws error if there are troubles. Requires a modern (by 2012 standards) +** browser, including WebSocket and WebSocket.binaryType == arraybuffer +** +**--------------------------------------------------------------------------*/ +function SpiceMainConn() +{ + if (typeof WebSocket === "undefined") + throw new Error("WebSocket unavailable. You need to use a different browser."); + + SpiceConn.apply(this, arguments); + +} + +SpiceMainConn.prototype = Object.create(SpiceConn.prototype); +SpiceMainConn.prototype.process_channel_message = function(msg) +{ + if (msg.type == SPICE_MSG_MAIN_INIT) + { + this.log_info("Connected to " + this.ws.url); + this.report_success("Connected") + this.main_init = new SpiceMsgMainInit(msg.data); + this.connection_id = this.main_init.session_id; + + if (DEBUG > 0) + { + // FIXME - there is a lot here we don't handle; mouse modes, agent, + // ram_hint, multi_media_time + this.log_info("session id " + this.main_init.session_id + + " ; display_channels_hint " + this.main_init.display_channels_hint + + " ; supported_mouse_modes " + this.main_init.supported_mouse_modes + + " ; current_mouse_mode " + this.main_init.current_mouse_mode + + " ; agent_connected " + this.main_init.agent_connected + + " ; agent_tokens " + this.main_init.agent_tokens + + " ; multi_media_time " + this.main_init.multi_media_time + + " ; ram_hint " + this.main_init.ram_hint); + } + + this.handle_mouse_mode(this.main_init.current_mouse_mode, + this.main_init.supported_mouse_modes); + + if (this.main_init.agent_connected) + this.connect_agent(); + + var attach = new SpiceMiniData; + attach.type = SPICE_MSGC_MAIN_ATTACH_CHANNELS; + attach.size = attach.buffer_size(); + this.send_msg(attach); + return true; + } + + if (msg.type == SPICE_MSG_MAIN_MOUSE_MODE) + { + var mode = new SpiceMsgMainMouseMode(msg.data); + DEBUG > 0 && this.log_info("Mouse supported modes " + mode.supported_modes + "; current " + mode.current_mode); + this.handle_mouse_mode(mode.current_mode, mode.supported_modes); + return true; + } + + if (msg.type == SPICE_MSG_MAIN_CHANNELS_LIST) + { + var i; + var chans; + DEBUG > 0 && console.log("channels"); + chans = new SpiceMsgChannels(msg.data); + for (i = 0; i < chans.channels.length; i++) + { + var conn = { + uri: this.ws.url, + parent: this, + connection_id : this.connection_id, + type : chans.channels[i].type, + chan_id : chans.channels[i].id + }; + if (chans.channels[i].type == SPICE_CHANNEL_DISPLAY) + this.display = new SpiceDisplayConn(conn); + else if (chans.channels[i].type == SPICE_CHANNEL_INPUTS) + { + this.inputs = new SpiceInputsConn(conn); + this.inputs.mouse_mode = this.mouse_mode; + } + else if (chans.channels[i].type == SPICE_CHANNEL_CURSOR) + this.cursor = new SpiceCursorConn(conn); + else if (chans.channels[i].type == SPICE_CHANNEL_PLAYBACK) + this.cursor = new SpicePlaybackConn(conn); + else + { + this.log_err("Channel type " + chans.channels[i].type + " unknown."); + if (! ("extra_channels" in this)) + this.extra_channels = []; + this.extra_channels[i] = new SpiceConn(conn); + } + + } + + return true; + } + + if (msg.type == SPICE_MSG_MAIN_AGENT_CONNECTED || + msg.type == SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS) + { + this.connect_agent(); + return true; + } + + if (msg.type == SPICE_MSG_MAIN_AGENT_DISCONNECTED) + { + this.agent_connected = false; + return true; + } + + return false; +} + +SpiceMainConn.prototype.stop = function(msg) +{ + this.state = "closing"; + + if (this.inputs) + { + this.inputs.cleanup(); + this.inputs = undefined; + } + + if (this.cursor) + { + this.cursor.cleanup(); + this.cursor = undefined; + } + + if (this.display) + { + this.display.cleanup(); + this.display.destroy_surfaces(); + this.display = undefined; + } + + this.cleanup(); + + if ("extra_channels" in this) + for (var e in this.extra_channels) + this.extra_channels[e].cleanup(); + this.extra_channels = undefined; +} + +SpiceMainConn.prototype.resize_window = function(flags, width, height, depth, x, y) +{ + if (this.agent_connected > 0) + { + var monitors_config = new VDAgentMonitorsConfig(flags, width, height, depth, x, y); + var agent_data = new SpiceMsgcMainAgentData(VD_AGENT_MONITORS_CONFIG, monitors_config); + var mr = new SpiceMiniData(); + mr.build_msg(SPICE_MSGC_MAIN_AGENT_DATA, agent_data); + this.send_msg(mr); + } +} + +SpiceMainConn.prototype.connect_agent = function() +{ + this.agent_connected = true; + + var agent_start = new SpiceMsgcMainAgentStart(0); + var mr = new SpiceMiniData(); + mr.build_msg(SPICE_MSGC_MAIN_AGENT_START, agent_start); + this.send_msg(mr); + + if (this.onagent !== undefined) + this.onagent(this); + +} + +SpiceMainConn.prototype.handle_mouse_mode = function(current, supported) +{ + this.mouse_mode = current; + if (current != SPICE_MOUSE_MODE_CLIENT && (supported & SPICE_MOUSE_MODE_CLIENT)) + { + var mode_request = new SpiceMsgcMainMouseModeRequest(SPICE_MOUSE_MODE_CLIENT); + var mr = new SpiceMiniData(); + mr.build_msg(SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST, mode_request); + this.send_msg(mr); + } + + if (this.inputs) + this.inputs.mouse_mode = current; +} + diff --git a/src/wok/plugins/kimchi/ui/spice-html5/pages/Makefile.am b/src/wok/plugins/kimchi/ui/spice-html5/pages/Makefile.am new file mode 100644 index 0000000..431ec6c --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/pages/Makefile.am @@ -0,0 +1,20 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2014 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +spicepagesdir = $(datadir)/wok/plugins/kimchi/ui/spice-html5/pages + +dist_spicepages_DATA = $(wildcard *.html) $(NULL) diff --git a/src/wok/plugins/kimchi/ui/spice-html5/pages/spice_auto.html b/src/wok/plugins/kimchi/ui/spice-html5/pages/spice_auto.html new file mode 100644 index 0000000..c87f5c2 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/pages/spice_auto.html @@ -0,0 +1,200 @@ +<!-- + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. + + -------------------------------------------------- + Spice Javascript client template. + Refer to main.js for more detailed information + -------------------------------------------------- + +--> + +<!doctype html> +<html> + <head> + + <!-- + The below sources were updated according to Kimchi configuration + to get the Javascript and CSS files from the installed spice-html5 + package. + Kimchi is not using the default spice_auto.html because Kimchi uses + wss:// for all connections and it is only supported by recent + versions of spice-html5. + In addition to it, Kimchi points user to the right token on URL + (check line 146 of this file). + --> + <title>Spice Javascript client</title> + <script src="spice-html5/spicearraybuffer.js"></script> + <script src="spice-html5/enums.js"></script> + <script src="spice-html5/atKeynames.js"></script> + <script src="spice-html5/utils.js"></script> + <script src="spice-html5/png.js"></script> + <script src="spice-html5/lz.js"></script> + <script src="spice-html5/quic.js"></script> + <script src="spice-html5/bitmap.js"></script> + <script src="spice-html5/spicedataview.js"></script> + <script src="spice-html5/spicetype.js"></script> + <script src="spice-html5/spicemsg.js"></script> + <script src="spice-html5/wire.js"></script> + <script src="spice-html5/spiceconn.js"></script> + <script src="spice-html5/display.js"></script> + <script src="spice-html5/main.js"></script> + <script src="spice-html5/inputs.js"></script> + <script src="spice-html5/webm.js"></script> + <script src="spice-html5/playback.js"></script> + <script src="spice-html5/simulatecursor.js"></script> + <script src="spice-html5/cursor.js"></script> + <script src="spice-html5/thirdparty/jsbn.js"></script> + <script src="spice-html5/thirdparty/rsa.js"></script> + <script src="spice-html5/thirdparty/prng4.js"></script> + <script src="spice-html5/thirdparty/rng.js"></script> + <script src="spice-html5/thirdparty/sha1.js"></script> + <script src="spice-html5/ticket.js"></script> + <script src="spice-html5/resize.js"></script> + <link rel="stylesheet" type="text/css" href="spice-html5/spice.css" /> + + <script> + var host = null, port = null; + var sc; + + function spice_set_cookie(name, value, days) { + var date, expires; + date = new Date(); + date.setTime(date.getTime() + (days*24*60*60*1000)); + expires = "; expires=" + date.toGMTString(); + document.cookie = name + "=" + value + expires + "; path=/"; + }; + + function spice_query_var(name, defvalue) { + var match = RegExp('[?&]' + name + '=([^&]*)') + .exec(window.location.search); + return match ? + decodeURIComponent(match[1].replace(/\+/g, ' ')) + : defvalue; + } + + function spice_error(e) + { + disconnect(); + } + + function connect() + { + var host, port, password, scheme = "ws://", uri; + + // By default, use the host and port of server that served this file + host = spice_query_var('host', window.location.hostname); + + // Note that using the web server port only makes sense + // if your web server has a reverse proxy to relay the WebSocket + // traffic to the correct destination port. + var default_port = window.location.port; + if (!default_port) { + if (window.location.protocol == 'http:') { + default_port = 80; + } + else if (window.location.protocol == 'https:') { + default_port = 443; + } + } + port = spice_query_var('port', default_port); + if (window.location.protocol == 'https:') { + scheme = "wss://"; + } + + // If a token variable is passed in, set the parameter in a cookie. + // This is used by nova-spiceproxy. + token = spice_query_var('token', null); + if (token) { + spice_set_cookie('token', token, 1) + } + + password = spice_query_var('password', ''); + path = spice_query_var('path', 'websockify'); + + if ((!host) || (!port)) { + console.log("must specify host and port in URL"); + return; + } + + if (sc) { + sc.stop(); + } + + /* + * The following line was modified from the original one: + * + * 'uri = scheme + host + ":" + port;' + * + * to point wok.user to a specific console represented by + * token value. + */ + uri = scheme + host + ":" + port + "/?token=" + token; + + try + { + sc = new SpiceMainConn({uri: uri, screen_id: "spice-screen", dump_id: "debug-div", + message_id: "message-div", password: password, onerror: spice_error, onagent: agent_connected }); + } + catch (e) + { + alert(e.toString()); + disconnect(); + } + + } + + function disconnect() + { + console.log(">> disconnect"); + if (sc) { + sc.stop(); + } + console.log("<< disconnect"); + } + + function agent_connected(sc) + { + window.addEventListener('resize', handle_resize); + window.spice_connection = this; + + resize_helper(this); + } + + connect(); + </script> + + </head> + + <body> + + <div id="login"> + <span class="logo">SPICE</span> + </div> + + <div id="spice-area"> + <div id="spice-screen" class="spice-screen"></div> + </div> + + <div id="message-div" class="spice-message"></div> + + <div id="debug-div"> + <!-- If DUMPXXX is turned on, dumped images will go here --> + </div> + + </body> +</html> diff --git a/src/wok/plugins/kimchi/ui/spice-html5/playback.js b/src/wok/plugins/kimchi/ui/spice-html5/playback.js new file mode 100644 index 0000000..7209fbe --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/playback.js @@ -0,0 +1,278 @@ +"use strict"; +/* + Copyright (C) 2014 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** SpicePlaybackConn +** Drive the Spice Playback channel (sound out) +**--------------------------------------------------------------------------*/ +function SpicePlaybackConn() +{ + SpiceConn.apply(this, arguments); + + this.queue = new Array(); + this.append_okay = false; + this.start_time = 0; + this.skip_until = 0; + this.gap_time = 0; +} + +SpicePlaybackConn.prototype = Object.create(SpiceConn.prototype); +SpicePlaybackConn.prototype.process_channel_message = function(msg) +{ + if (!!!window.MediaSource) + { + this.log_err('MediaSource API is not available'); + return false; + } + + if (msg.type == SPICE_MSG_PLAYBACK_START) + { + var start = new SpiceMsgPlaybackStart(msg.data); + + DEBUG > 0 && console.log("PlaybackStart; frequency " + start.frequency); + + if (start.frequency != OPUS_FREQUENCY) + { + this.log_err('This player cannot handle frequency ' + start.frequency); + return false; + } + + if (start.channels != OPUS_CHANNELS) + { + this.log_err('This player cannot handle ' + start.channels + ' channels'); + return false; + } + + if (start.format != SPICE_AUDIO_FMT_S16) + { + this.log_err('This player cannot format ' + start.format); + return false; + } + + if (! this.source_buffer) + { + this.media_source = new MediaSource(); + this.media_source.spiceconn = this; + + this.audio = document.createElement("audio"); + this.audio.setAttribute('autoplay', true); + this.audio.src = window.URL.createObjectURL(this.media_source); + document.getElementById(this.parent.screen_id).appendChild(this.audio); + + this.media_source.addEventListener('sourceopen', handle_source_open, false); + this.media_source.addEventListener('sourceended', handle_source_ended, false); + this.media_source.addEventListener('sourceclosed', handle_source_closed, false); + + this.bytes_written = 0; + + return true; + } + } + + if (msg.type == SPICE_MSG_PLAYBACK_DATA) + { + var data = new SpiceMsgPlaybackData(msg.data); + + // If this packet has the same time as the last, just bump up by one. + if (this.last_data_time && data.time <= this.last_data_time) + { + // FIXME - this is arguably wrong. But delaying the transmission was worse, + // in initial testing. Could use more research. + DEBUG > 1 && console.log("Hacking time of " + data.time + " to " + this.last_data_time + 1); + data.time = this.last_data_time + 1; + } + + /* Gap detection: If there has been a delay since our last packet, then audio must + have paused. Handling that gets tricky. In Chrome, you can seek forward, + but you cannot in Firefox. And seeking forward in Chrome is nice, as it keeps + Chrome from being overly cautious in it's buffer strategy. + + So we do two things. First, we seek forward. Second, we compute how much of a gap + there would have been, and essentially eliminate it. + */ + if (this.last_data_time && data.time >= (this.last_data_time + GAP_DETECTION_THRESHOLD)) + { + this.skip_until = data.time; + this.gap_time = (data.time - this.start_time) - + (this.source_buffer.buffered.end(this.source_buffer.buffered.end.length - 1) * 1000.0).toFixed(0); + } + + this.last_data_time = data.time; + + + DEBUG > 1 && console.log("PlaybackData; time " + data.time + "; length " + data.data.byteLength); + + if (! this.source_buffer) + return true; + + if (this.start_time == 0) + this.start_playback(data); + + else if (data.time - this.cluster_time >= MAX_CLUSTER_TIME || this.skip_until > 0) + this.new_cluster(data); + + else + this.simple_block(data, false); + + if (this.skip_until > 0) + { + this.audio.currentTime = (this.skip_until - this.start_time - this.gap_time) / 1000.0; + this.skip_until = 0; + } + + if (this.audio.paused) + this.audio.play(); + + return true; + } + + if (msg.type == SPICE_MSG_PLAYBACK_MODE) + { + var mode = new SpiceMsgPlaybackMode(msg.data); + if (mode.mode != SPICE_AUDIO_DATA_MODE_OPUS) + { + this.log_err('This player cannot handle mode ' + mode.mode); + delete this.source_buffer; + } + return true; + } + + if (msg.type == SPICE_MSG_PLAYBACK_STOP) + { + return true; + } + + return false; +} + +SpicePlaybackConn.prototype.start_playback = function(data) +{ + this.start_time = data.time; + + var h = new webm_Header(); + + var mb = new ArrayBuffer(h.buffer_size()) + + this.bytes_written = h.to_buffer(mb); + + this.source_buffer.addEventListener('error', handle_sourcebuffer_error, false); + this.source_buffer.addEventListener('updateend', handle_append_buffer_done, false); + playback_append_buffer(this, mb); + + this.new_cluster(data); +} + +SpicePlaybackConn.prototype.new_cluster = function(data) +{ + this.cluster_time = data.time; + + var c = new webm_Cluster(data.time - this.start_time - this.gap_time); + + var mb = new ArrayBuffer(c.buffer_size()); + this.bytes_written += c.to_buffer(mb); + + if (this.append_okay) + playback_append_buffer(this, mb); + else + this.queue.push(mb); + + this.simple_block(data, true); +} + +SpicePlaybackConn.prototype.simple_block = function(data, keyframe) +{ + var sb = new webm_SimpleBlock(data.time - this.cluster_time, data.data, keyframe); + var mb = new ArrayBuffer(sb.buffer_size()); + + this.bytes_written += sb.to_buffer(mb); + + if (this.append_okay) + playback_append_buffer(this, mb); + else + this.queue.push(mb); +} + +function handle_source_open(e) +{ + var p = this.spiceconn; + + if (p.source_buffer) + return; + + p.source_buffer = this.addSourceBuffer(SPICE_PLAYBACK_CODEC); + if (! p.source_buffer) + { + p.log_err('Codec ' + SPICE_PLAYBACK_CODEC + ' not available.'); + return; + } + p.source_buffer.spiceconn = p; + p.source_buffer.mode = "segments"; + + // FIXME - Experimentation with segments and sequences was unsatisfying. + // Switching to sequence did not solve our gap problem, + // but the browsers didn't fully support the time seek capability + // we would expect to gain from 'segments'. + // Segments worked at the time of this patch, so segments it is for now. + +} + +function handle_source_ended(e) +{ + var p = this.spiceconn; + p.log_err('Audio source unexpectedly ended.'); +} + +function handle_source_closed(e) +{ + var p = this.spiceconn; + p.log_err('Audio source unexpectedly closed.'); +} + +function handle_append_buffer_done(b) +{ + var p = this.spiceconn; + if (p.queue.length > 0) + { + var mb = p.queue.shift(); + playback_append_buffer(p, mb); + } + else + p.append_okay = true; + +} + +function handle_sourcebuffer_error(e) +{ + var p = this.spiceconn; + p.log_err('source_buffer error ' + e.message); +} + +function playback_append_buffer(p, b) +{ + try + { + p.source_buffer.appendBuffer(b); + p.append_okay = false; + } + catch (e) + { + p.log_err("Error invoking appendBuffer: " + e.message); + } +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/png.js b/src/wok/plugins/kimchi/ui/spice-html5/png.js new file mode 100644 index 0000000..6a26151 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/png.js @@ -0,0 +1,256 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** crc logic from rfc2083 ported to Javascript +**--------------------------------------------------------------------------*/ + +var rfc2083_crc_table = Array(256); +var rfc2083_crc_table_computed = 0; +/* Make the table for a fast CRC. */ +function rfc2083_make_crc_table() +{ + var c; + var n, k; + for (n = 0; n < 256; n++) + { + c = n; + for (k = 0; k < 8; k++) + { + if (c & 1) + c = ((0xedb88320 ^ (c >>> 1)) >>> 0) & 0xffffffff; + else + c = c >>> 1; + } + rfc2083_crc_table[n] = c; + } + + rfc2083_crc_table_computed = 1; +} + +/* Update a running CRC with the bytes buf[0..len-1]--the CRC + should be initialized to all 1's, and the transmitted value + is the 1's complement of the final running CRC (see the + crc() routine below)). */ + +function rfc2083_update_crc(crc, u8buf, at, len) +{ + var c = crc; + var n; + + if (!rfc2083_crc_table_computed) + rfc2083_make_crc_table(); + + for (n = 0; n < len; n++) + { + c = rfc2083_crc_table[(c ^ u8buf[at + n]) & 0xff] ^ (c >>> 8); + } + + return c; +} + +function rfc2083_crc(u8buf, at, len) +{ + return rfc2083_update_crc(0xffffffff, u8buf, at, len) ^ 0xffffffff; +} + +function crc32(mb, at, len) +{ + var u8 = new Uint8Array(mb); + return rfc2083_crc(u8, at, len); +} + +function PngIHDR(width, height) +{ + this.width = width; + this.height = height; + this.depth = 8; + this.type = 6; + this.compression = 0; + this.filter = 0; + this.interlace = 0; +} + +PngIHDR.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var orig = at; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.buffer_size() - 12); at += 4; + dv.setUint8(at, 'I'.charCodeAt(0)); at++; + dv.setUint8(at, 'H'.charCodeAt(0)); at++; + dv.setUint8(at, 'D'.charCodeAt(0)); at++; + dv.setUint8(at, 'R'.charCodeAt(0)); at++; + dv.setUint32(at, this.width); at += 4; + dv.setUint32(at, this.height); at += 4; + dv.setUint8(at, this.depth); at++; + dv.setUint8(at, this.type); at++; + dv.setUint8(at, this.compression); at++; + dv.setUint8(at, this.filter); at++; + dv.setUint8(at, this.interlace); at++; + dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4; + return at; + }, + buffer_size: function() + { + return 12 + 13; + } +} + + +function adler() +{ + this.s1 = 1; + this.s2 = 0; +} + +adler.prototype.update = function(b) +{ + this.s1 += b; + this.s1 %= 65521; + this.s2 += this.s1; + this.s2 %= 65521; +} + +function PngIDAT(width, height, bytes) +{ + if (bytes.byteLength > 65535) + { + throw new Error("Cannot handle more than 64K"); + } + this.data = bytes; + this.width = width; + this.height = height; +} + +PngIDAT.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var orig = at; + var x, y, i, j; + var dv = new SpiceDataView(a); + var zsum = new adler(); + dv.setUint32(at, this.buffer_size() - 12); at += 4; + dv.setUint8(at, 'I'.charCodeAt(0)); at++; + dv.setUint8(at, 'D'.charCodeAt(0)); at++; + dv.setUint8(at, 'A'.charCodeAt(0)); at++; + dv.setUint8(at, 'T'.charCodeAt(0)); at++; + + /* zlib header. */ + dv.setUint8(at, 0x78); at++; + dv.setUint8(at, 0x01); at++; + + /* Deflate header. Specifies uncompressed, final bit */ + dv.setUint8(at, 0x80); at++; + dv.setUint16(at, this.data.byteLength + this.height); at += 2; + dv.setUint16(at, ~(this.data.byteLength + this.height)); at += 2; + var u8 = new Uint8Array(this.data); + for (i = 0, y = 0; y < this.height; y++) + { + /* Filter type 0 - uncompressed */ + dv.setUint8(at, 0); at++; + zsum.update(0); + for (x = 0; x < this.width && i < this.data.byteLength; x++) + { + zsum.update(u8[i]); + dv.setUint8(at, u8[i++]); at++; + zsum.update(u8[i]); + dv.setUint8(at, u8[i++]); at++; + zsum.update(u8[i]); + dv.setUint8(at, u8[i++]); at++; + zsum.update(u8[i]); + dv.setUint8(at, u8[i++]); at++; + } + } + + /* zlib checksum. */ + dv.setUint16(at, zsum.s2); at+=2; + dv.setUint16(at, zsum.s1); at+=2; + + /* FIXME - something is not quite right with the zlib code; + you get an error from libpng if you open the image in + gimp. But it works, so it's good enough for now... */ + + dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4; + return at; + }, + buffer_size: function() + { + return 12 + this.data.byteLength + this.height + 4 + 2 + 1 + 2 + 2; + } +} + + +function PngIEND() +{ +} + +PngIEND.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var orig = at; + var i; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.buffer_size() - 12); at += 4; + dv.setUint8(at, 'I'.charCodeAt(0)); at++; + dv.setUint8(at, 'E'.charCodeAt(0)); at++; + dv.setUint8(at, 'N'.charCodeAt(0)); at++; + dv.setUint8(at, 'D'.charCodeAt(0)); at++; + dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4; + return at; + }, + buffer_size: function() + { + return 12; + } +} + + +function create_rgba_png(width, height, bytes) +{ + var i; + var ihdr = new PngIHDR(width, height); + var idat = new PngIDAT(width, height, bytes); + var iend = new PngIEND; + + var mb = new ArrayBuffer(ihdr.buffer_size() + idat.buffer_size() + iend.buffer_size()); + var at = ihdr.to_buffer(mb); + at = idat.to_buffer(mb, at); + at = iend.to_buffer(mb, at); + + var u8 = new Uint8Array(mb); + var str = ""; + for (i = 0; i < at; i++) + { + str += "%"; + if (u8[i] < 16) + str += "0"; + str += u8[i].toString(16); + } + + + return "%89PNG%0D%0A%1A%0A" + str; +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/quic.js b/src/wok/plugins/kimchi/ui/spice-html5/quic.js new file mode 100644 index 0000000..9bb9f47 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/quic.js @@ -0,0 +1,1335 @@ +/*"use strict";*/ +/* use strict is commented out because it results in a 5x slowdone in chrome */ +/* + * Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + * Copyright (C) 2012 by Aric Stewart <aric@codeweavers.com> + * + * This file is part of spice-html5. + * + * spice-html5 is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * spice-html5 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with spice-html5. If not, see <http://www.gnu.org/licenses/>. + */ + +var encoder; + +var QUIC_IMAGE_TYPE_INVALID = 0; +var QUIC_IMAGE_TYPE_GRAY = 1; +var QUIC_IMAGE_TYPE_RGB16 = 2; +var QUIC_IMAGE_TYPE_RGB24 = 3; +var QUIC_IMAGE_TYPE_RGB32 = 4; +var QUIC_IMAGE_TYPE_RGBA = 5; +var DEFevol = 3; +var DEFwmimax = 6; +var DEFwminext = 2048; +var need_init = true; +var DEFmaxclen = 26; +var evol = DEFevol; +var wmimax = DEFwmimax; +var wminext = DEFwminext; +var family_5bpc = { nGRcodewords:[0,0,0,0,0,0,0,0], + notGRcwlen:[0,0,0,0,0,0,0,0], + notGRprefixmask:[0,0,0,0,0,0,0,0], + notGRsuffixlen:[0,0,0,0,0,0,0,0], + xlatU2L:[0,0,0,0,0,0,0,0], + xlatL2U:[0,0,0,0,0,0,0,0] + }; +var family_8bpc = { nGRcodewords:[0,0,0,0,0,0,0,0], + notGRcwlen:[0,0,0,0,0,0,0,0], + notGRprefixmask:[0,0,0,0,0,0,0,0], + notGRsuffixlen:[0,0,0,0,0,0,0,0], + xlatU2L:[0,0,0,0,0,0,0,0], + xlatL2U:[0,0,0,0,0,0,0,0] + }; +var bppmask = [ 0x00000000, + 0x00000001, 0x00000003, 0x00000007, 0x0000000f, + 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, + 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, + 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, + 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, + 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, + 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, + 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff]; + +var zeroLUT = []; + +var besttrigtab = [ + [ 550, 900, 800, 700, 500, 350, 300, 200, 180, 180, 160], + [ 110, 550, 900, 800, 550, 400, 350, 250, 140, 160, 140], + [ 100, 120, 550, 900, 700, 500, 400, 300, 220, 250, 160]]; + +var J = [ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + +var lzeroes = [ + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0]; + +var tabrand_chaos = [ + 0x02c57542, 0x35427717, 0x2f5a2153, 0x9244f155, 0x7bd26d07, 0x354c6052, + 0x57329b28, 0x2993868e, 0x6cd8808c, 0x147b46e0, 0x99db66af, 0xe32b4cac, + 0x1b671264, 0x9d433486, 0x62a4c192, 0x06089a4b, 0x9e3dce44, 0xdaabee13, + 0x222425ea, 0xa46f331d, 0xcd589250, 0x8bb81d7f, 0xc8b736b9, 0x35948d33, + 0xd7ac7fd0, 0x5fbe2803, 0x2cfbc105, 0x013dbc4e, 0x7a37820f, 0x39f88e9e, + 0xedd58794, 0xc5076689, 0xfcada5a4, 0x64c2f46d, 0xb3ba3243, 0x8974b4f9, + 0x5a05aebd, 0x20afcd00, 0x39e2b008, 0x88a18a45, 0x600bde29, 0xf3971ace, + 0xf37b0a6b, 0x7041495b, 0x70b707ab, 0x06beffbb, 0x4206051f, 0xe13c4ee3, + 0xc1a78327, 0x91aa067c, 0x8295f72a, 0x732917a6, 0x1d871b4d, 0x4048f136, + 0xf1840e7e, 0x6a6048c1, 0x696cb71a, 0x7ff501c3, 0x0fc6310b, 0x57e0f83d, + 0x8cc26e74, 0x11a525a2, 0x946934c7, 0x7cd888f0, 0x8f9d8604, 0x4f86e73b, + 0x04520316, 0xdeeea20c, 0xf1def496, 0x67687288, 0xf540c5b2, 0x22401484, + 0x3478658a, 0xc2385746, 0x01979c2c, 0x5dad73c8, 0x0321f58b, 0xf0fedbee, + 0x92826ddf, 0x284bec73, 0x5b1a1975, 0x03df1e11, 0x20963e01, 0xa17cf12b, + 0x740d776e, 0xa7a6bf3c, 0x01b5cce4, 0x1118aa76, 0xfc6fac0a, 0xce927e9b, + 0x00bf2567, 0x806f216c, 0xbca69056, 0x795bd3e9, 0xc9dc4557, 0x8929b6c2, + 0x789d52ec, 0x3f3fbf40, 0xb9197368, 0xa38c15b5, 0xc3b44fa8, 0xca8333b0, + 0xb7e8d590, 0xbe807feb, 0xbf5f8360, 0xd99e2f5c, 0x372928e1, 0x7c757c4c, + 0x0db5b154, 0xc01ede02, 0x1fc86e78, 0x1f3985be, 0xb4805c77, 0x00c880fa, + 0x974c1b12, 0x35ab0214, 0xb2dc840d, 0x5b00ae37, 0xd313b026, 0xb260969d, + 0x7f4c8879, 0x1734c4d3, 0x49068631, 0xb9f6a021, 0x6b863e6f, 0xcee5debf, + 0x29f8c9fb, 0x53dd6880, 0x72b61223, 0x1f67a9fd, 0x0a0f6993, 0x13e59119, + 0x11cca12e, 0xfe6b6766, 0x16b6effc, 0x97918fc4, 0xc2b8a563, 0x94f2f741, + 0x0bfa8c9a, 0xd1537ae8, 0xc1da349c, 0x873c60ca, 0x95005b85, 0x9b5c080e, + 0xbc8abbd9, 0xe1eab1d2, 0x6dac9070, 0x4ea9ebf1, 0xe0cf30d4, 0x1ef5bd7b, + 0xd161043e, 0x5d2fa2e2, 0xff5d3cae, 0x86ed9f87, 0x2aa1daa1, 0xbd731a34, + 0x9e8f4b22, 0xb1c2c67a, 0xc21758c9, 0xa182215d, 0xccb01948, 0x8d168df7, + 0x04238cfe, 0x368c3dbc, 0x0aeadca5, 0xbad21c24, 0x0a71fee5, 0x9fc5d872, + 0x54c152c6, 0xfc329483, 0x6783384a, 0xeddb3e1c, 0x65f90e30, 0x884ad098, + 0xce81675a, 0x4b372f7d, 0x68bf9a39, 0x43445f1e, 0x40f8d8cb, 0x90d5acb6, + 0x4cd07282, 0x349eeb06, 0x0c9d5332, 0x520b24ef, 0x80020447, 0x67976491, + 0x2f931ca3, 0xfe9b0535, 0xfcd30220, 0x61a9e6cc, 0xa487d8d7, 0x3f7c5dd1, + 0x7d0127c5, 0x48f51d15, 0x60dea871, 0xc9a91cb7, 0x58b53bb3, 0x9d5e0b2d, + 0x624a78b4, 0x30dbee1b, 0x9bdf22e7, 0x1df5c299, 0x2d5643a7, 0xf4dd35ff, + 0x03ca8fd6, 0x53b47ed8, 0x6f2c19aa, 0xfeb0c1f4, 0x49e54438, 0x2f2577e6, + 0xbf876969, 0x72440ea9, 0xfa0bafb8, 0x74f5b3a0, 0x7dd357cd, 0x89ce1358, + 0x6ef2cdda, 0x1e7767f3, 0xa6be9fdb, 0x4f5f88f8, 0xba994a3a, 0x08ca6b65, + 0xe0893818, 0x9e00a16a, 0xf42bfc8f, 0x9972eedc, 0x749c8b51, 0x32c05f5e, + 0xd706805f, 0x6bfbb7cf, 0xd9210a10, 0x31a1db97, 0x923a9559, 0x37a7a1f6, + 0x059f8861, 0xca493e62, 0x65157e81, 0x8f6467dd, 0xab85ff9f, 0x9331aff2, + 0x8616b9f5, 0xedbd5695, 0xee7e29b1, 0x313ac44f, 0xb903112f, 0x432ef649, + 0xdc0a36c0, 0x61cf2bba, 0x81474925, 0xa8b6c7ad, 0xee5931de, 0xb2f8158d, + 0x59fb7409, 0x2e3dfaed, 0x9af25a3f, 0xe1fed4d5 ]; + +var rgb32_pixel_pad = 3; +var rgb32_pixel_r = 2; +var rgb32_pixel_g = 1; +var rgb32_pixel_b = 0; +var rgb32_pixel_size = 4; + +/* Helper Functions */ + +function ceil_log_2(val) +{ + if (val === 1) + return 0; + + var result = 1; + val -= 1; + while (val = val >>> 1) + result++; + + return result; +} + +function family_init(family, bpc, limit) +{ + var l; + for (l = 0; l < bpc; l++) + { + var altprefixlen, altcodewords; + altprefixlen = limit - bpc; + if (altprefixlen > bppmask[bpc - l]) + altprefixlen = bppmask[bpc - l]; + + altcodewords = bppmask[bpc] + 1 - (altprefixlen << l); + family.nGRcodewords[l] = (altprefixlen << l); + family.notGRcwlen[l] = altprefixlen + ceil_log_2(altcodewords); + family.notGRprefixmask[l] = bppmask[32 - altprefixlen]>>>0; + family.notGRsuffixlen[l] = ceil_log_2(altcodewords); + } + + /* decorelate_init */ + var pixelbitmask = bppmask[bpc]; + var pixelbitmaskshr = pixelbitmask >>> 1; + var s; + for (s = 0; s <= pixelbitmask; s++) { + if (s <= pixelbitmaskshr) { + family.xlatU2L[s] = s << 1; + } else { + family.xlatU2L[s] = ((pixelbitmask - s) << 1) + 1; + } + } + + /* corelate_init */ + for (s = 0; s <= pixelbitmask; s++) { + if (s & 0x01) { + family.xlatL2U[s] = pixelbitmask - (s >>> 1); + } else { + family.xlatL2U[s] = (s >>> 1); + } + } +} + +function quic_image_bpc(type) +{ + switch (type) { + case QUIC_IMAGE_TYPE_GRAY: + return 8; + case QUIC_IMAGE_TYPE_RGB16: + return 5; + case QUIC_IMAGE_TYPE_RGB24: + return 8; + case QUIC_IMAGE_TYPE_RGB32: + return 8; + case QUIC_IMAGE_TYPE_RGBA: + return 8; + case QUIC_IMAGE_TYPE_INVALID: + default: + console.log("quic: bad image type\n"); + return 0; + } +} + +function cnt_l_zeroes(bits) +{ + if (bits & 0xff800000) { + return lzeroes[bits >>> 24]; + } else if (bits & 0xffff8000) { + return 8 + lzeroes[(bits >>> 16) & 0x000000ff]; + } else if (bits & 0xffffff80) { + return 16 + lzeroes[(bits >>> 8) & 0x000000ff]; + } else { + return 24 + lzeroes[bits & 0x000000ff]; + } +} + +function golomb_decoding_8bpc(l, bits) +{ + var rc; + var cwlen; + + if (bits < 0 || bits > family_8bpc.notGRprefixmask[l]) + { + var zeroprefix = cnt_l_zeroes(bits); + cwlen = zeroprefix + 1 + l; + rc = (zeroprefix << l) | (bits >> (32-cwlen)) & bppmask[l]; + } + else + { + cwlen = family_8bpc.notGRcwlen[l]; + rc = family_8bpc.nGRcodewords[l] + ((bits >> (32-cwlen)) & bppmask[family_8bpc.notGRsuffixlen[l]]); + } + return {'codewordlen':cwlen, 'rc':rc}; +} + +function golomb_code_len_8bpc(n, l) +{ + if (n < family_8bpc.nGRcodewords[l]) { + return (n >>> l) + 1 + l; + } else { + return family_8bpc.notGRcwlen[l]; + } +} + +function QuicModel(bpc) +{ + var bstart; + var bend = 0; + + this.levels = 0x1 << bpc; + this.n_buckets_ptrs = 0; + + switch (evol) { + case 1: + this.repfirst = 3; + this.firstsize = 1; + this.repnext = 2; + this.mulsize = 2; + break; + case 3: + this.repfirst = 1; + this.firstsize = 1; + this.repnext = 1; + this.mulsize = 2; + break; + case 5: + this.repfirst = 1; + this.firstsize = 1; + this.repnext = 1; + this.mulsize = 4; + break; + case 0: + case 2: + case 4: + console.log("quic: findmodelparams(): evol value obsolete!!!\n"); + default: + console.log("quic: findmodelparams(): evol out of range!!!\n"); + } + + this.n_buckets = 0; + var repcntr = this.repfirst + 1; + var bsize = this.firstsize; + + do { + if (this.n_buckets) { + bstart = bend + 1; + } else { + bstart = 0; + } + + if (!--repcntr) { + repcntr = this.repnext; + bsize *= this.mulsize; + } + + bend = bstart + bsize - 1; + if (bend + bsize >= this.levels) { + bend = this.levels - 1; + } + + if (!this.n_buckets_ptrs) { + this.n_buckets_ptrs = this.levels; + } + + (this.n_buckets)++; + } while (bend < this.levels - 1); +} + +QuicModel.prototype = { + n_buckets : 0, + n_buckets_ptrs : 0, + repfirst : 0, + firstsize : 0, + repnext : 0, + mulsize : 0, + levels :0 +} + +function QuicBucket() +{ + this.counters = [0,0,0,0,0,0,0,0]; +} + +QuicBucket.prototype = { + bestcode: 0, + + reste : function (bpp) + { + this.bestcode = bpp; + this.counters = [0,0,0,0,0,0,0,0]; + }, + + update_model_8bpc : function (state, curval, bpp) + { + var i; + + var bestcode = bpp - 1; + var bestcodelen = (this.counters[bestcode] += golomb_code_len_8bpc(curval, bestcode)); + + for (i = bpp - 2; i >= 0; i--) { + var ithcodelen = (this.counters[i] += golomb_code_len_8bpc(curval, i)); + + if (ithcodelen < bestcodelen) { + bestcode = i; + bestcodelen = ithcodelen; + } + } + + this.bestcode = bestcode; + + if (bestcodelen > state.wm_trigger) { + for (i = 0; i < bpp; i++) { + this.counters[i] = this.counters[i] >>> 1; + } + } + } +} + +function QuicFamilyStat() +{ + this.buckets_ptrs = []; + this.buckets_buf = []; +} + +QuicFamilyStat.prototype = { + + fill_model_structures : function(model) + { + var bstart; + var bend = 0; + var bnumber = 0; + + var repcntr = model.repfirst + 1; + var bsize = model.firstsize; + + do { + if (bnumber) { + bstart = bend + 1; + } else { + bstart = 0; + } + + if (!--repcntr) { + repcntr = model.repnext; + bsize *= model.mulsize; + } + + bend = bstart + bsize - 1; + if (bend + bsize >= model.levels) { + bend = model.levels - 1; + } + + this.buckets_buf[bnumber] = new QuicBucket; + + var i; + for (i = bstart; i <= bend; i++) { + this.buckets_ptrs[i] = this.buckets_buf[bnumber]; + } + + bnumber++; + } while (bend < model.levels - 1); + return true; + } +} + +function QuicChannel(model_8bpc, model_5bpc) +{ + this.state = new CommonState; + this.family_stat_8bpc = new QuicFamilyStat; + this.family_stat_5bpc = new QuicFamilyStat; + this.correlate_row = { zero: 0 , row:[] }; + this.model_8bpc = model_8bpc; + this.model_5bpc = model_5bpc; + this.buckets_ptrs = []; + + if (!this.family_stat_8bpc.fill_model_structures(this.model_8bpc)) + return undefined; + + if (!this.family_stat_5bpc.fill_model_structures(this.model_5bpc)) + return undefined; +} + +QuicChannel.prototype = { + + reste : function (bpc) + { + var j; + this.correlate_row = { zero: 0 , row: []}; + + if (bpc == 8) { + for (j = 0; j < this.model_8bpc.n_buckets; j++) + this.family_stat_8bpc.buckets_buf[j].reste(7); + this.buckets_ptrs = this.family_stat_8bpc.buckets_ptrs; + } else if (bpc == 5) { + for (j = 0; j < this.model_5bpc.n_buckets; j++) + this.family_stat_8bpc.buckets_buf[j].reste(4); + this.buckets_ptrs = this.family_stat_5bpc.buckets_ptrs; + } else { + console.log("quic: %s: bad bpc %d\n", __FUNCTION__, bpc); + return false; + } + + this.state.reste(); + return true; + } +} + +function CommonState() +{ +} + +CommonState.prototype = { + waitcnt: 0, + tabrand_seed: 0xff, + wm_trigger: 0, + wmidx: 0, + wmileft: wminext, + melcstate: 0, + melclen: 0, + melcorder: 0, + + set_wm_trigger : function() + { + var wm = this.wmidx; + if (wm > 10) { + wm = 10; + } + + this.wm_trigger = besttrigtab[Math.floor(evol / 2)][wm]; + }, + + reste : function() + { + this.waitcnt = 0; + this.tabrand_seed = 0x0ff; + this.wmidx = 0; + this.wmileft = wminext; + + this.set_wm_trigger(); + + this.melcstate = 0; + this.melclen = J[0]; + this.melcorder = 1 << this.melclen; + }, + + tabrand : function() + { + this.tabrand_seed++; + return tabrand_chaos[this.tabrand_seed & 0x0ff]; + } +} + + +function QuicEncoder() +{ + this.rgb_state = new CommonState; + this.model_8bpc = new QuicModel(8); + this.model_5bpc = new QuicModel(5); + this.channels = []; + + var i; + for (i = 0; i < 4; i++) { + this.channels[i] = new QuicChannel(this.model_8bpc, this.model_5bpc); + if (!this.channels[i]) + { + console.log("quic: failed to create channel"); + return undefined; + } + } +} + +QuicEncoder.prototype = { + type: 0, + width: 0, + height: 0, + io_idx: 0, + io_available_bits: 0, + io_word: 0, + io_next_word: 0, + io_now: 0, + io_end: 0, + rows_completed: 0, + }; + +QuicEncoder.prototype.reste = function(io_ptr) +{ + this.rgb_state.reste(); + + this.io_now = io_ptr; + this.io_end = this.io_now.length; + this.io_idx = 0; + this.rows_completed = 0; + return true; +} + +QuicEncoder.prototype.read_io_word = function() +{ + if (this.io_idx >= this.io_end) + throw("quic: out of data"); + this.io_next_word = this.io_now[this.io_idx++] | this.io_now[this.io_idx++]<<8 | this.io_now[this.io_idx++]<<16 | this.io_now[this.io_idx++]<<24; +} + +QuicEncoder.prototype.decode_eatbits = function (len) +{ + this.io_word = this.io_word << len; + + var delta = (this.io_available_bits - len); + if (delta >= 0) + { + this.io_available_bits = delta; + this.io_word |= this.io_next_word >>> this.io_available_bits; + } + else + { + delta = -1 * delta; + this.io_word |= this.io_next_word << delta; + this.read_io_word(); + this.io_available_bits = 32 - delta; + this.io_word |= this.io_next_word >>> this.io_available_bits; + } +} + +QuicEncoder.prototype.decode_eat32bits = function() +{ + this.decode_eatbits(16); + this.decode_eatbits(16); +} + +QuicEncoder.prototype.reste_channels = function(bpc) +{ + var i; + + for (i = 0; i < 4; i++) + if (!this.channels[i].reste(bpc)) + return false; + return true; +} + +QuicEncoder.prototype.quic_decode_begin = function(io_ptr) +{ + if (!this.reste(io_ptr)) { + return false; + } + + this.io_idx = 0; + this.io_next_word = this.io_now[this.io_idx++] | this.io_now[this.io_idx++]<<8 | this.io_now[this.io_idx++]<<16 | this.io_now[this.io_idx++]<<24; + this.io_word = this.io_next_word; + this.io_available_bits = 0; + + var magic = this.io_word; + this.decode_eat32bits(); + if (magic != 0x43495551) /*QUIC*/ { + console.log("quic: bad magic "+magic.toString(16)); + return false; + } + + var version = this.io_word; + this.decode_eat32bits(); + if (version != ((0 << 16) | (0 & 0xffff))) { + console.log("quic: bad version "+version.toString(16)); + return false; + } + + this.type = this.io_word; + this.decode_eat32bits(); + + this.width = this.io_word; + this.decode_eat32bits(); + + this.height = this.io_word; + this.decode_eat32bits(); + + var bpc = quic_image_bpc(this.type); + + if (!this.reste_channels(bpc)) + return false; + + return true; +} + +QuicEncoder.prototype.quic_rgb32_uncompress_row0_seg = function (i, cur_row, end, + waitmask, bpc, bpc_mask) +{ + var stopidx; + var n_channels = 3; + var c; + var a; + + if (!i) { + cur_row[rgb32_pixel_pad] = 0; + c = 0; + do + { + a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].bestcode, this.io_word); + this.channels[c].correlate_row.row[0] = a.rc; + cur_row[2-c] = (family_8bpc.xlatL2U[a.rc]&0xFF); + this.decode_eatbits(a.codewordlen); + } while (++c < n_channels); + + if (this.rgb_state.waitcnt) { + --this.rgb_state.waitcnt; + } else { + this.rgb_state.waitcnt = (this.rgb_state.tabrand() & waitmask); + c = 0; + do + { + this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[0], bpc); + } while (++c < n_channels); + } + stopidx = ++i + this.rgb_state.waitcnt; + } else { + stopidx = i + this.rgb_state.waitcnt; + } + + while (stopidx < end) { + for (; i <= stopidx; i++) { + cur_row[(i* rgb32_pixel_size)+rgb32_pixel_pad] = 0; + c = 0; + do + { + a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i - 1]].bestcode, this.io_word); + this.channels[c].correlate_row.row[i] = a.rc; + cur_row[(i* rgb32_pixel_size)+(2-c)] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1) * rgb32_pixel_size) + (2-c)]) & bpc_mask; + this.decode_eatbits(a.codewordlen); + } while (++c < n_channels); + } + c = 0; + do + { + this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[stopidx - 1]].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[stopidx], bpc); + } while (++c < n_channels); + stopidx = i + (this.rgb_state.tabrand() & waitmask); + } + + for (; i < end; i++) { + cur_row[(i* rgb32_pixel_size)+rgb32_pixel_pad] = 0; + c = 0; + do + { + a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i - 1]].bestcode, this.io_word); + this.channels[c].correlate_row.row[i] = a.rc; + cur_row[(i* rgb32_pixel_size)+(2-c)] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1) * rgb32_pixel_size) + (2-c)]) & bpc_mask; + this.decode_eatbits(a.codewordlen); + } while (++c < n_channels); + } + this.rgb_state.waitcnt = stopidx - end; +} + +QuicEncoder.prototype.quic_rgb32_uncompress_row0 = function (cur_row) +{ + var bpc = 8; + var bpc_mask = 0xff; + var pos = 0; + var width = this.width; + + while ((wmimax > this.rgb_state.wmidx) && (this.rgb_state.wmileft <= width)) { + if (this.rgb_state.wmileft) { + this.quic_rgb32_uncompress_row0_seg(pos, cur_row, + pos + this.rgb_state.wmileft, + bppmask[this.rgb_state.wmidx], + bpc, bpc_mask); + pos += this.rgb_state.wmileft; + width -= this.rgb_state.wmileft; + } + + this.rgb_state.wmidx++; + this.rgb_state.set_wm_trigger(); + this.rgb_state.wmileft = wminext; + } + + if (width) { + this.quic_rgb32_uncompress_row0_seg(pos, cur_row, pos + width, + bppmask[this.rgb_state.wmidx], bpc, bpc_mask); + if (wmimax > this.rgb_state.wmidx) { + this.rgb_state.wmileft -= width; + } + } +} + +QuicEncoder.prototype.quic_rgb32_uncompress_row_seg = function( prev_row, cur_row, i, end, bpc, bpc_mask) +{ + var n_channels = 3; + var waitmask = bppmask[this.rgb_state.wmidx]; + + var a; + var run_index = 0; + var stopidx = 0; + var run_end = 0; + var c; + + if (!i) + { + cur_row[rgb32_pixel_pad] = 0; + + c = 0; + do { + a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].bestcode, this.io_word); + this.channels[c].correlate_row.row[0] = a.rc; + cur_row[2-c] = (family_8bpc.xlatL2U[this.channels[c].correlate_row.row[0]] + prev_row[2-c]) & bpc_mask; + this.decode_eatbits(a.codewordlen); + } while (++c < n_channels); + + if (this.rgb_state.waitcnt) { + --this.rgb_state.waitcnt; + } else { + this.rgb_state.waitcnt = (this.rgb_state.tabrand() & waitmask); + c = 0; + do { + this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[0], bpc); + } while (++c < n_channels); + } + stopidx = ++i + this.rgb_state.waitcnt; + } else { + stopidx = i + this.rgb_state.waitcnt; + } + for (;;) { + var rc = 0; + while (stopidx < end && !rc) { + for (; i <= stopidx && !rc; i++) { + var pixel = i * rgb32_pixel_size; + var pixelm1 = (i-1) * rgb32_pixel_size; + var pixelm2 = (i-2) * rgb32_pixel_size; + + if ( prev_row[pixelm1+rgb32_pixel_r] == prev_row[pixel+rgb32_pixel_r] && prev_row[pixelm1+rgb32_pixel_g] == prev_row[pixel+rgb32_pixel_g] && prev_row[pixelm1 + rgb32_pixel_b] == prev_row[pixel+rgb32_pixel_b]) + { + if (run_index != i && i > 2 && (cur_row[pixelm1+rgb32_pixel_r] == cur_row[pixelm2+rgb32_pixel_r] && cur_row[pixelm1+rgb32_pixel_g] == cur_row[pixelm2+rgb32_pixel_g] && cur_row[pixelm1+rgb32_pixel_b] == cur_row[pixelm2+rgb32_pixel_b])) + { + /* do run */ + this.rgb_state.waitcnt = stopidx - i; + run_index = i; + run_end = i + this.decode_run(this.rgb_state); + + for (; i < run_end; i++) { + var pixel = i * rgb32_pixel_size; + var pixelm1 = (i-1) * rgb32_pixel_size; + cur_row[pixel+rgb32_pixel_pad] = 0; + cur_row[pixel+rgb32_pixel_r] = cur_row[pixelm1+rgb32_pixel_r]; + cur_row[pixel+rgb32_pixel_g] = cur_row[pixelm1+rgb32_pixel_g]; + cur_row[pixel+rgb32_pixel_b] = cur_row[pixelm1+rgb32_pixel_b]; + } + + if (i == end) { + return; + } + else + { + stopidx = i + this.rgb_state.waitcnt; + rc = 1; + break; + } + } + } + + c = 0; + cur_row[pixel+rgb32_pixel_pad] = 0; + do { + var cc = this.channels[c]; + var cr = cc.correlate_row; + + a = golomb_decoding_8bpc(cc.buckets_ptrs[cr.row[i-1]].bestcode, this.io_word); + cr.row[i] = a.rc; + cur_row[pixel+(2-c)] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+(2-c)] + prev_row[pixel+(2-c)]) >> 1)) & bpc_mask; + this.decode_eatbits(a.codewordlen); + } while (++c < n_channels); + } + if (rc) + break; + + c = 0; + do { + this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[stopidx - 1]].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[stopidx], bpc); + } while (++c < n_channels); + + stopidx = i + (this.rgb_state.tabrand() & waitmask); + } + + for (; i < end && !rc; i++) { + var pixel = i * rgb32_pixel_size; + var pixelm1 = (i-1) * rgb32_pixel_size; + var pixelm2 = (i-2) * rgb32_pixel_size; + + if (prev_row[pixelm1+rgb32_pixel_r] == prev_row[pixel+rgb32_pixel_r] && prev_row[pixelm1+rgb32_pixel_g] == prev_row[pixel+rgb32_pixel_g] && prev_row[pixelm1+rgb32_pixel_b] == prev_row[pixel+rgb32_pixel_b]) + { + if (run_index != i && i > 2 && (cur_row[pixelm1+rgb32_pixel_r] == cur_row[pixelm2+rgb32_pixel_r] && cur_row[pixelm1+rgb32_pixel_g] == cur_row[pixelm2+rgb32_pixel_g] && cur_row[pixelm1+rgb32_pixel_b] == cur_row[pixelm2+rgb32_pixel_b])) + { + /* do run */ + this.rgb_state.waitcnt = stopidx - i; + run_index = i; + run_end = i + this.decode_run(this.rgb_state); + + for (; i < run_end; i++) { + var pixel = i * rgb32_pixel_size; + var pixelm1 = (i-1) * rgb32_pixel_size; + cur_row[pixel+rgb32_pixel_pad] = 0; + cur_row[pixel+rgb32_pixel_r] = cur_row[pixelm1+rgb32_pixel_r]; + cur_row[pixel+rgb32_pixel_g] = cur_row[pixelm1+rgb32_pixel_g]; + cur_row[pixel+rgb32_pixel_b] = cur_row[pixelm1+rgb32_pixel_b]; + } + + if (i == end) { + return; + } + else + { + stopidx = i + this.rgb_state.waitcnt; + rc = 1; + break; + } + } + } + + cur_row[pixel+rgb32_pixel_pad] = 0; + c = 0; + do + { + a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i-1]].bestcode, this.io_word); + this.channels[c].correlate_row.row[i] = a.rc; + cur_row[pixel+(2-c)] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+(2-c)] + prev_row[pixel+(2-c)]) >> 1)) & bpc_mask; + this.decode_eatbits(a.codewordlen); + } while (++c < n_channels); + } + + if (!rc) + { + this.rgb_state.waitcnt = stopidx - end; + return; + } + } +} + +QuicEncoder.prototype.decode_run = function(state) +{ + var runlen = 0; + + do { + var hits; + var x = (~(this.io_word >>> 24)>>>0)&0xff; + var temp = zeroLUT[x]; + + for (hits = 1; hits <= temp; hits++) { + runlen += state.melcorder; + + if (state.melcstate < 32) { + state.melclen = J[++state.melcstate]; + state.melcorder = (1 << state.melclen); + } + } + if (temp != 8) { + this.decode_eatbits(temp + 1); + + break; + } + this.decode_eatbits(8); + } while (true); + + if (state.melclen) { + runlen += this.io_word >>> (32 - state.melclen); + this.decode_eatbits(state.melclen); + } + + if (state.melcstate) { + state.melclen = J[--state.melcstate]; + state.melcorder = (1 << state.melclen); + } + + return runlen; +} + +QuicEncoder.prototype.quic_rgb32_uncompress_row = function (prev_row, cur_row) +{ + var bpc = 8; + var bpc_mask = 0xff; + var pos = 0; + var width = this.width; + + while ((wmimax > this.rgb_state.wmidx) && (this.rgb_state.wmileft <= width)) { + if (this.rgb_state.wmileft) { + this.quic_rgb32_uncompress_row_seg(prev_row, cur_row, pos, + pos + this.rgb_state.wmileft, bpc, bpc_mask); + pos += this.rgb_state.wmileft; + width -= this.rgb_state.wmileft; + } + + this.rgb_state.wmidx++; + this.rgb_state.set_wm_trigger(); + this.rgb_state.wmileft = wminext; + } + + if (width) { + this.quic_rgb32_uncompress_row_seg(prev_row, cur_row, pos, + pos + width, bpc, bpc_mask); + if (wmimax > this.rgb_state.wmidx) { + this.rgb_state.wmileft -= width; + } + } +} + +QuicEncoder.prototype.quic_four_uncompress_row0_seg = function (channel, i, + correlate_row, cur_row, end, waitmask, + bpc, bpc_mask) +{ + var stopidx; + var a; + + if (i == 0) { + a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.zero].bestcode, this.io_word); + correlate_row.row[0] = a.rc; + cur_row[rgb32_pixel_pad] = family_8bpc.xlatL2U[a.rc]; + this.decode_eatbits(a.codewordlen); + + if (channel.state.waitcnt) { + --channel.state.waitcnt; + } else { + channel.state.waitcnt = (channel.state.tabrand() & waitmask); + channel.buckets_ptrs[correlate_row.zero].update_model_8bpc(channel.state, correlate_row.row[0], bpc); + } + stopidx = ++i + channel.state.waitcnt; + } else { + stopidx = i + channel.state.waitcnt; + } + + while (stopidx < end) { + var pbucket; + + for (; i <= stopidx; i++) { + pbucket = channel.buckets_ptrs[correlate_row.row[i - 1]]; + + a = golomb_decoding_8bpc(pbucket.bestcode, this.io_word); + correlate_row.row[i] = a.rc; + cur_row[(i*rgb32_pixel_size)+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1)*rgb32_pixel_size)+rgb32_pixel_pad]) & bpc_mask; + this.decode_eatbits(a.codewordlen); + } + + pbucket.update_model_8bpc(channel.state, correlate_row.row[stopidx], bpc); + + stopidx = i + (channel.state.tabrand() & waitmask); + } + + for (; i < end; i++) { + a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.row[i-1]].bestcode, this.io_word); + + correlate_row.row[i] = a.rc; + cur_row[(i*rgb32_pixel_size)+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1)*rgb32_pixel_size)+rgb32_pixel_pad]) & bpc_mask; + this.decode_eatbits(a.codewordlen); + } + channel.state.waitcnt = stopidx - end; +} + +QuicEncoder.prototype.quic_four_uncompress_row0 = function(channel, cur_row) +{ + var bpc = 8; + var bpc_mask = 0xff; + var correlate_row = channel.correlate_row; + var pos = 0; + var width = this.width; + + while ((wmimax > channel.state.wmidx) && (channel.state.wmileft <= width)) { + if (channel.state.wmileft) { + this.quic_four_uncompress_row0_seg(channel, pos, correlate_row, cur_row, + pos + channel.state.wmileft, bppmask[channel.state.wmidx], + bpc, bpc_mask); + pos += channel.state.wmileft; + width -= channel.state.wmileft; + } + + channel.state.wmidx++; + channel.state.set_wm_trigger(); + channel.state.wmileft = wminext; + } + + if (width) { + this.quic_four_uncompress_row0_seg(channel, pos, correlate_row, cur_row, pos + width, + bppmask[channel.state.wmidx], bpc, bpc_mask); + if (wmimax > channel.state.wmidx) { + channel.state.wmileft -= width; + } + } +} + +QuicEncoder.prototype.quic_four_uncompress_row_seg = function (channel, + correlate_row, prev_row, cur_row, i, + end, bpc, bpc_mask) +{ + var waitmask = bppmask[channel.state.wmidx]; + var stopidx; + + var run_index = 0; + var run_end; + + var a; + + if (i == 0) { + a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.zero].bestcode, this.io_word); + + correlate_row.row[0] = a.rc + cur_row[rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + prev_row[rgb32_pixel_pad]) & bpc_mask; + this.decode_eatbits(a.codewordlen); + + if (channel.state.waitcnt) { + --channel.state.waitcnt; + } else { + channel.state.waitcnt = (channel.state.tabrand() & waitmask); + channel.buckets_ptrs[correlate_row.zero].update_model_8bpc(channel.state, correlate_row.row[0], bpc); + } + stopidx = ++i + channel.state.waitcnt; + } else { + stopidx = i + channel.state.waitcnt; + } + for (;;) { + var rc = 0; + while (stopidx < end && !rc) { + var pbucket; + for (; i <= stopidx && !rc; i++) { + var pixel = i * rgb32_pixel_size; + var pixelm1 = (i-1) * rgb32_pixel_size; + var pixelm2 = (i-2) * rgb32_pixel_size; + + if (prev_row[pixelm1+rgb32_pixel_pad] == prev_row[pixel+rgb32_pixel_pad]) + { + if (run_index != i && i > 2 && cur_row[pixelm1+rgb32_pixel_pad] == cur_row[pixelm2+rgb32_pixel_pad]) + { + /* do run */ + channel.state.waitcnt = stopidx - i; + run_index = i; + + run_end = i + this.decode_run(channel.state); + + for (; i < run_end; i++) { + var pixel = i * rgb32_pixel_size; + var pixelm1 = (i-1) * rgb32_pixel_size; + cur_row[pixel+rgb32_pixel_pad] = cur_row[pixelm1+rgb32_pixel_pad]; + } + + if (i == end) { + return; + } + else + { + stopidx = i + channel.state.waitcnt; + rc = 1; + break; + } + } + } + + pbucket = channel.buckets_ptrs[correlate_row.row[i - 1]]; + a = golomb_decoding_8bpc(pbucket.bestcode, this.io_word); + correlate_row.row[i] = a.rc + cur_row[pixel+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+rgb32_pixel_pad] + prev_row[pixel+rgb32_pixel_pad]) >> 1)) & bpc_mask; + this.decode_eatbits(a.codewordlen); + } + if (rc) + break; + + pbucket.update_model_8bpc(channel.state, correlate_row.row[stopidx], bpc); + + stopidx = i + (channel.state.tabrand() & waitmask); + } + + for (; i < end && !rc; i++) { + var pixel = i * rgb32_pixel_size; + var pixelm1 = (i-1) * rgb32_pixel_size; + var pixelm2 = (i-2) * rgb32_pixel_size; + if (prev_row[pixelm1+rgb32_pixel_pad] == prev_row[pixel+rgb32_pixel_pad]) + { + if (run_index != i && i > 2 && cur_row[pixelm1+rgb32_pixel_pad] == cur_row[pixelm2+rgb32_pixel_pad]) + { + /* do run */ + channel.state.waitcnt = stopidx - i; + run_index = i; + + run_end = i + this.decode_run(channel.state); + + for (; i < run_end; i++) { + var pixel = i * rgb32_pixel_size; + var pixelm1 = (i-1) * rgb32_pixel_size; + cur_row[pixel+rgb32_pixel_pad] = cur_row[pixelm1+rgb32_pixel_pad]; + } + + if (i == end) { + return; + } + else + { + stopidx = i + channel.state.waitcnt; + rc = 1; + break; + } + } + } + + a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.row[i-1]].bestcode, this.io_word); + correlate_row.row[i] = a.rc; + cur_row[pixel+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+rgb32_pixel_pad] + prev_row[pixel+rgb32_pixel_pad]) >> 1)) & bpc_mask; + this.decode_eatbits(a.codewordlen); + } + + if (!rc) + { + channel.state.waitcnt = stopidx - end; + return; + } + } +} + +QuicEncoder.prototype.quic_four_uncompress_row = function(channel, prev_row, + cur_row) +{ + var bpc = 8; + var bpc_mask = 0xff; + var correlate_row = channel.correlate_row; + var pos = 0; + var width = this.width; + + while ((wmimax > channel.state.wmidx) && (channel.state.wmileft <= width)) { + if (channel.state.wmileft) { + this.quic_four_uncompress_row_seg(channel, correlate_row, prev_row, cur_row, pos, + pos + channel.state.wmileft, bpc, bpc_mask); + pos += channel.state.wmileft; + width -= channel.state.wmileft; + } + + channel.state.wmidx++; + channel.state.set_wm_trigger(); + channel.state.wmileft = wminext; + } + + if (width) { + this.quic_four_uncompress_row_seg(channel, correlate_row, prev_row, cur_row, pos, + pos + width, bpc, bpc_mask); + if (wmimax > channel.state.wmidx) { + channel.state.wmileft -= width; + } + } +} + +/* We need to be generating rgb32 or rgba */ +QuicEncoder.prototype.quic_decode = function(buf, stride) +{ + var row; + + switch (this.type) + { + case QUIC_IMAGE_TYPE_RGB32: + case QUIC_IMAGE_TYPE_RGB24: + this.channels[0].correlate_row.zero = 0; + this.channels[1].correlate_row.zero = 0; + this.channels[2].correlate_row.zero = 0; + this.quic_rgb32_uncompress_row0(buf); + + this.rows_completed++; + for (row = 1; row < this.height; row++) + { + var prev = buf; + buf = prev.subarray(stride); + this.channels[0].correlate_row.zero = this.channels[0].correlate_row.row[0]; + this.channels[1].correlate_row.zero = this.channels[1].correlate_row.row[0]; + this.channels[2].correlate_row.zero = this.channels[2].correlate_row.row[0]; + this.quic_rgb32_uncompress_row(prev, buf); + this.rows_completed++; + }; + break; + case QUIC_IMAGE_TYPE_RGB16: + console.log("quic: unsupported output format\n"); + return false; + break; + case QUIC_IMAGE_TYPE_RGBA: + this.channels[0].correlate_row.zero = 0; + this.channels[1].correlate_row.zero = 0; + this.channels[2].correlate_row.zero = 0; + this.quic_rgb32_uncompress_row0(buf); + + this.channels[3].correlate_row.zero = 0; + this.quic_four_uncompress_row0(this.channels[3], buf); + + this.rows_completed++; + for (row = 1; row < this.height; row++) { + var prev = buf; + buf = prev.subarray(stride); + + this.channels[0].correlate_row.zero = this.channels[0].correlate_row.row[0]; + this.channels[1].correlate_row.zero = this.channels[1].correlate_row.row[0]; + this.channels[2].correlate_row.zero = this.channels[2].correlate_row.row[0]; + this.quic_rgb32_uncompress_row(prev, buf); + + this.channels[3].correlate_row.zero = this.channels[3].correlate_row.row[0]; + this.quic_four_uncompress_row(encoder.channels[3], prev, buf); + this.rows_completed++; + } + break; + + case QUIC_IMAGE_TYPE_GRAY: + console.log("quic: unsupported output format\n"); + return false; + break; + + case QUIC_IMAGE_TYPE_INVALID: + default: + console.log("quic: bad image type\n"); + return false; + } + return true; +} + +QuicEncoder.prototype.simple_quic_decode = function(buf) +{ + var stride = 4; /* FIXME - proper stride calc please */ + if (!this.quic_decode_begin(buf)) + return undefined; + if (this.type != QUIC_IMAGE_TYPE_RGB32 && this.type != QUIC_IMAGE_TYPE_RGB24 + && this.type != QUIC_IMAGE_TYPE_RGBA) + return undefined; + var out = new Uint8Array(this.width*this.height*4); + out[0] = 69; + if (this.quic_decode( out, (this.width * stride))) + return out; + return undefined; +} + +function SpiceQuic() +{ +} + +SpiceQuic.prototype = +{ + from_dv: function(dv, at, mb) + { + if (!encoder) + throw("quic: no quic encoder"); + this.data_size = dv.getUint32(at, true); + at += 4; + var buf = new Uint8Array(mb.slice(at)); + this.outptr = encoder.simple_quic_decode(buf); + if (this.outptr) + { + this.type = encoder.type; + this.width = encoder.width; + this.height = encoder.height; + } + at += buf.length; + return at; + }, +} + +function convert_spice_quic_to_web(context, spice_quic) +{ + var ret = context.createImageData(spice_quic.width, spice_quic.height); + var i; + for (i = 0; i < (ret.width * ret.height * 4); i+=4) + { + ret.data[i + 0] = spice_quic.outptr[i + 2]; + ret.data[i + 1] = spice_quic.outptr[i + 1]; + ret.data[i + 2] = spice_quic.outptr[i + 0]; + if (spice_quic.type !== QUIC_IMAGE_TYPE_RGBA) + ret.data[i + 3] = 255; + else + ret.data[i + 3] = 255 - spice_quic.outptr[i + 3]; + } + return ret; +} + +/* Module initialization */ +if (need_init) +{ + need_init = false; + + family_init(family_8bpc, 8, DEFmaxclen); + family_init(family_5bpc, 5, DEFmaxclen); + /* init_zeroLUT */ + var i, j, k, l; + + j = k = 1; + l = 8; + for (i = 0; i < 256; ++i) { + zeroLUT[i] = l; + --k; + if (k == 0) { + k = j; + --l; + j *= 2; + } + } + + encoder = new QuicEncoder; + + if (!encoder) + throw("quic: failed to create encoder"); +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/resize.js b/src/wok/plugins/kimchi/ui/spice-html5/resize.js new file mode 100644 index 0000000..f5410d3 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/resize.js @@ -0,0 +1,70 @@ +"use strict"; +/* + Copyright (C) 2014 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** resize.js +** This bit of Javascript is a set of logic to help with window +** resizing, using the agent channel to request screen resizes. +** +** It's a bit tricky, as we want to wait for resizing to settle down +** before sending a size. Further, while horizontal resizing to use the whole +** browser width is fairly easy to arrange with css, resizing an element to use +** the whole vertical space (or to force a middle div to consume the bulk of the browser +** window size) is tricky, and the consensus seems to be that Javascript is +** the only right way to do it. +**--------------------------------------------------------------------------*/ +function resize_helper(sc) +{ + var w = document.getElementById(sc.screen_id).clientWidth; + var h = document.getElementById(sc.screen_id).clientHeight; + + var m = document.getElementById(sc.message_id); + + /* Resize vertically; basically we leave a 20 pixel margin + at the bottom, and use the position of the message window + to figure out how to resize */ + var hd = window.innerHeight - m.offsetHeight - m.offsetTop - 20; + + /* Xorg requires height be a multiple of 8; round up */ + h = h + hd; + if (h % 8 > 0) + h += (8 - (h % 8)); + + /* Xorg requires width be a multiple of 8; round up */ + if (w % 8 > 0) + w += (8 - (w % 8)); + + + sc.resize_window(0, w, h, 32, 0, 0); + sc.spice_resize_timer = undefined; +} + +function handle_resize(e) +{ + var sc = window.spice_connection; + + if (sc && sc.spice_resize_timer) + { + window.clearTimeout(sc.spice_resize_timer); + sc.spice_resize_timer = undefined; + } + + sc.spice_resize_timer = window.setTimeout(resize_helper, 200, sc); +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/simulatecursor.js b/src/wok/plugins/kimchi/ui/spice-html5/simulatecursor.js new file mode 100644 index 0000000..b1fce06 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/simulatecursor.js @@ -0,0 +1,202 @@ +"use strict"; +/* + Copyright (C) 2013 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** SpiceSimulateCursor +** Internet Explorer 10 does not support data uri's in cursor assignment. +** This file provides a number of gimmicks to compensate. First, if there +** is a preloaded cursor available, we will use that. Failing that, we will +** simulate a cursor using an image that is moved around the screen. +**--------------------------------------------------------------------------*/ +var SpiceSimulateCursor = { + +cursors : new Array(), +unknown_cursors : new Array(), +warned: false, + +add_cursor: function(sha1, value) +{ + SpiceSimulateCursor.cursors[sha1] = value; +}, + +unknown_cursor: function(sha1, curdata) +{ + if (! SpiceSimulateCursor.warned) + { + SpiceSimulateCursor.warned = true; + alert("Internet Explorer does not support dynamic cursors. " + + "This page will now simulate cursors with images, " + + "which will be imperfect. We recommend using Chrome or Firefox instead. " + + "\n\nIf you need to use Internet Explorer, you can create a static cursor " + + "file for each cursor your application uses. " + + "View the console log for more information on creating static cursors for your environment."); + } + + if (! SpiceSimulateCursor.unknown_cursors[sha1]) + { + SpiceSimulateCursor.unknown_cursors[sha1] = curdata; + console.log('Unknown cursor. Simulation required. To avoid simulation for this cursor, create and include a custom javascript file, and add the following line:'); + console.log('SpiceCursorSimulator.add_cursor("' + sha1 + '"), "<your filename here>.cur");'); + console.log('And then run following command, redirecting output into <your filename here>.cur:'); + console.log('php -r "echo urldecode(\'' + curdata + '\');"'); + } +}, + +simulate_cursor: function (spicecursor, cursor, screen, pngstr) +{ + var cursor_sha = hex_sha1(pngstr + ' ' + cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y); + if (typeof SpiceSimulateCursor.cursors != 'undefined') + if (typeof SpiceSimulateCursor.cursors[cursor_sha] != 'undefined') + { + var curstr = 'url(' + SpiceSimulateCursor.cursors[cursor_sha] + '), default'; + screen.style.cursor = curstr; + } + + if (window.getComputedStyle(screen, null).cursor == 'auto') + { + SpiceSimulateCursor.unknown_cursor(cursor_sha, + SpiceSimulateCursor.create_icondir(cursor.header.width, cursor.header.height, + cursor.data.byteLength, cursor.header.hot_spot_x, cursor.header.hot_spot_y) + pngstr); + + document.getElementById(spicecursor.parent.screen_id).style.cursor = 'none'; + if (! spicecursor.spice_simulated_cursor) + { + spicecursor.spice_simulated_cursor = document.createElement('img'); + + spicecursor.spice_simulated_cursor.style.position = 'absolute'; + spicecursor.spice_simulated_cursor.style.display = 'none'; + spicecursor.spice_simulated_cursor.style.overflow = 'hidden'; + + spicecursor.spice_simulated_cursor.spice_screen = document.getElementById(spicecursor.parent.screen_id); + + spicecursor.spice_simulated_cursor.addEventListener('mousemove', SpiceSimulateCursor.handle_sim_mousemove); + + spicecursor.spice_simulated_cursor.spice_screen.appendChild(spicecursor.spice_simulated_cursor); + } + + spicecursor.spice_simulated_cursor.src = 'data:image/png,' + pngstr; + + spicecursor.spice_simulated_cursor.spice_hot_x = cursor.header.hot_spot_x; + spicecursor.spice_simulated_cursor.spice_hot_y = cursor.header.hot_spot_y; + + spicecursor.spice_simulated_cursor.style.pointerEvents = "none"; + } + else + { + if (spicecursor.spice_simulated_cursor) + { + spicecursor.spice_simulated_cursor.spice_screen.removeChild(spicecursor.spice_simulated_cursor); + delete spicecursor.spice_simulated_cursor; + } + } +}, + +handle_sim_mousemove: function(e) +{ + var retval; + var f = SpiceSimulateCursor.duplicate_mouse_event(e, this.spice_screen); + return this.spice_screen.dispatchEvent(f); +}, + +duplicate_mouse_event: function(e, target) +{ + var evt = document.createEvent("mouseevent"); + evt.initMouseEvent(e.type, true, true, e.view, e.detail, + e.screenX, e.screenY, e.clientX, e.clientY, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget); + return evt; +}, + +ICONDIR: function () +{ +}, + +ICONDIRENTRY: function(width, height, bytes, hot_x, hot_y) +{ + this.width = width; + this.height = height; + this.bytes = bytes; + this.hot_x = hot_x; + this.hot_y = hot_y; +}, + + +create_icondir: function (width, height, bytes, hot_x, hot_y) +{ + var i; + var header = new SpiceSimulateCursor.ICONDIR(); + var entry = new SpiceSimulateCursor.ICONDIRENTRY(width, height, bytes, hot_x, hot_y); + + var mb = new ArrayBuffer(header.buffer_size() + entry.buffer_size()); + var at = header.to_buffer(mb); + at = entry.to_buffer(mb, at); + + var u8 = new Uint8Array(mb); + var str = ""; + for (i = 0; i < at; i++) + { + str += "%"; + if (u8[i] < 16) + str += "0"; + str += u8[i].toString(16); + } + return str; +}, + +}; + +SpiceSimulateCursor.ICONDIR.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint16(at, 0, true); at += 2; + dv.setUint16(at, 2, true); at += 2; + dv.setUint16(at, 1, true); at += 2; + return at; + }, + buffer_size: function() + { + return 6; + } +}; + +SpiceSimulateCursor.ICONDIRENTRY.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint8(at, this.width); at++; + dv.setUint8(at, this.height); at++; + dv.setUint8(at, 0); at++; /* color palette count, unused */ + dv.setUint8(at, 0); at++; /* reserved */ + dv.setUint16(at, this.hot_x, true); at += 2; + dv.setUint16(at, this.hot_y, true); at += 2; + dv.setUint32(at, this.bytes, true); at += 4; + dv.setUint32(at, at + 4, true); at += 4; /* Offset to bytes */ + return at; + }, + buffer_size: function() + { + return 16; + } +}; diff --git a/src/wok/plugins/kimchi/ui/spice-html5/spicearraybuffer.js b/src/wok/plugins/kimchi/ui/spice-html5/spicearraybuffer.js new file mode 100644 index 0000000..228bce6 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/spicearraybuffer.js @@ -0,0 +1,58 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** SpiceArrayBufferSlice +** This function is a work around for IE 10, which has no slice() +** method in it's subclass. +**--------------------------------------------------------------------------*/ +function SpiceArrayBufferSlice(start, end) +{ + start = start || 0; + end = end || this.byteLength; + if (end < 0) + end = this.byteLength + end; + if (start < 0) + start = this.byteLength + start; + if (start < 0) + start = 0; + if (end < 0) + end = 0; + if (end > this.byteLength) + end = this.byteLength; + if (start > end) + start = end; + + var ret = new ArrayBuffer(end - start); + var in1 = new Uint8Array(this, start, end - start); + var out = new Uint8Array(ret); + var i; + + for (i = 0; i < end - start; i++) + out[i] = in1[i]; + + return ret; +} + +if (! ArrayBuffer.prototype.slice) +{ + ArrayBuffer.prototype.slice = SpiceArrayBufferSlice; + console.log("WARNING: ArrayBuffer.slice() is missing; we are extending ArrayBuffer to compensate"); +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/spiceconn.js b/src/wok/plugins/kimchi/ui/spice-html5/spiceconn.js new file mode 100644 index 0000000..e33227e --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/spiceconn.js @@ -0,0 +1,460 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** SpiceConn +** This is the base Javascript class for establishing and +** managing a connection to a Spice Server. +** It is used to provide core functionality to the Spice main, +** display, inputs, and cursor channels. See main.js for +** usage. +**--------------------------------------------------------------------------*/ +function SpiceConn(o) +{ + if (o === undefined || o.uri === undefined || ! o.uri) + throw new Error("You must specify a uri"); + + this.ws = new WebSocket(o.uri, 'binary'); + + if (! this.ws.binaryType) + throw new Error("WebSocket doesn't support binaryType. Try a different browser."); + + this.connection_id = o.connection_id !== undefined ? o.connection_id : 0; + this.type = o.type !== undefined ? o.type : SPICE_CHANNEL_MAIN; + this.chan_id = o.chan_id !== undefined ? o.chan_id : 0; + if (o.parent !== undefined) + { + this.parent = o.parent; + this.message_id = o.parent.message_id; + this.password = o.parent.password; + } + if (o.screen_id !== undefined) + this.screen_id = o.screen_id; + if (o.dump_id !== undefined) + this.dump_id = o.dump_id; + if (o.message_id !== undefined) + this.message_id = o.message_id; + if (o.password !== undefined) + this.password = o.password; + if (o.onerror !== undefined) + this.onerror = o.onerror; + if (o.onsuccess !== undefined) + this.onsuccess = o.onsuccess; + if (o.onagent !== undefined) + this.onagent = o.onagent; + + this.state = "connecting"; + this.ws.parent = this; + this.wire_reader = new SpiceWireReader(this, this.process_inbound); + this.messages_sent = 0; + this.warnings = []; + + this.ws.addEventListener('open', function(e) { + DEBUG > 0 && console.log(">> WebSockets.onopen"); + DEBUG > 0 && console.log("id " + this.parent.connection_id +"; type " + this.parent.type); + + /*********************************************************************** + ** WHERE IT ALL REALLY BEGINS + ***********************************************************************/ + this.parent.send_hdr(); + this.parent.wire_reader.request(SpiceLinkHeader.prototype.buffer_size()); + this.parent.state = "start"; + }); + this.ws.addEventListener('error', function(e) { + this.parent.log_err(">> WebSockets.onerror" + e.toString()); + this.parent.report_error(e); + }); + this.ws.addEventListener('close', function(e) { + DEBUG > 0 && console.log(">> WebSockets.onclose"); + DEBUG > 0 && console.log("id " + this.parent.connection_id +"; type " + this.parent.type); + DEBUG > 0 && console.log(e); + if (this.parent.state != "closing" && this.parent.state != "error" && this.parent.onerror !== undefined) + { + var e; + if (this.parent.state == "connecting") + e = new Error("Connection refused."); + else if (this.parent.state == "start" || this.parent.state == "link") + e = new Error("Unexpected protocol mismatch."); + else if (this.parent.state == "ticket") + e = new Error("Bad password."); + else + e = new Error("Unexpected close while " + this.parent.state); + + this.parent.onerror(e); + this.parent.log_err(e.toString()); + } + }); + + if (this.ws.readyState == 2 || this.ws.readyState == 3) + throw new Error("Unable to connect to " + o.uri); + + this.timeout = window.setTimeout(spiceconn_timeout, SPICE_CONNECT_TIMEOUT, this); +} + +SpiceConn.prototype = +{ + send_hdr : function () + { + var hdr = new SpiceLinkHeader; + var msg = new SpiceLinkMess; + + msg.connection_id = this.connection_id; + msg.channel_type = this.type; + // FIXME - we're not setting a channel_id... + msg.common_caps.push( + (1 << SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION) | + (1 << SPICE_COMMON_CAP_MINI_HEADER) + ); + + if (msg.channel_type == SPICE_CHANNEL_PLAYBACK) + msg.channel_caps.push( + (1 << SPICE_PLAYBACK_CAP_OPUS) + ); + + hdr.size = msg.buffer_size(); + + var mb = new ArrayBuffer(hdr.buffer_size() + msg.buffer_size()); + hdr.to_buffer(mb); + msg.to_buffer(mb, hdr.buffer_size()); + + DEBUG > 1 && console.log("Sending header:"); + DEBUG > 2 && hexdump_buffer(mb); + this.ws.send(mb); + }, + + send_ticket: function(ticket) + { + var hdr = new SpiceLinkAuthTicket(); + hdr.auth_mechanism = SPICE_COMMON_CAP_AUTH_SPICE; + // FIXME - we need to implement RSA to make this work right + hdr.encrypted_data = ticket; + var mb = new ArrayBuffer(hdr.buffer_size()); + + hdr.to_buffer(mb); + DEBUG > 1 && console.log("Sending ticket:"); + DEBUG > 2 && hexdump_buffer(mb); + this.ws.send(mb); + }, + + send_msg: function(msg) + { + var mb = new ArrayBuffer(msg.buffer_size()); + msg.to_buffer(mb); + this.messages_sent++; + DEBUG > 0 && console.log(">> hdr " + this.channel_type() + " type " + msg.type + " size " + mb.byteLength); + DEBUG > 2 && hexdump_buffer(mb); + this.ws.send(mb); + }, + + process_inbound: function(mb, saved_header) + { + DEBUG > 2 && console.log(this.type + ": processing message of size " + mb.byteLength + "; state is " + this.state); + if (this.state == "ready") + { + if (saved_header == undefined) + { + var msg = new SpiceMiniData(mb); + + if (msg.type > 500) + { + alert("Something has gone very wrong; we think we have message of type " + msg.type); + debugger; + } + + if (msg.size == 0) + { + this.process_message(msg); + this.wire_reader.request(SpiceMiniData.prototype.buffer_size()); + } + else + { + this.wire_reader.request(msg.size); + this.wire_reader.save_header(msg); + } + } + else + { + saved_header.data = mb; + this.process_message(saved_header); + this.wire_reader.request(SpiceMiniData.prototype.buffer_size()); + this.wire_reader.save_header(undefined); + } + } + + else if (this.state == "start") + { + this.reply_hdr = new SpiceLinkHeader(mb); + if (this.reply_hdr.magic != SPICE_MAGIC) + { + this.state = "error"; + var e = new Error('Error: magic mismatch: ' + this.reply_hdr.magic); + this.report_error(e); + } + else + { + // FIXME - Determine major/minor version requirements + this.wire_reader.request(this.reply_hdr.size); + this.state = "link"; + } + } + + else if (this.state == "link") + { + this.reply_link = new SpiceLinkReply(mb); + // FIXME - Screen the caps - require minihdr at least, right? + if (this.reply_link.error) + { + this.state = "error"; + var e = new Error('Error: reply link error ' + this.reply_link.error); + this.report_error(e); + } + else + { + this.send_ticket(rsa_encrypt(this.reply_link.pub_key, this.password + String.fromCharCode(0))); + this.state = "ticket"; + this.wire_reader.request(SpiceLinkAuthReply.prototype.buffer_size()); + } + } + + else if (this.state == "ticket") + { + this.auth_reply = new SpiceLinkAuthReply(mb); + if (this.auth_reply.auth_code == SPICE_LINK_ERR_OK) + { + DEBUG > 0 && console.log(this.type + ': Connected'); + + if (this.type == SPICE_CHANNEL_DISPLAY) + { + // FIXME - pixmap and glz dictionary config info? + var dinit = new SpiceMsgcDisplayInit(); + var reply = new SpiceMiniData(); + reply.build_msg(SPICE_MSGC_DISPLAY_INIT, dinit); + DEBUG > 0 && console.log("Request display init"); + this.send_msg(reply); + } + this.state = "ready"; + this.wire_reader.request(SpiceMiniData.prototype.buffer_size()); + if (this.timeout) + { + window.clearTimeout(this.timeout); + delete this.timeout; + } + } + else + { + this.state = "error"; + if (this.auth_reply.auth_code == SPICE_LINK_ERR_PERMISSION_DENIED) + { + var e = new Error("Permission denied."); + } + else + { + var e = new Error("Unexpected link error " + this.auth_reply.auth_code); + } + this.report_error(e); + } + } + }, + + process_common_messages : function(msg) + { + if (msg.type == SPICE_MSG_SET_ACK) + { + var ack = new SpiceMsgSetAck(msg.data); + // FIXME - what to do with generation? + this.ack_window = ack.window; + DEBUG > 1 && console.log(this.type + ": set ack to " + ack.window); + this.msgs_until_ack = this.ack_window; + var ackack = new SpiceMsgcAckSync(ack); + var reply = new SpiceMiniData(); + reply.build_msg(SPICE_MSGC_ACK_SYNC, ackack); + this.send_msg(reply); + return true; + } + + if (msg.type == SPICE_MSG_PING) + { + DEBUG > 1 && console.log("ping!"); + var pong = new SpiceMiniData; + pong.type = SPICE_MSGC_PONG; + if (msg.data) + { + pong.data = msg.data.slice(0, 12); + } + pong.size = pong.buffer_size(); + this.send_msg(pong); + return true; + } + + if (msg.type == SPICE_MSG_NOTIFY) + { + // FIXME - Visibility + what + var notify = new SpiceMsgNotify(msg.data); + if (notify.severity == SPICE_NOTIFY_SEVERITY_ERROR) + this.log_err(notify.message); + else if (notify.severity == SPICE_NOTIFY_SEVERITY_WARN ) + this.log_warn(notify.message); + else + this.log_info(notify.message); + return true; + } + + return false; + + }, + + process_message: function(msg) + { + var rc; + DEBUG > 0 && console.log("<< hdr " + this.channel_type() + " type " + msg.type + " size " + (msg.data && msg.data.byteLength)); + rc = this.process_common_messages(msg); + if (! rc) + { + if (this.process_channel_message) + { + rc = this.process_channel_message(msg); + if (! rc) + this.log_warn(this.type + ": Unknown message type " + msg.type + "!"); + } + else + this.log_err(this.type + ": No message handlers for this channel; message " + msg.type); + } + + if (this.msgs_until_ack !== undefined && this.ack_window) + { + this.msgs_until_ack--; + if (this.msgs_until_ack <= 0) + { + this.msgs_until_ack = this.ack_window; + var ack = new SpiceMiniData(); + ack.type = SPICE_MSGC_ACK; + this.send_msg(ack); + DEBUG > 1 && console.log(this.type + ": sent ack"); + } + } + + return rc; + }, + + channel_type: function() + { + if (this.type == SPICE_CHANNEL_MAIN) + return "main"; + else if (this.type == SPICE_CHANNEL_DISPLAY) + return "display"; + else if (this.type == SPICE_CHANNEL_INPUTS) + return "inputs"; + else if (this.type == SPICE_CHANNEL_CURSOR) + return "cursor"; + return "unknown-" + this.type; + + }, + + log_info: function() + { + var msg = Array.prototype.join.call(arguments, " "); + console.log(msg); + if (this.message_id) + { + var p = document.createElement("p"); + p.appendChild(document.createTextNode(msg)); + p.className += "spice-message-info"; + document.getElementById(this.message_id).appendChild(p); + } + }, + + log_warn: function() + { + var msg = Array.prototype.join.call(arguments, " "); + console.log("WARNING: " + msg); + if (this.message_id) + { + var p = document.createElement("p"); + p.appendChild(document.createTextNode(msg)); + p.className += "spice-message-warning"; + document.getElementById(this.message_id).appendChild(p); + } + }, + + log_err: function() + { + var msg = Array.prototype.join.call(arguments, " "); + console.log("ERROR: " + msg); + if (this.message_id) + { + var p = document.createElement("p"); + p.appendChild(document.createTextNode(msg)); + p.className += "spice-message-error"; + document.getElementById(this.message_id).appendChild(p); + } + }, + + known_unimplemented: function(type, msg) + { + if ( (!this.warnings[type]) || DEBUG > 1) + { + var str = ""; + if (DEBUG <= 1) + str = " [ further notices suppressed ]"; + this.log_warn("Unimplemented function " + type + "(" + msg + ")" + str); + this.warnings[type] = true; + } + }, + + report_error: function(e) + { + this.log_err(e.toString()); + if (this.onerror != undefined) + this.onerror(e); + else + throw(e); + }, + + report_success: function(m) + { + if (this.onsuccess != undefined) + this.onsuccess(m); + }, + + cleanup: function() + { + if (this.timeout) + { + window.clearTimeout(this.timeout); + delete this.timeout; + } + if (this.ws) + { + this.ws.close(); + this.ws = undefined; + } + }, + + handle_timeout: function() + { + var e = new Error("Connection timed out."); + this.report_error(e); + }, +} + +function spiceconn_timeout(sc) +{ + SpiceConn.prototype.handle_timeout.call(sc); +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/spicedataview.js b/src/wok/plugins/kimchi/ui/spice-html5/spicedataview.js new file mode 100644 index 0000000..800df03 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/spicedataview.js @@ -0,0 +1,120 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** SpiceDataView +** FIXME FIXME +** This is used because Firefox does not have DataView yet. +** We should use DataView if we have it, because it *has* to +** be faster than this code +**--------------------------------------------------------------------------*/ +function SpiceDataView(buffer, byteOffset, byteLength) +{ + if (byteOffset !== undefined) + { + if (byteLength !== undefined) + this.u8 = new Uint8Array(buffer, byteOffset, byteLength); + else + this.u8 = new Uint8Array(buffer, byteOffset); + } + else + this.u8 = new Uint8Array(buffer); +}; + +SpiceDataView.prototype = { + getUint8: function(byteOffset) + { + return this.u8[byteOffset]; + }, + getUint16: function(byteOffset, littleEndian) + { + var low = 1, high = 0; + if (littleEndian) + { + low = 0; + high = 1; + } + + return (this.u8[byteOffset + high] << 8) | this.u8[byteOffset + low]; + }, + getUint32: function(byteOffset, littleEndian) + { + var low = 2, high = 0; + if (littleEndian) + { + low = 0; + high = 2; + } + + return (this.getUint16(byteOffset + high, littleEndian) << 16) | + this.getUint16(byteOffset + low, littleEndian); + }, + getUint64: function (byteOffset, littleEndian) + { + var low = 4, high = 0; + if (littleEndian) + { + low = 0; + high = 4; + } + + return (this.getUint32(byteOffset + high, littleEndian) << 32) | + this.getUint32(byteOffset + low, littleEndian); + }, + setUint8: function(byteOffset, b) + { + this.u8[byteOffset] = (b & 0xff); + }, + setUint16: function(byteOffset, i, littleEndian) + { + var low = 1, high = 0; + if (littleEndian) + { + low = 0; + high = 1; + } + this.u8[byteOffset + high] = (i & 0xffff) >> 8; + this.u8[byteOffset + low] = (i & 0x00ff); + }, + setUint32: function(byteOffset, w, littleEndian) + { + var low = 2, high = 0; + if (littleEndian) + { + low = 0; + high = 2; + } + + this.setUint16(byteOffset + high, (w & 0xffffffff) >> 16, littleEndian); + this.setUint16(byteOffset + low, (w & 0x0000ffff), littleEndian); + }, + setUint64: function(byteOffset, w, littleEndian) + { + var low = 4, high = 0; + if (littleEndian) + { + low = 0; + high = 4; + } + + this.setUint32(byteOffset + high, (w & 0xffffffffffffffff) >> 32, littleEndian); + this.setUint32(byteOffset + low, (w & 0x00000000ffffffff), littleEndian); + }, +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/spicemsg.js b/src/wok/plugins/kimchi/ui/spice-html5/spicemsg.js new file mode 100644 index 0000000..c64f5a3 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/spicemsg.js @@ -0,0 +1,1047 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** Spice messages +** This file contains classes for passing messages to and from +** a spice server. This file should arguably be generated from +** spice.proto, but it was instead put together by hand. +**--------------------------------------------------------------------------*/ +function SpiceLinkHeader(a, at) +{ + this.magic = SPICE_MAGIC; + this.major_version = SPICE_VERSION_MAJOR; + this.minor_version = SPICE_VERSION_MINOR; + this.size = 0; + if (a !== undefined) + this.from_buffer(a, at); +} + +SpiceLinkHeader.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.magic = ""; + for (var i = 0; i < 4; i++) + this.magic += String.fromCharCode(dv.getUint8(at + i)); + at += 4; + + this.major_version = dv.getUint32(at, true); at += 4; + this.minor_version = dv.getUint32(at, true); at += 4; + this.size = dv.getUint32(at, true); at += 4; + }, + + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + for (var i = 0; i < 4; i++) + dv.setUint8(at + i, this.magic.charCodeAt(i)); + at += 4; + + dv.setUint32(at, this.major_version, true); at += 4; + dv.setUint32(at, this.minor_version, true); at += 4; + dv.setUint32(at, this.size, true); at += 4; + }, + buffer_size: function() + { + return 16; + }, +} + +function SpiceLinkMess(a, at) +{ + this.connection_id = 0; + this.channel_type = 0; + this.channel_id = 0; + this.common_caps = []; + this.channel_caps = []; + + if (a !== undefined) + this.from_buffer(a, at); +} + +SpiceLinkMess.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var i; + var orig_at = at; + var dv = new SpiceDataView(a); + this.connection_id = dv.getUint32(at, true); at += 4; + this.channel_type = dv.getUint8(at, true); at++; + this.channel_id = dv.getUint8(at, true); at++; + var num_common_caps = dv.getUint32(at, true); at += 4; + var num_channel_caps = dv.getUint32(at, true); at += 4; + var caps_offset = dv.getUint32(at, true); at += 4; + + at = orig_at + caps_offset; + this.common_caps = []; + for (i = 0; i < num_common_caps; i++) + { + this.common_caps.unshift(dv.getUint32(at, true)); at += 4; + } + + this.channel_caps = []; + for (i = 0; i < num_channel_caps; i++) + { + this.channel_caps.unshift(dv.getUint32(at, true)); at += 4; + } + }, + + to_buffer: function(a, at) + { + at = at || 0; + var orig_at = at; + var i; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.connection_id, true); at += 4; + dv.setUint8(at, this.channel_type, true); at++; + dv.setUint8(at, this.channel_id, true); at++; + dv.setUint32(at, this.common_caps.length, true); at += 4; + dv.setUint32(at, this.channel_caps.length, true); at += 4; + dv.setUint32(at, (at - orig_at) + 4, true); at += 4; + + for (i = 0; i < this.common_caps.length; i++) + { + dv.setUint32(at, this.common_caps[i], true); at += 4; + } + + for (i = 0; i < this.channel_caps.length; i++) + { + dv.setUint32(at, this.channel_caps[i], true); at += 4; + } + }, + buffer_size: function() + { + return 18 + (4 * this.common_caps.length) + (4 * this.channel_caps.length); + } +} + +function SpiceLinkReply(a, at) +{ + this.error = 0; + this.pub_key = undefined; + this.common_caps = []; + this.channel_caps = []; + + if (a !== undefined) + this.from_buffer(a, at); +} + +SpiceLinkReply.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var i; + var orig_at = at; + var dv = new SpiceDataView(a); + this.error = dv.getUint32(at, true); at += 4; + + this.pub_key = create_rsa_from_mb(a, at); + at += SPICE_TICKET_PUBKEY_BYTES; + + var num_common_caps = dv.getUint32(at, true); at += 4; + var num_channel_caps = dv.getUint32(at, true); at += 4; + var caps_offset = dv.getUint32(at, true); at += 4; + + at = orig_at + caps_offset; + this.common_caps = []; + for (i = 0; i < num_common_caps; i++) + { + this.common_caps.unshift(dv.getUint32(at, true)); at += 4; + } + + this.channel_caps = []; + for (i = 0; i < num_channel_caps; i++) + { + this.channel_caps.unshift(dv.getUint32(at, true)); at += 4; + } + }, +} + +function SpiceLinkAuthTicket(a, at) +{ + this.auth_mechanism = 0; + this.encrypted_data = undefined; +} + +SpiceLinkAuthTicket.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var i; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.auth_mechanism, true); at += 4; + for (i = 0; i < SPICE_TICKET_KEY_PAIR_LENGTH / 8; i++) + { + if (this.encrypted_data && i < this.encrypted_data.length) + dv.setUint8(at, this.encrypted_data[i], true); + else + dv.setUint8(at, 0, true); + at++; + } + }, + buffer_size: function() + { + return 4 + (SPICE_TICKET_KEY_PAIR_LENGTH / 8); + } +} + +function SpiceLinkAuthReply(a, at) +{ + this.auth_code = 0; + if (a !== undefined) + this.from_buffer(a, at); +} + +SpiceLinkAuthReply.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.auth_code = dv.getUint32(at, true); at += 4; + }, + buffer_size: function() + { + return 4; + } +} + +function SpiceMiniData(a, at) +{ + this.type = 0; + this.size = 0; + this.data = undefined; + if (a !== undefined) + this.from_buffer(a, at); +} + +SpiceMiniData.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var i; + var dv = new SpiceDataView(a); + this.type = dv.getUint16(at, true); at += 2; + this.size = dv.getUint32(at, true); at += 4; + if (a.byteLength > at) + { + this.data = a.slice(at); + at += this.data.byteLength; + } + }, + to_buffer : function(a, at) + { + at = at || 0; + var i; + var dv = new SpiceDataView(a); + dv.setUint16(at, this.type, true); at += 2; + dv.setUint32(at, this.data ? this.data.byteLength : 0, true); at += 4; + if (this.data && this.data.byteLength > 0) + { + var u8arr = new Uint8Array(this.data); + for (i = 0; i < u8arr.length; i++, at++) + dv.setUint8(at, u8arr[i], true); + } + }, + build_msg : function(in_type, extra) + { + this.type = in_type; + this.size = extra.buffer_size(); + this.data = new ArrayBuffer(this.size); + extra.to_buffer(this.data); + }, + buffer_size: function() + { + if (this.data) + return 6 + this.data.byteLength; + else + return 6; + }, +} + +function SpiceMsgChannels(a, at) +{ + this.num_of_channels = 0; + this.channels = []; + if (a !== undefined) + this.from_buffer(a, at); +} + +SpiceMsgChannels.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var i; + var dv = new SpiceDataView(a); + this.num_of_channels = dv.getUint32(at, true); at += 4; + for (i = 0; i < this.num_of_channels; i++) + { + var chan = new SpiceChannelId(); + at = chan.from_dv(dv, at, a); + this.channels.push(chan); + } + }, +} + +function SpiceMsgMainInit(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgMainInit.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.session_id = dv.getUint32(at, true); at += 4; + this.display_channels_hint = dv.getUint32(at, true); at += 4; + this.supported_mouse_modes = dv.getUint32(at, true); at += 4; + this.current_mouse_mode = dv.getUint32(at, true); at += 4; + this.agent_connected = dv.getUint32(at, true); at += 4; + this.agent_tokens = dv.getUint32(at, true); at += 4; + this.multi_media_time = dv.getUint32(at, true); at += 4; + this.ram_hint = dv.getUint32(at, true); at += 4; + }, +} + +function SpiceMsgMainMouseMode(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgMainMouseMode.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.supported_modes = dv.getUint16(at, true); at += 2; + this.current_mode = dv.getUint16(at, true); at += 2; + }, +} + +function SpiceMsgSetAck(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgSetAck.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.generation = dv.getUint32(at, true); at += 4; + this.window = dv.getUint32(at, true); at += 4; + }, +} + +function SpiceMsgcAckSync(ack) +{ + this.generation = ack.generation; +} + +SpiceMsgcAckSync.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.generation, true); at += 4; + }, + buffer_size: function() + { + return 4; + } +} + +function SpiceMsgcMainMouseModeRequest(mode) +{ + this.mode = mode; +} + +SpiceMsgcMainMouseModeRequest.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint16(at, this.mode, true); at += 2; + }, + buffer_size: function() + { + return 2; + } +} + +function SpiceMsgcMainAgentStart(num_tokens) +{ + this.num_tokens = num_tokens; +} + +SpiceMsgcMainAgentStart.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.num_tokens, true); at += 4; + }, + buffer_size: function() + { + return 4; + } +} + +function SpiceMsgcMainAgentData(type, data) +{ + this.protocol = VD_AGENT_PROTOCOL; + this.type = type; + this.opaque = 0; + this.size = data.buffer_size(); + this.data = data; +} + +SpiceMsgcMainAgentData.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.protocol, true); at += 4; + dv.setUint32(at, this.type, true); at += 4; + dv.setUint64(at, this.opaque, true); at += 8; + dv.setUint32(at, this.size, true); at += 4; + this.data.to_buffer(a, at); + }, + buffer_size: function() + { + return 4 + 4 + 8 + 4 + this.data.buffer_size(); + } +} + +function VDAgentMonitorsConfig(flags, width, height, depth, x, y) +{ + this.num_mon = 1; + this.flags = flags; + this.width = width; + this.height = height; + this.depth = depth; + this.x = x; + this.y = y; +} + +VDAgentMonitorsConfig.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.num_mon, true); at += 4; + dv.setUint32(at, this.flags, true); at += 4; + dv.setUint32(at, this.height, true); at += 4; + dv.setUint32(at, this.width, true); at += 4; + dv.setUint32(at, this.depth, true); at += 4; + dv.setUint32(at, this.x, true); at += 4; + dv.setUint32(at, this.y, true); at += 4; + }, + buffer_size: function() + { + return 28; + } +} + +function SpiceMsgNotify(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgNotify.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var i; + var dv = new SpiceDataView(a); + this.time_stamp = dv.getUint64(at, true); at += 8; + this.severity = dv.getUint32(at, true); at += 4; + this.visibility = dv.getUint32(at, true); at += 4; + this.what = dv.getUint32(at, true); at += 4; + this.message_len = dv.getUint32(at, true); at += 4; + this.message = ""; + for (i = 0; i < this.message_len; i++) + { + var c = dv.getUint8(at, true); at++; + this.message += String.fromCharCode(c); + } + }, +} + +function SpiceMsgcDisplayInit() +{ + this.pixmap_cache_id = 1; + this.glz_dictionary_id = 0; + this.pixmap_cache_size = 10 * 1024 * 1024; + this.glz_dictionary_window_size = 0; +} + +SpiceMsgcDisplayInit.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint8(at, this.pixmap_cache_id, true); at++; + dv.setUint64(at, this.pixmap_cache_size, true); at += 8; + dv.setUint8(at, this.glz_dictionary_id, true); at++; + dv.setUint32(at, this.glz_dictionary_window_size, true); at += 4; + }, + buffer_size: function() + { + return 14; + } +} + +function SpiceMsgDisplayBase() +{ +} + +SpiceMsgDisplayBase.prototype = +{ + from_dv : function(dv, at, mb) + { + this.surface_id = dv.getUint32(at, true); at += 4; + this.box = new SpiceRect; + at = this.box.from_dv(dv, at, mb); + this.clip = new SpiceClip; + return this.clip.from_dv(dv, at, mb); + }, +} + +function SpiceMsgDisplayDrawCopy(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgDisplayDrawCopy.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.base = new SpiceMsgDisplayBase; + at = this.base.from_dv(dv, at, a); + this.data = new SpiceCopy; + return this.data.from_dv(dv, at, a); + }, +} + +function SpiceMsgDisplayDrawFill(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgDisplayDrawFill.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.base = new SpiceMsgDisplayBase; + at = this.base.from_dv(dv, at, a); + this.data = new SpiceFill; + return this.data.from_dv(dv, at, a); + }, +} + +function SpiceMsgDisplayCopyBits(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgDisplayCopyBits.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.base = new SpiceMsgDisplayBase; + at = this.base.from_dv(dv, at, a); + this.src_pos = new SpicePoint; + return this.src_pos.from_dv(dv, at, a); + }, +} + + +function SpiceMsgSurfaceCreate(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgSurfaceCreate.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.surface = new SpiceSurface; + return this.surface.from_dv(dv, at, a); + }, +} + +function SpiceMsgSurfaceDestroy(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgSurfaceDestroy.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.surface_id = dv.getUint32(at, true); at += 4; + }, +} + +function SpiceMsgInputsInit(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgInputsInit.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.keyboard_modifiers = dv.getUint16(at, true); at += 2; + return at; + }, +} + +function SpiceMsgInputsKeyModifiers(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgInputsKeyModifiers.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.keyboard_modifiers = dv.getUint16(at, true); at += 2; + return at; + }, +} + +function SpiceMsgCursorInit(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgCursorInit.prototype = +{ + from_buffer: function(a, at, mb) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.position = new SpicePoint16; + at = this.position.from_dv(dv, at, mb); + this.trail_length = dv.getUint16(at, true); at += 2; + this.trail_frequency = dv.getUint16(at, true); at += 2; + this.visible = dv.getUint8(at, true); at ++; + this.cursor = new SpiceCursor; + return this.cursor.from_dv(dv, at, a); + }, +} + +function SpiceMsgPlaybackData(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgPlaybackData.prototype = +{ + from_buffer: function(a, at, mb) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.time = dv.getUint32(at, true); at += 4; + if (a.byteLength > at) + { + this.data = a.slice(at); + at += this.data.byteLength; + } + return at; + }, +} + +function SpiceMsgPlaybackMode(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgPlaybackMode.prototype = +{ + from_buffer: function(a, at, mb) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.time = dv.getUint32(at, true); at += 4; + this.mode = dv.getUint16(at, true); at += 2; + if (a.byteLength > at) + { + this.data = a.slice(at); + at += this.data.byteLength; + } + return at; + }, +} + +function SpiceMsgPlaybackStart(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgPlaybackStart.prototype = +{ + from_buffer: function(a, at, mb) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.channels = dv.getUint32(at, true); at += 4; + this.format = dv.getUint16(at, true); at += 2; + this.frequency = dv.getUint32(at, true); at += 4; + this.time = dv.getUint32(at, true); at += 4; + return at; + }, +} + + + +function SpiceMsgCursorSet(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgCursorSet.prototype = +{ + from_buffer: function(a, at, mb) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.position = new SpicePoint16; + at = this.position.from_dv(dv, at, mb); + this.visible = dv.getUint8(at, true); at ++; + this.cursor = new SpiceCursor; + return this.cursor.from_dv(dv, at, a); + }, +} + + +function SpiceMsgcMousePosition(sc, e) +{ + // FIXME - figure out how to correctly compute display_id + this.display_id = 0; + this.buttons_state = sc.buttons_state; + if (e) + { + var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; + var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft; + + this.x = e.clientX - sc.display.surfaces[sc.display.primary_surface].canvas.offsetLeft + scrollLeft; + this.y = e.clientY - sc.display.surfaces[sc.display.primary_surface].canvas.offsetTop + scrollTop; + sc.mousex = this.x; + sc.mousey = this.y; + } + else + { + this.x = this.y = this.buttons_state = 0; + } +} + +SpiceMsgcMousePosition.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.x, true); at += 4; + dv.setUint32(at, this.y, true); at += 4; + dv.setUint16(at, this.buttons_state, true); at += 2; + dv.setUint8(at, this.display_id, true); at += 1; + return at; + }, + buffer_size: function() + { + return 11; + } +} + +function SpiceMsgcMouseMotion(sc, e) +{ + // FIXME - figure out how to correctly compute display_id + this.display_id = 0; + this.buttons_state = sc.buttons_state; + if (e) + { + this.x = e.clientX - sc.display.surfaces[sc.display.primary_surface].canvas.offsetLeft; + this.y = e.clientY - sc.display.surfaces[sc.display.primary_surface].canvas.offsetTop; + + if (sc.mousex !== undefined) + { + this.x -= sc.mousex; + this.y -= sc.mousey; + } + sc.mousex = e.clientX - sc.display.surfaces[sc.display.primary_surface].canvas.offsetLeft; + sc.mousey = e.clientY - sc.display.surfaces[sc.display.primary_surface].canvas.offsetTop; + } + else + { + this.x = this.y = this.buttons_state = 0; + } +} + +/* Use the same functions as for MousePosition */ +SpiceMsgcMouseMotion.prototype.to_buffer = SpiceMsgcMousePosition.prototype.to_buffer; +SpiceMsgcMouseMotion.prototype.buffer_size = SpiceMsgcMousePosition.prototype.buffer_size; + +function SpiceMsgcMousePress(sc, e) +{ + if (e) + { + this.button = e.button + 1; + this.buttons_state = 1 << e.button; + sc.buttons_state = this.buttons_state; + } + else + { + this.button = SPICE_MOUSE_BUTTON_LEFT; + this.buttons_state = SPICE_MOUSE_BUTTON_MASK_LEFT; + } +} + +SpiceMsgcMousePress.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint8(at, this.button, true); at ++; + dv.setUint16(at, this.buttons_state, true); at += 2; + return at; + }, + buffer_size: function() + { + return 3; + } +} + +function SpiceMsgcMouseRelease(sc, e) +{ + if (e) + { + this.button = e.button + 1; + this.buttons_state = 0; + sc.buttons_state = this.buttons_state; + } + else + { + this.button = SPICE_MOUSE_BUTTON_LEFT; + this.buttons_state = 0; + } +} + +/* Use the same functions as for MousePress */ +SpiceMsgcMouseRelease.prototype.to_buffer = SpiceMsgcMousePress.prototype.to_buffer; +SpiceMsgcMouseRelease.prototype.buffer_size = SpiceMsgcMousePress.prototype.buffer_size; + + +function SpiceMsgcKeyDown(e) +{ + if (e) + { + this.code = keycode_to_start_scan(e.keyCode); + } + else + { + this.code = 0; + } +} + +SpiceMsgcKeyDown.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.code, true); at += 4; + return at; + }, + buffer_size: function() + { + return 4; + } +} + +function SpiceMsgcKeyUp(e) +{ + if (e) + { + this.code = keycode_to_end_scan(e.keyCode); + } + else + { + this.code = 0; + } +} + +/* Use the same functions as for KeyDown */ +SpiceMsgcKeyUp.prototype.to_buffer = SpiceMsgcKeyDown.prototype.to_buffer; +SpiceMsgcKeyUp.prototype.buffer_size = SpiceMsgcKeyDown.prototype.buffer_size; + +function SpiceMsgDisplayStreamCreate(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgDisplayStreamCreate.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.surface_id = dv.getUint32(at, true); at += 4; + this.id = dv.getUint32(at, true); at += 4; + this.flags = dv.getUint8(at, true); at += 1; + this.codec_type = dv.getUint8(at, true); at += 1; + this.stamp = dv.getUint64(at, true); at += 8; + this.stream_width = dv.getUint32(at, true); at += 4; + this.stream_height = dv.getUint32(at, true); at += 4; + this.src_width = dv.getUint32(at, true); at += 4; + this.src_height = dv.getUint32(at, true); at += 4; + + this.dest = new SpiceRect; + at = this.dest.from_dv(dv, at, a); + this.clip = new SpiceClip; + this.clip.from_dv(dv, at, a); + }, +} + +function SpiceStreamDataHeader(a, at) +{ +} + +SpiceStreamDataHeader.prototype = +{ + from_dv : function(dv, at, mb) + { + this.id = dv.getUint32(at, true); at += 4; + this.multi_media_time = dv.getUint32(at, true); at += 4; + return at; + }, +} + +function SpiceMsgDisplayStreamData(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgDisplayStreamData.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.base = new SpiceStreamDataHeader; + at = this.base.from_dv(dv, at, a); + this.data_size = dv.getUint32(at, true); at += 4; + this.data = dv.u8.subarray(at, at + this.data_size); + }, +} + +function SpiceMsgDisplayStreamClip(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgDisplayStreamClip.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.id = dv.getUint32(at, true); at += 4; + this.clip = new SpiceClip; + this.clip.from_dv(dv, at, a); + }, +} + +function SpiceMsgDisplayStreamDestroy(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgDisplayStreamDestroy.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.id = dv.getUint32(at, true); at += 4; + }, +} + +function SpiceMsgDisplayInvalList(a, at) +{ + this.count = 0; + this.resources = []; + this.from_buffer(a,at); +} + +SpiceMsgDisplayInvalList.prototype = +{ + from_buffer: function (a, at) + { + var i; + at = at || 0; + var dv = new SpiceDataView(a); + this.count = dv.getUint16(at, true); at += 2; + for (i = 0; i < this.count; i++) + { + this.resources[i] = {}; + this.resources[i].type = dv.getUint8(at, true); at++; + this.resources[i].id = dv.getUint64(at, true); at += 8; + } + }, +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/spicetype.js b/src/wok/plugins/kimchi/ui/spice-html5/spicetype.js new file mode 100644 index 0000000..951b277 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/spicetype.js @@ -0,0 +1,473 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** Spice types +** This file contains classes for common spice types. +** Generally, they are used as helpers in reading and writing messages +** to and from the server. +**--------------------------------------------------------------------------*/ + +function SpiceChannelId() +{ +} +SpiceChannelId.prototype = +{ + from_dv: function(dv, at, mb) + { + this.type = dv.getUint8(at, true); at ++; + this.id = dv.getUint8(at, true); at ++; + return at; + }, +} + +function SpiceRect() +{ +} + +SpiceRect.prototype = +{ + from_dv: function(dv, at, mb) + { + this.top = dv.getUint32(at, true); at += 4; + this.left = dv.getUint32(at, true); at += 4; + this.bottom = dv.getUint32(at, true); at += 4; + this.right = dv.getUint32(at, true); at += 4; + return at; + }, + is_same_size : function(r) + { + if ((this.bottom - this.top) == (r.bottom - r.top) && + (this.right - this.left) == (r.right - r.left) ) + return true; + + return false; + }, +} + +function SpiceClipRects() +{ +} + +SpiceClipRects.prototype = +{ + from_dv: function(dv, at, mb) + { + var i; + this.num_rects = dv.getUint32(at, true); at += 4; + if (this.num_rects > 0) + this.rects = []; + for (i = 0; i < this.num_rects; i++) + { + this.rects[i] = new SpiceRect(); + at = this.rects[i].from_dv(dv, at, mb); + } + return at; + }, +} + +function SpiceClip() +{ +} + +SpiceClip.prototype = +{ + from_dv: function(dv, at, mb) + { + this.type = dv.getUint8(at, true); at ++; + if (this.type == SPICE_CLIP_TYPE_RECTS) + { + this.rects = new SpiceClipRects(); + at = this.rects.from_dv(dv, at, mb); + } + return at; + }, +} + +function SpiceImageDescriptor() +{ +} + +SpiceImageDescriptor.prototype = +{ + from_dv: function(dv, at, mb) + { + this.id = dv.getUint64(at, true); at += 8; + this.type = dv.getUint8(at, true); at ++; + this.flags = dv.getUint8(at, true); at ++; + this.width = dv.getUint32(at, true); at += 4; + this.height= dv.getUint32(at, true); at += 4; + return at; + }, +} + +function SpicePalette() +{ +} + +SpicePalette.prototype = +{ + from_dv: function(dv, at, mb) + { + var i; + this.unique = dv.getUint64(at, true); at += 8; + this.num_ents = dv.getUint16(at, true); at += 2; + this.ents = []; + for (i = 0; i < this.num_ents; i++) + { + this.ents[i] = dv.getUint32(at, true); at += 4; + } + return at; + }, +} + +function SpiceBitmap() +{ +} + +SpiceBitmap.prototype = +{ + from_dv: function(dv, at, mb) + { + this.format = dv.getUint8(at, true); at++; + this.flags = dv.getUint8(at, true); at++; + this.x = dv.getUint32(at, true); at += 4; + this.y = dv.getUint32(at, true); at += 4; + this.stride = dv.getUint32(at, true); at += 4; + if (this.flags & SPICE_BITMAP_FLAGS_PAL_FROM_CACHE) + { + this.palette_id = dv.getUint64(at, true); at += 8; + } + else + { + var offset = dv.getUint32(at, true); at += 4; + if (offset == 0) + this.palette = null; + else + { + this.palette = new SpicePalette; + this.palette.from_dv(dv, offset, mb); + } + } + // FIXME - should probably constrain this to the offset + // of palette, if non zero + this.data = mb.slice(at); + at += this.data.byteLength; + return at; + }, +} + +function SpiceImage() +{ +} + +SpiceImage.prototype = +{ + from_dv: function(dv, at, mb) + { + this.descriptor = new SpiceImageDescriptor; + at = this.descriptor.from_dv(dv, at, mb); + + if (this.descriptor.type == SPICE_IMAGE_TYPE_LZ_RGB) + { + this.lz_rgb = new Object(); + this.lz_rgb.length = dv.getUint32(at, true); at += 4; + var initial_at = at; + this.lz_rgb.magic = ""; + for (var i = 3; i >= 0; i--) + this.lz_rgb.magic += String.fromCharCode(dv.getUint8(at + i)); + at += 4; + + // NOTE: The endian change is *correct* + this.lz_rgb.version = dv.getUint32(at); at += 4; + this.lz_rgb.type = dv.getUint32(at); at += 4; + this.lz_rgb.width = dv.getUint32(at); at += 4; + this.lz_rgb.height = dv.getUint32(at); at += 4; + this.lz_rgb.stride = dv.getUint32(at); at += 4; + this.lz_rgb.top_down = dv.getUint32(at); at += 4; + + var header_size = at - initial_at; + + this.lz_rgb.data = mb.slice(at, this.lz_rgb.length + at - header_size); + at += this.lz_rgb.data.byteLength; + + } + + if (this.descriptor.type == SPICE_IMAGE_TYPE_BITMAP) + { + this.bitmap = new SpiceBitmap; + at = this.bitmap.from_dv(dv, at, mb); + } + + if (this.descriptor.type == SPICE_IMAGE_TYPE_SURFACE) + { + this.surface_id = dv.getUint32(at, true); at += 4; + } + + if (this.descriptor.type == SPICE_IMAGE_TYPE_JPEG) + { + this.jpeg = new Object; + this.jpeg.data_size = dv.getUint32(at, true); at += 4; + this.jpeg.data = mb.slice(at); + at += this.jpeg.data.byteLength; + } + + if (this.descriptor.type == SPICE_IMAGE_TYPE_JPEG_ALPHA) + { + this.jpeg_alpha = new Object; + this.jpeg_alpha.flags = dv.getUint8(at, true); at += 1; + this.jpeg_alpha.jpeg_size = dv.getUint32(at, true); at += 4; + this.jpeg_alpha.data_size = dv.getUint32(at, true); at += 4; + this.jpeg_alpha.data = mb.slice(at, this.jpeg_alpha.jpeg_size + at); + at += this.jpeg_alpha.data.byteLength; + // Alpha channel is an LZ image + this.jpeg_alpha.alpha = new Object(); + this.jpeg_alpha.alpha.length = this.jpeg_alpha.data_size - this.jpeg_alpha.jpeg_size; + var initial_at = at; + this.jpeg_alpha.alpha.magic = ""; + for (var i = 3; i >= 0; i--) + this.jpeg_alpha.alpha.magic += String.fromCharCode(dv.getUint8(at + i)); + at += 4; + + // NOTE: The endian change is *correct* + this.jpeg_alpha.alpha.version = dv.getUint32(at); at += 4; + this.jpeg_alpha.alpha.type = dv.getUint32(at); at += 4; + this.jpeg_alpha.alpha.width = dv.getUint32(at); at += 4; + this.jpeg_alpha.alpha.height = dv.getUint32(at); at += 4; + this.jpeg_alpha.alpha.stride = dv.getUint32(at); at += 4; + this.jpeg_alpha.alpha.top_down = dv.getUint32(at); at += 4; + + var header_size = at - initial_at; + + this.jpeg_alpha.alpha.data = mb.slice(at, this.jpeg_alpha.alpha.length + at - header_size); + at += this.jpeg_alpha.alpha.data.byteLength; + } + + if (this.descriptor.type == SPICE_IMAGE_TYPE_QUIC) + { + this.quic = new SpiceQuic; + at = this.quic.from_dv(dv, at, mb); + } + return at; + }, +} + + +function SpiceQMask() +{ +} + +SpiceQMask.prototype = +{ + from_dv: function(dv, at, mb) + { + this.flags = dv.getUint8(at, true); at++; + this.pos = new SpicePoint; + at = this.pos.from_dv(dv, at, mb); + var offset = dv.getUint32(at, true); at += 4; + if (offset == 0) + { + this.bitmap = null; + return at; + } + + this.bitmap = new SpiceImage; + return this.bitmap.from_dv(dv, offset, mb); + }, +} + + +function SpicePattern() +{ +} + +SpicePattern.prototype = +{ + from_dv: function(dv, at, mb) + { + var offset = dv.getUint32(at, true); at += 4; + if (offset == 0) + { + this.pat = null; + } + else + { + this.pat = new SpiceImage; + this.pat.from_dv(dv, offset, mb); + } + + this.pos = new SpicePoint; + return this.pos.from_dv(dv, at, mb); + } +} + +function SpiceBrush() +{ +} + +SpiceBrush.prototype = +{ + from_dv: function(dv, at, mb) + { + this.type = dv.getUint8(at, true); at ++; + if (this.type == SPICE_BRUSH_TYPE_SOLID) + { + this.color = dv.getUint32(at, true); at += 4; + } + else if (this.type == SPICE_BRUSH_TYPE_PATTERN) + { + this.pattern = new SpicePattern; + at = this.pattern.from_dv(dv, at, mb); + } + return at; + }, +} + +function SpiceFill() +{ +} + +SpiceFill.prototype = +{ + from_dv: function(dv, at, mb) + { + this.brush = new SpiceBrush; + at = this.brush.from_dv(dv, at, mb); + this.rop_descriptor = dv.getUint16(at, true); at += 2; + this.mask = new SpiceQMask; + return this.mask.from_dv(dv, at, mb); + }, +} + + +function SpiceCopy() +{ +} + +SpiceCopy.prototype = +{ + from_dv: function(dv, at, mb) + { + var offset = dv.getUint32(at, true); at += 4; + if (offset == 0) + { + this.src_bitmap = null; + } + else + { + this.src_bitmap = new SpiceImage; + this.src_bitmap.from_dv(dv, offset, mb); + } + this.src_area = new SpiceRect; + at = this.src_area.from_dv(dv, at, mb); + this.rop_descriptor = dv.getUint16(at, true); at += 2; + this.scale_mode = dv.getUint8(at, true); at ++; + this.mask = new SpiceQMask; + return this.mask.from_dv(dv, at, mb); + }, +} + +function SpicePoint16() +{ +} + +SpicePoint16.prototype = +{ + from_dv: function(dv, at, mb) + { + this.x = dv.getUint16(at, true); at += 2; + this.y = dv.getUint16(at, true); at += 2; + return at; + }, +} + +function SpicePoint() +{ +} + +SpicePoint.prototype = +{ + from_dv: function(dv, at, mb) + { + this.x = dv.getUint32(at, true); at += 4; + this.y = dv.getUint32(at, true); at += 4; + return at; + }, +} + +function SpiceCursorHeader() +{ +} + +SpiceCursorHeader.prototype = +{ + from_dv: function(dv, at, mb) + { + this.unique = dv.getUint64(at, true); at += 8; + this.type = dv.getUint8(at, true); at ++; + this.width = dv.getUint16(at, true); at += 2; + this.height = dv.getUint16(at, true); at += 2; + this.hot_spot_x = dv.getUint16(at, true); at += 2; + this.hot_spot_y = dv.getUint16(at, true); at += 2; + return at; + }, +} + +function SpiceCursor() +{ +} + +SpiceCursor.prototype = +{ + from_dv: function(dv, at, mb) + { + this.flags = dv.getUint16(at, true); at += 2; + if (this.flags & SPICE_CURSOR_FLAGS_NONE) + this.header = null; + else + { + this.header = new SpiceCursorHeader; + at = this.header.from_dv(dv, at, mb); + this.data = mb.slice(at); + at += this.data.byteLength; + } + return at; + }, +} + +function SpiceSurface() +{ +} + +SpiceSurface.prototype = +{ + from_dv: function(dv, at, mb) + { + this.surface_id = dv.getUint32(at, true); at += 4; + this.width = dv.getUint32(at, true); at += 4; + this.height = dv.getUint32(at, true); at += 4; + this.format = dv.getUint32(at, true); at += 4; + this.flags = dv.getUint32(at, true); at += 4; + return at; + }, +} + +/* FIXME - SpiceImage types lz_plt, jpeg, zlib_glz, and jpeg_alpha are + completely unimplemented */ diff --git a/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/Makefile.am b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/Makefile.am new file mode 100644 index 0000000..474478d --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/Makefile.am @@ -0,0 +1,20 @@ +# +# Kimchi +# +# Copyright IBM, Corp. 2014 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +thirdpartydir = $(datadir)/wok/plugins/kimchi/ui/spice-html5/thirdparty + +dist_thirdparty_DATA = $(wildcard *.js) $(NULL) diff --git a/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js new file mode 100644 index 0000000..9b9476e --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/jsbn.js @@ -0,0 +1,589 @@ +// Downloaded from http://www-cs-students.stanford.edu/~tjw/jsbn/ by Jeremy White on 6/1/2012 + +/* + * Copyright (c) 2003-2005 Tom Wu + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + + +// Basic JavaScript BN library - subset useful for RSA encryption. + +// Bits per digit +var dbits; + +// JavaScript engine analysis +var canary = 0xdeadbeefcafe; +var j_lm = ((canary&0xffffff)==0xefcafe); + +// (public) Constructor +function BigInteger(a,b,c) { + if(a != null) + if("number" == typeof a) this.fromNumber(a,b,c); + else if(b == null && "string" != typeof a) this.fromString(a,256); + else this.fromString(a,b); +} + +// return new, unset BigInteger +function nbi() { return new BigInteger(null); } + +// am: Compute w_j += (x*this_i), propagate carries, +// c is initial carry, returns final carry. +// c < 3*dvalue, x < 2*dvalue, this_i < dvalue +// We need to select the fastest one that works in this environment. + +// am1: use a single mult and divide to get the high bits, +// max digit bits should be 26 because +// max internal value = 2*dvalue^2-2*dvalue (< 2^53) +function am1(i,x,w,j,c,n) { + while(--n >= 0) { + var v = x*this[i++]+w[j]+c; + c = Math.floor(v/0x4000000); + w[j++] = v&0x3ffffff; + } + return c; +} +// am2 avoids a big mult-and-extract completely. +// Max digit bits should be <= 30 because we do bitwise ops +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) +function am2(i,x,w,j,c,n) { + var xl = x&0x7fff, xh = x>>15; + while(--n >= 0) { + var l = this[i]&0x7fff; + var h = this[i++]>>15; + var m = xh*l+h*xl; + l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff); + c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); + w[j++] = l&0x3fffffff; + } + return c; +} +// Alternately, set max digit bits to 28 since some +// browsers slow down when dealing with 32-bit numbers. +function am3(i,x,w,j,c,n) { + var xl = x&0x3fff, xh = x>>14; + while(--n >= 0) { + var l = this[i]&0x3fff; + var h = this[i++]>>14; + var m = xh*l+h*xl; + l = xl*l+((m&0x3fff)<<14)+w[j]+c; + c = (l>>28)+(m>>14)+xh*h; + w[j++] = l&0xfffffff; + } + return c; +} +if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) { + BigInteger.prototype.am = am2; + dbits = 30; +} +else if(j_lm && (navigator.appName != "Netscape")) { + BigInteger.prototype.am = am1; + dbits = 26; +} +else { // Mozilla/Netscape seems to prefer am3 + BigInteger.prototype.am = am3; + dbits = 28; +} + +BigInteger.prototype.DB = dbits; +BigInteger.prototype.DM = ((1<<dbits)-1); +BigInteger.prototype.DV = (1<<dbits); + +var BI_FP = 52; +BigInteger.prototype.FV = Math.pow(2,BI_FP); +BigInteger.prototype.F1 = BI_FP-dbits; +BigInteger.prototype.F2 = 2*dbits-BI_FP; + +// Digit conversions +var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; +var BI_RC = new Array(); +var rr,vv; +rr = "0".charCodeAt(0); +for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv; +rr = "a".charCodeAt(0); +for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; +rr = "A".charCodeAt(0); +for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; + +function int2char(n) { return BI_RM.charAt(n); } +function intAt(s,i) { + var c = BI_RC[s.charCodeAt(i)]; + return (c==null)?-1:c; +} + +// (protected) copy this to r +function bnpCopyTo(r) { + for(var i = this.t-1; i >= 0; --i) r[i] = this[i]; + r.t = this.t; + r.s = this.s; +} + +// (protected) set from integer value x, -DV <= x < DV +function bnpFromInt(x) { + this.t = 1; + this.s = (x<0)?-1:0; + if(x > 0) this[0] = x; + else if(x < -1) this[0] = x+DV; + else this.t = 0; +} + +// return bigint initialized to value +function nbv(i) { var r = nbi(); r.fromInt(i); return r; } + +// (protected) set from string and radix +function bnpFromString(s,b) { + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 256) k = 8; // byte array + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else { this.fromRadix(s,b); return; } + this.t = 0; + this.s = 0; + var i = s.length, mi = false, sh = 0; + while(--i >= 0) { + var x = (k==8)?s[i]&0xff:intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if(sh == 0) + this[this.t++] = x; + else if(sh+k > this.DB) { + this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh; + this[this.t++] = (x>>(this.DB-sh)); + } + else + this[this.t-1] |= x<<sh; + sh += k; + if(sh >= this.DB) sh -= this.DB; + } + if(k == 8 && (s[0]&0x80) != 0) { + this.s = -1; + if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh; + } + this.clamp(); + if(mi) BigInteger.ZERO.subTo(this,this); +} + +// (protected) clamp off excess high words +function bnpClamp() { + var c = this.s&this.DM; + while(this.t > 0 && this[this.t-1] == c) --this.t; +} + +// (public) return string representation in given radix +function bnToString(b) { + if(this.s < 0) return "-"+this.negate().toString(b); + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else return this.toRadix(b); + var km = (1<<k)-1, d, m = false, r = "", i = this.t; + var p = this.DB-(i*this.DB)%k; + if(i-- > 0) { + if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); } + while(i >= 0) { + if(p < k) { + d = (this[i]&((1<<p)-1))<<(k-p); + d |= this[--i]>>(p+=this.DB-k); + } + else { + d = (this[i]>>(p-=k))&km; + if(p <= 0) { p += this.DB; --i; } + } + if(d > 0) m = true; + if(m) r += int2char(d); + } + } + return m?r:"0"; +} + +// (public) -this +function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } + +// (public) |this| +function bnAbs() { return (this.s<0)?this.negate():this; } + +// (public) return + if this > a, - if this < a, 0 if equal +function bnCompareTo(a) { + var r = this.s-a.s; + if(r != 0) return r; + var i = this.t; + r = i-a.t; + if(r != 0) return r; + while(--i >= 0) if((r=this[i]-a[i]) != 0) return r; + return 0; +} + +// returns bit length of the integer x +function nbits(x) { + var r = 1, t; + if((t=x>>>16) != 0) { x = t; r += 16; } + if((t=x>>8) != 0) { x = t; r += 8; } + if((t=x>>4) != 0) { x = t; r += 4; } + if((t=x>>2) != 0) { x = t; r += 2; } + if((t=x>>1) != 0) { x = t; r += 1; } + return r; +} + +// (public) return the number of bits in "this" +function bnBitLength() { + if(this.t <= 0) return 0; + return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM)); +} + +// (protected) r = this << n*DB +function bnpDLShiftTo(n,r) { + var i; + for(i = this.t-1; i >= 0; --i) r[i+n] = this[i]; + for(i = n-1; i >= 0; --i) r[i] = 0; + r.t = this.t+n; + r.s = this.s; +} + +// (protected) r = this >> n*DB +function bnpDRShiftTo(n,r) { + for(var i = n; i < this.t; ++i) r[i-n] = this[i]; + r.t = Math.max(this.t-n,0); + r.s = this.s; +} + +// (protected) r = this << n +function bnpLShiftTo(n,r) { + var bs = n%this.DB; + var cbs = this.DB-bs; + var bm = (1<<cbs)-1; + var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i; + for(i = this.t-1; i >= 0; --i) { + r[i+ds+1] = (this[i]>>cbs)|c; + c = (this[i]&bm)<<bs; + } + for(i = ds-1; i >= 0; --i) r[i] = 0; + r[ds] = c; + r.t = this.t+ds+1; + r.s = this.s; + r.clamp(); +} + +// (protected) r = this >> n +function bnpRShiftTo(n,r) { + r.s = this.s; + var ds = Math.floor(n/this.DB); + if(ds >= this.t) { r.t = 0; return; } + var bs = n%this.DB; + var cbs = this.DB-bs; + var bm = (1<<bs)-1; + r[0] = this[ds]>>bs; + for(var i = ds+1; i < this.t; ++i) { + r[i-ds-1] |= (this[i]&bm)<<cbs; + r[i-ds] = this[i]>>bs; + } + if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs; + r.t = this.t-ds; + r.clamp(); +} + +// (protected) r = this - a +function bnpSubTo(a,r) { + var i = 0, c = 0, m = Math.min(a.t,this.t); + while(i < m) { + c += this[i]-a[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + if(a.t < this.t) { + c -= a.s; + while(i < this.t) { + c += this[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while(i < a.t) { + c -= a[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = (c<0)?-1:0; + if(c < -1) r[i++] = this.DV+c; + else if(c > 0) r[i++] = c; + r.t = i; + r.clamp(); +} + +// (protected) r = this * a, r != this,a (HAC 14.12) +// "this" should be the larger one if appropriate. +function bnpMultiplyTo(a,r) { + var x = this.abs(), y = a.abs(); + var i = x.t; + r.t = i+y.t; + while(--i >= 0) r[i] = 0; + for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t); + r.s = 0; + r.clamp(); + if(this.s != a.s) BigInteger.ZERO.subTo(r,r); +} + +// (protected) r = this^2, r != this (HAC 14.16) +function bnpSquareTo(r) { + var x = this.abs(); + var i = r.t = 2*x.t; + while(--i >= 0) r[i] = 0; + for(i = 0; i < x.t-1; ++i) { + var c = x.am(i,x[i],r,2*i,0,1); + if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { + r[i+x.t] -= x.DV; + r[i+x.t+1] = 1; + } + } + if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1); + r.s = 0; + r.clamp(); +} + +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) +// r != q, this != m. q or r may be null. +function bnpDivRemTo(m,q,r) { + var pm = m.abs(); + if(pm.t <= 0) return; + var pt = this.abs(); + if(pt.t < pm.t) { + if(q != null) q.fromInt(0); + if(r != null) this.copyTo(r); + return; + } + if(r == null) r = nbi(); + var y = nbi(), ts = this.s, ms = m.s; + var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus + if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } + else { pm.copyTo(y); pt.copyTo(r); } + var ys = y.t; + var y0 = y[ys-1]; + if(y0 == 0) return; + var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0); + var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2; + var i = r.t, j = i-ys, t = (q==null)?nbi():q; + y.dlShiftTo(j,t); + if(r.compareTo(t) >= 0) { + r[r.t++] = 1; + r.subTo(t,r); + } + BigInteger.ONE.dlShiftTo(ys,t); + t.subTo(y,y); // "negative" y so we can replace sub with am later + while(y.t < ys) y[y.t++] = 0; + while(--j >= 0) { + // Estimate quotient digit + var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2); + if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out + y.dlShiftTo(j,t); + r.subTo(t,r); + while(r[i] < --qd) r.subTo(t,r); + } + } + if(q != null) { + r.drShiftTo(ys,q); + if(ts != ms) BigInteger.ZERO.subTo(q,q); + } + r.t = ys; + r.clamp(); + if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder + if(ts < 0) BigInteger.ZERO.subTo(r,r); +} + +// (public) this mod a +function bnMod(a) { + var r = nbi(); + this.abs().divRemTo(a,null,r); + if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); + return r; +} + +// Modular reduction using "classic" algorithm +function Classic(m) { this.m = m; } +function cConvert(x) { + if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return x; +} +function cRevert(x) { return x; } +function cReduce(x) { x.divRemTo(this.m,null,x); } +function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } +function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +Classic.prototype.convert = cConvert; +Classic.prototype.revert = cRevert; +Classic.prototype.reduce = cReduce; +Classic.prototype.mulTo = cMulTo; +Classic.prototype.sqrTo = cSqrTo; + +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction +// justification: +// xy == 1 (mod m) +// xy = 1+km +// xy(2-xy) = (1+km)(1-km) +// x[y(2-xy)] = 1-k^2m^2 +// x[y(2-xy)] == 1 (mod m^2) +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. +// JS multiply "overflows" differently from C/C++, so care is needed here. +function bnpInvDigit() { + if(this.t < 1) return 0; + var x = this[0]; + if((x&1) == 0) return 0; + var y = x&3; // y == 1/x mod 2^2 + y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 + y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 + y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y>0)?this.DV-y:-y; +} + +// Montgomery reduction +function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp&0x7fff; + this.mph = this.mp>>15; + this.um = (1<<(m.DB-15))-1; + this.mt2 = 2*m.t; +} + +// xR mod m +function montConvert(x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t,r); + r.divRemTo(this.m,null,r); + if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); + return r; +} + +// x/R mod m +function montRevert(x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; +} + +// x = x/R mod m (HAC 14.32) +function montReduce(x) { + while(x.t <= this.mt2) // pad x so am has enough room later + x[x.t++] = 0; + for(var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x[i]&0x7fff; + var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM; + // use am to combine the multiply-shift-add into one call + j = i+this.m.t; + x[j] += this.m.am(0,u0,x,i,0,this.m.t); + // propagate carry + while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } + } + x.clamp(); + x.drShiftTo(this.m.t,x); + if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); +} + +// r = "x^2/R mod m"; x != r +function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +// r = "xy/R mod m"; x,y != r +function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Montgomery.prototype.convert = montConvert; +Montgomery.prototype.revert = montRevert; +Montgomery.prototype.reduce = montReduce; +Montgomery.prototype.mulTo = montMulTo; +Montgomery.prototype.sqrTo = montSqrTo; + +// (protected) true iff this is even +function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; } + +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) +function bnpExp(e,z) { + if(e > 0xffffffff || e < 1) return BigInteger.ONE; + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; + g.copyTo(r); + while(--i >= 0) { + z.sqrTo(r,r2); + if((e&(1<<i)) > 0) z.mulTo(r2,g,r); + else { var t = r; r = r2; r2 = t; } + } + return z.revert(r); +} + +// (public) this^e % m, 0 <= e < 2^32 +function bnModPowInt(e,m) { + var z; + if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); + return this.exp(e,z); +} + +// protected +BigInteger.prototype.copyTo = bnpCopyTo; +BigInteger.prototype.fromInt = bnpFromInt; +BigInteger.prototype.fromString = bnpFromString; +BigInteger.prototype.clamp = bnpClamp; +BigInteger.prototype.dlShiftTo = bnpDLShiftTo; +BigInteger.prototype.drShiftTo = bnpDRShiftTo; +BigInteger.prototype.lShiftTo = bnpLShiftTo; +BigInteger.prototype.rShiftTo = bnpRShiftTo; +BigInteger.prototype.subTo = bnpSubTo; +BigInteger.prototype.multiplyTo = bnpMultiplyTo; +BigInteger.prototype.squareTo = bnpSquareTo; +BigInteger.prototype.divRemTo = bnpDivRemTo; +BigInteger.prototype.invDigit = bnpInvDigit; +BigInteger.prototype.isEven = bnpIsEven; +BigInteger.prototype.exp = bnpExp; + +// public +BigInteger.prototype.toString = bnToString; +BigInteger.prototype.negate = bnNegate; +BigInteger.prototype.abs = bnAbs; +BigInteger.prototype.compareTo = bnCompareTo; +BigInteger.prototype.bitLength = bnBitLength; +BigInteger.prototype.mod = bnMod; +BigInteger.prototype.modPowInt = bnModPowInt; + +// "constants" +BigInteger.ZERO = nbv(0); +BigInteger.ONE = nbv(1); diff --git a/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/prng4.js b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/prng4.js new file mode 100644 index 0000000..4715372 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/prng4.js @@ -0,0 +1,79 @@ +// Downloaded from http://www-cs-students.stanford.edu/~tjw/jsbn/ by Jeremy White on 6/1/2012 + +/* + * Copyright (c) 2003-2005 Tom Wu + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + + +// prng4.js - uses Arcfour as a PRNG + +function Arcfour() { + this.i = 0; + this.j = 0; + this.S = new Array(); +} + +// Initialize arcfour context from key, an array of ints, each from [0..255] +function ARC4init(key) { + var i, j, t; + for(i = 0; i < 256; ++i) + this.S[i] = i; + j = 0; + for(i = 0; i < 256; ++i) { + j = (j + this.S[i] + key[i % key.length]) & 255; + t = this.S[i]; + this.S[i] = this.S[j]; + this.S[j] = t; + } + this.i = 0; + this.j = 0; +} + +function ARC4next() { + var t; + this.i = (this.i + 1) & 255; + this.j = (this.j + this.S[this.i]) & 255; + t = this.S[this.i]; + this.S[this.i] = this.S[this.j]; + this.S[this.j] = t; + return this.S[(t + this.S[this.i]) & 255]; +} + +Arcfour.prototype.init = ARC4init; +Arcfour.prototype.next = ARC4next; + +// Plug in your RNG constructor here +function prng_newstate() { + return new Arcfour(); +} + +// Pool size must be a multiple of 4 and greater than 32. +// An array of bytes the size of the pool will be passed to init() +var rng_psize = 256; diff --git a/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/rng.js b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/rng.js new file mode 100644 index 0000000..829a23c --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/rng.js @@ -0,0 +1,102 @@ +// Downloaded from http://www-cs-students.stanford.edu/~tjw/jsbn/ by Jeremy White on 6/1/2012 + +/* + * Copyright (c) 2003-2005 Tom Wu + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + + +// Random number generator - requires a PRNG backend, e.g. prng4.js + +// For best results, put code like +// <body onClick='rng_seed_time();' onKeyPress='rng_seed_time();'> +// in your main HTML document. + +var rng_state; +var rng_pool; +var rng_pptr; + +// Mix in a 32-bit integer into the pool +function rng_seed_int(x) { + rng_pool[rng_pptr++] ^= x & 255; + rng_pool[rng_pptr++] ^= (x >> 8) & 255; + rng_pool[rng_pptr++] ^= (x >> 16) & 255; + rng_pool[rng_pptr++] ^= (x >> 24) & 255; + if(rng_pptr >= rng_psize) rng_pptr -= rng_psize; +} + +// Mix in the current time (w/milliseconds) into the pool +function rng_seed_time() { + rng_seed_int(new Date().getTime()); +} + +// Initialize the pool with junk if needed. +if(rng_pool == null) { + rng_pool = new Array(); + rng_pptr = 0; + var t; + if(navigator.appName == "Netscape" && navigator.appVersion < "5" && window.crypto) { + // Extract entropy (256 bits) from NS4 RNG if available + var z = window.crypto.random(32); + for(t = 0; t < z.length; ++t) + rng_pool[rng_pptr++] = z.charCodeAt(t) & 255; + } + while(rng_pptr < rng_psize) { // extract some randomness from Math.random() + t = Math.floor(65536 * Math.random()); + rng_pool[rng_pptr++] = t >>> 8; + rng_pool[rng_pptr++] = t & 255; + } + rng_pptr = 0; + rng_seed_time(); + //rng_seed_int(window.screenX); + //rng_seed_int(window.screenY); +} + +function rng_get_byte() { + if(rng_state == null) { + rng_seed_time(); + rng_state = prng_newstate(); + rng_state.init(rng_pool); + for(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr) + rng_pool[rng_pptr] = 0; + rng_pptr = 0; + //rng_pool = null; + } + // TODO: allow reseeding after first request + return rng_state.next(); +} + +function rng_get_bytes(ba) { + var i; + for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte(); +} + +function SecureRandom() {} + +SecureRandom.prototype.nextBytes = rng_get_bytes; diff --git a/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/rsa.js b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/rsa.js new file mode 100644 index 0000000..1bbf249 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/rsa.js @@ -0,0 +1,146 @@ +// Downloaded from http://www-cs-students.stanford.edu/~tjw/jsbn/ by Jeremy White on 6/1/2012 + +/* + * Copyright (c) 2003-2005 Tom Wu + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + + +// Depends on jsbn.js and rng.js + +// Version 1.1: support utf-8 encoding in pkcs1pad2 + +// convert a (hex) string to a bignum object +function parseBigInt(str,r) { + return new BigInteger(str,r); +} + +function linebrk(s,n) { + var ret = ""; + var i = 0; + while(i + n < s.length) { + ret += s.substring(i,i+n) + "\n"; + i += n; + } + return ret + s.substring(i,s.length); +} + +function byte2Hex(b) { + if(b < 0x10) + return "0" + b.toString(16); + else + return b.toString(16); +} + +// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint +function pkcs1pad2(s,n) { + if(n < s.length + 11) { // TODO: fix for utf-8 + alert("Message too long for RSA"); + return null; + } + var ba = new Array(); + var i = s.length - 1; + while(i >= 0 && n > 0) { + var c = s.charCodeAt(i--); + if(c < 128) { // encode using utf-8 + ba[--n] = c; + } + else if((c > 127) && (c < 2048)) { + ba[--n] = (c & 63) | 128; + ba[--n] = (c >> 6) | 192; + } + else { + ba[--n] = (c & 63) | 128; + ba[--n] = ((c >> 6) & 63) | 128; + ba[--n] = (c >> 12) | 224; + } + } + ba[--n] = 0; + var rng = new SecureRandom(); + var x = new Array(); + while(n > 2) { // random non-zero pad + x[0] = 0; + while(x[0] == 0) rng.nextBytes(x); + ba[--n] = x[0]; + } + ba[--n] = 2; + ba[--n] = 0; + return new BigInteger(ba); +} + +// "empty" RSA key constructor +function RSAKey() { + this.n = null; + this.e = 0; + this.d = null; + this.p = null; + this.q = null; + this.dmp1 = null; + this.dmq1 = null; + this.coeff = null; +} + +// Set the public key fields N and e from hex strings +function RSASetPublic(N,E) { + if(N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + } + else + alert("Invalid RSA public key"); +} + +// Perform raw public operation on "x": return x^e (mod n) +function RSADoPublic(x) { + return x.modPowInt(this.e, this.n); +} + +// Return the PKCS#1 RSA encryption of "text" as an even-length hex string +function RSAEncrypt(text) { + var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3); + if(m == null) return null; + var c = this.doPublic(m); + if(c == null) return null; + var h = c.toString(16); + if((h.length & 1) == 0) return h; else return "0" + h; +} + +// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string +//function RSAEncryptB64(text) { +// var h = this.encrypt(text); +// if(h) return hex2b64(h); else return null; +//} + +// protected +RSAKey.prototype.doPublic = RSADoPublic; + +// public +RSAKey.prototype.setPublic = RSASetPublic; +RSAKey.prototype.encrypt = RSAEncrypt; +//RSAKey.prototype.encrypt_b64 = RSAEncryptB64; diff --git a/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/sha1.js b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/sha1.js new file mode 100644 index 0000000..8118cb4 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/thirdparty/sha1.js @@ -0,0 +1,346 @@ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS 180-1 + * Version 2.2 Copyright Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ + + /* Downloaded 6/1/2012 from the above address by Jeremy White. + License reproduce here for completeness: + +Copyright (c) 1998 - 2009, Paul Johnston & Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_sha1(s) { return rstr2hex(rstr_sha1(str2rstr_utf8(s))); } +function b64_sha1(s) { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); } +function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); } +function hex_hmac_sha1(k, d) + { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); } +function b64_hmac_sha1(k, d) + { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); } +function any_hmac_sha1(k, d, e) + { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); } + +/* + * Perform a simple self-test to see if the VM is working + */ +function sha1_vm_test() +{ + return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d"; +} + +/* + * Calculate the SHA1 of a raw string + */ +function rstr_sha1(s) +{ + return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8)); +} + +/* + * Calculate the HMAC-SHA1 of a key and some data (raw strings) + */ +function rstr_hmac_sha1(key, data) +{ + var bkey = rstr2binb(key); + if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8); + + var ipad = Array(16), opad = Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8); + return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160)); +} + +/* + * Convert a raw string to a hex string + */ +function rstr2hex(input) +{ + try { hexcase } catch(e) { hexcase=0; } + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var output = ""; + var x; + for(var i = 0; i < input.length; i++) + { + x = input.charCodeAt(i); + output += hex_tab.charAt((x >>> 4) & 0x0F) + + hex_tab.charAt( x & 0x0F); + } + return output; +} + +/* + * Convert a raw string to a base-64 string + */ +function rstr2b64(input) +{ + try { b64pad } catch(e) { b64pad=''; } + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var output = ""; + var len = input.length; + for(var i = 0; i < len; i += 3) + { + var triplet = (input.charCodeAt(i) << 16) + | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) + | (i + 2 < len ? input.charCodeAt(i+2) : 0); + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > input.length * 8) output += b64pad; + else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); + } + } + return output; +} + +/* + * Convert a raw string to an arbitrary string encoding + */ +function rstr2any(input, encoding) +{ + var divisor = encoding.length; + var remainders = Array(); + var i, q, x, quotient; + + /* Convert to an array of 16-bit big-endian values, forming the dividend */ + var dividend = Array(Math.ceil(input.length / 2)); + for(i = 0; i < dividend.length; i++) + { + dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); + } + + /* + * Repeatedly perform a long division. The binary array forms the dividend, + * the length of the encoding is the divisor. Once computed, the quotient + * forms the dividend for the next step. We stop when the dividend is zero. + * All remainders are stored for later use. + */ + while(dividend.length > 0) + { + quotient = Array(); + x = 0; + for(i = 0; i < dividend.length; i++) + { + x = (x << 16) + dividend[i]; + q = Math.floor(x / divisor); + x -= q * divisor; + if(quotient.length > 0 || q > 0) + quotient[quotient.length] = q; + } + remainders[remainders.length] = x; + dividend = quotient; + } + + /* Convert the remainders to the output string */ + var output = ""; + for(i = remainders.length - 1; i >= 0; i--) + output += encoding.charAt(remainders[i]); + + /* Append leading zero equivalents */ + var full_length = Math.ceil(input.length * 8 / + (Math.log(encoding.length) / Math.log(2))) + for(i = output.length; i < full_length; i++) + output = encoding[0] + output; + + return output; +} + +/* + * Encode a string as utf-8. + * For efficiency, this assumes the input is valid utf-16. + */ +function str2rstr_utf8(input) +{ + var output = ""; + var i = -1; + var x, y; + + while(++i < input.length) + { + /* Decode utf-16 surrogate pairs */ + x = input.charCodeAt(i); + y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; + if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) + { + x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); + i++; + } + + /* Encode output as utf-8 */ + if(x <= 0x7F) + output += String.fromCharCode(x); + else if(x <= 0x7FF) + output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), + 0x80 | ( x & 0x3F)); + else if(x <= 0xFFFF) + output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), + 0x80 | ((x >>> 6 ) & 0x3F), + 0x80 | ( x & 0x3F)); + else if(x <= 0x1FFFFF) + output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), + 0x80 | ((x >>> 12) & 0x3F), + 0x80 | ((x >>> 6 ) & 0x3F), + 0x80 | ( x & 0x3F)); + } + return output; +} + +/* + * Encode a string as utf-16 + */ +function str2rstr_utf16le(input) +{ + var output = ""; + for(var i = 0; i < input.length; i++) + output += String.fromCharCode( input.charCodeAt(i) & 0xFF, + (input.charCodeAt(i) >>> 8) & 0xFF); + return output; +} + +function str2rstr_utf16be(input) +{ + var output = ""; + for(var i = 0; i < input.length; i++) + output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, + input.charCodeAt(i) & 0xFF); + return output; +} + +/* + * Convert a raw string to an array of big-endian words + * Characters >255 have their high-byte silently ignored. + */ +function rstr2binb(input) +{ + var output = Array(input.length >> 2); + for(var i = 0; i < output.length; i++) + output[i] = 0; + for(var i = 0; i < input.length * 8; i += 8) + output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32); + return output; +} + +/* + * Convert an array of big-endian words to a string + */ +function binb2rstr(input) +{ + var output = ""; + for(var i = 0; i < input.length * 32; i += 8) + output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF); + return output; +} + +/* + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ +function binb_sha1(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + var w = Array(80); + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + var e = -1009589776; + + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + var olde = e; + + for(var j = 0; j < 80; j++) + { + if(j < 16) w[j] = x[i + j]; + else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); + var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = bit_rol(b, 30); + b = a; + a = t; + } + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return Array(a, b, c, d, e); + +} + +/* + * Perform the appropriate triplet combination function for the current + * iteration + */ +function sha1_ft(t, b, c, d) +{ + if(t < 20) return (b & c) | ((~b) & d); + if(t < 40) return b ^ c ^ d; + if(t < 60) return (b & c) | (b & d) | (c & d); + return b ^ c ^ d; +} + +/* + * Determine the appropriate additive constant for the current iteration + */ +function sha1_kt(t) +{ + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function bit_rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/ticket.js b/src/wok/plugins/kimchi/ui/spice-html5/ticket.js new file mode 100644 index 0000000..96577a3 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/ticket.js @@ -0,0 +1,250 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +var SHA_DIGEST_LENGTH = 20; + +/*---------------------------------------------------------------------------- +** General ticket RSA encryption functions - just good enough to +** support what we need to send back an encrypted ticket. +**--------------------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------------- +** OAEP padding functions. Inspired by the OpenSSL implementation. +**--------------------------------------------------------------------------*/ +function MGF1(mask, seed) +{ + var i, j, outlen; + for (i = 0, outlen = 0; outlen < mask.length; i++) + { + var combo_buf = new String; + + for (j = 0; j < seed.length; j++) + combo_buf += String.fromCharCode(seed[j]); + combo_buf += String.fromCharCode((i >> 24) & 255); + combo_buf += String.fromCharCode((i >> 16) & 255); + combo_buf += String.fromCharCode((i >> 8) & 255); + combo_buf += String.fromCharCode((i) & 255); + + var combo_hash = rstr_sha1(combo_buf); + for (j = 0; j < combo_hash.length && outlen < mask.length; j++, outlen++) + { + mask[outlen] = combo_hash.charCodeAt(j); + } + } +} + + +function RSA_padding_add_PKCS1_OAEP(tolen, from, param) +{ + var seed = new Array(SHA_DIGEST_LENGTH); + var rand = new SecureRandom(); + rand.nextBytes(seed); + + var dblen = tolen - 1 - seed.length; + var db = new Array(dblen); + var padlen = dblen - from.length - 1; + var i; + + if (param === undefined) + param = ""; + + if (padlen < SHA_DIGEST_LENGTH) + { + console.log("Error - data too large for key size."); + return null; + } + + for (i = 0; i < padlen; i++) + db[i] = 0; + + var param_hash = rstr_sha1(param); + for (i = 0; i < param_hash.length; i++) + db[i] = param_hash.charCodeAt(i); + + db[padlen] = 1; + for (i = 0; i < from.length; i++) + db[i + padlen + 1] = from.charCodeAt(i); + + var dbmask = new Array(dblen); + if (MGF1(dbmask, seed) < 0) + return null; + + for (i = 0; i < dbmask.length; i++) + db[i] ^= dbmask[i]; + + + var seedmask = Array(SHA_DIGEST_LENGTH); + if (MGF1(seedmask, db) < 0) + return null; + + for (i = 0; i < seedmask.length; i++) + seed[i] ^= seedmask[i]; + + var ret = new String; + ret += String.fromCharCode(0); + for (i = 0; i < seed.length; i++) + ret += String.fromCharCode(seed[i]); + for (i = 0; i < db.length; i++) + ret += String.fromCharCode(db[i]); + return ret; +} + + +function asn_get_length(u8, at) +{ + var len = u8[at++]; + if (len > 0x80) + { + if (len != 0x81) + { + console.log("Error: we lazily don't support keys bigger than 255 bytes. It'd be easy to fix."); + return null; + } + len = u8[at++]; + } + + return [ at, len]; +} + +function find_sequence(u8, at) +{ + var lenblock; + at = at || 0; + if (u8[at++] != 0x30) + { + console.log("Error: public key should start with a sequence flag."); + return null; + } + + lenblock = asn_get_length(u8, at); + if (! lenblock) + return null; + return lenblock; +} + +/*---------------------------------------------------------------------------- +** Extract an RSA key from a memory buffer +**--------------------------------------------------------------------------*/ +function create_rsa_from_mb(mb, at) +{ + var u8 = new Uint8Array(mb); + var lenblock; + var seq; + var ba; + var i; + var ret; + + /* We have a sequence which contains a sequence followed by a bit string */ + seq = find_sequence(u8, at); + if (! seq) + return null; + + at = seq[0]; + seq = find_sequence(u8, at); + if (! seq) + return null; + + /* Skip over the contained sequence */ + at = seq[0] + seq[1]; + if (u8[at++] != 0x3) + { + console.log("Error: expecting bit string next."); + return null; + } + + /* Get the bit string, which is *itself* a sequence. Having fun yet? */ + lenblock = asn_get_length(u8, at); + if (! lenblock) + return null; + + at = lenblock[0]; + if (u8[at] != 0 && u8[at + 1] != 0x30) + { + console.log("Error: unexpected values in bit string."); + return null; + } + + /* Okay, now we have a sequence of two binary values, we hope. */ + seq = find_sequence(u8, at + 1); + if (! seq) + return null; + + at = seq[0]; + if (u8[at++] != 0x02) + { + console.log("Error: expecting integer n next."); + return null; + } + lenblock = asn_get_length(u8, at); + if (! lenblock) + return null; + at = lenblock[0]; + + ba = new Array(lenblock[1]); + for (i = 0; i < lenblock[1]; i++) + ba[i] = u8[at + i]; + + ret = new RSAKey(); + ret.n = new BigInteger(ba); + + at += lenblock[1]; + + if (u8[at++] != 0x02) + { + console.log("Error: expecting integer e next."); + return null; + } + lenblock = asn_get_length(u8, at); + if (! lenblock) + return null; + at = lenblock[0]; + + ret.e = u8[at++]; + for (i = 1; i < lenblock[1]; i++) + { + ret.e <<= 8; + ret.e |= u8[at++]; + } + + return ret; +} + +function rsa_encrypt(rsa, str) +{ + var i; + var ret = []; + var oaep = RSA_padding_add_PKCS1_OAEP((rsa.n.bitLength()+7)>>3, str); + if (! oaep) + return null; + + var ba = new Array(oaep.length); + + for (i = 0; i < oaep.length; i++) + ba[i] = oaep.charCodeAt(i); + var bigint = new BigInteger(ba); + var enc = rsa.doPublic(bigint); + var h = enc.toString(16); + if ((h.length & 1) != 0) + h = "0" + h; + for (i = 0; i < h.length; i += 2) + ret[i / 2] = parseInt(h.substring(i, i + 2), 16); + return ret; +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/utils.js b/src/wok/plugins/kimchi/ui/spice-html5/utils.js new file mode 100644 index 0000000..9eb42ff --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/utils.js @@ -0,0 +1,265 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** Utility settings and functions for Spice +**--------------------------------------------------------------------------*/ +var DEBUG = 0; +var DUMP_DRAWS = false; +var DUMP_CANVASES = false; + + +/*---------------------------------------------------------------------------- +** combine_array_buffers +** Combine two array buffers. +** FIXME - this can't be optimal. See wire.js about eliminating the need. +**--------------------------------------------------------------------------*/ +function combine_array_buffers(a1, a2) +{ + var in1 = new Uint8Array(a1); + var in2 = new Uint8Array(a2); + var ret = new ArrayBuffer(a1.byteLength + a2.byteLength); + var out = new Uint8Array(ret); + var o = 0; + var i; + for (i = 0; i < in1.length; i++) + out[o++] = in1[i]; + for (i = 0; i < in2.length; i++) + out[o++] = in2[i]; + + return ret; +} + +/*---------------------------------------------------------------------------- +** hexdump_buffer +**--------------------------------------------------------------------------*/ +function hexdump_buffer(a) +{ + var mg = new Uint8Array(a); + var hex = ""; + var str = ""; + var last_zeros = 0; + for (var i = 0; i < mg.length; i++) + { + var h = Number(mg[i]).toString(16); + if (h.length == 1) + hex += "0"; + hex += h + " "; + + if (mg[i] == 10 || mg[i] == 13 || mg[i] == 8) + str += "."; + else + str += String.fromCharCode(mg[i]); + + if ((i % 16 == 15) || (i == (mg.length - 1))) + { + while (i % 16 != 15) + { + hex += " "; + i++; + } + + if (last_zeros == 0) + console.log(hex + " | " + str); + + if (hex == "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ") + { + if (last_zeros == 1) + { + console.log("."); + last_zeros++; + } + else if (last_zeros == 0) + last_zeros++; + } + else + last_zeros = 0; + + hex = str = ""; + } + } +} + +/*---------------------------------------------------------------------------- +** Converting keycodes to AT scancodes is very hard. +** luckly there are some resources on the web and in the Xorg driver that help +** us figure out what browser depenend keycodes match to what scancodes. +** +** This will most likely not work for non US keyboard and browsers other than +** modern Chrome and FireFox. +**--------------------------------------------------------------------------*/ +var common_scanmap = []; +common_scanmap['Q'.charCodeAt(0)] = KEY_Q; +common_scanmap['W'.charCodeAt(0)] = KEY_W; +common_scanmap['E'.charCodeAt(0)] = KEY_E; +common_scanmap['R'.charCodeAt(0)] = KEY_R; +common_scanmap['T'.charCodeAt(0)] = KEY_T; +common_scanmap['Y'.charCodeAt(0)] = KEY_Y; +common_scanmap['U'.charCodeAt(0)] = KEY_U; +common_scanmap['I'.charCodeAt(0)] = KEY_I; +common_scanmap['O'.charCodeAt(0)] = KEY_O; +common_scanmap['P'.charCodeAt(0)] = KEY_P; +common_scanmap['A'.charCodeAt(0)] = KEY_A; +common_scanmap['S'.charCodeAt(0)] = KEY_S; +common_scanmap['D'.charCodeAt(0)] = KEY_D; +common_scanmap['F'.charCodeAt(0)] = KEY_F; +common_scanmap['G'.charCodeAt(0)] = KEY_G; +common_scanmap['H'.charCodeAt(0)] = KEY_H; +common_scanmap['J'.charCodeAt(0)] = KEY_J; +common_scanmap['K'.charCodeAt(0)] = KEY_K; +common_scanmap['L'.charCodeAt(0)] = KEY_L; +common_scanmap['Z'.charCodeAt(0)] = KEY_Z; +common_scanmap['X'.charCodeAt(0)] = KEY_X; +common_scanmap['C'.charCodeAt(0)] = KEY_C; +common_scanmap['V'.charCodeAt(0)] = KEY_V; +common_scanmap['B'.charCodeAt(0)] = KEY_B; +common_scanmap['N'.charCodeAt(0)] = KEY_N; +common_scanmap['M'.charCodeAt(0)] = KEY_M; +common_scanmap[' '.charCodeAt(0)] = KEY_Space; +common_scanmap[13] = KEY_Enter; +common_scanmap[27] = KEY_Escape; +common_scanmap[8] = KEY_BackSpace; +common_scanmap[9] = KEY_Tab; +common_scanmap[16] = KEY_ShiftL; +common_scanmap[17] = KEY_LCtrl; +common_scanmap[18] = KEY_Alt; +common_scanmap[20] = KEY_CapsLock; +common_scanmap[144] = KEY_NumLock; +common_scanmap[112] = KEY_F1; +common_scanmap[113] = KEY_F2; +common_scanmap[114] = KEY_F3; +common_scanmap[115] = KEY_F4; +common_scanmap[116] = KEY_F5; +common_scanmap[117] = KEY_F6; +common_scanmap[118] = KEY_F7; +common_scanmap[119] = KEY_F8; +common_scanmap[120] = KEY_F9; +common_scanmap[121] = KEY_F10; +common_scanmap[122] = KEY_F11; +common_scanmap[123] = KEY_F12; + +/* These externded scancodes do not line up with values from atKeynames */ +common_scanmap[42] = 99; +common_scanmap[19] = 101; // Break +common_scanmap[111] = 0xE035; // KP_Divide +common_scanmap[106] = 0xE037; // KP_Multiply +common_scanmap[36] = 0xE047; // Home +common_scanmap[38] = 0xE048; // Up +common_scanmap[33] = 0xE049; // PgUp +common_scanmap[37] = 0xE04B; // Left +common_scanmap[39] = 0xE04D; // Right +common_scanmap[35] = 0xE04F; // End +common_scanmap[40] = 0xE050; // Down +common_scanmap[34] = 0xE051; // PgDown +common_scanmap[45] = 0xE052; // Insert +common_scanmap[46] = 0xE053; // Delete +common_scanmap[44] = 0x2A37; // Print + +/* These are not common between ALL browsers but are between Firefox and DOM3 */ +common_scanmap['1'.charCodeAt(0)] = KEY_1; +common_scanmap['2'.charCodeAt(0)] = KEY_2; +common_scanmap['3'.charCodeAt(0)] = KEY_3; +common_scanmap['4'.charCodeAt(0)] = KEY_4; +common_scanmap['5'.charCodeAt(0)] = KEY_5; +common_scanmap['6'.charCodeAt(0)] = KEY_6; +common_scanmap['7'.charCodeAt(0)] = KEY_7; +common_scanmap['8'.charCodeAt(0)] = KEY_8; +common_scanmap['9'.charCodeAt(0)] = KEY_9; +common_scanmap['0'.charCodeAt(0)] = KEY_0; +common_scanmap[145] = KEY_ScrollLock; +common_scanmap[103] = KEY_KP_7; +common_scanmap[104] = KEY_KP_8; +common_scanmap[105] = KEY_KP_9; +common_scanmap[100] = KEY_KP_4; +common_scanmap[101] = KEY_KP_5; +common_scanmap[102] = KEY_KP_6; +common_scanmap[107] = KEY_KP_Plus; +common_scanmap[97] = KEY_KP_1; +common_scanmap[98] = KEY_KP_2; +common_scanmap[99] = KEY_KP_3; +common_scanmap[96] = KEY_KP_0; +common_scanmap[110] = KEY_KP_Decimal; +common_scanmap[191] = KEY_Slash; +common_scanmap[190] = KEY_Period; +common_scanmap[188] = KEY_Comma; +common_scanmap[220] = KEY_BSlash; +common_scanmap[192] = KEY_Tilde; +common_scanmap[222] = KEY_Quote; +common_scanmap[219] = KEY_LBrace; +common_scanmap[221] = KEY_RBrace; + +common_scanmap[91] = 0xE05B; //KEY_LMeta +common_scanmap[92] = 0xE05C; //KEY_RMeta +common_scanmap[93] = 0xE05D; //KEY_Menu + +/* Firefox/Mozilla codes */ +var firefox_scanmap = []; +firefox_scanmap[173] = KEY_Minus; +firefox_scanmap[109] = KEY_Minus; +firefox_scanmap[61] = KEY_Equal; +firefox_scanmap[59] = KEY_SemiColon; + +/* DOM3 codes */ +var DOM_scanmap = []; +DOM_scanmap[189] = KEY_Minus; +DOM_scanmap[187] = KEY_Equal; +DOM_scanmap[186] = KEY_SemiColon; + +function get_scancode(code) +{ + if (common_scanmap[code] === undefined) + { + if (navigator.userAgent.indexOf("Firefox") != -1) + return firefox_scanmap[code]; + else + return DOM_scanmap[code]; + } + else + return common_scanmap[code]; +} + +function keycode_to_start_scan(code) +{ + var scancode = get_scancode(code); + if (scancode === undefined) + { + alert('no map for ' + code); + return 0; + } + + if (scancode < 0x100) { + return scancode; + } else { + return 0xe0 | ((scancode - 0x100) << 8); + } +} + +function keycode_to_end_scan(code) +{ + var scancode = get_scancode(code); + if (scancode === undefined) + return 0; + + if (scancode < 0x100) { + return scancode | 0x80; + } else { + return 0x80e0 | ((scancode - 0x100) << 8); + } +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/webm.js b/src/wok/plugins/kimchi/ui/spice-html5/webm.js new file mode 100644 index 0000000..35cbc07 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/webm.js @@ -0,0 +1,553 @@ +"use strict"; +/* + Copyright (C) 2014 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + + +/*---------------------------------------------------------------------------- +** EBML identifiers +**--------------------------------------------------------------------------*/ +var EBML_HEADER = [ 0x1a, 0x45, 0xdf, 0xa3 ]; +var EBML_HEADER_VERSION = [ 0x42, 0x86 ]; +var EBML_HEADER_READ_VERSION = [ 0x42, 0xf7 ]; +var EBML_HEADER_MAX_ID_LENGTH = [ 0x42, 0xf2 ]; +var EBML_HEADER_MAX_SIZE_LENGTH = [ 0x42, 0xf3 ]; +var EBML_HEADER_DOC_TYPE = [ 0x42, 0x82 ]; +var EBML_HEADER_DOC_TYPE_VERSION = [ 0x42, 0x87 ]; +var EBML_HEADER_DOC_TYPE_READ_VERSION = [ 0x42, 0x85 ]; + +var WEBM_SEGMENT_HEADER = [ 0x18, 0x53, 0x80, 0x67 ]; +var WEBM_SEGMENT_INFORMATION = [ 0x15, 0x49, 0xA9, 0x66 ]; + +var WEBM_TIMECODE_SCALE = [ 0x2A, 0xD7, 0xB1 ]; +var WEBM_MUXING_APP = [ 0x4D, 0x80 ]; +var WEBM_WRITING_APP = [ 0x57, 0x41 ]; + +var WEBM_SEEK_HEAD = [ 0x11, 0x4D, 0x9B, 0x74 ]; +var WEBM_SEEK = [ 0x4D, 0xBB ]; +var WEBM_SEEK_ID = [ 0x53, 0xAB ]; +var WEBM_SEEK_POSITION = [ 0x53, 0xAC ]; + +var WEBM_TRACKS = [ 0x16, 0x54, 0xAE, 0x6B ]; +var WEBM_TRACK_ENTRY = [ 0xAE ]; +var WEBM_TRACK_NUMBER = [ 0xD7 ]; +var WEBM_TRACK_UID = [ 0x73, 0xC5 ]; +var WEBM_TRACK_TYPE = [ 0x83 ]; +var WEBM_FLAG_ENABLED = [ 0xB9 ]; +var WEBM_FLAG_DEFAULT = [ 0x88 ]; +var WEBM_FLAG_FORCED = [ 0x55, 0xAA ]; +var WEBM_FLAG_LACING = [ 0x9C ]; +var WEBM_MIN_CACHE = [ 0x6D, 0xE7 ]; + +var WEBM_MAX_BLOCK_ADDITION_ID = [ 0x55, 0xEE ]; +var WEBM_CODEC_DECODE_ALL = [ 0xAA ]; +var WEBM_SEEK_PRE_ROLL = [ 0x56, 0xBB ]; +var WEBM_CODEC_DELAY = [ 0x56, 0xAA ]; +var WEBM_CODEC_PRIVATE = [ 0x63, 0xA2 ]; +var WEBM_CODEC_ID = [ 0x86 ]; + +var WEBM_AUDIO = [ 0xE1 ] ; +var WEBM_SAMPLING_FREQUENCY = [ 0xB5 ] ; +var WEBM_CHANNELS = [ 0x9F ] ; + +var WEBM_CLUSTER = [ 0x1F, 0x43, 0xB6, 0x75 ]; +var WEBM_TIME_CODE = [ 0xE7 ] ; +var WEBM_SIMPLE_BLOCK = [ 0xA3 ] ; + +/*---------------------------------------------------------------------------- +** Various OPUS / Webm constants +**--------------------------------------------------------------------------*/ +var CLUSTER_SIMPLEBLOCK_FLAG_KEYFRAME = 1 << 7; + +var OPUS_FREQUENCY = 48000; +var OPUS_CHANNELS = 2; + +var SPICE_PLAYBACK_CODEC = 'audio/webm; codecs="opus"'; +var MAX_CLUSTER_TIME = 1000; + +var GAP_DETECTION_THRESHOLD = 50; + +/*---------------------------------------------------------------------------- +** EBML utility functions +** These classes can create the binary representation of a webm file +**--------------------------------------------------------------------------*/ +function EBML_write_u1_data_len(len, dv, at) +{ + var b = 0x80 | len; + dv.setUint8(at, b); + return at + 1; +} + +function EBML_write_u8_value(id, val, dv, at) +{ + at = EBML_write_array(id, dv, at); + at = EBML_write_u1_data_len(1, dv, at); + dv.setUint8(at, val); + return at + 1; +} + +function EBML_write_u32_value(id, val, dv, at) +{ + at = EBML_write_array(id, dv, at); + at = EBML_write_u1_data_len(4, dv, at); + dv.setUint32(at, val); + return at + 4; +} + +function EBML_write_u16_value(id, val, dv, at) +{ + at = EBML_write_array(id, dv, at); + at = EBML_write_u1_data_len(2, dv, at); + dv.setUint16(at, val); + return at + 2; +} + +function EBML_write_float_value(id, val, dv, at) +{ + at = EBML_write_array(id, dv, at); + at = EBML_write_u1_data_len(4, dv, at); + dv.setFloat32(at, val); + return at + 4; +} + + + +function EBML_write_u64_data_len(len, dv, at) +{ + /* Javascript doesn't do 64 bit ints, so this cheats and + just has a max of 32 bits. Fine for our purposes */ + dv.setUint8(at++, 0x01); + dv.setUint8(at++, 0x00); + dv.setUint8(at++, 0x00); + dv.setUint8(at++, 0x00); + var val = len & 0xFFFFFFFF; + for (var shift = 24; shift >= 0; shift -= 8) + dv.setUint8(at++, val >> shift); + return at; +} + +function EBML_write_array(arr, dv, at) +{ + for (var i = 0; i < arr.length; i++) + dv.setUint8(at + i, arr[i]); + return at + arr.length; +} + +function EBML_write_string(str, dv, at) +{ + for (var i = 0; i < str.length; i++) + dv.setUint8(at + i, str.charCodeAt(i)); + return at + str.length; +} + +function EBML_write_data(id, data, dv, at) +{ + at = EBML_write_array(id, dv, at); + if (data.length < 127) + at = EBML_write_u1_data_len(data.length, dv, at); + else + at = EBML_write_u64_data_len(data.length, dv, at); + if ((typeof data) == "string") + at = EBML_write_string(data, dv, at); + else + at = EBML_write_array(data, dv, at); + return at; +} + +/*---------------------------------------------------------------------------- +** Webm objects +** These classes can create the binary representation of a webm file +**--------------------------------------------------------------------------*/ +function EBMLHeader() +{ + this.id = EBML_HEADER; + this.Version = 1; + this.ReadVersion = 1; + this.MaxIDLength = 4; + this.MaxSizeLength = 8; + this.DocType = "webm"; + this.DocTypeVersion = 2; /* Not well specified by the WebM guys, but functionally required for Firefox */ + this.DocTypeReadVersion = 2; +} + +EBMLHeader.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new DataView(a); + + at = EBML_write_array(this.id, dv, at); + at = EBML_write_u64_data_len(0x1f, dv, at); + at = EBML_write_u8_value(EBML_HEADER_VERSION, this.Version, dv, at); + at = EBML_write_u8_value(EBML_HEADER_READ_VERSION, this.ReadVersion, dv, at); + at = EBML_write_u8_value(EBML_HEADER_MAX_ID_LENGTH, this.MaxIDLength, dv, at); + at = EBML_write_u8_value(EBML_HEADER_MAX_SIZE_LENGTH, this.MaxSizeLength, dv, at); + at = EBML_write_data(EBML_HEADER_DOC_TYPE, this.DocType, dv, at); + at = EBML_write_u8_value(EBML_HEADER_DOC_TYPE_VERSION, this.DocTypeVersion, dv, at); + at = EBML_write_u8_value(EBML_HEADER_DOC_TYPE_READ_VERSION, this.DocTypeReadVersion, dv, at); + + return at; + }, + buffer_size: function() + { + return 0x1f + 8 + this.id.length; + }, +} + +function webm_Segment() +{ + this.id = WEBM_SEGMENT_HEADER; +} + +webm_Segment.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new DataView(a); + + at = EBML_write_array(this.id, dv, at); + dv.setUint8(at++, 0xff); + return at; + }, + buffer_size: function() + { + return this.id.length + 1; + }, +} + +function webm_SegmentInformation() +{ + this.id = WEBM_SEGMENT_INFORMATION; + this.timecode_scale = 1000000; /* 1 ms */ + this.muxing_app = "spice"; + this.writing_app = "spice-html5"; + +} + +webm_SegmentInformation.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new DataView(a); + + at = EBML_write_array(this.id, dv, at); + at = EBML_write_u64_data_len(this.buffer_size() - 8 - this.id.length, dv, at); + at = EBML_write_u32_value(WEBM_TIMECODE_SCALE, this.timecode_scale, dv, at); + at = EBML_write_data(WEBM_MUXING_APP, this.muxing_app, dv, at); + at = EBML_write_data(WEBM_WRITING_APP, this.writing_app, dv, at); + return at; + }, + buffer_size: function() + { + return this.id.length + 8 + + WEBM_TIMECODE_SCALE.length + 1 + 4 + + WEBM_MUXING_APP.length + 1 + this.muxing_app.length + + WEBM_WRITING_APP.length + 1 + this.writing_app.length; + }, +} + +function webm_Audio(frequency) +{ + this.id = WEBM_AUDIO; + this.sampling_frequency = frequency; + this.channels = OPUS_CHANNELS; +} + +webm_Audio.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new DataView(a); + at = EBML_write_array(this.id, dv, at); + at = EBML_write_u64_data_len(this.buffer_size() - 8 - this.id.length, dv, at); + at = EBML_write_u8_value(WEBM_CHANNELS, this.channels, dv, at); + at = EBML_write_float_value(WEBM_SAMPLING_FREQUENCY, this.sampling_frequency, dv, at); + return at; + }, + buffer_size: function() + { + return this.id.length + 8 + + WEBM_SAMPLING_FREQUENCY.length + 1 + 4 + + WEBM_CHANNELS.length + 1 + 1; + }, +} + + +/* --------------------------- + SeekHead not currently used. Hopefully not needed. +*/ +function webm_Seek(seekid, pos) +{ + this.id = WEBM_SEEK; + this.pos = pos; + this.seekid = seekid; +} + +webm_Seek.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new DataView(a); + at = EBML_write_array(this.id, dv, at); + at = EBML_write_u1_data_len(this.buffer_size() - 1 - this.id.length, dv, at); + + at = EBML_write_data(WEBM_SEEK_ID, this.seekid, dv, at) + at = EBML_write_u16_value(WEBM_SEEK_POSITION, this.pos, dv, at) + + return at; + }, + buffer_size: function() + { + return this.id.length + 1 + + WEBM_SEEK_ID.length + 1 + this.seekid.length + + WEBM_SEEK_POSITION.length + 1 + 2; + }, +} +function webm_SeekHead(info_pos, track_pos) +{ + this.id = WEBM_SEEK_HEAD; + this.info = new webm_Seek(WEBM_SEGMENT_INFORMATION, info_pos); + this.track = new webm_Seek(WEBM_TRACKS, track_pos); +} + +webm_SeekHead.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new DataView(a); + at = EBML_write_array(this.id, dv, at); + at = EBML_write_u64_data_len(this.buffer_size() - 8 - this.id.length, dv, at); + + at = this.info.to_buffer(a, at); + at = this.track.to_buffer(a, at); + + return at; + }, + buffer_size: function() + { + return this.id.length + 8 + + this.info.buffer_size() + + this.track.buffer_size(); + }, +} + +/* ------------------------------- + End of Seek Head +*/ + +function webm_TrackEntry() +{ + this.id = WEBM_TRACK_ENTRY; + this.number = 1; + this.uid = 1; + this.type = 2; // Audio + this.flag_enabled = 1; + this.flag_default = 1; + this.flag_forced = 1; + this.flag_lacing = 0; + this.min_cache = 0; // fixme - check + this.max_block_addition_id = 0; + this.codec_decode_all = 0; // fixme - check + this.seek_pre_roll = 0; // 80000000; // fixme - check + this.codec_delay = 80000000; // Must match codec_private.preskip + this.codec_id = "A_OPUS"; + this.audio = new webm_Audio(OPUS_FREQUENCY); + + // See: http://tools.ietf.org/html/draft-terriberry-oggopus-01 + this.codec_private = [ 0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, // OpusHead + 0x01, // Version + OPUS_CHANNELS, + 0x00, 0x0F, // Preskip - 3840 samples - should be 8ms at 48kHz + 0x80, 0xbb, 0x00, 0x00, // 48000 + 0x00, 0x00, // Output gain + 0x00 // Channel mapping family + ]; +} + +webm_TrackEntry.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new DataView(a); + at = EBML_write_array(this.id, dv, at); + at = EBML_write_u64_data_len(this.buffer_size() - 8 - this.id.length, dv, at); + at = EBML_write_u8_value(WEBM_TRACK_NUMBER, this.number, dv, at); + at = EBML_write_u8_value(WEBM_TRACK_UID, this.uid, dv, at); + at = EBML_write_u8_value(WEBM_FLAG_ENABLED, this.flag_enabled, dv, at); + at = EBML_write_u8_value(WEBM_FLAG_DEFAULT, this.flag_default, dv, at); + at = EBML_write_u8_value(WEBM_FLAG_FORCED, this.flag_forced, dv, at); + at = EBML_write_u8_value(WEBM_FLAG_LACING, this.flag_lacing, dv, at); + at = EBML_write_data(WEBM_CODEC_ID, this.codec_id, dv, at); + at = EBML_write_u8_value(WEBM_MIN_CACHE, this.min_cache, dv, at); + at = EBML_write_u8_value(WEBM_MAX_BLOCK_ADDITION_ID, this.max_block_addition_id, dv, at); + at = EBML_write_u8_value(WEBM_CODEC_DECODE_ALL, this.codec_decode_all, dv, at); + at = EBML_write_u32_value(WEBM_CODEC_DELAY, this.codec_delay, dv, at); + at = EBML_write_u32_value(WEBM_SEEK_PRE_ROLL, this.seek_pre_roll, dv, at); + at = EBML_write_u8_value(WEBM_TRACK_TYPE, this.type, dv, at); + at = EBML_write_data(WEBM_CODEC_PRIVATE, this.codec_private, dv, at); + + at = this.audio.to_buffer(a, at); + return at; + }, + buffer_size: function() + { + return this.id.length + 8 + + WEBM_TRACK_NUMBER.length + 1 + 1 + + WEBM_TRACK_UID.length + 1 + 1 + + WEBM_TRACK_TYPE.length + 1 + 1 + + WEBM_FLAG_ENABLED.length + 1 + 1 + + WEBM_FLAG_DEFAULT.length + 1 + 1 + + WEBM_FLAG_FORCED.length + 1 + 1 + + WEBM_FLAG_LACING.length + 1 + 1 + + WEBM_MIN_CACHE.length + 1 + 1 + + WEBM_MAX_BLOCK_ADDITION_ID.length + 1 + 1 + + WEBM_CODEC_DECODE_ALL.length + 1 + 1 + + WEBM_SEEK_PRE_ROLL.length + 1 + 4 + + WEBM_CODEC_DELAY.length + 1 + 4 + + WEBM_CODEC_ID.length + this.codec_id.length + 1 + + WEBM_CODEC_PRIVATE.length + 1 + this.codec_private.length + + this.audio.buffer_size(); + }, +} +function webm_Tracks(entry) +{ + this.id = WEBM_TRACKS; + this.track_entry = entry; +} + +webm_Tracks.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new DataView(a); + at = EBML_write_array(this.id, dv, at); + at = EBML_write_u64_data_len(this.buffer_size() - 8 - this.id.length, dv, at); + at = this.track_entry.to_buffer(a, at); + return at; + }, + buffer_size: function() + { + return this.id.length + 8 + + this.track_entry.buffer_size(); + }, +} + +function webm_Cluster(timecode, data) +{ + this.id = WEBM_CLUSTER; + this.timecode = timecode; + this.data = data; +} + +webm_Cluster.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new DataView(a); + at = EBML_write_array(this.id, dv, at); + dv.setUint8(at++, 0xff); + at = EBML_write_u32_value(WEBM_TIME_CODE, this.timecode, dv, at); + return at; + }, + buffer_size: function() + { + return this.id.length + 1 + + WEBM_TIME_CODE.length + 1 + 4; + }, +} + +function webm_SimpleBlock(timecode, data, keyframe) +{ + this.id = WEBM_SIMPLE_BLOCK; + this.timecode = timecode; + this.data = data; + this.keyframe = keyframe; +} + +webm_SimpleBlock.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new DataView(a); + at = EBML_write_array(this.id, dv, at); + at = EBML_write_u64_data_len(this.data.byteLength + 4, dv, at); + at = EBML_write_u1_data_len(1, dv, at); // Track # + dv.setUint16(at, this.timecode); at += 2; // timecode - relative to cluster + dv.setUint8(at, this.keyframe ? CLUSTER_SIMPLEBLOCK_FLAG_KEYFRAME : 0); at += 1; // flags + + // FIXME - There should be a better way to copy + var u8 = new Uint8Array(this.data); + for (var i = 0; i < this.data.byteLength; i++) + dv.setUint8(at++, u8[i]); + + return at; + }, + buffer_size: function() + { + return this.id.length + 8 + + 1 + 2 + 1 + + this.data.byteLength; + }, +} + +function webm_Header() +{ + this.ebml = new EBMLHeader; + this.segment = new webm_Segment; + this.seek_head = new webm_SeekHead(0, 0); + + this.seek_head.info.pos = this.segment.buffer_size() + this.seek_head.buffer_size(); + + this.info = new webm_SegmentInformation; + + this.seek_head.track.pos = this.seek_head.info.pos + this.info.buffer_size(); + + this.track_entry = new webm_TrackEntry; + this.tracks = new webm_Tracks(this.track_entry); +} + +webm_Header.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + at = this.ebml.to_buffer(a, at); + at = this.segment.to_buffer(a, at); + at = this.info.to_buffer(a, at); + at = this.tracks.to_buffer(a, at); + + return at; + }, + buffer_size: function() + { + return this.ebml.buffer_size() + + this.segment.buffer_size() + + this.info.buffer_size() + + this.tracks.buffer_size(); + }, +} diff --git a/src/wok/plugins/kimchi/ui/spice-html5/wire.js b/src/wok/plugins/kimchi/ui/spice-html5/wire.js new file mode 100644 index 0000000..7407ce7 --- /dev/null +++ b/src/wok/plugins/kimchi/ui/spice-html5/wire.js @@ -0,0 +1,123 @@ +"use strict"; +/* + Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*-------------------------------------------------------------------------------------- +** SpiceWireReader +** This class will receive messages from a WebSocket and relay it to a given +** callback. It will optionally save and pass along a header, useful in processing +** the mini message format. +**--------------------------------------------------------------------------------------*/ +function SpiceWireReader(sc, callback) +{ + this.sc = sc; + this.callback = callback; + this.needed = 0; + + this.buffers = []; + + this.sc.ws.wire_reader = this; + this.sc.ws.binaryType = "arraybuffer"; + this.sc.ws.addEventListener('message', wire_blob_catcher); +} + +SpiceWireReader.prototype = +{ + + /*------------------------------------------------------------------------ + ** Process messages coming in from our WebSocket + **----------------------------------------------------------------------*/ + inbound: function (mb) + { + var at; + + /* Just buffer if we don't need anything yet */ + if (this.needed == 0) + { + this.buffers.push(mb); + return; + } + + /* Optimization - if we have just one inbound block, and it's + suitable for our needs, just use it. */ + if (this.buffers.length == 0 && mb.byteLength >= this.needed) + { + if (mb.byteLength > this.needed) + { + this.buffers.push(mb.slice(this.needed)); + mb = mb.slice(0, this.needed); + } + this.callback.call(this.sc, mb, + this.saved_msg_header || undefined); + } + else + { + this.buffers.push(mb); + } + + + /* If we have fragments that add up to what we need, combine them */ + /* FIXME - it would be faster to revise the processing code to handle + ** multiple fragments directly. Essentially, we should be + ** able to do this without any slice() or combine_array_buffers() calls */ + while (this.buffers.length > 1 && this.buffers[0].byteLength < this.needed) + { + var mb1 = this.buffers.shift(); + var mb2 = this.buffers.shift(); + + this.buffers.unshift(combine_array_buffers(mb1, mb2)); + } + + + while (this.buffers.length > 0 && this.buffers[0].byteLength >= this.needed) + { + mb = this.buffers.shift(); + if (mb.byteLength > this.needed) + { + this.buffers.unshift(mb.slice(this.needed)); + mb = mb.slice(0, this.needed); + } + this.callback.call(this.sc, mb, + this.saved_msg_header || undefined); + } + + }, + + request: function(n) + { + this.needed = n; + }, + + save_header: function(h) + { + this.saved_msg_header = h; + }, + + clear_header: function() + { + this.saved_msg_header = undefined; + }, +} + +function wire_blob_catcher(e) +{ + DEBUG > 1 && console.log(">> WebSockets.onmessage"); + DEBUG > 1 && console.log("id " + this.wire_reader.sc.connection_id +"; type " + this.wire_reader.sc.type); + SpiceWireReader.prototype.inbound.call(this.wire_reader, e.data); +} diff --git a/src/wok/plugins/kimchi/utils.py b/src/wok/plugins/kimchi/utils.py new file mode 100644 index 0000000..2480362 --- /dev/null +++ b/src/wok/plugins/kimchi/utils.py @@ -0,0 +1,39 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import re + +from wok.exception import InvalidParameter + + +def _uri_to_name(collection, uri): + expr = '/plugins/kimchi/%s/(.*?)$' % collection + m = re.match(expr, uri) + if not m: + raise InvalidParameter("WOKUTILS0001E", {'uri': uri}) + return m.group(1) + + +def template_name_from_uri(uri): + return _uri_to_name('templates', uri) + + +def pool_name_from_uri(uri): + return _uri_to_name('storagepools', uri) diff --git a/src/wok/plugins/kimchi/vmtemplate.py b/src/wok/plugins/kimchi/vmtemplate.py new file mode 100644 index 0000000..07e70ba --- /dev/null +++ b/src/wok/plugins/kimchi/vmtemplate.py @@ -0,0 +1,431 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import stat +import time +import urlparse +import uuid +from lxml import etree +from lxml.builder import E + +from wok.exception import InvalidParameter, ImageFormatError, IsoFormatError +from wok.exception import MissingParameter, OperationFailed +from wok.utils import check_url_path + +import imageinfo +import osinfo +from isoinfo import IsoImage +from utils import pool_name_from_uri +from xmlutils.cpu import get_cpu_xml +from xmlutils.disk import get_disk_xml +from xmlutils.graphics import get_graphics_xml +from xmlutils.interface import get_iface_xml +from xmlutils.qemucmdline import get_qemucmdline_xml + + +class VMTemplate(object): + def __init__(self, args, scan=False): + """ + Construct a VM Template from a widely variable amount of information. + The only required parameter is a name for the VMTemplate. If present, + the os_distro and os_version fields are used to lookup recommended + settings. Any parameters provided by the caller will override the + defaults. If scan is True and a cdrom or a base img is present, the + operating system will be detected by probing the installation media. + """ + self.info = {} + self.fc_host_support = args.get('fc_host_support') + + # Fetch defaults based on the os distro and version + try: + distro, version = self._get_os_info(args, scan) + except ImageFormatError as e: + raise OperationFailed('KCHTMPL0020E', {'err': e.message}) + os_distro = args.get('os_distro', distro) + os_version = args.get('os_version', version) + entry = osinfo.lookup(os_distro, os_version) + self.info.update(entry) + + # Auto-generate a template name and no one is passed + if 'name' not in args or args['name'] == '': + args['name'] = self._gen_name(distro, version) + self.name = args['name'] + + # Override with the passed in parameters + graph_args = args.get('graphics') + if graph_args: + graphics = dict(self.info['graphics']) + graphics.update(graph_args) + args['graphics'] = graphics + self.info.update(args) + + # Assign right disk format to logical and [i]scsi storagepools + if self._get_storage_type() in ['logical', 'iscsi', 'scsi']: + for i, disk in enumerate(self.info['disks']): + self.info['disks'][i]['format'] = 'raw' + + def _get_os_info(self, args, scan): + distro = version = 'unknown' + + # Identify the cdrom if present + iso = args.get('cdrom', '') + if len(iso) > 0: + if not iso.startswith('/'): + self.info.update({'iso_stream': True}) + + if scan: + distro, version = self.get_iso_info(iso) + + return distro, version + + # CDROM is not presented: check for base image + base_imgs = [] + for d in args.get('disks', []): + if 'base' in d.keys(): + base_imgs.append(d) + if scan: + distro, version = imageinfo.probe_image(d['base']) + + if 'size' not in d.keys(): + d_info = imageinfo.probe_img_info(d['base']) + d['size'] = d_info['virtual-size'] + + if len(base_imgs) == 0: + raise MissingParameter("KCHTMPL0016E") + + return distro, version + + def _gen_name(self, distro, version): + if distro == 'unknown': + name = str(uuid.uuid4()) + else: + name = distro + version + '.' + str(int(time.time() * 1000)) + return name + + def get_iso_info(self, iso): + iso_prefixes = ['/', 'http', 'https', 'ftp', 'ftps', 'tftp'] + if len(filter(iso.startswith, iso_prefixes)) == 0: + raise InvalidParameter("KCHTMPL0006E", {'param': iso}) + try: + iso_img = IsoImage(iso) + return iso_img.probe() + except IsoFormatError: + raise InvalidParameter("KCHISO0001E", {'filename': iso}) + + def _get_cdrom_xml(self, libvirt_stream_protocols): + if 'cdrom' not in self.info: + return '' + + params = {} + params['type'] = 'cdrom' + params['format'] = 'raw' + params['bus'] = self.info['cdrom_bus'] + params['index'] = self.info['cdrom_index'] + params['path'] = self.info['cdrom'] + + if self.info.get('iso_stream', False): + protocol = urlparse.urlparse(params['path']).scheme + if protocol not in libvirt_stream_protocols: + driveOpt = 'file=%(path)s,if=none,id=drive-%(bus)s0-1-0,' + driveOpt += 'readonly=on,format=%(format)s' + + deviceOpt = '%(bus)s-cd,bus=%(bus)s.1,unit=0,' + deviceOpt += 'drive=drive-%(bus)s0-1-0,id=%(bus)s0-1-0' + + args = {} + args['-drive'] = driveOpt % params + args['-device'] = deviceOpt % params + # return qemucmdline XML + return get_qemucmdline_xml(args) + + dev, xml = get_disk_xml(params) + return xml + + def _get_disks_xml(self, vm_uuid): + # Current implementation just allows to create disk in one single + # storage pool, so we cannot mix the types (scsi volumes vs img file) + storage_type = self._get_storage_type() + storage_path = self._get_storage_path() + + base_disk_params = {'type': 'disk', 'disk': 'file', + 'bus': self.info['disk_bus'], 'format': 'qcow2'} + logical_disk_params = {'format': 'raw'} + iscsi_disk_params = {'disk': 'block', 'format': 'raw'} + + scsi_disk = 'volume' if self.fc_host_support else 'block' + scsi_disk_params = {'disk': scsi_disk, 'type': 'lun', + 'format': 'raw', 'bus': 'scsi'} + + disks_xml = '' + pool_name = pool_name_from_uri(self.info['storagepool']) + for index, disk in enumerate(self.info['disks']): + params = dict(base_disk_params) + params['format'] = disk.get('format', params['format']) + params.update(locals().get('%s_disk_params' % storage_type, {})) + params['index'] = index + + volume = disk.get('volume') + if volume is not None: + params['path'] = self._get_volume_path(pool_name, volume) + else: + volume = "%s-%s.img" % (vm_uuid, params['index']) + params['path'] = os.path.join(storage_path, volume) + + disks_xml += get_disk_xml(params)[1] + + return unicode(disks_xml, 'utf-8') + + def to_volume_list(self, vm_uuid): + storage_path = self._get_storage_path() + fmt = 'raw' if self._get_storage_type() in ['logical'] else 'qcow2' + ret = [] + for i, d in enumerate(self.info['disks']): + index = d.get('index', i) + volume = "%s-%s.img" % (vm_uuid, index) + + info = {'name': volume, + 'capacity': d['size'], + 'format': fmt, + 'path': '%s/%s' % (storage_path, volume)} + + if 'logical' == self._get_storage_type() or \ + fmt not in ['qcow2', 'raw']: + info['allocation'] = info['capacity'] + else: + info['allocation'] = 0 + + if 'base' in d: + info['base'] = dict() + base_fmt = imageinfo.probe_img_info(d['base'])['format'] + if base_fmt is None: + raise InvalidParameter("KCHTMPL0024E", {'path': d['base']}) + info['base']['path'] = d['base'] + info['base']['format'] = base_fmt + + v_tree = E.volume(E.name(info['name'])) + v_tree.append(E.allocation(str(info['allocation']), unit='G')) + v_tree.append(E.capacity(str(info['capacity']), unit='G')) + target = E.target( + E.format(type=info['format']), E.path(info['path'])) + if 'base' in d: + v_tree.append(E.backingStore( + E.path(info['base']['path']), + E.format(type=info['base']['format']))) + v_tree.append(target) + info['xml'] = etree.tostring(v_tree) + ret.append(info) + return ret + + def _get_networks_xml(self): + networks = "" + params = {'type': 'network', + 'model': self.info['nic_model']} + for nw in self.info['networks']: + params['network'] = nw + networks += get_iface_xml(params, self.info['arch'], + self.info['os_distro'], + self.info['os_version']) + return unicode(networks, 'utf-8') + + def _get_input_output_xml(self): + sound = """ + <sound model='%(sound_model)s' /> + """ + mouse = """ + <input type='mouse' bus='%(mouse_bus)s'/> + """ + + keyboard = """ + <input type='%(kbd_type)s' bus='%(kbd_bus)s'> </input> + """ + + tablet = """ + <input type='tablet' bus='%(kbd_bus)s'> </input> + """ + + video = """ + <video> + <model type='%(video_model)s'/> + </video> + """ + + input_output = "" + if 'mouse_bus' in self.info.keys(): + input_output += mouse % self.info + if 'kbd_bus' in self.info.keys(): + input_output += keyboard % self.info + if 'tablet_bus' in self.info.keys(): + input_output += tablet % self.info + if 'sound_model' in self.info.keys(): + input_output += sound % self.info + if 'video_model' in self.info.keys(): + input_output += video % self.info + return input_output + + def _get_cpu_xml(self): + # Include CPU topology, if provided + cpu_info = self.info.get('cpu_info') + if cpu_info is not None: + cpu_topo = cpu_info.get('topology') + return get_cpu_xml(self.info.get('cpus'), + self.info.get('memory') << 10, + cpu_topo) + + def to_vm_xml(self, vm_name, vm_uuid, **kwargs): + params = dict(self.info) + params['name'] = vm_name + params['uuid'] = vm_uuid + params['networks'] = self._get_networks_xml() + params['input_output'] = self._get_input_output_xml() + params['qemu-namespace'] = '' + params['cdroms'] = '' + params['qemu-stream-cmdline'] = '' + params['cpu_info'] = self._get_cpu_xml() + params['disks'] = self._get_disks_xml(vm_uuid) + + graphics = dict(self.info['graphics']) + graphics.update(kwargs.get('graphics', {})) + params['graphics'] = get_graphics_xml(graphics) + + libvirt_stream_protocols = kwargs.get('libvirt_stream_protocols', []) + cdrom_xml = self._get_cdrom_xml(libvirt_stream_protocols) + + if not urlparse.urlparse(self.info.get('cdrom', "")).scheme in \ + libvirt_stream_protocols and \ + params.get('iso_stream', False): + params['qemu-stream-cmdline'] = cdrom_xml + else: + params['cdroms'] = cdrom_xml + + # Setting maximum number of slots to avoid errors when hotplug memory + # Number of slots are the numbers of chunks of 1GB that fit inside + # the max_memory of the host minus memory assigned to the VM + params['slots'] = ((params['max_memory'] >> 10) - + params['memory']) >> 10 + if params['slots'] < 0: + raise OperationFailed("KCHVM0041E") + elif params['slots'] == 0: + params['slots'] = 1 + + xml = """ + <domain type='%(domain)s'> + %(qemu-stream-cmdline)s + <name>%(name)s</name> + <uuid>%(uuid)s</uuid> + <maxMemory slots='%(slots)s' unit='KiB'>%(max_memory)s</maxMemory> + <memory unit='MiB'>%(memory)s</memory> + <vcpu>%(cpus)s</vcpu> + %(cpu_info)s + <os> + <type arch='%(arch)s'>hvm</type> + <boot dev='hd'/> + <boot dev='cdrom'/> + </os> + <features> + <acpi/> + <apic/> + <pae/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + %(disks)s + %(cdroms)s + %(networks)s + %(graphics)s + %(input_output)s + <memballoon model='virtio' /> + </devices> + </domain> + """ % params + + # Adding PPC console configuration + if params['arch'] in ['ppc', 'ppc64']: + ppc_console = """<memballoon model='virtio' /> + <console type='pty'> + <target type='serial' port='1'/> + <address type='spapr-vio' reg='0x30001000'/> + </console>""" + xml = xml.replace("<memballoon model='virtio' />", ppc_console) + + return xml + + def validate(self): + self._storage_validate() + self._network_validate() + self._iso_validate() + + def _iso_validate(self): + pass + + def _network_validate(self): + pass + + def _storage_validate(self): + pass + + def fork_vm_storage(self, vm_uuid): + pass + + def _get_storage_path(self): + return '' + + def _get_storage_type(self): + return '' + + def _get_volume_path(self): + return '' + + def _get_all_networks_name(self): + return [] + + def _get_all_storagepools_name(self): + return [] + + def validate_integrity(self): + invalid = {} + # validate networks integrity + invalid_networks = list(set(self.info['networks']) - + set(self._get_all_networks_name())) + if invalid_networks: + invalid['networks'] = invalid_networks + + # validate storagepools integrity + pool_uri = self.info['storagepool'] + pool_name = pool_name_from_uri(pool_uri) + if pool_name not in self._get_all_storagepools_name(): + invalid['storagepools'] = [pool_name] + + # validate iso integrity + # FIXME when we support multiples cdrom devices + iso = self.info.get('cdrom') + if iso: + if os.path.exists(iso): + st_mode = os.stat(iso).st_mode + if not (stat.S_ISREG(st_mode) or stat.S_ISBLK(st_mode)): + invalid['cdrom'] = [iso] + elif not check_url_path(iso): + invalid['cdrom'] = [iso] + + self.info['invalid'] = invalid + + return self.info diff --git a/src/wok/plugins/kimchi/vnc.py b/src/wok/plugins/kimchi/vnc.py new file mode 100644 index 0000000..2532449 --- /dev/null +++ b/src/wok/plugins/kimchi/vnc.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python2 +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import base64 +import errno +import os +from multiprocessing import Process +from websockify import WebSocketProxy + +from wok.config import config, paths + + +WS_TOKENS_DIR = '/var/lib/wok/vnc-tokens' + + +def new_ws_proxy(): + try: + os.makedirs(WS_TOKENS_DIR, mode=0755) + except OSError as e: + if e.errno == errno.EEXIST: + pass + + cert = config.get('server', 'ssl_cert') + key = config.get('server', 'ssl_key') + if not (cert and key): + cert = '%s/wok-cert.pem' % paths.conf_dir + key = '%s/wok-key.pem' % paths.conf_dir + + params = {'web': os.path.join(paths.ui_dir, 'pages/websockify'), + 'listen_port': config.get('display', 'display_proxy_port'), + 'target_cfg': WS_TOKENS_DIR, + 'key': key, 'cert': cert, 'ssl_only': True} + + def start_proxy(): + server = WebSocketProxy(**params) + server.start_server() + + proc = Process(target=start_proxy) + proc.start() + return proc + + +def add_proxy_token(name, port): + with open(os.path.join(WS_TOKENS_DIR, name), 'w') as f: + """ + From python documentation base64.urlsafe_b64encode(s) + substitutes - instead of + and _ instead of / in the + standard Base64 alphabet, BUT the result can still + contain = which is not safe in a URL query component. + So remove it when needed as base64 can work well without it. + """ + name = base64.urlsafe_b64encode(name).rstrip('=') + f.write('%s: localhost:%s' % (name.encode('utf-8'), port)) + + +def remove_proxy_token(name): + try: + os.unlink(os.path.join(WS_TOKENS_DIR, name)) + except OSError: + pass diff --git a/src/wok/plugins/kimchi/xmlutils/Makefile.am b/src/wok/plugins/kimchi/xmlutils/Makefile.am new file mode 100644 index 0000000..207ad7f --- /dev/null +++ b/src/wok/plugins/kimchi/xmlutils/Makefile.am @@ -0,0 +1,25 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +xmlutils_PYTHON = *.py + +xmlutilsdir = $(pythondir)/wok/plugins/kimchi/xmlutils + +install-data-local: + $(MKDIR_P) $(DESTDIR)$(xmlutilsdir) diff --git a/src/wok/plugins/kimchi/xmlutils/__init__.py b/src/wok/plugins/kimchi/xmlutils/__init__.py new file mode 100644 index 0000000..ca7ede4 --- /dev/null +++ b/src/wok/plugins/kimchi/xmlutils/__init__.py @@ -0,0 +1,18 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/src/wok/plugins/kimchi/xmlutils/cpu.py b/src/wok/plugins/kimchi/xmlutils/cpu.py new file mode 100644 index 0000000..32c01a4 --- /dev/null +++ b/src/wok/plugins/kimchi/xmlutils/cpu.py @@ -0,0 +1,60 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import lxml.etree as ET +from lxml.builder import E + + +def get_numa_xml(cpus, memory): + # Returns the NUMA xml to be add into CPU element + # Currently, supports only one node/cell + # <numa> + # <cell id='0' cpus='0-3' memory='512000' unit='KiB'/> + # </numa> + xml = E.numa(E.cell( + id='0', + cpus='0-' + str(cpus - 1) if cpus > 1 else '0', + memory=str(memory), + unit='KiB')) + return ET.tostring(xml) + + +def get_topology_xml(cpu_topo): + # Return the cpu TOPOLOGY element + # <topology sockets='1' cores='2' threads='1'/> + xml = E.topology( + sockets=str(cpu_topo['sockets']), + cores=str(cpu_topo['cores']), + threads=str(cpu_topo['threads'])) + return ET.tostring(xml) + + +def get_cpu_xml(cpus, memory, cpu_topo=None): + # Returns the libvirt CPU element based on given numa and topology + # CPU element will always have numa element + # <cpu> + # <numa> + # <cell id='0' cpus='0-3' memory='512000' unit='KiB'/> + # </numa> + # <topology sockets='1' cores='2' threads='1'/> + # </cpu> + xml = E.cpu(ET.fromstring(get_numa_xml(cpus, memory))) + if cpu_topo is not None: + xml.insert(0, ET.fromstring(get_topology_xml(cpu_topo))) + return ET.tostring(xml) diff --git a/src/wok/plugins/kimchi/xmlutils/disk.py b/src/wok/plugins/kimchi/xmlutils/disk.py new file mode 100644 index 0000000..126ce77 --- /dev/null +++ b/src/wok/plugins/kimchi/xmlutils/disk.py @@ -0,0 +1,164 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import lxml.etree as ET +import os +import socket +import stat +import string +import urlparse +from lxml import objectify +from lxml.builder import E + +from wok.exception import InvalidParameter, NotFoundError +from wok.utils import check_url_path + + +BUS_TO_DEV_MAP = {'ide': 'hd', 'virtio': 'vd', 'scsi': 'sd'} +DEV_TYPE_SRC_ATTR_MAP = {'file': 'file', 'block': 'dev'} + + +def get_disk_xml(params): + """ + <disk type='file' device='cdrom'> + <driver name='qemu' type='raw'/> + + [source XML according to src_type] + + <target dev='%(dev)s' bus='%(bus)s'/> + <readonly/> + </disk> + """ + path = params['path'] + disk_type = params.get('disk', None) + if disk_type is None: + disk_type = _get_disk_type(path) if len(path) > 0 else 'file' + disk = E.disk(type=disk_type, device=params['type']) + driver = E.driver(name='qemu', type=params['format']) + if params['type'] != 'cdrom': + driver.set('cache', 'none') + + disk.append(driver) + + # Get device name according to bus and index values + dev = params.get('dev', (BUS_TO_DEV_MAP[params['bus']] + + string.lowercase[params.get('index', 0)])) + disk.append(E.target(dev=dev, bus=params['bus'])) + + if params.get('address'): + # ide disk target id is always '0' + disk.append(E.address( + type='drive', controller=params['address']['controller'], + bus=params['address']['bus'], target='0', + unit=params['address']['unit'])) + + if len(params['path']) == 0: + return (dev, ET.tostring(disk, encoding='utf-8', pretty_print=True)) + + if disk_type == 'network': + """ + <source protocol='%(protocol)s' name='%(url_path)s'> + <host name='%(hostname)s' port='%(port)s'/> + </source> + """ + output = urlparse.urlparse(params['path']) + port = str(output.port or socket.getservbyname(output.scheme)) + + source = E.source(protocol=output.scheme, name=output.path) + source.append(E.host(name=output.hostname, port=port)) + else: + """ + <source file='%(src)s' /> + """ + source = E.source() + source.set(DEV_TYPE_SRC_ATTR_MAP[disk_type], params['path']) + + disk.append(source) + return (dev, ET.tostring(disk, encoding='utf-8', pretty_print=True)) + + +def _get_disk_type(path): + if check_url_path(path): + return 'network' + + if not os.path.exists(path): + raise InvalidParameter("KCHVMSTOR0003E", {'value': path}) + + # Check if path is a valid local path + if os.path.isfile(path): + return 'file' + + r_path = os.path.realpath(path) + if stat.S_ISBLK(os.stat(r_path).st_mode): + return 'block' + + raise InvalidParameter("KCHVMSTOR0003E", {'value': path}) + + +def get_device_node(dom, dev_name): + xml = dom.XMLDesc(0) + devices = objectify.fromstring(xml).devices + disk = devices.xpath("./disk/target[@dev='%s']/.." % dev_name) + + if not disk: + raise NotFoundError("KCHVMSTOR0007E", + {'dev_name': dev_name, + 'vm_name': dom.name()}) + + return disk[0] + + +def get_vm_disk_info(dom, dev_name): + # Retrieve disk xml and format return dict + disk = get_device_node(dom, dev_name) + if disk is None: + return None + + try: + source = disk.source + if source is not None: + src_type = disk.attrib['type'] + if src_type == 'network': + host = source.host + path = (source.attrib['protocol'] + '://' + + host.attrib['name'] + ':' + + host.attrib['port'] + source.attrib['name']) + else: + path = source.attrib[DEV_TYPE_SRC_ATTR_MAP[src_type]] + except: + path = "" + + return {'dev': dev_name, + 'path': path, + 'type': disk.attrib['device'], + 'format': disk.driver.attrib['type'], + 'bus': disk.target.attrib['bus']} + + +def get_vm_disks(dom): + xml = dom.XMLDesc(0) + devices = objectify.fromstring(xml).devices + + storages = {} + all_disks = devices.xpath("./disk[@device='disk']") + all_disks.extend(devices.xpath("./disk[@device='cdrom']")) + for disk in all_disks: + storages[disk.target.attrib['dev']] = disk.target.attrib['bus'] + + return storages diff --git a/src/wok/plugins/kimchi/xmlutils/graphics.py b/src/wok/plugins/kimchi/xmlutils/graphics.py new file mode 100644 index 0000000..2b4346a --- /dev/null +++ b/src/wok/plugins/kimchi/xmlutils/graphics.py @@ -0,0 +1,45 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import lxml.etree as ET +from lxml.builder import E + + +def get_graphics_xml(params): + """ + <graphics type='%(type)s' autoport='yes' listen='%(listen)s'/> + + - For spice graphics: + + <channel type='spicevmc'> + <target type='virtio' name='com.redhat.spice.0'/> + </channel> + """ + graphics = E.graphics(type=params['type'], autoport='yes', + listen=params['listen']) + graphics_xml = ET.tostring(graphics, encoding='utf-8', pretty_print=True) + + if params['type'] == 'vnc': + return graphics_xml + + # For spice graphics, a channel also must be configured + channel = E.channel(type='spicevmc') + channel.append(E.target(type='virtio', name='com.redhat.spice.0')) + channel_xml = ET.tostring(channel, encoding='utf-8', pretty_print=True) + return graphics_xml + channel_xml diff --git a/src/wok/plugins/kimchi/xmlutils/interface.py b/src/wok/plugins/kimchi/xmlutils/interface.py new file mode 100644 index 0000000..0f3e848 --- /dev/null +++ b/src/wok/plugins/kimchi/xmlutils/interface.py @@ -0,0 +1,61 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014-2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import lxml.etree as ET +from distutils.version import LooseVersion +from lxml.builder import E + +from .. import osinfo + + +def get_iface_xml(params, arch=None, os_distro=None, os_version=None): + """ + <interface type='network'> + <source network='default'/> + <model type='virtio'/> + </interface> + """ + interface = E.interface(type=params['type']) + interface.append(E.source(network=params['network'])) + + model = params.get('model') + + # no model specified; let's try querying osinfo + if model is None: + # if os_distro and os_version are invalid, nic_model will also be None + model = osinfo.lookup(os_distro, os_version).get('nic_model') + + # only append 'model' to the XML if it's been specified as a parameter or + # returned by osinfo.lookup; otherwise let libvirt use its default value + if model is not None: + interface.append(E.model(type=model)) + + mac = params.get('mac', None) + if mac is not None: + interface.append(E.mac(address=mac)) + + # Hack to disable vhost feature in Ubuntu LE and SLES LE (PPC) + if arch == 'ppc64' and \ + ((os_distro == 'ubuntu' and + LooseVersion(os_version) >= LooseVersion('14.04')) or + (os_distro == 'sles' and + LooseVersion(os_version) >= LooseVersion('12'))): + interface.append(E.driver(name='qemu')) + + return ET.tostring(interface, encoding='utf-8', pretty_print=True) diff --git a/src/wok/plugins/kimchi/xmlutils/network.py b/src/wok/plugins/kimchi/xmlutils/network.py new file mode 100644 index 0000000..c73aad9 --- /dev/null +++ b/src/wok/plugins/kimchi/xmlutils/network.py @@ -0,0 +1,122 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import ipaddr +import lxml.etree as ET +from lxml.builder import E + + +# FIXME, do not support ipv6 +def _get_dhcp_elem(**kwargs): + """ + <dhcp> + <range start="192.168.122.100" end="192.168.122.254" /> + <host mac="00:16:3e:77:e2:ed" name="foo.test.com" ip="192.168.122.10" /> + <host mac="00:16:3e:3e:a9:1a" name="bar.test.com" ip="192.168.122.11" /> + </dhcp> + """ + dhcp = E.dhcp() + if 'range' in kwargs.keys(): + dhcp_range = E.range(start=kwargs['range']['start'], + end=kwargs['range']['end']) + dhcp.append(dhcp_range) + + if 'hosts' in kwargs.keys(): + for host in kwargs['hosts']: + dhcp.append(E.host(mac=host['mac'], + name=host['name'], + ip=host['ip'])) + + return dhcp if len(dhcp) > 0 else None + + +def _get_ip_elem(**kwargs): + """ + <ip address="192.168.152.1" netmask="255.255.255.0"> + <dhcp> + <range start="192.168.152.2" end="192.168.152.254" /> + </dhcp> + </ip> + """ + if 'net' not in kwargs.keys(): + return None + + net = ipaddr.IPNetwork(kwargs['net']) + ip = E.ip(address=str(net.ip), netmask=str(net.netmask)) + + dhcp_params = kwargs.get('dhcp', {}) + dhcp = _get_dhcp_elem(**dhcp_params) + if dhcp is not None: + ip.append(dhcp) + + return ip + + +def _get_forward_elem(**kwargs): + """ + <forward mode='hostdev' dev='eth0' managed='yes'> + </forward> + """ + if "mode" in kwargs.keys() and kwargs['mode'] is None: + return None + + forward = E.forward() + if 'mode' in kwargs.keys(): + forward.set('mode', kwargs['mode']) + + if 'dev' in kwargs.keys(): + forward.set('dev', kwargs['dev']) + + if 'managed' in kwargs.keys(): + forward.set('managed', kwargs['managed']) + + return forward + + +def to_network_xml(**kwargs): + network = E.network(E.name(kwargs['name'])) + bridge = kwargs.get('bridge') + if bridge: + network.append(E.bridge(name=bridge)) + + # None means is Isolated network, {} means default mode nat + params = kwargs.get('forward', {"mode": None}) + forward = _get_forward_elem(**params) + if forward is not None: + network.append(forward) + + if 'net' in kwargs: + network.append(_get_ip_elem(**kwargs)) + + return ET.tostring(network) + + +def create_vlan_tagged_bridge_xml(bridge, interface, vlan_id): + vlan = E.vlan(E.interface(name=interface)) + vlan.set('tag', vlan_id) + m = E.interface( + E.start(mode='onboot'), + E.bridge( + E.interface( + vlan, + type='vlan', + name='.'.join([interface, vlan_id]))), + type='bridge', + name=bridge) + return ET.tostring(m) diff --git a/src/wok/plugins/kimchi/xmlutils/qemucmdline.py b/src/wok/plugins/kimchi/xmlutils/qemucmdline.py new file mode 100644 index 0000000..66238a7 --- /dev/null +++ b/src/wok/plugins/kimchi/xmlutils/qemucmdline.py @@ -0,0 +1,45 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import lxml.etree as ET +from lxml.builder import ElementMaker + +QEMU_NAMESPACE = "http://libvirt.org/schemas/domain/qemu/1.0" + + +def get_qemucmdline_xml(args): + """ + <qemu:commandline xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> + <qemu:arg value='-drive'/> + <qemu:arg value='file=%(path)s,if=none,id=drive-%(bus)s0-1-0, + readonly=on,format=%(format)s'/> + <qemu:arg value='-device'/> + <qemu:arg value='%(bus)s-cd,bus=%(bus)s.1,unit=0, + drive=drive-%(bus)s0-1-0,id=%(bus)s0-1-0'/> + </qemu:commandline> + """ + EM = ElementMaker(namespace=QEMU_NAMESPACE, + nsmap={'qemu': QEMU_NAMESPACE}) + + root = EM.commandline() + for opt, value in args.iteritems(): + root.append(EM.arg(value=opt)) + root.append(EM.arg(value=value)) + + return ET.tostring(root, encoding='utf-8', pretty_print=True) diff --git a/src/wok/plugins/kimchi/yumparser.py b/src/wok/plugins/kimchi/yumparser.py new file mode 100644 index 0000000..74f9fa0 --- /dev/null +++ b/src/wok/plugins/kimchi/yumparser.py @@ -0,0 +1,283 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import subprocess +from os import listdir +from os.path import isfile, splitext + + +class YumRepoObject(object): + + def __init__(self, repo_id, repofile): + self.repo_id = repo_id + self.name = None + self.baseurl = None + self.enabled = True + self.gpgcheck = True + self.gpgkey = None + self.metalink = None + self.mirrorlist = None + self.repofile = repofile + self.string_attrs = ['baseurl', 'gpgkey', 'name', + 'metalink', 'mirrorlist'] + self.boolean_attrs = ['enabled', 'gpgcheck'] + + def set_attribute(self, key, strvalue): + if key in self.string_attrs: + setattr(self, key, strvalue) + elif key in self.boolean_attrs: + setattr(self, key, (strvalue == '1')) + + def get_attribute_str(self, key): + if key not in self.get_attributes(): + return None + + if key in self.boolean_attrs: + str_value = '1' if getattr(self, key) is True else '0' + else: + str_value = getattr(self, key) + + if str_value is None: + return None + + return key + '=' + str_value + + def get_attributes(self): + return self.string_attrs + self.boolean_attrs + + def enable(self): + self.enabled = True + + def disable(self): + self.enabled = False + + def __str__(self): + str_obj = '[' + self.repo_id + ']' + '\n' + for key in self.get_attributes(): + if self.get_attribute_str(key) is not None: + str_obj += self.get_attribute_str(key) + '\n' + return str_obj + + +def get_repo_files(): + def _is_repository_file(f): + _, f_extension = splitext(f) + return isfile(f) and (f_extension == '.repo') + + YUM_REPO_DIR = '/etc/yum.repos.d' + return [YUM_REPO_DIR+'/'+f for f in listdir(YUM_REPO_DIR) + if _is_repository_file(YUM_REPO_DIR+'/'+f)] + + +def _ignore_line_repo_file(line): + return line.startswith("#") or '=' not in line + + +def _get_repos_from_file(repo_file): + repos_from_file = {} + current_repo = None + current_repo_id = None + with open(repo_file) as f: + for line in f.readlines(): + line = line.strip() + if line.startswith("["): + if current_repo is not None: + repos_from_file[current_repo_id] = current_repo + current_repo_id = line.strip('[]') + current_repo = YumRepoObject(current_repo_id, repo_file) + continue + if _ignore_line_repo_file(line): + continue + key, value = line.split('=', 1) + key = key.strip() + value = value.strip() + current_repo.set_attribute(key, value) + + # add the last repo from file. + if current_repo is not None: + repos_from_file[current_repo_id] = current_repo + + return repos_from_file + + +def get_yum_repositories(): + repo_files = get_repo_files() + repos = {} + for yum_repo in repo_files: + repos.update(_get_repos_from_file(yum_repo)) + + return repos + + +def _retrieve_repo_line_index(data, repo): + repo_entry = '[' + repo.repo_id + ']\n' + try: + repo_index = data.index(repo_entry) + except: + return None + return repo_index + + +def _update_repo_file_data(data, repo, repo_index): + remaining_repo_attrs = repo.get_attributes() + + for i in range(repo_index + 1, len(data)): + line = data[i].strip() + if line.startswith('['): + break + if _ignore_line_repo_file(line): + continue + key, _ = line.split('=', 1) + key = key.strip() + attr_str = repo.get_attribute_str(key) + if attr_str is None: + continue + remaining_repo_attrs.remove(key) + data[i] = attr_str + '\n' + + for attr in remaining_repo_attrs: + attr_str = repo.get_attribute_str(attr) + if attr_str is None: + continue + data.insert(repo_index+1, attr_str + '\n') + + return data + + +def write_repo_to_file(repo): + with open(repo.repofile) as f: + data = f.readlines() + + repo_index = _retrieve_repo_line_index(data, repo) + if repo_index is None: + return + + data = _update_repo_file_data(data, repo, repo_index) + + with open(repo.repofile, 'w') as f: + f.writelines(data) + + +def _get_last_line_repo(data, repo_index): + stop_delete_index = None + for i in range(repo_index+1, len(data)): + line = data[i].strip() + if line.startswith('['): + stop_delete_index = i - 1 + break + if stop_delete_index is None: + stop_delete_index = len(data) - 1 + + return stop_delete_index + + +def _remove_repo_file_data(data, repo_index): + last_line_repo = _get_last_line_repo(data, repo_index) + for i in range(last_line_repo, repo_index - 1, -1): + data.pop(i) + return data + + +def delete_repo_from_file(repo): + with open(repo.repofile) as f: + data = f.readlines() + + repo_index = _retrieve_repo_line_index(data, repo) + if repo_index is None: + return + + data = _remove_repo_file_data(data, repo_index) + + with open(repo.repofile, 'w') as f: + f.writelines(data) + + +class YumUpdatePackageObject(object): + + def __init__(self, name, arch, version, repo): + self.name = name + self.arch = arch + self.version = version + self.ui_from_repo = repo + + +def _include_line_checkupdate_output(line): + tokens = line.split() + + if len(tokens) != 3: + return False + + if '.' not in tokens[0]: + return False + + return True + + +def _ignore_obsoleting_packages_in(output): + out = '' + for l in output.split('\n'): + if 'Obsoleting ' in l: + break + out += l + '\n' + return out + + +def _filter_lines_checkupdate_output(output): + if output is None: + return [] + + output = _ignore_obsoleting_packages_in(output) + + out = [l for l in output.split('\n') + if _include_line_checkupdate_output(l)] + return out + + +def _get_yum_checkupdate_output(): + cmd = ['yum', 'check-update', '-d0'] + yum_update_cmd = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, error = yum_update_cmd.communicate() + return_code = yum_update_cmd.returncode + if return_code == 1: + return None + + return out + + +def get_yum_packages_list_update(checkupdate_output=None): + if checkupdate_output is None: + checkupdate_output = _get_yum_checkupdate_output() + + filtered_output = _filter_lines_checkupdate_output(checkupdate_output) + + packages = [] + for line in filtered_output: + line = line.split() + index = 0 + name_arch = line[index] + index += 1 + version = line[index] + index += 1 + repo = line[index] + name, arch = name_arch.rsplit('.', 1) + packages.append(YumUpdatePackageObject(name, arch, version, repo)) + + return packages diff --git a/src/wok/plugins/sample/API.json b/src/wok/plugins/sample/API.json new file mode 100644 index 0000000..6ee7d91 --- /dev/null +++ b/src/wok/plugins/sample/API.json @@ -0,0 +1,56 @@ +{ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Plugin Sample API", + "description": "Json schema for Wok's Sample Plugin API", + "type": "object", + "error": "SPAPI0001E", + "properties": { + "rectangles_create": { + "type": "object", + "error": "SPRET0003E", + "properties": { + "name": { + "description": "The name of the new rectangle instance", + "type": "string", + "required": true, + "error": "SPRET0004E" + }, + "length": { + "$ref": "#/definitions/positiveNumber", + "required": true, + "error": "SPRET0005E" + }, + "width": { + "$ref": "#/definitions/positiveNumber", + "required": true, + "error": "SPRET0006E" + } + } + }, + "circles_create": { + "type": "object", + "error": "SPCIRC0003E", + "properties": { + "name": { + "description": "The name of the new circle instance", + "type": "string", + "required": true, + "error": "SPCIRC0004E" + }, + "radius": { + "$ref": "#/definitions/positiveNumber", + "required": true, + "error": "SPCIRC0005E" + } + } + } + }, + "definitions": { + "positiveNumber": { + "error": "SPAPI0002E", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + } + } +} diff --git a/src/wok/plugins/sample/Makefile.am b/src/wok/plugins/sample/Makefile.am new file mode 100644 index 0000000..876ab54 --- /dev/null +++ b/src/wok/plugins/sample/Makefile.am @@ -0,0 +1,29 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +SUBDIRS = ui po + +EXTRA_DIST = API.json sample.conf.in $(wildcard *.py) config.status + +all-local: + while read L && test -n "$$L"; do \ + dir=mo/$$L/LC_MESSAGES ; \ + $(MKDIR_P) $$dir ; \ + ln -sf ../../../po/$$L.gmo $$dir/sample.mo ; \ + done < po/LINGUAS diff --git a/src/wok/plugins/sample/__init__.py b/src/wok/plugins/sample/__init__.py new file mode 100644 index 0000000..a3a8f05 --- /dev/null +++ b/src/wok/plugins/sample/__init__.py @@ -0,0 +1,97 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import json +import os +from cherrypy import expose + + +from wok.config import PluginPaths +from wok.control.base import Collection, Resource +from wok.root import WokRoot + + +from plugins.sample.i18n import messages +from plugins.sample.model import Model + + +model = Model() + + +class Drawings(WokRoot): + def __init__(self, wok_options): + Resource.__init__(self, model) + self.description = Description(model) + self.rectangles = Rectangles(model) + self.circles = Circles(model) + self.paths = PluginPaths('sample') + self.domain = 'sample' + self.messages = messages + self.api_schema = json.load(open(os.path.join(os.path.dirname( + os.path.abspath(__file__)), 'API.json'))) + + @expose + def index(self): + return 'This is a sample plugin for Wok' + + +class Description(Resource): + def __init__(self, model): + super(Description, self).__init__(model) + + @property + def data(self): + return {'name': 'sample', 'version': '0.1'} + + +class Circles(Collection): + def __init__(self, model): + super(Circles, self).__init__(model) + self.resource = Circle + self.admin_methods = ['POST', 'PUT'] + + +class Rectangles(Collection): + def __init__(self, model): + super(Rectangles, self).__init__(model) + self.resource = Rectangle + self.admin_methods = ['POST', 'PUT'] + + +class Circle(Resource): + def __init__(self, model, ident): + super(Circle, self).__init__(model, ident) + self.update_params = ['radius'] + + @property + def data(self): + ret = {'name': self.ident} + ret.update(self.info) + return ret + + +class Rectangle(Resource): + def __init__(self, model, ident): + super(Rectangle, self).__init__(model, ident) + self.update_params = ['length', 'width'] + + @property + def data(self): + self.info.update({'name': self.ident}) + return self.info diff --git a/src/wok/plugins/sample/config.status b/src/wok/plugins/sample/config.status new file mode 120000 index 0000000..6cd6b4f --- /dev/null +++ b/src/wok/plugins/sample/config.status @@ -0,0 +1 @@ +../../config.status \ No newline at end of file diff --git a/src/wok/plugins/sample/i18n.py b/src/wok/plugins/sample/i18n.py new file mode 100644 index 0000000..763970f --- /dev/null +++ b/src/wok/plugins/sample/i18n.py @@ -0,0 +1,40 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import gettext + +_ = gettext.gettext + + +messages = { + "SPAPI0001E": _("Unkown parameter specified %(value)s"), + "SPAPI0002E": _("The specified value %(value)s is not a positive number"), + + "SPCIRC0002E": _("Circle %(name)s does not exist"), + "SPCIRC0003E": _("Specify name and radius to create a Circle"), + "SPCIRC0004E": _("Circle name must be a string"), + "SPCIRC0005E": _("Circle radius must be a positive number"), + + "SPRET0001E": _("Rectangle %(name)s already exists"), + "SPRET0002E": _("Rectangle %(name)s does not exist"), + "SPRET0003E": _("Specify name, length and width to create a Rectangle"), + "SPRET0004E": _("Rectangle name must be a string"), + "SPRET0005E": _("Rectangle length must be a positive number"), + "SPRET0006E": _("Rectangle width must be a positive number"), +} diff --git a/src/wok/plugins/sample/model.py b/src/wok/plugins/sample/model.py new file mode 100644 index 0000000..4ada648 --- /dev/null +++ b/src/wok/plugins/sample/model.py @@ -0,0 +1,131 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from wok.basemodel import BaseModel +from wok.exception import InvalidOperation, NotFoundError + + +class CirclesModel(object): + def __init__(self): + self._circles = {} + + def create(self, params): + name = params['name'] + if name in self._circles: + raise InvalidOperation("SPCIRCLE0001E", {'name': name}) + self._circles[name] = Circle(params['radius']) + return name + + def get_list(self): + return sorted(self._circles) + + +class CircleModel(object): + def __init__(self, parent_model): + # Circel and Circles models are friends, it's OK to share _circles. + self._circles = parent_model._circles + + def lookup(self, name): + try: + circle = self._circles[name] + except KeyError: + raise NotFoundError("SPCIRC0002E", {'name': name}) + return {'radius': circle.radius} + + def update(self, name, params): + if name not in self._circles: + raise NotFoundError("SPCIRC0002E", {'name': name}) + self._circles[name].radius = params['radius'] + return name + + def delete(self, name): + try: + del self._circles[name] + except KeyError: + pass + + +class RectanglesModel(object): + def __init__(self): + self._rectangles = {} + + def create(self, params): + name = params['name'] + if name in self._rectangles: + raise InvalidOperation("SPRET0001E", {'name': name}) + self._rectangles[name] = Rectangle(params['length'], params['width']) + return name + + def get_list(self): + return sorted(self._rectangles) + + +class RectangleModel(object): + def __init__(self, parent_model): + self._rectangles = parent_model._rectangles + + def lookup(self, name): + try: + rectangle = self._rectangles[name] + except KeyError: + raise NotFoundError("SPRET0002E", {'name': name}) + return {'length': rectangle.length, 'width': rectangle.width} + + def update(self, name, params): + if name not in self._rectangles: + raise NotFoundError("SPRET0002E", {'name': name}) + try: + self._rectangles[name].length = params['length'] + except KeyError: + pass + + try: + self._rectangles[name].width = params['width'] + except KeyError: + pass + return name + + def delete(self, name): + try: + del self._rectangles[name] + except KeyError: + pass + + +class Model(BaseModel): + def __init__(self): + circles = CirclesModel() + circle = CircleModel(circles) + + rectangles = RectanglesModel() + rectangle = RectangleModel(rectangles) + + return super(Model, self).__init__( + [circle, circles, rectangle, rectangles]) + + +class Rectangle(object): + def __init__(self, length, width): + self.length = length + self.width = width + + +class Circle(object): + def __init__(self, radius): + self.radius = radius diff --git a/src/wok/plugins/sample/po/LINGUAS b/src/wok/plugins/sample/po/LINGUAS new file mode 100644 index 0000000..469998e --- /dev/null +++ b/src/wok/plugins/sample/po/LINGUAS @@ -0,0 +1,3 @@ +en_US +pt_BR +zh_CN diff --git a/src/wok/plugins/sample/po/Makefile.in.in b/src/wok/plugins/sample/po/Makefile.in.in new file mode 100644 index 0000000..52ab81c --- /dev/null +++ b/src/wok/plugins/sample/po/Makefile.in.in @@ -0,0 +1,400 @@ +# Makefile for PO directory in any package using GNU gettext. +# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper@gnu.ai.mit.edu> +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU General Public +# License but which still want to provide support for the GNU gettext +# functionality. +# Please note that the actual code of GNU gettext is covered by the GNU +# General Public License and is *not* in the public domain. +# +# Origin: gettext-0.18 +GETTEXT_MACRO_VERSION = 0.18 + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ + +SHELL = /bin/sh +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +datadir = @datadir@ +localedir = @prefix@/share/locale +gettextsrcdir = $(datadir)/gettext/po + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +# We use $(MKDIR_P). +# This macro uses the 'mkdir -p' command if possible. Otherwise, it falls back +# on invoking install-sh with the -d option, so your package should contain +# install-sh as described under AC_PROG_INSTALL. +mkinstalldirs = $(SHELL) @install_sh@ -d +install_sh = $(SHELL) @install_sh@ +MKDIR_P = @MKDIR_P@ +MKDIR_P = @MKDIR_P@ + +GMSGFMT_ = @GMSGFMT@ +GMSGFMT_no = @GMSGFMT@ +GMSGFMT_yes = @GMSGFMT_015@ +GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) +MSGFMT_ = @MSGFMT@ +MSGFMT_no = @MSGFMT@ +MSGFMT_yes = @MSGFMT_015@ +MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) +XGETTEXT_ = @XGETTEXT@ +XGETTEXT_no = @XGETTEXT@ +XGETTEXT_yes = @XGETTEXT_015@ +XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) +MSGMERGE = msgmerge +MSGMERGE_UPDATE = @MSGMERGE@ --update +MSGINIT = msginit +MSGCONV = msgconv +MSGFILTER = msgfilter + +POFILES = @POFILES@ +GMOFILES = @GMOFILES@ +UPDATEPOFILES = @UPDATEPOFILES@ +DUMMYPOFILES = @DUMMYPOFILES@ +DISTFILES.common = Makefile.in.in \ +$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) +DISTFILES = $(DISTFILES.common) Makevars POTFILES.in gen-pot \ +$(POFILES) $(GMOFILES) \ +$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) + +POTFILES = \ + +CATALOGS = @CATALOGS@ + +# Makevars gets inserted here. (Don't remove this line!) + +.SUFFIXES: +.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update + +.po.mo: + @echo "$(MSGFMT) -c -o $@ $<"; \ + $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ + +.po.gmo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \ + cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo + +.sin.sed: + sed -e '/^#/d' $< > t-$@ + mv t-$@ $@ + + +all: check-macro-version update-gmo all-@USE_NLS@ + +all-yes: stamp-po +all-no: + +# Ensure that the gettext macros and this Makefile.in.in are in sync. +check-macro-version: + @test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \ + || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \ + exit 1; \ + } + +# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no +# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because +# we don't want to bother translators with empty POT files). We assume that +# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. +# In this case, stamp-po is a nop (i.e. a phony target). + +# stamp-po is a timestamp denoting the last time at which the CATALOGS have +# been loosely updated. Its purpose is that when a developer or translator +# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, +# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent +# invocations of "make" will do nothing. This timestamp would not be necessary +# if updating the $(CATALOGS) would always touch them; however, the rule for +# $(POFILES) has been designed to not touch files that don't need to be +# changed. +stamp-po: $(srcdir)/$(DOMAIN).pot + test ! -f $(srcdir)/$(DOMAIN).pot || \ + test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) + @test ! -f $(srcdir)/$(DOMAIN).pot || { \ + echo "touch stamp-po" && \ + echo timestamp > stamp-poT && \ + mv stamp-poT stamp-po; \ + } + +# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', +# otherwise packages like GCC can not be built if only parts of the source +# have been downloaded. + +$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in + $(srcdir)/gen-pot $(POTFILES) + +# This rule has no dependencies: we don't need to update $(DOMAIN).pot at +# every "make" invocation, only create it when it is missing. +# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. +$(srcdir)/$(DOMAIN).pot: + $(MAKE) $(DOMAIN).pot-update + +# This target rebuilds a PO file if $(DOMAIN).pot has changed. +# Note that a PO file is not touched if it doesn't need to be changed. +$(POFILES): $(srcdir)/$(DOMAIN).pot + @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ + if test -f "$(srcdir)/$${lang}.po"; then \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \ + cd $(srcdir) \ + && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ + $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ + *) \ + $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \ + esac; \ + }; \ + else \ + $(MAKE) $${lang}.po-create; \ + fi + + +install: + +install-exec: +install-data: install-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(MKDIR_P) $(DESTDIR)$(gettextsrcdir); \ + for file in $(DISTFILES.common) Makevars.template; do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + for file in Makevars; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +install-data-no: all +install-data-yes: all + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(MKDIR_P) $(DESTDIR)$$dir; \ + if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ + $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ + echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ + fi; \ + done; \ + done + +install-strip: install + +installdirs: installdirs-exec installdirs-data +installdirs-exec: +installdirs-data: installdirs-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(MKDIR_P) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi +installdirs-data-no: +installdirs-data-yes: + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(MKDIR_P) $(DESTDIR)$$dir; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + fi; \ + done; \ + done + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: + +uninstall-exec: +uninstall-data: uninstall-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + for file in $(DISTFILES.common) Makevars.template; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +uninstall-data-no: +uninstall-data-yes: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + done; \ + done + +check: all + +info dvi ps pdf html tags TAGS ctags CTAGS ID: + +mostlyclean: + rm -f remove-potcdate.sed + rm -f stamp-poT + rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f stamp-po $(GMOFILES) + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: + $(MAKE) update-po + @$(MAKE) dist2 +# This is a separate target because 'update-po' must be executed before. +dist2: stamp-po $(DISTFILES) + dists="$(DISTFILES)"; \ + if test "$(PACKAGE)" = "gettext-tools"; then \ + dists="$$dists Makevars.template"; \ + fi; \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + dists="$$dists $(DOMAIN).pot stamp-po"; \ + fi; \ + if test -f $(srcdir)/ChangeLog; then \ + dists="$$dists ChangeLog"; \ + fi; \ + for i in 0 1 2 3 4 5 6 7 8 9; do \ + if test -f $(srcdir)/ChangeLog.$$i; then \ + dists="$$dists ChangeLog.$$i"; \ + fi; \ + done; \ + if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ + for file in $$dists; do \ + if test -f $$file; then \ + cp -p $$file $(distdir) || exit 1; \ + else \ + cp -p $(srcdir)/$$file $(distdir) || exit 1; \ + fi; \ + done + +update-po: Makefile + $(MAKE) $(DOMAIN).pot-update + test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) + $(MAKE) update-gmo + +# General rule for creating PO files. + +.nop.po-create: + @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ + echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ + exit 1 + +# General rule for updating PO files. + +.nop.po-update: + @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ + if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ + cd $(srcdir); \ + if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ + $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ + *) \ + $(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ + esac; \ + }; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +$(DUMMYPOFILES): + +update-gmo: Makefile $(GMOFILES) + @: + +# Recreate Makefile by invoking config.status. Explicitly invoke the shell, +# because execution permission bits may not work on the current file system. +# Use @SHELL@, which is the shell determined by autoconf for the use by its +# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient. +Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ + cd $(top_builddir) \ + && @SHELL@ ./config.status $(subdir)/$@.in po-directories + +force: + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/wok/plugins/sample/po/Makevars b/src/wok/plugins/sample/po/Makevars new file mode 100644 index 0000000..60de3f1 --- /dev/null +++ b/src/wok/plugins/sample/po/Makevars @@ -0,0 +1,41 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = sample + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = kimchi-devel@ovirt.org + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = diff --git a/src/wok/plugins/sample/po/POTFILES.in b/src/wok/plugins/sample/po/POTFILES.in new file mode 100644 index 0000000..7dbfb6c --- /dev/null +++ b/src/wok/plugins/sample/po/POTFILES.in @@ -0,0 +1,2 @@ +# List of source files which contain translatable strings. +plugins/sample/ui/pages/*.tmpl diff --git a/src/wok/plugins/sample/po/en_US.po b/src/wok/plugins/sample/po/en_US.po new file mode 100644 index 0000000..207d3c3 --- /dev/null +++ b/src/wok/plugins/sample/po/en_US.po @@ -0,0 +1,21 @@ +# English translations for kimchi package. +# Copyright (C) 2014 THE kimchi'S COPYRIGHT HOLDER +# This file is distributed under the same license as the kimchi package. +# shhfeng <shaohef@linux.vnet.ibm.com>, 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 1.2.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-24 09:39-0300\n" +"PO-Revision-Date: 2014-05-17 02:08+0800\n" +"Last-Translator: shhfeng <shaohef@linux.vnet.ibm.com>\n" +"Language-Team: English\n" +"Language: en_US\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ASCII\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" + +msgid "SampleTab" +msgstr "SampleTab" diff --git a/src/wok/plugins/sample/po/gen-pot b/src/wok/plugins/sample/po/gen-pot new file mode 100755 index 0000000..c1cfb8f --- /dev/null +++ b/src/wok/plugins/sample/po/gen-pot @@ -0,0 +1,9 @@ +#!/bin/bash + +for src in $@; do + if [ ${src: -3} == ".py" ]; then + cat $src + else + cat $src | cheetah compile - + fi +done | xgettext --no-location -o sample.pot -L Python - diff --git a/src/wok/plugins/sample/po/pt_BR.po b/src/wok/plugins/sample/po/pt_BR.po new file mode 100644 index 0000000..8519d74 --- /dev/null +++ b/src/wok/plugins/sample/po/pt_BR.po @@ -0,0 +1,24 @@ +# Portuguese translations for kimchi package +# Copyright (C) 2014 THE kimchi'S COPYRIGHT HOLDER +# This file is distributed under the same license as the kimchi package. +# shhfeng <shaohef@linux.vnet.ibm.com>, 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 1.2.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-24 09:39-0300\n" +"PO-Revision-Date: 2014-05-17 02:09+0800\n" +"Last-Translator: Cr��stian Viana <vianac@linux.vnet.ibm.com>\n" +"Language-Team: Aline Manera <alinefm@br.ibm.com>\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"X-Poedit-Country: Brazil\n" +"X-Poedit-Language: Portuguese\n" +"X-Poedit-SourceCharset: utf-8\n" + +msgid "SampleTab" +msgstr "Tab de exemplo" diff --git a/src/wok/plugins/sample/po/sample.pot b/src/wok/plugins/sample/po/sample.pot new file mode 100644 index 0000000..458ffe9 --- /dev/null +++ b/src/wok/plugins/sample/po/sample.pot @@ -0,0 +1,21 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-24 09:39-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "SampleTab" +msgstr "" diff --git a/src/wok/plugins/sample/po/zh_CN.po b/src/wok/plugins/sample/po/zh_CN.po new file mode 100644 index 0000000..04b2501 --- /dev/null +++ b/src/wok/plugins/sample/po/zh_CN.po @@ -0,0 +1,24 @@ +# Chinese translations for kimchi package +# Copyright (C) 2014 THE kimchi'S COPYRIGHT HOLDER +# This file is distributed under the same license as the kimchi package. +# shhfeng <shaohef@linux.vnet.ibm.com>, 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: kimchi 1.2.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-24 09:39-0300\n" +"PO-Revision-Date: 2014-05-17 02:10+0800\n" +"Last-Translator: shhfeng <shaohef@linux.vnet.ibm.com>\n" +"Language-Team: Chinese (simplified)\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"X-Poedit-Country: CHINA\n" +"X-Poedit-Language: Chinese\n" +"X-Poedit-SourceCharset: utf-8\n" + +msgid "SampleTab" +msgstr "������������" diff --git a/src/wok/plugins/sample/sample.conf.in b/src/wok/plugins/sample/sample.conf.in new file mode 100644 index 0000000..9da33e1 --- /dev/null +++ b/src/wok/plugins/sample/sample.conf.in @@ -0,0 +1,27 @@ +[wok] +enable = @ENABLE_SAMPLE@ +plugin_class = "Drawings" +uri = "/plugins/sample" + +[/] +tools.nocache.on = True +tools.trailing_slash.on = False +tools.sessions.on = True +tools.sessions.name = 'wok' +tools.sessions.httponly = True +tools.sessions.locking = 'explicit' +tools.sessions.storage_type = 'ram' + +[/description] +tools.wokauth.on = True + +[/rectangles] +tools.wokauth.on = True + +[/circles] +tools.wokauth.on = True + +[/help] +tools.staticdir.on = True +tools.nocache.on = True +tools.staticdir.dir = wok.config.PluginPaths('sample').ui_dir + '/pages/help' diff --git a/src/wok/plugins/sample/ui/Makefile.am b/src/wok/plugins/sample/ui/Makefile.am new file mode 100644 index 0000000..37fec98 --- /dev/null +++ b/src/wok/plugins/sample/ui/Makefile.am @@ -0,0 +1,22 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +SUBDIRS = config js pages + + diff --git a/src/wok/plugins/sample/ui/config/Makefile.am b/src/wok/plugins/sample/ui/config/Makefile.am new file mode 100644 index 0000000..cf9e09e --- /dev/null +++ b/src/wok/plugins/sample/ui/config/Makefile.am @@ -0,0 +1,21 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2013 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +EXTRA_DIST = tab-ext.xml + diff --git a/src/wok/plugins/sample/ui/config/tab-ext.xml b/src/wok/plugins/sample/ui/config/tab-ext.xml new file mode 100644 index 0000000..aff0d14 --- /dev/null +++ b/src/wok/plugins/sample/ui/config/tab-ext.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<tabs-ext> + <tab> + <access role="admin" mode="admin"/> + <access role="user" mode="none"/> + + <title>SampleTab 1</title> + <path>plugins/sample/sample-tab1.html</path> + </tab> + <tab> + <access role="admin" mode="admin"/> + <access role="user" mode="none"/> + + <title>SampleTab 2</title> + <path>plugins/sample/sample-tab2.html</path> + </tab> +</tabs-ext> diff --git a/src/wok/plugins/sample/ui/css/.gitignore b/src/wok/plugins/sample/ui/css/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/src/wok/plugins/sample/ui/images/.gitignore b/src/wok/plugins/sample/ui/images/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/src/wok/plugins/sample/ui/js/.gitignore b/src/wok/plugins/sample/ui/js/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/src/wok/plugins/sample/ui/js/Makefile.am b/src/wok/plugins/sample/ui/js/Makefile.am new file mode 100644 index 0000000..4d536ae --- /dev/null +++ b/src/wok/plugins/sample/ui/js/Makefile.am @@ -0,0 +1,20 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +EXTRA_DIST = util.js diff --git a/src/wok/plugins/sample/ui/js/util.js b/src/wok/plugins/sample/ui/js/util.js new file mode 100644 index 0000000..7689a81 --- /dev/null +++ b/src/wok/plugins/sample/ui/js/util.js @@ -0,0 +1,33 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +sample = {}; + +sample.description = function(suc, err){ + wok.requestJSON({ + url : 'plugins/sample/description', + type : 'GET', + contentType : 'application/json', + dataType : 'json', + resend : true, + success : suc, + error : err || function(data) { + wok.message.error(data.responseJSON.reason); + } + }); +}; diff --git a/src/wok/plugins/sample/ui/libs/.gitignore b/src/wok/plugins/sample/ui/libs/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/src/wok/plugins/sample/ui/pages/Makefile.am b/src/wok/plugins/sample/ui/pages/Makefile.am new file mode 100644 index 0000000..3da95a2 --- /dev/null +++ b/src/wok/plugins/sample/ui/pages/Makefile.am @@ -0,0 +1,20 @@ +# +# Kimchi +# +# Copyright IBM Corp, 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +EXTRA_DIST = i18n.json.tmpl sample-tab1.html.tmpl sample-tab2.html.tmpl diff --git a/src/wok/plugins/sample/ui/pages/help/en_US/sample-tab1.html b/src/wok/plugins/sample/ui/pages/help/en_US/sample-tab1.html new file mode 100644 index 0000000..7122124 --- /dev/null +++ b/src/wok/plugins/sample/ui/pages/help/en_US/sample-tab1.html @@ -0,0 +1 @@ +Help page for TAB 1 of Wok's Sample plugin. diff --git a/src/wok/plugins/sample/ui/pages/help/en_US/sample-tab2.html b/src/wok/plugins/sample/ui/pages/help/en_US/sample-tab2.html new file mode 100644 index 0000000..1bfe448 --- /dev/null +++ b/src/wok/plugins/sample/ui/pages/help/en_US/sample-tab2.html @@ -0,0 +1 @@ +Help page for TAB 2 of Wok's Sample plugin. diff --git a/src/wok/plugins/sample/ui/pages/i18n.json.tmpl b/src/wok/plugins/sample/ui/pages/i18n.json.tmpl new file mode 100644 index 0000000..737bb39 --- /dev/null +++ b/src/wok/plugins/sample/ui/pages/i18n.json.tmpl @@ -0,0 +1,26 @@ +#* + * Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang) +#silent _ = t.gettext +#silent _t = t.gettext +{ + "SampleTab": "$_("SampleTab")" +} diff --git a/src/wok/plugins/sample/ui/pages/sample-tab1.html.tmpl b/src/wok/plugins/sample/ui/pages/sample-tab1.html.tmpl new file mode 100644 index 0000000..4354d81 --- /dev/null +++ b/src/wok/plugins/sample/ui/pages/sample-tab1.html.tmpl @@ -0,0 +1,30 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +<!DOCTYPE html> +<html> +<script type="text/javascript" src="plugins/sample/js/util.js"></script> +<body> + <div id="samplebody"/> +</body> +<script> + sample.description(function(r){ + \$("#samplebody").html("name: " + r.name + " version: " + r.version); + }); +</script> +</html> diff --git a/src/wok/plugins/sample/ui/pages/sample-tab2.html.tmpl b/src/wok/plugins/sample/ui/pages/sample-tab2.html.tmpl new file mode 100644 index 0000000..4354d81 --- /dev/null +++ b/src/wok/plugins/sample/ui/pages/sample-tab2.html.tmpl @@ -0,0 +1,30 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +<!DOCTYPE html> +<html> +<script type="text/javascript" src="plugins/sample/js/util.js"></script> +<body> + <div id="samplebody"/> +</body> +<script> + sample.description(function(r){ + \$("#samplebody").html("name: " + r.name + " version: " + r.version); + }); +</script> +</html> -- 2.1.4
From: Paulo Vital <pvital@linux.vnet.ibm.com> Update some imports from Kimchi plugin code to be absolute instead of relative. Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- src/wok/plugins/kimchi/control/storagepools.py | 2 +- src/wok/plugins/kimchi/model/debugreports.py | 2 +- src/wok/plugins/kimchi/model/diskutils.py | 2 +- src/wok/plugins/kimchi/model/host.py | 8 ++++---- src/wok/plugins/kimchi/model/interfaces.py | 2 +- src/wok/plugins/kimchi/model/libvirtstoragepool.py | 2 +- src/wok/plugins/kimchi/model/networks.py | 10 +++++----- src/wok/plugins/kimchi/model/storagepools.py | 6 +++--- src/wok/plugins/kimchi/model/storagevolumes.py | 4 ++-- src/wok/plugins/kimchi/model/templates.py | 6 +++--- src/wok/plugins/kimchi/model/vmifaces.py | 2 +- src/wok/plugins/kimchi/model/vms.py | 14 +++++++------- src/wok/plugins/kimchi/model/vmstorages.py | 6 +++--- src/wok/plugins/kimchi/xmlutils/interface.py | 2 +- 14 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/wok/plugins/kimchi/control/storagepools.py b/src/wok/plugins/kimchi/control/storagepools.py index e5f264e..8bc7e50 100644 --- a/src/wok/plugins/kimchi/control/storagepools.py +++ b/src/wok/plugins/kimchi/control/storagepools.py @@ -24,7 +24,7 @@ from wok.control.utils import get_class_name, model_fn from wok.control.utils import validate_params from wok.control.utils import UrlSubNode -from ..model.storagepools import ISO_POOL_NAME +from wok.plugins.kimchi.model.storagepools import ISO_POOL_NAME from storagevolumes import IsoVolumes, StorageVolumes diff --git a/src/wok/plugins/kimchi/model/debugreports.py b/src/wok/plugins/kimchi/model/debugreports.py index 48e6b26..dcd1b64 100644 --- a/src/wok/plugins/kimchi/model/debugreports.py +++ b/src/wok/plugins/kimchi/model/debugreports.py @@ -31,7 +31,7 @@ from wok.utils import add_task, wok_log from wok.utils import run_command from wok.model.tasks import TaskModel -from .. import config +from wok.plugins.kimchi import config class DebugReportsModel(object): diff --git a/src/wok/plugins/kimchi/model/diskutils.py b/src/wok/plugins/kimchi/model/diskutils.py index 350e6eb..59d5afa 100644 --- a/src/wok/plugins/kimchi/model/diskutils.py +++ b/src/wok/plugins/kimchi/model/diskutils.py @@ -20,7 +20,7 @@ from wok.exception import OperationFailed, NotFoundError from wok.utils import wok_log -from ..xmlutils.disk import get_vm_disk_info, get_vm_disks +from wok.plugins.kimchi.xmlutils.disk import get_vm_disk_info, get_vm_disks from vms import VMModel, VMsModel """ diff --git a/src/wok/plugins/kimchi/model/host.py b/src/wok/plugins/kimchi/model/host.py index 75d4de0..6a3e942 100644 --- a/src/wok/plugins/kimchi/model/host.py +++ b/src/wok/plugins/kimchi/model/host.py @@ -33,10 +33,10 @@ from wok.xmlutils.utils import xpath_get_text from wok.model.tasks import TaskModel import hostdev -from .. import disks -from .. import netinfo -from ..repositories import Repositories -from ..swupdate import SoftwareUpdate +from wok.plugins.kimchi import disks +from wok.plugins.kimchi import netinfo +from wok.plugins.kimchi.repositories import Repositories +from wok.plugins.kimchi.swupdate import SoftwareUpdate from config import CapabilitiesModel from vms import DOM_STATE_MAP diff --git a/src/wok/plugins/kimchi/model/interfaces.py b/src/wok/plugins/kimchi/model/interfaces.py index 149afe3..b8b679c 100644 --- a/src/wok/plugins/kimchi/model/interfaces.py +++ b/src/wok/plugins/kimchi/model/interfaces.py @@ -19,7 +19,7 @@ from wok.exception import NotFoundError -from .. import netinfo +from wok.plugins.kimchi import netinfo from networks import NetworksModel diff --git a/src/wok/plugins/kimchi/model/libvirtstoragepool.py b/src/wok/plugins/kimchi/model/libvirtstoragepool.py index b22856b..5da0b3b 100644 --- a/src/wok/plugins/kimchi/model/libvirtstoragepool.py +++ b/src/wok/plugins/kimchi/model/libvirtstoragepool.py @@ -27,7 +27,7 @@ from wok.exception import InvalidParameter, OperationFailed, TimeoutExpired from wok.rollbackcontext import RollbackContext from wok.utils import parse_cmd_output, run_command, wok_log -from ..iscsi import TargetClient +from wok.plugins.kimchi.iscsi import TargetClient class StoragePoolDef(object): diff --git a/src/wok/plugins/kimchi/model/networks.py b/src/wok/plugins/kimchi/model/networks.py index b579865..71ea595 100644 --- a/src/wok/plugins/kimchi/model/networks.py +++ b/src/wok/plugins/kimchi/model/networks.py @@ -30,11 +30,11 @@ from wok.rollbackcontext import RollbackContext from wok.utils import run_command, wok_log from wok.xmlutils.utils import xpath_get_text -from .. import netinfo -from .. import network as knetwork -from ..osinfo import defaults as tmpl_defaults -from ..xmlutils.network import create_vlan_tagged_bridge_xml -from ..xmlutils.network import to_network_xml +from wok.plugins.kimchi import netinfo +from wok.plugins.kimchi import network as knetwork +from wok.plugins.kimchi.osinfo import defaults as tmpl_defaults +from wok.plugins.kimchi.xmlutils.network import create_vlan_tagged_bridge_xml +from wok.plugins.kimchi.xmlutils.network import to_network_xml KIMCHI_BRIDGE_PREFIX = 'kb' diff --git a/src/wok/plugins/kimchi/model/storagepools.py b/src/wok/plugins/kimchi/model/storagepools.py index 0db2ef4..db68252 100644 --- a/src/wok/plugins/kimchi/model/storagepools.py +++ b/src/wok/plugins/kimchi/model/storagepools.py @@ -28,9 +28,9 @@ from wok.exception import NotFoundError, OperationFailed from wok.utils import add_task, run_command, wok_log from wok.xmlutils.utils import xpath_get_text -from ..osinfo import defaults as tmpl_defaults -from ..scan import Scanner -from ..utils import pool_name_from_uri +from wok.plugins.kimchi.osinfo import defaults as tmpl_defaults +from wok.plugins.kimchi.scan import Scanner +from wok.plugins.kimchi.utils import pool_name_from_uri from config import CapabilitiesModel from host import DeviceModel from libvirtstoragepool import StoragePoolDef diff --git a/src/wok/plugins/kimchi/model/storagevolumes.py b/src/wok/plugins/kimchi/model/storagevolumes.py index 99b17d3..5d28966 100644 --- a/src/wok/plugins/kimchi/model/storagevolumes.py +++ b/src/wok/plugins/kimchi/model/storagevolumes.py @@ -34,8 +34,8 @@ from wok.utils import wok_log from wok.xmlutils.utils import xpath_get_text from wok.model.tasks import TaskModel -from ..config import READONLY_POOL_TYPE -from ..isoinfo import IsoImage +from wok.plugins.kimchi.config import READONLY_POOL_TYPE +from wok.plugins.kimchi.isoinfo import IsoImage from diskutils import get_disk_used_by, set_disk_used_by from storagepools import StoragePoolModel diff --git a/src/wok/plugins/kimchi/model/templates.py b/src/wok/plugins/kimchi/model/templates.py index 4f0b204..b6fb84e 100644 --- a/src/wok/plugins/kimchi/model/templates.py +++ b/src/wok/plugins/kimchi/model/templates.py @@ -27,9 +27,9 @@ from wok.exception import NotFoundError, OperationFailed from wok.utils import probe_file_permission_as_user, run_setfacl_set_attr from wok.xmlutils.utils import xpath_get_text -from ..kvmusertests import UserTests -from ..utils import pool_name_from_uri -from ..vmtemplate import VMTemplate +from wok.plugins.kimchi.kvmusertests import UserTests +from wok.plugins.kimchi.utils import pool_name_from_uri +from wok.plugins.kimchi.vmtemplate import VMTemplate from cpuinfo import CPUInfoModel diff --git a/src/wok/plugins/kimchi/model/vmifaces.py b/src/wok/plugins/kimchi/model/vmifaces.py index 87565c8..8f4997f 100644 --- a/src/wok/plugins/kimchi/model/vmifaces.py +++ b/src/wok/plugins/kimchi/model/vmifaces.py @@ -24,7 +24,7 @@ from lxml import etree, objectify from wok.exception import InvalidParameter, MissingParameter from wok.exception import NotFoundError, InvalidOperation -from ..xmlutils.interface import get_iface_xml +from wok.plugins.kimchi.xmlutils.interface import get_iface_xml from config import CapabilitiesModel from vms import DOM_STATE_MAP, VMModel diff --git a/src/wok/plugins/kimchi/model/vms.py b/src/wok/plugins/kimchi/model/vms.py index f37b5d6..fbbbe1d 100644 --- a/src/wok/plugins/kimchi/model/vms.py +++ b/src/wok/plugins/kimchi/model/vms.py @@ -38,13 +38,13 @@ from wok.xmlutils.utils import xpath_get_text, xml_item_update from wok.xmlutils.utils import dictize from wok.model.tasks import TaskModel -from .. import model -from .. import vnc -from ..config import READONLY_POOL_TYPE -from ..kvmusertests import UserTests -from ..screenshot import VMScreenshot -from ..utils import template_name_from_uri -from ..xmlutils.cpu import get_cpu_xml, get_numa_xml +from wok.plugins.kimchi import model +from wok.plugins.kimchi import vnc +from wok.plugins.kimchi.config import READONLY_POOL_TYPE +from wok.plugins.kimchi.kvmusertests import UserTests +from wok.plugins.kimchi.screenshot import VMScreenshot +from wok.plugins.kimchi.utils import template_name_from_uri +from wok.plugins.kimchi.xmlutils.cpu import get_cpu_xml, get_numa_xml from config import CapabilitiesModel from templates import TemplateModel from utils import get_vm_name diff --git a/src/wok/plugins/kimchi/model/vmstorages.py b/src/wok/plugins/kimchi/model/vmstorages.py index bec16c6..9d7bcaa 100644 --- a/src/wok/plugins/kimchi/model/vmstorages.py +++ b/src/wok/plugins/kimchi/model/vmstorages.py @@ -24,9 +24,9 @@ from wok.exception import InvalidOperation, InvalidParameter, NotFoundError from wok.exception import OperationFailed from wok.utils import wok_log -from ..osinfo import lookup -from ..xmlutils.disk import get_device_node, get_disk_xml -from ..xmlutils.disk import get_vm_disk_info, get_vm_disks +from wok.plugins.kimchi.osinfo import lookup +from wok.plugins.kimchi.xmlutils.disk import get_device_node, get_disk_xml +from wok.plugins.kimchi.xmlutils.disk import get_vm_disk_info, get_vm_disks from config import CapabilitiesModel from diskutils import get_disk_used_by, set_disk_used_by from storagevolumes import StorageVolumeModel diff --git a/src/wok/plugins/kimchi/xmlutils/interface.py b/src/wok/plugins/kimchi/xmlutils/interface.py index 0f3e848..64df8cd 100644 --- a/src/wok/plugins/kimchi/xmlutils/interface.py +++ b/src/wok/plugins/kimchi/xmlutils/interface.py @@ -21,7 +21,7 @@ import lxml.etree as ET from distutils.version import LooseVersion from lxml.builder import E -from .. import osinfo +from wok.plugins.kimchi import osinfo def get_iface_xml(params, arch=None, os_distro=None, os_version=None): -- 2.4.3
From: Paulo Vital <pvital@linux.vnet.ibm.com> Updated build (configure.ac and Makefile.am) files to reflect the new paths of plugins after move to src/wok structure. Moved the creation of objectstore file from the Wok's Makefile.am to the Kimchi one and changed the hard-coded '$(DESTDIR)/var' to '$(DESTDIR)/$(localstatedir)' path. Also, updated src/wok/config.py.in file with new plugins path and correct paths of symbolic links and POTFILES. Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- Makefile.am | 20 ++++++++++---------- configure.ac | 16 ++++++++-------- src/wok/Makefile.am | 2 +- src/wok/config.py.in | 7 ++++--- src/wok/plugins/kimchi/Makefile.am | 18 +++++++++++------- src/wok/plugins/kimchi/contrib/kimchi.spec.fedora.in | 11 ++++++----- src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in | 11 ++++++----- src/wok/plugins/sample/config.status | 2 +- src/wok/plugins/sample/po/POTFILES.in | 2 +- 9 files changed, 48 insertions(+), 41 deletions(-) diff --git a/Makefile.am b/Makefile.am index c7914d0..337aa24 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,7 +16,8 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -SUBDIRS = src ui docs contrib po plugins + +SUBDIRS = src ui docs contrib po man_MANS = docs/wokd.8 @@ -35,11 +36,11 @@ EXTRA_DIST = \ $(NULL) -PEP8_BLACKLIST = *src/wok/config.py,*src/wok/i18n.py,*plugins/kimchi +PEP8_BLACKLIST = *src/wok/config.py,*src/wok/i18n.py,*src/wok/plugins/kimchi SKIP_PYFLAKES_ERR = "\./src/wok/websocket\.py" -I18N_FILES = plugins/*/i18n.py \ +I18N_FILES = src/wok/plugins/*/i18n.py \ src/wok/i18n.py \ $(NULL) @@ -69,7 +70,6 @@ all-local: install-deb: install cp -R $(top_srcdir)/contrib/DEBIAN $(DESTDIR)/ - touch $(DESTDIR)/var/lib/wok/objectstore $(MKDIR_P) $(DESTDIR)/etc/init $(MKDIR_P) $(DESTDIR)/usr/lib/firewalld/services cp -R $(top_srcdir)/contrib/wokd-upstart.conf.debian \ @@ -123,10 +123,10 @@ install-data-local: mkdir -p $(DESTDIR)/usr/lib/firewalld/services/; \ $(INSTALL_DATA) src/firewalld.xml $(DESTDIR)/usr/lib/firewalld/services/wokd.xml; \ fi; \ - touch $(DESTDIR)/var/lib/wok/objectstore - mkdir -p $(DESTDIR)/var/log/wok/ - touch $(DESTDIR)/var/log/wok/wok-access.log - touch $(DESTDIR)/var/log/wok/wok-error.log + mkdir -p $(DESTDIR)/$(localstatedir)/lib/wok/ + mkdir -p $(DESTDIR)/$(localstatedir)/log/wok/ + touch $(DESTDIR)/$(localstatedir)/log/wok/wok-access.log + touch $(DESTDIR)/$(localstatedir)/log/wok/wok-error.log mkdir -p $(DESTDIR)/etc/wok/ $(INSTALL_DATA) src/dhparams.pem $(DESTDIR)/etc/wok/dhparams.pem touch $(DESTDIR)/etc/nginx/conf.d/wok.conf @@ -141,8 +141,8 @@ uninstall-local: if test -d /usr/lib/firewalld/services/; then \ $(RM) $(DESTDIR)/usr/lib/firewalld/services/wokd.xml; \ fi; \ - $(RM) -rf $(DESTDIR)/var/lib/wok - $(RM) -rf $(DESTDIR)/var/log/wok + $(RM) -rf $(DESTDIR)/$(localstatedir)/lib/wok + $(RM) -rf $(DESTDIR)/$(localstatedir)/log/wok $(RM) -rf $(DESTDIR)/etc/wok $(RM) $(DESTDIR)/etc/nginx/conf.d/wok.conf diff --git a/configure.ac b/configure.ac index e11a17d..6d4119b 100644 --- a/configure.ac +++ b/configure.ac @@ -94,14 +94,14 @@ AC_CONFIG_FILES([ src/wok/control/Makefile src/wok/model/Makefile src/wok/xmlutils/Makefile - plugins/Makefile - plugins/sample/Makefile - plugins/sample/po/Makefile.in - plugins/sample/sample.conf - plugins/sample/ui/Makefile - plugins/sample/ui/config/Makefile - plugins/sample/ui/js/Makefile - plugins/sample/ui/pages/Makefile + src/wok/plugins/Makefile + src/wok/plugins/sample/Makefile + src/wok/plugins/sample/po/Makefile.in + src/wok/plugins/sample/sample.conf + src/wok/plugins/sample/ui/Makefile + src/wok/plugins/sample/ui/config/Makefile + src/wok/plugins/sample/ui/js/Makefile + src/wok/plugins/sample/ui/pages/Makefile ui/Makefile ui/css/Makefile ui/css/fontawesome/Makefile diff --git a/src/wok/Makefile.am b/src/wok/Makefile.am index 6e00907..47aefd5 100644 --- a/src/wok/Makefile.am +++ b/src/wok/Makefile.am @@ -17,7 +17,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -SUBDIRS = control model xmlutils +SUBDIRS = control model xmlutils plugins wok_PYTHON = $(filter-out config.py, $(wildcard *.py)) diff --git a/src/wok/config.py.in b/src/wok/config.py.in index 616c013..219eee2 100644 --- a/src/wok/config.py.in +++ b/src/wok/config.py.in @@ -80,7 +80,7 @@ class Paths(object): self.log_dir = self.add_prefix('log') self.conf_dir = self.add_prefix('src') self.src_dir = self.add_prefix('src/wok') - self.plugins_dir = self.add_prefix('plugins') + self.plugins_dir = self.add_prefix('src/wok/plugins') self.mo_dir = self.add_prefix('mo') def get_prefix(self): @@ -108,14 +108,15 @@ class PluginPaths(Paths): def __init__(self, name): super(PluginPaths, self).__init__() - self.plugin_dir = os.path.join('plugins', name) if self.installed: - self.state_dir = '@localstatedir@/lib/%s' % name + self.plugin_dir = os.path.join('plugins', name) + self.state_dir = os.path.join(paths.state_dir, self.plugin_dir) self.conf_dir = '@sysconfdir@/wok/plugins.d' self.src_dir = os.path.join('@wokdir@', self.plugin_dir) self.mo_dir = '@prefix@/share/locale' else: + self.plugin_dir = os.path.join(paths.plugins_dir, name) self.state_dir = self.add_prefix(os.path.join(self.plugin_dir, 'data')) self.conf_dir = self.add_prefix(self.plugin_dir) diff --git a/src/wok/plugins/kimchi/Makefile.am b/src/wok/plugins/kimchi/Makefile.am index 49c835e..34ddef4 100644 --- a/src/wok/plugins/kimchi/Makefile.am +++ b/src/wok/plugins/kimchi/Makefile.am @@ -98,10 +98,12 @@ config.py: config.py.in Makefile install-deb: install cp -R $(top_srcdir)/contrib/DEBIAN $(DESTDIR)/ - mkdir -p $(DESTDIR)/var/lib/kimchi/vnc-tokens - mkdir -p $(DESTDIR)/var/lib/kimchi/debugreports - mkdir -p $(DESTDIR)/var/lib/kimchi/screenshots - mkdir -p $(DESTDIR)/var/lib/kimchi/isos + mkdir -p $(DESTDIR)/$(localstatedir)/lib/wok/ + touch $(DESTDIR)/$(localstatedir)/lib/wok/objectstore + mkdir -p $(DESTDIR)/$(localstatedir)/lib/wok/plugins/kimchi/vnc-tokens + mkdir -p $(DESTDIR)/$(localstatedir)/lib/wok/plugins/kimchi/debugreports + mkdir -p $(DESTDIR)/$(localstatedir)/lib/wok/plugins/kimchi/screenshots + mkdir -p $(DESTDIR)/$(localstatedir)/lib/wok/plugins/kimchi/isos deb: contrib/make-deb.sh @@ -137,14 +139,16 @@ ChangeLog: fi install-data-local: + $(MKDIR_P) $(DESTDIR)/$(localstatedir)/lib/wok/ + touch $(DESTDIR)/$(localstatedir)/lib/wok/objectstore $(MKDIR_P) $(DESTDIR)$(kimchidir) $(INSTALL_DATA) API.json $(DESTDIR)$(kimchidir)/API.json - mkdir -p $(DESTDIR)/var/lib/kimchi/vnc-tokens - mkdir -p $(DESTDIR)/var/lib/kimchi/{debugreports,isos,screenshots} + mkdir -p $(DESTDIR)/$(localstatedir)/lib/wok/plugins/kimchi/vnc-tokens + mkdir -p $(DESTDIR)/$(localstatedir)/lib/wok/plugins/kimchi/{debugreports,isos,screenshots} uninstall-local: $(RM) $(DESTDIR)$(kimchidir)/API.json - $(RM) -rf $(DESTDIR)/var/lib/kimchi + $(RM) -rf $(DESTDIR)/$(localstatedir)/lib/wok/plugins/kimchi VERSION: @if test -d .git; then \ diff --git a/src/wok/plugins/kimchi/contrib/kimchi.spec.fedora.in b/src/wok/plugins/kimchi/contrib/kimchi.spec.fedora.in index 0db3d7e..9097043 100644 --- a/src/wok/plugins/kimchi/contrib/kimchi.spec.fedora.in +++ b/src/wok/plugins/kimchi/contrib/kimchi.spec.fedora.in @@ -95,11 +95,12 @@ rm -rf $RPM_BUILD_ROOT %{_sysconfdir}/kimchi/distros.d/ubuntu.json %{_sysconfdir}/kimchi/distros.d/gentoo.json %{_sysconfdir}/kimchi/ -%{_sharedstatedir}/kimchi/debugreports/ -%{_sharedstatedir}/kimchi/isos/ -%{_sharedstatedir}/kimchi/screenshots/ -%{_sharedstatedir}/kimchi/vnc-tokens/ -%{_sharedstatedir}/kimchi/ +%{_sharedstatedir}/wok/plugins/kimchi/debugreports/ +%{_sharedstatedir}/wok/plugins/kimchi/isos/ +%{_sharedstatedir}/wok/plugins/kimchi/screenshots/ +%{_sharedstatedir}/wok/plugins/kimchi/vnc-tokens/ +%{_sharedstatedir}/wok/plugins/kimchi/ +%{_sharedstatedir}/wok/objectstore %changelog diff --git a/src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in b/src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in index e466961..2fbdaf7 100644 --- a/src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in +++ b/src/wok/plugins/kimchi/contrib/kimchi.spec.suse.in @@ -82,11 +82,12 @@ rm -rf $RPM_BUILD_ROOT %{_sysconfdir}/kimchi/distros.d/ubuntu.json %{_sysconfdir}/kimchi/distros.d/gentoo.json %{_sysconfdir}/kimchi/ -%{_var}/lib/kimchi/debugreports/ -%{_var}/lib/kimchi/isos/ -%{_var}/lib/kimchi/screenshots/ -%{_var}/lib/kimchi/vnc-tokens/ -%{_var}/lib/kimchi/ +%{_var}/lib/wok/plugins/kimchi/debugreports/ +%{_var}/lib/wok/plugins/kimchi/isos/ +%{_var}/lib/wok/plugins/kimchi/screenshots/ +%{_var}/lib/wok/plugins/kimchi/vnc-tokens/ +%{_var}/lib/wok/plugins/kimchi/ +%{_var}/lib/wok/objectstore %changelog diff --git a/src/wok/plugins/sample/config.status b/src/wok/plugins/sample/config.status index 6cd6b4f..7297963 120000 --- a/src/wok/plugins/sample/config.status +++ b/src/wok/plugins/sample/config.status @@ -1 +1 @@ -../../config.status \ No newline at end of file +../../../../config.status \ No newline at end of file diff --git a/src/wok/plugins/sample/po/POTFILES.in b/src/wok/plugins/sample/po/POTFILES.in index 7dbfb6c..0aaf102 100644 --- a/src/wok/plugins/sample/po/POTFILES.in +++ b/src/wok/plugins/sample/po/POTFILES.in @@ -1,2 +1,2 @@ # List of source files which contain translatable strings. -plugins/sample/ui/pages/*.tmpl +src/wok/plugins/sample/ui/pages/*.tmpl -- 2.4.3
From: Paulo Vital <pvital@linux.vnet.ibm.com> Removed the hard-coded state_dir path (/var/lib/kimchi) and make it dynamic to get based on PluginPaths() value. By default, this value is set to /var/lib/wok/plugins/kimchi. Changed the state_dir path (/var/lib/kimchi) to the new path using Wok structure (/var/lib/wok/plugins/kimchi) in documentation and tests. Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- src/wok/plugins/kimchi/docs/README.md | 2 +- src/wok/plugins/kimchi/model/libvirtstoragepool.py | 4 +++- src/wok/plugins/kimchi/model/storagepools.py | 2 +- src/wok/plugins/kimchi/tests/test_mock_storagepool.py | 2 +- src/wok/plugins/kimchi/tests/test_mock_storagevolume.py | 2 +- src/wok/plugins/kimchi/tests/test_model.py | 2 +- src/wok/plugins/kimchi/tests/test_model_storagepool.py | 2 +- src/wok/plugins/kimchi/tests/test_storagepoolxml.py | 2 +- src/wok/plugins/kimchi/tests/test_template.py | 2 +- 9 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/wok/plugins/kimchi/docs/README.md b/src/wok/plugins/kimchi/docs/README.md index f400333..b52892a 100644 --- a/src/wok/plugins/kimchi/docs/README.md +++ b/src/wok/plugins/kimchi/docs/README.md @@ -223,7 +223,7 @@ new template using the "+" button in the upper right corner. To create a template, you need an ISO on your host or using remote one. If you are willing to use your own ISO, please copy it to out of box storage -pool (default path is: /var/lib/kimchi/isos). +pool (default path is: /var/lib/wok/plugins/kimchi/isos). Known Issues ------------ diff --git a/src/wok/plugins/kimchi/model/libvirtstoragepool.py b/src/wok/plugins/kimchi/model/libvirtstoragepool.py index 5da0b3b..108c381 100644 --- a/src/wok/plugins/kimchi/model/libvirtstoragepool.py +++ b/src/wok/plugins/kimchi/model/libvirtstoragepool.py @@ -23,6 +23,7 @@ import os import tempfile from lxml.builder import E +from wok.config import PluginPaths from wok.exception import InvalidParameter, OperationFailed, TimeoutExpired from wok.rollbackcontext import RollbackContext from wok.utils import parse_cmd_output, run_command, wok_log @@ -77,7 +78,8 @@ class NetfsPoolDef(StoragePoolDef): def __init__(self, poolArgs): super(NetfsPoolDef, self).__init__(poolArgs) - self.path = '/var/lib/kimchi/nfs_mount/' + self.poolArgs['name'] + self.path = PluginPaths('kimchi').state_dir + '/nfs_mount/' + self.path = self.path + self.poolArgs['name'] def prepare(self, conn): mnt_point = tempfile.mkdtemp(dir='/tmp') diff --git a/src/wok/plugins/kimchi/model/storagepools.py b/src/wok/plugins/kimchi/model/storagepools.py index db68252..1764fe9 100644 --- a/src/wok/plugins/kimchi/model/storagepools.py +++ b/src/wok/plugins/kimchi/model/storagepools.py @@ -79,7 +79,7 @@ class StoragePoolsModel(object): pools[default_pool] = {'path': '/var/lib/libvirt/images'} if config.get("server", "create_iso_pool") == "true": - pools['ISO'] = {'path': '/var/lib/kimchi/isos'} + pools['ISO'] = {'path': PluginPaths('kimchi').state_dir + '/isos'} error_msg = ("Please, check the configuration in %s/template.conf to " "ensure it has a valid storage pool." % diff --git a/src/wok/plugins/kimchi/tests/test_mock_storagepool.py b/src/wok/plugins/kimchi/tests/test_mock_storagepool.py index 5cf5b3e..07c3e07 100644 --- a/src/wok/plugins/kimchi/tests/test_mock_storagepool.py +++ b/src/wok/plugins/kimchi/tests/test_mock_storagepool.py @@ -82,7 +82,7 @@ class MockStoragepoolTests(unittest.TestCase): 'path': '/tmp/kimchi-images'}, {'type': 'netfs', 'name': u'k������h��UnitTestNSFPool', 'source': {'host': 'localhost', - 'path': '/var/lib/kimchi/nfs-pool'}}, + 'path': '/var/lib/wok/plugins/kimchi/nfs-pool'}}, {'type': 'scsi', 'name': u'k������h��UnitTestSCSIFCPool', 'source': {'adapter_name': fc_devs[0]}}, {'type': 'iscsi', 'name': u'k������h��UnitTestISCSIPool', diff --git a/src/wok/plugins/kimchi/tests/test_mock_storagevolume.py b/src/wok/plugins/kimchi/tests/test_mock_storagevolume.py index 9d0a5ad..643fe1b 100644 --- a/src/wok/plugins/kimchi/tests/test_mock_storagevolume.py +++ b/src/wok/plugins/kimchi/tests/test_mock_storagevolume.py @@ -77,7 +77,7 @@ class MockStorageVolumeTests(unittest.TestCase): 'path': '/tmp/kimchi-images'}, {'type': 'netfs', 'name': u'k������h��UnitTestNSFPool', 'source': {'host': 'localhost', - 'path': '/var/lib/kimchi/nfs-pool'}}, + 'path': '/var/lib/wok/plugins/kimchi/nfs-pool'}}, {'type': 'scsi', 'name': u'k������h��UnitTestSCSIFCPool', 'source': {'adapter_name': fc_devs[0]}}, {'type': 'iscsi', 'name': u'k������h��UnitTestISCSIPool', diff --git a/src/wok/plugins/kimchi/tests/test_model.py b/src/wok/plugins/kimchi/tests/test_model.py index 7c89048..4b8ea69 100644 --- a/src/wok/plugins/kimchi/tests/test_model.py +++ b/src/wok/plugins/kimchi/tests/test_model.py @@ -49,7 +49,7 @@ invalid_repository_urls = ['www.fedora.org', # missing protocol 'http://www.fedora', # invalid domain name 'file:///home/foobar'] # invalid path -TMP_DIR = '/var/lib/kimchi/tests/' +TMP_DIR = '/var/lib/wok/plugins/kimchi/tests/' UBUNTU_ISO = TMP_DIR + 'ubuntu14.04.iso' diff --git a/src/wok/plugins/kimchi/tests/test_model_storagepool.py b/src/wok/plugins/kimchi/tests/test_model_storagepool.py index 5f9b966..7c5d6eb 100644 --- a/src/wok/plugins/kimchi/tests/test_model_storagepool.py +++ b/src/wok/plugins/kimchi/tests/test_model_storagepool.py @@ -107,7 +107,7 @@ class StoragepoolTests(unittest.TestCase): self.assertEquals(len(storagepools) + 3, len(pools)) # Create a pool with an existing path - tmp_path = tempfile.mkdtemp(dir='/var/lib/kimchi') + tmp_path = tempfile.mkdtemp(dir='/var/lib/wok/plugins/kimchi') rollback.prependDefer(os.rmdir, tmp_path) req = json.dumps({'name': 'existing_path', 'type': 'dir', 'path': tmp_path}) diff --git a/src/wok/plugins/kimchi/tests/test_storagepoolxml.py b/src/wok/plugins/kimchi/tests/test_storagepoolxml.py index 7e45cca..86c3198 100644 --- a/src/wok/plugins/kimchi/tests/test_storagepoolxml.py +++ b/src/wok/plugins/kimchi/tests/test_storagepoolxml.py @@ -53,7 +53,7 @@ class StoragepoolXMLTests(unittest.TestCase): <dir path='/var/export'/> </source> <target> - <path>/var/lib/kimchi/nfs_mount/unitTestNFSPool</path> + <path>/var/lib/wok/plugins/kimchi/nfs_mount/unitTestNFSPool</path> </target> </pool> """}, diff --git a/src/wok/plugins/kimchi/tests/test_template.py b/src/wok/plugins/kimchi/tests/test_template.py index c7de182..ca95c91 100644 --- a/src/wok/plugins/kimchi/tests/test_template.py +++ b/src/wok/plugins/kimchi/tests/test_template.py @@ -311,7 +311,7 @@ class TemplateTests(unittest.TestCase): 'path': '/tmp/kimchi-images'}, {'type': 'netfs', 'name': u'k������h��UnitTestNSFPool', 'source': {'host': 'localhost', - 'path': '/var/lib/kimchi/nfs-pool'}}, + 'path': '/var/lib/wok/plugins/kimchi/nfs-pool'}}, {'type': 'scsi', 'name': u'k������h��UnitTestSCSIFCPool', 'source': {'adapter_name': fc_devs[0]}}, {'type': 'iscsi', 'name': u'k������h��UnitTestISCSIPool', -- 2.4.3
From: Paulo Vital <pvital@linux.vnet.ibm.com> Adding ASL2 and LGPL license files and contribution file. Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- src/wok/plugins/kimchi/CONTRIBUTE.md | 16 + src/wok/plugins/kimchi/COPYING | 19 + src/wok/plugins/kimchi/COPYING.ASL2 | 202 ++++ src/wok/plugins/kimchi/COPYING.LGPL | 165 +++ src/wok/plugins/kimchi/ChangeLog | 2155 ++++++++++++++++++++++++++++++++++ 5 files changed, 2557 insertions(+) create mode 100644 src/wok/plugins/kimchi/CONTRIBUTE.md create mode 100644 src/wok/plugins/kimchi/COPYING create mode 100644 src/wok/plugins/kimchi/COPYING.ASL2 create mode 100644 src/wok/plugins/kimchi/COPYING.LGPL create mode 100644 src/wok/plugins/kimchi/ChangeLog diff --git a/src/wok/plugins/kimchi/CONTRIBUTE.md b/src/wok/plugins/kimchi/CONTRIBUTE.md new file mode 100644 index 0000000..f4dcaec --- /dev/null +++ b/src/wok/plugins/kimchi/CONTRIBUTE.md @@ -0,0 +1,16 @@ +How to Contribute +================= + +All development discussion happens on the mailing list. All development is done +using the `git` SCM. Patches should be sent using the `git send-email` command +to the kimchi-devel@ovirt.org mailing list. + +Good examples of how to send patches are included in +[QEMU SubmitAPatch](http://wiki.qemu.org/Contribute/SubmitAPatch) and +[Linux SubmittingPatches](https://www.kernel.org/doc/Documentation/SubmittingPatches). + +All documentation and READMEs are written using +[Markdown](http://daringfireball.net/projects/markdown/). + +For a patch to be committed, it must receive at least one "Reviewed-by" on the +mailing list. diff --git a/src/wok/plugins/kimchi/COPYING b/src/wok/plugins/kimchi/COPYING new file mode 100644 index 0000000..4cc4028 --- /dev/null +++ b/src/wok/plugins/kimchi/COPYING @@ -0,0 +1,19 @@ +Wok/Kimchi are distributed pursuant to the terms of two different licenses. +The user interface (located in ui/ and plugins/kimchi/ui in this distribution) +is governed by the Apache License version 2.0. + +Except the imported code under the following directories: +- plugins/kimchi/ui/spice-html5 which is imported from spice-html5 project +(http://cgit.freedesktop.org/spice/spice-html5); +- ui/libs which is imported from JQuery UI (http://jqueryui.com); +- ui/fontello which is generated by http://fontello.com open source project. + +The rest of this distribution is governed by the GNU Lesser General Public +License version 3. + +See COPYING.LGPL and COPYING.ASL2. + +The name "Gentoo" and the "g" logo are trademarks of Gentoo Foundation, Inc. +The content, project, site, product or any other type of item with which the +"Gentoo" name is associated is not part of the Gentoo project and is not +directed or managed by Gentoo Foundation, Inc. diff --git a/src/wok/plugins/kimchi/COPYING.ASL2 b/src/wok/plugins/kimchi/COPYING.ASL2 new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/src/wok/plugins/kimchi/COPYING.ASL2 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/wok/plugins/kimchi/COPYING.LGPL b/src/wok/plugins/kimchi/COPYING.LGPL new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/src/wok/plugins/kimchi/COPYING.LGPL @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/src/wok/plugins/kimchi/ChangeLog b/src/wok/plugins/kimchi/ChangeLog new file mode 100644 index 0000000..0075a2f --- /dev/null +++ b/src/wok/plugins/kimchi/ChangeLog @@ -0,0 +1,2155 @@ +CHANGELOG +========= + +#### [1.5.1] #### + * [19ded0b] Update ChangeLog and Version files for 1.5.1 release (Aline Manera) + * [b183877] Update pt_BR translations (Aline Manera) + * [355e206] Raw volumes validation: update tests (Paulo Vital) + * [6b5727e] Raw volumes validation: back-end and front-end (Paulo Vital) + * [cffec17] Raw volumes validation: update contrib and README (Paulo Vital) + * [584b8d9] Add missing translations (Aline Manera) + * [251d82e] Add volume to storage pool label not formatted properly in some languages (Socorro Stoppler) + * [ee25fb9] Update help pages for ja_JP and pt_BR (Aline Manera) + * [4f76ccf] Isolate strings in guest-edit and template-add (Ramon Medeiros) + * [045a97c] PCI filter not in sync with device listing (Socorro Stoppler) + * [8c1a0c9] Fix confirmation box for delete and clone (Socorro Stoppler) + * [90cc4d8] Handles http redirection when checking url path (Jose Ricardo Ziviani) + * [7d40ff4] Expands all possible variables in a repo url to validate it (Jose Ricardo Ziviani) + * [a727d32] Implement a method to expand variables in a url (Jose Ricardo Ziviani) + * [9fe226b] Add translation for "Users" and "Groups" on guest edit (Ramon Medeiros) + * [4f4c4fc] Update build process to include jquery.base64.js (Aline Manera) + * [e3613ef] Adds the new display_repo_name field in the JSON API (Jose Ricardo Ziviani) + * [c58b1aa] Display the expanded repo name instead of variables (Jose Ricardo Ziviani) + * [598670f] Implement a method to display the repo name expanding variables (Jose Ricardo Ziviani) + * [f3b25c4] Remove colon character from template cpu edit window (Rodrigo Trujillo) + * [20efb22] Add Fedora 22 as remote ISO option. (Paulo Vital) + * [3ec935c] Add Fedora 21 as remote ISO option. (Paulo Vital) + * [03fd734] Update Fedora Live 20 URL as remote ISO (Paulo Vital) + * [13e95ce] Add unity tests for start/shutdown/poweroff response commands (Ramon Medeiros) + * [2f3ffd8] Issues #682/#684/#685: Change some code errors when start, shutdown or power.. (Ramon Medeiros) + * [760e5a8] Issue #667: Unable to rename guest when it is paused (Ramon Medeiros) + * [e32d366] Bug fix: Access guest console when guest name has non-ASCII characters (Aline Manera) + * [8187a97] Update server configuration to expose jquery.base64.js (Aline Manera) + * [cd1c0c7] Import Jquery Base64 code (Aline Manera) + * [a7712c3] Fix bug #450: Allow creating guest with non-ASCII characters in name (Aline Manera) + * [1e537c4] Create helper method to remove metadata node (Aline Manera) + * [123f2cc] Allow setting multiple metadata nodes at once (Aline Manera) + * [5ce57b1] Remove manual <metadata> manupulation (Aline Manera) + * [a3f2525] Disallow storage format changes in UI for templates based on image file (Jose Ricardo Ziviani) + * [e2c6b8c] Avoid show user/password in url browser (Rodrigo Trujillo) + * [453155d] Add missing translations (Aline Manera) + * [d78e0b4] Improve code to get default disk format for VMTemplate (Aline Manera) + * [4ad0c61] Add m4/pkg.m4 to .gitignore (Aline Manera) + * [baa58d1] Fix SLES 11 reg exp to recognize SLE-11-SP4-SAP-DVD-ppc64-GM-DVD1.iso (Ramon Medeiros) + * [93c77d3] Set default VM template memory to 2048 in Power (Daniel Henrique Barboza) + * [c9c80c2] Improve code performance on UI (Ramon Medeiros) + * [5a906b7] PCI Node filtering (Socorro Stoppler) + * [358bb48] Force qcow2 when creating a VM based on backing image (Jose Ricardo Ziviani) + * [20564f8] vmHostDevModel: returning 'product' and 'vendor' in lookup (Daniel Henrique Barboza) + * [947030a] Change getsebool to run silently. (Jose Ricardo Ziviani) + * [583824f] Add option 'silent' in run_command (Jose Ricardo Ziviani) + * [17ad4cd] Fixing compilation problems with translation files (Daniel Henrique Barboza) + * [dc76a2a] Translation updates (Daniel Henrique Barboza) + * [5775d48] Template disk format test fixes (Daniel Henrique Barboza) + * [630d2ae] Remove unecessary call to node_dev.parent() (Ramon Medeiros) + * [1f3ad8b] Update Fedora 20 ISO path to mirrors.kernel.org (Ramon Medeiros) + * [10e0170] Detach group of PCI Devices from host before attaching to guest (Jose Ricardo Ziviani) + * [c5e33e4] New unit tests to check disk creation behavior (Daniel Henrique Barboza) + * [859cff7] Getting default disk format from template.conf (Daniel Henrique Barboza) + * [6195bf8] Mockmodel and test changes for the new API (Daniel Henrique Barboza) + * [73b2917] Adding new API in the UI APIs and docs (Daniel Henrique Barboza) + * [e9cb253] Get available host passthrough devices: model changes (Daniel Henrique Barboza) + * [9e47f9e] Fix displaying numerous error msgs when host is shut down (Socorro Stoppler) + * [44fcf75] Fix minus in manpage (Frederic Bonnard) + * [f0915d4] Help updates for Kimchi (Kersten Richter) + * [fe1d00a] Issue #670: openSUSE: problem while building Kimchi (Ramon Medeiros) + * [55df955] Issue #670: openSUSE: problem while building Kimchi (Ramon Medeiros) + * [5924897] Github 663: software update improvements (Daniel Henrique Barboza) + * [b052da8] Bug fix: Allow creating a pool using an existing path (Aline Manera) + +#### [1.5.0] #### + * [38ee948] Update ChangeLog, VERSION and .po files for 1.5 release (Aline Manera) + * [87bc47f] Prevent Kimchi against TLS Logjam attacks (Rodrigo Trujillo) + * [aaa60fa] Issue #653: "make rpm" requests authentication with non-root (Ramon Medeiros) + * [51f4dd5] Bug fix: Use a temp directory under /var to avoid permission errors (Aline Manera) + * [e0db9f2] Bug fix: Detach host device prior to attach to guest (Aline Manera) + * [ebd8f65] Gtihub #660 - Fixing .repo file with no repos handling (Daniel Henrique Barboza) + * [dfb220f] Support xorriso ISOs detection (Ramon Medeiros) + * [fc7ecea] Github #657 - fixing yum check-update parsing (Daniel Henrique Barboza) + * [30ceeea] Bug fix: Allow user creates multiple templates (Aline Manera) + * [c4d040b] Changing repositories and swupdate to use yumparser module (Daniel Henrique Barboza) + * [4bfddd1] Unit tests for the yumparser module (Daniel Henrique Barboza) + * [964d5eb] Adding yumparser module (Daniel Henrique Barboza) + * [0c3a3e8] Fix bug #647: Properly set qxl as video model for Fedora 22 (Aline Manera) + * [392feb9] Update po files for 1.5 release (Aline Manera) + * [b19989b] Change the width of Actions button (Socorro Stoppler) + * [c074f60] Fix tests, adds slot and memory hotplug tests (Rodrigo Trujillo) + * [94826cf] Add maxMemory and numa configuration to guest xml (Rodrigo Trujillo) + * [437e989] Add maxMemory into templates (Rodrigo Trujillo) + * [86f0e13] Feature test to check support to memory devices (Rodrigo Trujillo) + * [d2741fa] pep8 fixes (Daniel Henrique Barboza) + * [7a4bd1b] UI-Template Edit: Enable user to change disk format (Rodrigo Trujillo) + * [ee0c11d] Supress error messages while checking vm metadata (Ramon Medeiros) + * [a1ad10e] Add support for Pause/Resume UI (Socorro Stoppler) + * [9dea5f6] Does not list non-bootable images (Ramon Medeiros) + * [577d85d] Enable storage volume upload on UI (Aline Manera) + * [2d4cb23] Storage volume upload: Let the 'format' parameter be an empty string (Aline Manera) + * [8a83cbe] Storage volume upload: Keep the task tracking to update the UI (Aline Manera) + * [6704c66] Set 'used_by' to [] when creating some volumes (Cr��stian Deives) + * [c384530] Replace storage volume 'ref_cnt' with 'used_by' (Cr��stian Deives) + * [34634e9] Update test cases to reflect MAC address update changes (Jose Ricardo Ziviani) + * [a1ac29f] Implement frontend code to edit MAC address of a guest (Jose Ricardo Ziviani) + * [3058559] Implement backend code to edit MAC address of a guest (Jose Ricardo Ziviani) + * [2ccb544] Add vfio driver as default for powerkvm systems. (Jose Ricardo Ziviani) + * [82d4308] Removing the hardcoded version of kimchi and make it depend of PACKAGE_VERSION (Fr��d��ric Bonnard) + * [0ef10a1] UI: Enable virtual NIC hot plug/unplug (Aline Manera) + * [16e2944] Change log message if command to run is not found (Jose Ricardo Ziviani) + * [04d2953] Install service on make install (Ramon Medeiros) + * [1aa919c] Fix SLES version checking in interfaces.py (Rodrigo Trujillo) + * [0902323] Remove storage volume creation from file (Aline Manera) + * [7f33702] Upload storage volume (Aline Manera) + * [1327f49] Update controller to make update accept formdata params (Royce Lv) + * [83e470f] Fix URI format of guest interfaces (Jose Ricardo Ziviani) + * [872e379] Display MAC Address in guest interface tab (Jose Ricardo Ziviani) + * [205a3f4] Avoid certificate validation on tests (Ramon Medeiros) + * [8b5b932] Handle invalid path in 'get_disk_ref_cnt' (Cr��stian Deives) + * [16c4b9b] fix: Use correct path when setting 'ref_cnt' to a new volume (Cr��stian Deives) + * [b231913] Bug fix: Build default pools list according to user input (Aline Manera) + * [f1a13ac] Fixed section number within the man page itself (Frederic Bonnard) + * [1cc236f] Add documentation for VM suspend/resume (Cr��stian Deives) + * [b61931d] Verify storage pool set as Template default prior to server starts up (Aline Manera) + * [e0a6fb5] Verify all networks set as Template defaults prior to server start up (Aline Manera) + * [e1ac636] Make Template defaults configurable (Aline Manera) + * [2f0a442] snapshot: Handle non-existing snapshots in mock lookup (Cr��stian Deives) + * [9b3fec5] Create option to auto create ISO pool or not on server start up (Aline Manera) + * [bef2836] Add libvirt-daemon-config-network package as Kimchi dependency (Aline Manera) + * [f6e0177] Merge common_spec with defaults value in osinfo.py (Aline Manera) + * [aa36517] Remove useless variable in osinfo.py (Aline Manera) + * [14e0179] Create VMs Asynchronously: UI (Aline Manera) + * [8c85938] Create VMs Asynchronously: Tests (Christy Perez) + * [698797a] Create VMs asynchronously: Backend (Christy Perez) + * [a2c5abc] UI changes for new clone target_uri (Christy Perez) + * [6aef7da] Tests for new clone target_uri (Christy Perez) + * [e7eef4d] Append clone to target_uri for vm clone task (Christy Perez) + * [a65075a] Do not resolve hostname to IP in using remote ISOs (Aline Manera) + * [d6ec766] Improve code to retrieve the number of host CPUs (Jose Ricardo Ziviani) + * [fde36c0] Move kimchi nginx config file to nginx default directory. (Jose Ricardo Ziviani) + * [16a25ce] Add a warn about NM running in the system. (Jose Ricardo Ziviani) + * [69af91d] Implement function to check if NM is running. (Jose Ricardo Ziviani) + * [ec0a453] Host tests (Aline Manera) + * [81dd7ce] issue #548: Hotplug network interfaces (Cr��stian Deives) + * [aeb667d] Use default network model when attaching a NIC (Cr��stian Deives) + * [838a30c] Handle missing parameter "network" when attaching a NIC (Cr��stian Deives) + * [a00b2f7] Parse osinfo.lookup return parameters correctly (Cr��stian Deives) + * [738165d] Remove nginx conf on suse (Ramon Medeiros) + * [7fbb521] Create empty files on rpm build (Ramon Medeiros) + * [b80e55c] Adds tests to check disk format information in new templates (Rodrigo Trujillo) + * [85e9bac] Set qcow2 as default disk format in new templates (Rodrigo Trujillo) + * [79c6105] Template: Assign 'raw' to disk format if pool is 'logical' or [i]scsi (Rodrigo Trujillo) + * [61ede25] Server tests (Aline Manera) + * [95cd887] Object store tests (Aline Manera) + * [82e5658] Add support for VM suspend and resume (Cr��stian Viana) + * [94533f9] Update some VM state conditions (Cr��stian Viana) + * [a6b2ce2] Optimize VM update function (Cr��stian Viana) + * [f393e07] Move stats-related VM functions to VMModel (Cr��stian Deives) + * [9175b3e] Update stats when looking up one single VM (Cr��stian Deives) + * [0cc163d] Add %Used in the header for storage (Socorro Stoppler) + * [2ce0387] Security: Prevent Bar Mitzvah attacks by disabling RC4 (Aline Manera) + * [1c716c6] issue #461: Add 'metalink' support for YUM repositories (Cr��stian Viana) + * [65e10c2] Use more generic message in repo mirror list error (Cr��stian Viana) + * [0190298] Handle empty variables when updating YUM repository (Cr��stian Viana) + * [671fc4c] Update host number of cpus and total physical memory (Jose Ricardo Ziviani) + * [61ffb22] Making urls relative (Frederic Bonnard) + * [9185c35] test/test_model: Power architecture fixes (Daniel Henrique Barboza) + * [6017105] Fix Network create name checking in backend (slashes and quotes) (Rodrigo Trujillo) + * [0cb27b1] Move slash checking in storagepool name from UI to backend (Rodrigo Trujillo) + * [acca0c3] Prohibits slashes '/' in VM name (Rodrigo Trujillo) + * [8c4386c] issue #628: Set ref_cnt=1 on cloned disks (Cr��stian Viana) + * [53779bd] Issue #623: Fix mismatch in host device details query (Royce Lv) + * [a0b6ca0] Fix a ZeroDivisionError when starting kimchi service in Qemu. (Jose Ricardo Ziviani) + +#### [1.4.1] #### + * [9123208] Update ChangeLog and VERSION file for 1.4.1 release (Aline Manera) + * [5044020] Update pt_BR translations for Kimchi 1.4.1 (Aline Manera) + * [4781452] Update .po files for translation (Aline Manera) + * [44f0788] Kimchi tests: Power system fixes - removing hardcoded values (Daniel Henrique Barboza) + * [6714909] tests/test_osinfo.py: fixes for Power architecture (Daniel Henrique Barboza) + * [47d66eb] Specify user when changing VM disks permission (Cr��stian Viana) + * [8f5c248] issue #518: Simplify template URL verification (Cr��stian Viana) + * [923bf2d] Update ISO file's ACL before checking its permission (Cr��stian Viana) + * [d501a6e] issue #564: Parse logical volumes to find out their actual formats (Cr��stian Viana) + * [8eb00ed] issue #565: Allow a template's ISO to be a block device (Cr��stian Viana) + * [f1a009b] Fix test_model.py to reset Singleton classes when initializing the tests (Aline Manera) + * [0fe437f] Bug fix: Consider server is being started up on servermethod function (Aline Manera) + * [fe65e09] Use the right firewall-cmd command to open Kimchi ports (Aline Manera) + * [91e18b9] Fix issue #597: Get the right arch when using libvirt Test driver (Aline Manera) + * [2cf3920] Fix issue #617: Base URL may be an empty string when updating YUM repo (Aline Manera) + * [a6406e4] Fix issue #621: Catch libvirt exception when network does not have bridge name (Aline Manera) + * [99dc469] Fix issue #620: Allow use iSCSI/SCSI volume on Template (Aline Manera) + * [650655a] Add support to recognize RHEL-LE distro and version (Jose Ricardo Ziviani) + * [bb9ccf7] Deregister peer information when kimchid exit (Royce Lv) + * [27210d7] Update doc for federation (Royce Lv) + * [70010ea] Assign HTML labels to their corresponding elements (Cr��stian Viana) + * [d5e7800] Fix wrong usage of feature tests (Royce Lv) + * [d2c3ad2] Avoid using server dependent feature tests when server not running (Royce Lv) + * [30cf319] Remove slash "/" filter in template name when create VM (Rodrigo Trujillo) + * [13de741] Remove unsupported Fedora ISO link (Royce Lv) + * [c1553bb] Issue #587: Man page submission for kimchid (Frederic Bonnard) + * [784c0bd] RHEL7: Guide user to install spice-html5 (Aline Manera) + * [9a73497] Template tests (Aline Manera) + * [7691b5a] bug fix: Allow adding a iSCSI/SCSI volume from a non-ASCII pool to a template (Aline Manera) + * [77fe74e] Fix shallow scan test: wait until storage volume creation finished (Royce Lv) + * [50b2a60] Change from using /usr/bin/python to /usr/bin/env python2 to improve portabi.. (Alan Jenkins) + * [4143018] issue #595: Return correct memory value when VM is shutoff (Cr��stian Viana) + * [37d5af1] Add function to convert data sizes (Cr��stian Viana) + * [a338573] issue #545: Handle simultaneous authentication methods when updating VM perm.. (Cr��stian Viana) + * [b5d1a03] Bug fix: Properly raise authenticate error when login fails (Aline Manera) + * [0240f0c] Bug fix: Properly reload grid content (Aline Manera) + * [2c6b1dc] Set a common message to KCHGRD6002M (Aline Manera) + * [a17379a] Fix grammar for selected messages (Christy Perez) + * [1a43119] Stop collecting background stats (Christy Perez) + * [b529c0c] issue #512: Attach the function "showMessage" to the UI grid class (Cr��stian Viana) + * [7fd7aed] Add Arch Linux entry to isoinfo. (Alan Jenkins) + * [2aacf14] Add modern entry for Arch Linux. (Alan Jenkins) + * [3cdb137] Set allocation=capacity when creating images in logical pools (Christy Perez) + * [bef7afd] Disable SSL on nginx (Tulio Magno Quites Machado Filho) + * [16d7e48] Fix issue #589: Add listener to remove Kimchi leftovers (Aline Manera) + * [2f6a5d2] Fix issue #591: Get the right arch for MockModel (Aline Manera) + * [0c41e50] Bugfix: Kimchi: Better to list storage pool paths (Wen Wang) + * [eaf2349] Issue #573: Kimchi on ppc64el (Ramon Medeiros) + * [a8a057e] Transient StoragePool POST request handling (Christy Perez) + * [7714f22] Transient Network POST request handling (Christy Perez) + * [97a47d2] Transient VM POST request handling (Christy Perez) + * [464f5ee] Handle requests differently for transient objects (Christy Perez) + * [640b257] On Ubuntu, current libvirt library requires <os><type arch= (Thierry Fauck) + * [a9232d8] Revert "Remove workaround when deleting a VM due to tests" (Aline Manera) + * [c434e4a] tests/iso_gen.py: adding fake bootable PowerPC ISO (Daniel Henrique Barboza) + * [f56cee2] Build kimchi package in Fedora and SuSE as noarch (Ramon Medeiros) + * [902d0b3] Storage volume tests (Aline Manera) + * [445a070] Update rollback_wrapper function to handle nested API (Aline Manera) + * [55cfce3] Storage volumes: Update docs/API.md (Aline Manera) + * [a5ffb4d] Bug fix: Allow clonning a volume from a pool with non-ASCII characters (Aline Manera) + * [e828458] Bug fix: Use VIR_STORAGE_VOL_RESIZE_SHRINK flag when decreasing the volume s.. (Aline Manera) + * [50a334f] Remove policycoreutils-python as Kimchi dependency (Aline Manera) + * [26b70ca] Update copyright according to last changes (Aline Manera) + * [c81574c] Storage pool tests (Aline Manera) + * [4b65688] MockModel: Fix devices filter (Aline Manera) + * [107cf42] MockModel: Extend logical storage pool (Aline Manera) + * [dea4295] MockModel: Add mock code to list partitions to /host/partitions API (Aline Manera) + * [23a4ab4] MockModel: Override storage pool validation (Aline Manera) + * [8dee69a] Storage pool: Fix encoding/decoding while dealing with storage pools (Aline Manera) + * [1c5296a] Storage Pools: Update docs/API.md (Aline Manera) + * [8e35911] Rename test_storagepool.py to test_storagepoolxml.py (Aline Manera) + * [aca40a1] Bugfix: Template disk allocation changed back to default(10G) (Wen Wang) + * [dfc664a] Allow -v to be passed through in run_tests.sh (Julien Goodwin) + * [a1c4754] issue #526: Support updating name for VMs with snapshots (Cr��stian Viana) + * [e8dd163] Solve the snapshot revert problem, relate to issue #526 (Zongmei Gou) + * [743c9d9] Fix file handler leak in netinfo.py (Royce Lv) + * [3e25bdf] Work around eventfd leak using multiprocessing (Royce Lv) + * [e0371d4] Fix leak in check_url_path (Royce Lv) + * [10a58be] close fh after iso scanning (Royce Lv) + * [5583e6f] Close json schema file after loading (Royce Lv) + * [df87f99] Fix file handler leak for uptime file (Royce Lv) + * [36fa2e1] Fix md5 file handler leak (Royce Lv) + * [0b1c4b1] Run Model tests prior to MockModel tests (Aline Manera) + * [7c2c32c] Update copyright date (Aline Manera) + * [fe38d23] Remove workaround when deleting a VM due to tests (Cr��stian Viana) + * [7e33df1] Add build-aux/compile to gitignore. (Julien Goodwin) + * [6614a72] Update config test to expect robots.txt. (Julien Goodwin) + * [fbd2536] Add a robots.txt file. (Julien Goodwin) + * [5ab71df] Update Debian dependecy list. (Paulo Vital) + * [e494883] Issue #563: Delete network button works even disabled (Zongmei Gou) + * [fcc38fd] Issue #456: Firewall ports are not open after firewall restart v4 (Ramon Medeiros) + * [5dc11fb] Do not reuse names when cloning the same VM more than once at the same time (Cr��stian Viana) + * [f9bd067] Add vm names to delete/deactivate network error message (Rodrigo Trujillo) + * [e153572] Reorganize the network tests (Aline Manera) + * [5d23de2] Move rollback_wrapper function to a common place (Aline Manera) + * [cc35328] Network API: Update docs/API.md (Aline Manera) + * [40fe791] Bug fix: Allow deleting VLAN tagging bridged network (Aline Manera) + * [0222c8b] Add message to KCHNET0010E code (Aline Manera) + * [7e990e0] Improve PUT param checking (Royce Lv) + * [394f32a] Po: Minor changes to Chinese translation (Wen Wang) + * [ce016f2] Add a disk to the VM when testing snapshot (Cr��stian Viana) + * [cfba104] issue #544: Refactor storage volume download (Cr��stian Viana) + * [6801022] Use 'bytes' as volume capacity and allocation unit (Cr��stian Viana) + * [3dd94b6] Change "_get_storagevolume" to static (Cr��stian Viana) + * [75fc427] Remove directories under /var/lib/kimchi if empty on ubuntu (Ramon Medeiros) + * [67f963b] Don't let empty directories left on suse (Ramon Medeiros) + * [e651a4f] Remove empty directories after rpm -e kimchi on fedora (Ramon Medeiros) + * [56a6838] issue #543: Generate unique names when creating volumes without name (Cr��stian Viana) + * [cf9842e] bugfix: Fix regexp in "kimchi.utils.get_next_clone_name" (Cr��stian Viana) + +#### [1.4.0] #### + * [d19c5d9] Update VERSION, ChangeLog and po files for 1.4 release (Aline Manera) + * [33362ff] Po support: translation for Chinese (Wen Wang) + * [318efd5] Update Portuguese translations (Aline Manera) + * [02c82dd] Update po files (Aline Manera) + * [6afd60a] Bugfix#527 Reverting a snapshot doesn't change initial state of "Edit Guest" (Wen Wang) + * [d53ae80] issue #553: Use required parameter in "snapshotLookupByName" (Cr��stian Viana) + * [2f86e63] Bug fix #463: Allow add networks with non-ASCII characters to template and g.. (Aline Manera) + * [009fc38] Issue#536: raise proper error message when disk os info absent (Royce Lv) + * [a378799] Revert "Bug #482 Fix: Interfaces stacked in template edit" (Aline Manera) + * [ee4acc5] Bug #482 Fix: Interfaces stacked in template edit (Yu Xin Huo) + * [1c18dc2] Bug 487 Fix: Dropdown & Filter not aligned(mobile) (Yu Xin Huo) + * [70f178c] Bug fix #529: Kill all Kimchi processes when stopping kimchid service (Aline Manera) + * [f61cccd] issue #474: Add default value for ldap_admin_id (Royce Lv) + * [d0aad8f] Bugfix#549 VM button icons unaligned (Wen Wang) + * [f1e6004] issue #504: Add details on how to install test dependencies (Cr��stian Viana) + * [c66bfdb] issue #438: Display nicer error message when starting network (Cr��stian Viana) + * [514465b] Bug fix #530: Update distros.d/ files (Aline Manera) + * [f908c7c] Bug #443: Do not crash Kimchi when federation is enabled and openslp is not .. (Aline Manera) + * [091936e] Bugfix #479: Allow non-admin users get devices passthrough information (Aline Manera) + * [1e308f3] Bug #495 Fix: Remove error popup when non-admin login (Yu Xin Huo) + * [f22bbca] Bugfix #477 Fix snapshot time didn't align issue (Wen Wang) + * [4f8f229] Bug #546 Fix: Network button state issue (Yu Xin Huo) + * [b2ae21e] issue #498: Fix typos on Kimchi messages (Aline Manera) + * [b104ed7] issue #491: Check model parameter exists when generating the interface XML (Aline Manera) + * [6e3a3f4] issue #515: Add check_i18n.py to EXTRA_DIST (Royce Lv) + * [b88672f] List as many pools' info as possible (Christy Perez) + * [18cbe25] issue #532: Fix ldap admin filtering (Royce Lv) + * [e03f9f0] issue #475: Properly set cert and key variables when starting nginx proxy (Aline Manera) + * [3ae2454] UI: Use capabilities cached values on 'Host PCI Device' tab (Aline Manera) + * [bf2a92c] issue #492: Expressly set autoport to yes in vm graphics. (Alan Jenkins) + * [40142e9] Bugfix: fix testcase for repository update (Royce Lv) + * [3ec90a0] Bugfix: Disable actions not supported by non-persistent VMs (Wen Wang) + * [2e8b9f2] Change pattern match in pep8 filtering (Royce Lv) + * [4844a1a] Revert "snapshot: Clone snapshots when cloning a VM" (Cr��stian Viana) + * [f3dffe4] Only allow VM snapshots to be taken on 'qcow2' disks (Cr��stian Viana) + * [8c3c530] Update ChangeLog, VERSION and po files (Aline Manera) + * [322bd6e] RHEL7: Guide user to subscribe to "RHEL Server Optional" channel (Aline Manera) + +#### [1.4.0-rc1] #### + * [61f6ba3] Update ChangeLog for 1.4.0-rc1 (Aline Manera) + * [b76db0e] Change guest edit permission logic (Royce Lv) + * [f9e2d28] UI: support ldap vm permission tag (Royce Lv) + * [fa07b67] vmtemplate: allow allocation = 0 for type 'raw' (Daniel Henrique Barboza) + * [34ba2f1] Mockmodel test for cpuinfo (Christy Perez) + * [b145158] Parts to allow Kimchi to configure the cpu topology. (Christy Perez) + * [64601ca] UI: CPU Topology (Yu Xin Huo) + * [ab308ec] UI: Guest Snapshot (Yu Xin Huo) + * [4c4e582] Pass through libvirt error if storage create fails (Christy Perez) + * [c786647] Remove README statement that advises user does not use Kimchi in production (Aline Manera) + * [984e5b9] Return empty dict when VM doesn't have current snasphot (Cr��stian Viana) + * [997b6c3] Update test model for authentication and authorization (Royce Lv) + * [e1a7e1d] change vm permission tag (Royce Lv) + * [1230d98] Move validation to authorizaiton (Royce Lv) + * [5846a81] Split users and groups for permission query (Royce Lv) + * [b856c0d] Bugfix: UI Disable button "Create" when adding a VM (Wen Wang) + * [10ef1d9] Edit Template redefined (Wen Wang) + * [03a6fb8] bugfix: Use correct error code when current snapshot does not exist (Cr��stian Viana) + * [4ff0c5f] Return empty dict when request body is empty (Cr��stian Viana) + * [35a9442] Use dedicate function to remove unused namespace (Royce Lv) + * [f7dbd47] Don't fail if no translation can be found (C��dric Bosdonnat) + * [5039154] Fix test cases for authentication (Royce Lv) + * [db15509] Add LDAP authentication (Royce Lv) + * [ed07977] Split PAM and LDAP authentication (Royce Lv) + * [1393eb2] Add configuration of LDAP (Royce Lv) + * [502e95e] Improve french translation (C��dric Bosdonnat) + * [fb49863] MockModel refactor: Create MockModel based on Model("test:///default") (Aline Manera) + * [c087f65] snapshot: Clone snapshots when cloning a VM (Cr��stian Viana) + * [4fb6786] snapshot: Delete snapshots when deleting a VM (Cr��stian Viana) + * [049720c] snapshot: Add model tests (Cr��stian Viana) + * [f3d5b01] snapshot: Revert a domain to a snapshot (Cr��stian Viana) + * [c857e25] snapshot: Lookup current snapshot on a domain (Cr��stian Viana) + * [5900d68] snapshot: Delete a domain snapshot (Cr��stian Viana) + * [a724e69] snapshot: List domain snapshots (Cr��stian Viana) + * [8f010d8] snapshot: Lookup a domain snapshot (Cr��stian Viana) + * [d1cf5c8] snapshot: Create domain snapshots (Cr��stian Viana) + * [96f19e4] Update clone test (Cr��stian Viana) + * [4b22966] bug fix: Update storage volume ref_cnt when VM is deleted (Aline Manera) + * [411fbd4] Pass libvirt connection as CapabilitiesModel parameter (Aline Manera) + * [0f38c74] Ensure the guest volume exists to remove it (Aline Manera) + * [e1f2d60] Check currentMemory exists prior to remote its XML node (Aline Manera) + * [c5cb151] Use objectify to Remove metadata namespace (Aline Manera) + * [7b84638] Re-raise the original exception when creating a new Template (Aline Manera) + * [bde438e] Issue #473: Update selectMenu method to set a default value. (Paulo Vital) + * [9983fe9] Prevent disks from being added twice (Christy Perez) + * [eb6fd62] Delete ui/js/modernizr.custom.2.6.2.min.js (Aline Manera) + * [ea2b1b0] Delete ui/libs/modernizr.custom.76777.js (Aline Manera) + * [6f88b09] UI: Clone Guest(static message) (Yu Xin Huo) + * [15a965c] Add tests and mockmodel for the cloning feature (Cr��stian Viana) + * [37635c1] Clone virtual machine (Cr��stian Viana) + * [0a5714b] Clone storage volume (Cr��stian Viana) + * [8ba3537] Clean up test pool directories (Cr��stian Viana) + * [659096d] Add model function to wait for task (Cr��stian Viana) + * [00b7e6f] storagepool-add: showing Fibre Channel devices (Daniel Henrique Barboza) + * [8b2865c] Fix content of the SW update list after disable a repository. (Paulo Vital) + * [22d18e2] Add PPC console configuration to guest XML (Rodrigo Trujillo) + * [42d364c] Move featuretests.py to /model (Aline Manera) + * [e4794c0] Set domain type in FeatureTests according libvirt URI (Aline Manera) + * [ff90fbf] Update FeatureTests to use the same libvirt connection used by Model (Aline Manera) + * [7fd8c95] netinfo.py: adding 'link_detected' to get_interface_info (Daniel Henrique Barboza) + * [736f24d] Create common function to generate interface guest XML (Aline Manera) + * [0efc87e] Use lxml to generate graphics XML and update VMTemplate to use it (Aline Manera) + * [e4e95cf] bug fix: Properly generate guest disks on VMTemplate (Aline Manera) + * [c779bfb] Guest disk hot plug UI (Wen Wang) + * [6144431] Render different types of data in generate_action_handler (Cr��stian Viana) + * [7e78a07] Allow updating XML attribute in "xml_item_update" (Cr��stian Viana) + * [99e8034] Make function "randomMAC" public (Cr��stian Viana) + * [749abbf] Remove VMTemplate._get_scsi_disks_xml() and VMTemplate._get_iscsi_disks_xml() (Aline Manera) + * [cdd146a] Change VMTemplate._get_disks_xml() to handle all type of disks (Aline Manera) + * [c07a031] Change VMTemplate._get_disks_xml() to use the common get_disk_xml() (Aline Manera) + * [67e89a9] Change VMTemplate._get_iscsi_disks_xml() to use the common get_disk_xml() (Aline Manera) + * [08c1154] Change VMTemplate._get_scsi_disks_xml() to use the common get_disk_xml() (Aline Manera) + * [44fdf7d] Set guest disk cache to none to support live migration (Aline Manera) + * [aa09dbe] Make disk type an optional parameter on get_disk_xml() (Aline Manera) + * [d29a9c5] ISSUE#466: Filter valid format only on volume type of 'file' (Royce Lv) + * [07aef06] Enhancement: PCI Device information enhancement (Wen Wang) + * [f7dfaae] Unit tests for the new disk image format (Daniel Henrique Barboza) + * [e0a6ccd] Choose disk image format in vm template - backend (Daniel Henrique Barboza) + * [72865eb] Create xmlutils/qemucmdline.py to generate <qemu:commandline> XML (Aline Manera) + * [686c314] Update vmtemplate.py to use get_disk_xml() while generating CDROM XML (Aline Manera) + * [b94678e] Check QEMU stream DNS capability when attaching new disk to guest (Aline Manera) + * [cded6a6] Get disk type according to file path on get_disk_xml() (Aline Manera) + * [f2582f3] Remove ignore_src parameter from get_disk_xml() (Aline Manera) + * [79930fd] Update get_disk_xml() to get the device same according to bus and index values (Aline Manera) + * [8e89056] Remove 'bus' paramater from /vms/<name>/storages documentation (Aline Manera) + * [f8b771f] Move vmdisks.py functions to xmlutils/disk.py (Aline Manera) + * [291a778] Move _get_storage_xml() to xmlutils/disk.py (Aline Manera) + * [be83d06] Number of CPUs in Host's Basic Information. (Paulo Vital) + * [043db33] Remove libxml2-python as Kimchi dependency (Aline Manera) + * [6a7704f] Use lxml.etree on gen-index.py script instead of libxml2 (Aline Manera) + * [bd6d163] Use lxml.etree on xmlutils/utils.py instead of xml.etree and libxml2 (Aline Manera) + * [d712d75] Remove pyc files on make clean (Christy Perez) + * [c44aa09] AsyncTask: Improve continuous status feedback (Zhou Zheng Sheng) + * [f33afdc] Translations for new cpu_info messages (Christy Perez) + * [b6876d6] cpu_info tests for model and mockmodel (Christy Perez) + * [c5dbd1f] Backend support for templates with sockets, cores, and threads (Christy Perez) + * [1c8c539] ConfigTests: Fix novnc paths (Zhou Zheng Sheng) + * [2000911] ModelTests: Improve leftover cleaning (Zhou Zheng Sheng) + * [f28d16e] VMsModel: Make _update_guests_stats() robust against race condition (Zhou Zheng Sheng) + * [a72d94b] LibvirtConnection: Share underlying connections between instances (Zhou Zheng Sheng) + * [53b6b16] Update libvirtstoragepool.py to use lxml.builder (Aline Manera) + * [4888826] add sub-makefile in src/kimchi/xmlutils (Simon Jin) + * [e238fd2] Disabling screen log in production environment (Daniel Henrique Barboza) + * [f14fcbf] Move networkxml.py to xmlutils module and update it to use lxml.builder (Aline Manera) + * [f57a4af] Create a xmlutils module to hold all the XML manipulation (Aline Manera) + * [65621fe] Update COPYING content to expose the imported code (Aline Manera) + * [ac96bcb] Delete former imported spice code (Aline Manera) + * [5a14498] Update Kimchi to use the installed spice-html5 (Aline Manera) + * [6557b31] Add new spice-html5 code to Kimchi build process (Aline Manera) + * [6083f7c] Modify spice_auto.html for Kimchi proposals (Aline Manera) + * [b13f615] Import the latest spice-html5 code into Kimchi (Aline Manera) + * [e62154a] Changes in sample plugin to fix and improve help (Rodrigo Trujillo) + * [b5a3900] Fix problems to open plugin's help pages (Rodrigo Trujillo) + * [1229515] Host device passthrough (Front-end): Add PCI Devices to VM (Yu Xin Huo) + * [9cf9747] Host device passthrough: Add unit tests and documents (Zhou Zheng Sheng) + * [604df1f] Host device passthrough: List VMs that are holding a host device (Zhou Zheng Sheng) + * [12f650b] Host device passthrough: Directly assign and dissmis host device from VM (Zhou Zheng Sheng) + * [42e642d] Host device passthrough: List eligible device to passthrough (Zhou Zheng Sheng) + * [4fa2282] Host device passthrough: List all types of host devices (Zhou Zheng Sheng) + * [aa6105d] Delete imported novnc code (Aline Manera) + * [1774b96] Add novnc as Kimchi dependency (Aline Manera) + * [afc42d0] Bugfix#414: Cannot login by clicking on the login button (Wen Wang) + * [322f2f1] Enable remote libvirtd (Brent Baude) + * [18deb57] Delete imported websockify code (Aline Manera) + * [613650d] Add websockify as Kimchi dependency (Aline Manera) + * [e41e2b8] bug fix: Redirect user to the URL accessed prior to login (Aline Manera) + * [ff5b629] pep8: Use blacklist instead of whitelist (Cr��stian Viana) + * [9d1b192] pep8: Fix errors in all files (Cr��stian Viana) + * [0f6f05c] Display "README" with markdown style on Github (Cr��stian Viana) + * [a660b2a] Fix: accelerate mockmodel for file upload (Royce Lv) + * [1795a92] Bugfix: Cancel option not working properly in New Storage Define (Wen Wang) + * [b4d48bd] Bug Fix: Correct select menu to handle empty input (Yu Xin Huo) + * [65f14b2] Fix wrong config param of repository creation (Royce Lv) + * [b6e00c5] Fix: retrieve right bus type in vmstorage update (Royce Lv) + +#### [1.3.0] #### + * [57509ae] Update ChangeLog for 1.3 release (Aline Manera) + * [eaa00fc] Update po files for 1.3 release (Aline Manera) + * [244d933] issue #447: Check download URL prior to start Task (Aline Manera) + * [cca060b] Update distros.d files to point to a valid URL (Aline Manera) + * [2873011] issue #454: Properly display storage volumes in a pool with sub-directories (Aline Manera) + * [ab97b92] Fix: Add rollback to update repository (Royce Lv) + * [1d77625] Reject improper format for storage types (Royce Lv) + * [05acc88] Fix: filter unsupported source type from volume list (Royce Lv) + * [e5689c0] issue #445: Request /peers on every click (Aline Manera) + * [c3c13e9] issue #462: Do not allow user to enter non-integer template disk size (Cr��stian Viana) + * [e1623c3] build: Add README-federation.md to Kimchi package (Aline Manera) + * [9754639] issue #447: Remove downloaded volume if an error occurs (Cr��stian Viana) + * [d95faf6] issue #432: Display unique values for iSCSI targets (Aline Manera) + * [c3975cc] issue #433: Fix repository tests (Cr��stian Viana) + * [bff1039] issue #437: Only allow a bootable image file to be used on template (Aline Manera) + * [705ae2a] issue #417: Validate image file path when creating a new template (Aline Manera) + * [14b6ef0] Bugfix#424: Edit Template, "Disk (GB)" is changing with storage pool (Wen Wang) + * [9ceea59] Update Chinese transtation to po (Wen Wang) + * [e32155c] issue #435: Fix resource authorization logic (Cr��stian Viana) + * [f1cfa3e] Bugfix#426: When no interface available, creating network popup error (Wen Wang) + * [aa3b35b] help i18n: Add new languages to build process (Aline Manera) + * [26283af] Bugfix#: Prevent overlap issue occurs under General tab on Edit (Wen Wang) + * [812e490] Bugfix: Overlap issue occurs on the Power Off confirmation dialog (Wen Wang) + * [762e7f6] Bug 431 Fix (Yu Xin Huo) + * [75a00ca] issue #429: Properly set rollback function when creating vlan tagged bridged (Aline Manera) + * [2426144] issue #415: Do not allow renaming a debug report to the same name (Cr��stian Viana) + * [745c47e] Add firewall instructions to README-federation (Aline Manera) + * [6152215] mock: Do not write file when downloading a volume (Cr��stian Viana) + * [a045783] issue #447: Use required parameter in function "refresh" (Cr��stian Viana) + * [ab9fe6f] Bug 416 Fix (Yu Xin Huo) + * [71258eb] Bug 418 Fix (Yu Xin Huo) + * [de32236] Issue #421: Grid Column Header Issue (Hongliang Wang) + * [81b59c5] guest-storage-add: removing "Storage Name" backend support (Daniel Henrique Barboza) + * [7f82708] guest-storage-add: removing "Storage Name" field (Daniel Henrique Barboza) + * [6e1e469] bug fix: Probe image file only during the template creation (Aline Manera) + * [e8fc599] Bug 446 Fix (Yu Xin Huo) + * [2bb91e8] Bug 457 Fix (Yu Xin Huo) + * [086fb80] Bugfix#420 UI: Pop up errors when log out at "Host" tab (Wen Wang) + * [7964dcd] Revert "help i18n: Update Makefile to refeclt new languages." (Aline Manera) + * [1937dff] help i18n: Update Simplified Chinese translation (Paulo Vital) + * [072f9d6] help i18n: Update Portuguese (Brazil) translation (Paulo Vital) + * [596d639] help i18n: Add Traditional Chinese translation (Paulo Vital) + * [e240d51] help i18n: Add Russian translation (Paulo Vital) + * [cddb664] help i18n: Add Korean translation (Paulo Vital) + * [0c39477] help i18n: Add Japanese translation (Paulo Vital) + * [0fe4a66] help i18n: Add Italian translation (Paulo Vital) + * [e3568a3] help i18n: Add French translation (Paulo Vital) + * [0cd30d5] help i18n: Add Spanish translation (Paulo Vital) + * [0e016d1] help i18n: Add German translation (Paulo Vital) + * [c964983] help i18n: Update Makefile to refeclt new languages. (Paulo Vital) + * [340cf6d] Fix issue #430: Properly list packages update on openSUSE systems (Aline Manera) + * [6e6a155] Delete useless variables assignment (Aline Manera) + * [638dd40] Update openSUSE section in docs/README.md (Aline Manera) + * [1ab51bf] Fix cdrom eject (Royce Lv) + * [a0b280b] Disable upload option while adding a volume to a pool (Aline Manera) + * [dbba218] Storage Pool Add Volume UI: Connect the Feature in Storage Tab (Hongliang Wang) + * [5a92df3] Storage Pool Add Volume UI: Implement Download/Upload Volume Function (Hongliang Wang) + * [0dfa0fa] Storage Pool Add Volume UI: Add i18n Strings (Hongliang Wang) + * [4d0e3dd] Storage Pool Add Volume UI: Add APIs to kimchi.api.js (Hongliang Wang) + * [3e2ac07] bug fix: Pass the right data format to run_command() (Aline Manera) + * [7f477ea] python 2.6 compatibility: Use 'with' statement only with one context (Aline Manera) + * [3114d5c] Update po files according to Transifex translations. (Aline Manera) + * [975ab70] Update messages (Aline Manera) + * [897a405] storagevolume: Use default value for param 'name' when appropriate (Cr��stian Viana) + * [a6c7654] bug fix: Properly set max body size to nginx proxy (Aline Manera) + * [8a8c959] Identify Kimchi variables from nginx config variables in nginx.conf.in file (Aline Manera) + * [426e982] model.host: considering older libvirt versions (Daniel Henrique Barboza) + * [afa9258] Increase read chunk size to 1MB while uploading file (Aline Manera) + * [1e18c35] Only disable report buttons when the selected report is pending (Aline Manera) + * [c635244] List pending debug reports while loading report grid (Aline Manera) + * [29b926e] Add function to list all pending debug reports (Aline Manera) + * [bb7881a] Add common function to track Task (Aline Manera) + * [2778558] Add function to get pending tasks according to filter (Aline Manera) + * [e434d3b] Fix: Use "max_request_body_size" value as int instead of string (Cr��stian Viana) + * [cbf2bbf] UI: Template with VM Image - List (Yu Xin Huo) + * [c02fcb8] UI: Template with VM Image - Edit (Yu Xin Huo) + * [5faf008] UI: Template with VM Image - Create (Yu Xin Huo) + * [95a05c6] Storage volume upload: Change mockmodel and test (Royce Lv) + * [f041ffb] Storage volume upload: Adding progress to task message (Royce Lv) + * [e4f152a] Storage volume upload: Support file based upload (Royce Lv) + * [e3b79e3] Storage volume upload: Control request body size of kimchi (Royce Lv) + * [22ca761] Storage volume upload: Parse params for upload formdata (Royce Lv) + * [f07d4fa] Fix mockmodel reset for objectstore (Royce Lv) + * [12220b7] Storage volume upload: Update API.md (Royce Lv) + * [1e271aa] storagevolume: Set target URI when creating Task (Cr��stian Viana) + * [2eae7ac] storagevolume: Add download progress to task (Cr��stian Viana) + * [6befff6] storagevolume: Check storage pool before adding a volume (Cr��stian Viana) + * [12d90ac] storagevolume: Download remote images to a storage pool (Cr��stian Viana) + * [efe4d5c] Update current code to report target_uri while creating a Task (Aline Manera) + * [f8f43b3] Expose target_uri on Task resource (Aline Manera) + * [3ca880a] Update License Statement (Hongliang Wang) + * [ff1bb81] Storage volume upload: Change storagevolumes to AsyncCollection (Royce Lv) + * [9071b49] Storage volume upload: Dispatch volume create to right handler (Royce Lv) + * [6f35bac] UI bug fix: Properly display storage volumes on Storage tab (Aline Manera) + * [bd7b517] Guest storage: fix volume format overwrite (Royce Lv) + * [535f0c0] UI: List Kimchi Peers (Yu Xin Huo) + * [7749c16] Expose federation on /config/capabilities (Aline Manera) + * [59e1d7e] Add documentation on how to enable federation on Kimchi (Aline Manera) + * [6066971] Discover Kimchi peers using openSLP (Aline Manera) + * [77b921f] Add federation option to Kimchi config file (Aline Manera) + * [19d1ec3] Delete http_port from /config API as it is not in use anymore (Aline Manera) + * [1b1c38f] Update kimchi.config values according to command line input (Aline Manera) + * [6b06a50] Fix sample plugin configuration (Aline Manera) + * [1798ae2] Guest storage: Fix attaching type judgement (Royce Lv) + * [1fb4257] UI: List iSCSI Servers & Targets (Yu Xin Huo) + * [e405e87] model.host: changing listDevices() to listAllDevices() (Daniel Henrique Barboza) + * [6c10ea3] bug fix: Properly get the graphics expiration time (Aline Manera) + * [d839a47] bug fix: Auto-generate guest console password when the passed value is an em.. (Aline Manera) + * [a7d2942] i18n support: Add new languages in login page. (Paulo Vital) + * [7cd3597] Allow user updates the passwd expiration time without changing the passwd (Aline Manera) + * [c8bf6e2] Centralize graphics information (Aline Manera) + * [e6931d7] Update iSCSI volume XML when creating a VM from an iSCSI pool (Aline Manera) + * [30ca516] Fix duplicated message string in en_US.po file. (Paulo Vital) + * [eaa20f5] i18n support: Add Traditional Chinese translation files. (Paulo Vital) + * [ae21f41] i18n support: Add Russian translation files. (Paulo Vital) + * [fa7d765] 18n support: Add Korean translation files. (Paulo Vital) + * [b483d37] i18n support: Add Japanese translation files. (Paulo Vital) + * [5608d41] i18n support: Add Italian translation files. (Paulo Vital) + * [01aa06e] i18n support: Add French translation files. (Paulo Vital) + * [4db8fce] i18n support: Add Spanish translation files. (Paulo Vital) + * [1d23275] i18n support: Add German translation files. (Paulo Vital) + * [0e15736] i18n support: Changed the file type of plugins/sample/po/LINGUAS (Paulo Vital) + * [93a21ec] Update po files (Aline Manera) + * [60c44f7] Add PowerKVM information as ISO otpion to installation. (Paulo Vital) + * [3022860] Support tablet type as input device in VM's XML. (Eli Qiao) + * [c456d43] Change function that verifies network interface status (Ramon Medeiros) + * [1ebd9b2] Add unit tests for new vm 'persistent' property. (Christy Perez) + * [f2ac85f] Add a check in the UI for the new 'persistent' flag of a VM. (Christy Perez) + * [2238df2] Add persistent flag to VM info (Christy Perez) + * [f1f9015] model/storagetargets: filtering used nfs paths (Daniel Henrique Barboza) + * [e1fb135] Issue #405 - Fix enter hit in storage tab under guest edit window (Rodrigo Trujillo) + * [2524fb4] Issue #405 - Fix cancel button in edit guest storage tab (Rodrigo Trujillo) + * [e7b7a57] Allow admin user change permission settings when VM is running (Wen Wang) + * [cff488a] UI: Delete Manage Media function from action list (Wen Wang) + * [191c2f4] Bugfix UI: Change button text to indicate user network is generating (Wen Wang) + * [0415a5f] Bugfix: Log out from Administrator tab raises popup errors (Wen Wang) + * [47232dc] Fix UI: Show proper message when detaching a guest storage (Rodrigo Trujillo) + * [55c053d] Refactor vmstorage name generation (Royce Lv) + * [256c432] Remote ISO attachment: fix UI to accept remote ISO link for cdrom attachment (Royce Lv) + * [7107956] Add unit tests for remote-backed CD ROM updates. (Christy Perez) + * [aaea005] Fix verification of remote ISO (Christy Perez) + * [f4006fe] Fix Key Error when editing CD ROM path (Christy Perez) + * [6a4d2b3] UI: refactor guest edit code. (ShaoHe Feng) + * [11f68f3] UI enhancement: Request /config/capabilities as soon as possible (Aline Manera) + * [fd48ebb] Change default environment configuration to production mode. (Paulo Vital) + * [28ea390] list host user names as less as possible (Simon Jin) + * [945b6d5] bug fix: Properly list host partitions for Ubuntu 14.04 server (Aline Manera) + * [dc8d508] Fix issue #340: Show error message when server fails to list host partitions (Aline Manera) + * [50b5763] Increasing nginx proxy timeout (Daniel Henrique Barboza) + * [1e2db06] repository: Remove error message prefix (Cr��stian Viana) + * [103594e] typo: Fix "repositorie" (Cr��stian Viana) + * [2696052] Issue #377: Validate repository URLs (Cr��stian Viana) + * [424b436] bug fix: Allow kimchi runs in multiple platforms (Aline Manera) + * [d001da8] bug fix: Add spice.css to Makefile and spec files (Aline Manera) + * [ea41c72] Add tests for image based template (Royce Lv) + * [cfdea72] Update mockmodel of base img vm (Royce Lv) + * [169c77c] Create volume based on backing store image (Royce Lv) + * [be8762e] Fix: Prevent iso links filling in osinfo.py (Royce Lv) + * [9a54959] Change 'cdrom' to a optional param (Royce Lv) + * [16a5810] Change doc and api specification (Royce Lv) + * [4acea3b] Add image probe function (Royce Lv) + * [672738d] Update testcases for bus type decision making (Royce Lv) + * [dcf8f7b] Delete 'bus' selection from UI (Royce Lv) + * [e4370ed] Delete 'bus' param from backend (Royce Lv) + * [733a083] Update Chnagelog for 1.2.1.1 tag (Aline Manera) + * [5ea98c7] Update license to LGPLv3 (Aline Manera) + * [5f34ec8] Remove useless jquery files (Aline Manera) + * [980b365] Remove useless image files (Aline Manera) + * [2e90908] Install kimchi.mo files in the default locale dir (Aline Manera) + * [d8e6e47] Add missing license headers (Aline Manera) + * [e466333] Update copyright date (Aline Manera) + * [1a926c1] UI bug fix: Properly display partitions when extending a logical pool (Aline Manera) + * [dcc5838] Fix pep8 errors according to pep8 1.5.6 (Aline Manera) + * [8188d7c] Disable vhost feature in Ubuntu and SLES (PPC64 LE) (Rodrigo Trujillo) + * [3ddeefb] Change modern distro versions for PPC (Rodrigo Trujillo) + * [d0984ca] PowerPC bootable ISO detection code (Daniel Henrique Barboza) + * [4e65d8a] bug fix: Update genChangelog script (Aline Manera) + * [228a56a] fix test case for volume filtering (Royce Lv) + * [c5a90bd] Filter directory in storage volume listing (Royce Lv) + * [0cf6558] Bugfix Issue #397 UI Broken when cookie is clear (Wen Wang) + * [403d227] Fix pyflakes errors in make check (Royce Lv) + * [52dcea3] bug fix: Avoid equals sign in VM console URL (Aline Manera) + * [174a7be] Get user groups correctly (Cr��stian Viana) + * [220d37c] Update ChangeLog and VERSION files for 1.2.1.1 release (Aline Manera) + * [2136c20] Update Kimchi tag to remove 'kimchi-' prefix (Aline Manera) + * [fc99a95] issue #389: Use 127.0.0.1 as VNC listener IP (Aline Manera) + * [7f2963f] authorization: Update test cases based on last changes (Cr��stian Viana) + * [f4b91ac] List "admin" as a valid system user in mockmodel (Cr��stian Viana) + * [75a9acc] Move "fake_user" credentials to mockmodel (Cr��stian Viana) + * [5bec021] Return some groups for every user in mockmodel (Cr��stian Viana) + * [ba442f9] authorization: Remove authorization config from UrlSubNode (Aline Manera) + * [ebb8392] authorization: Update control files to set role_key and admin_methods (Aline Manera) + * [5570723] authorization: Restrict access to Resource instance (Aline Manera) + * [19aa234] authorization: Restrict Collection access based on admin_methods parameter (Aline Manera) + * [40f746f] authorization: Filter resources by users and groups (Aline Manera) + * [e01a336] vm ticket in backend: update test case (ShaoHe Feng) + * [85617c4] vm ticket in backend: update mockmodel (ShaoHe Feng) + * [d6bf0bc] vm ticket in backend: update model (ShaoHe Feng) + * [fabf9d8] vm ticket in backend: update controller and API.json (ShaoHe Feng) + * [aff9cda] vm ticket in backend: update API.md (ShaoHe Feng) + * [e47fc1e] authorization: update po files (Yu Xin Huo) + * [286e8b2] authorization: add users/groups to vm (Yu Xin Huo) + * [9f0933f] issue #374: Use base64 encoding to launch VM console (Aline Manera) + * [0fb08af] Authorization: Remove actions based on roles (Wen Wang) + * [eb5abf8] Authorization: remove [+] icon from non-root users view (Wen Wang) + * [48d64cf] Authorization: remove host/template tabs for non-root users (Wen Wang) + * [22eba43] Add roles into cookie (Wen Wang) + * [c47c62e] add a base64 safe url encode and decode to js utils (ShaoHe Feng) + * [e0a6e80] Let frontend redirect user after logging (Aline Manera) + * [8bf9597] Remove special console rules from nginx configuration (Aline Manera) + * [ea3db7e] Remove former login design files (Aline Manera) + * [1fdda55] Update test case to reflect new login design (Aline Manera) + * [14fbfe3] authorization: Get role according to tab instead of sudo rights (Aline Manera) + * [a99cde0] authorization: Add "access" parameter to VM resource (Aline Manera) + * [48b6a55] authorization: Add "access" elements to tabs.xml to describe user view (Aline Manera) + * [1df92ad] authorization: Update /login to return user roles instead of sudo parameter (Aline Manera) + * [7a62bf1] authorization: Update authorization rules per API (Aline Manera) + * [582928c] Always use unicode in KimchiException message (Aline Manera) + * [7c9b576] Debug Report Rename: Update Test Code (Royce Lv) + * [12aa218] Debug Report: Update MockModel (Hongliang Wang) + * [20aad65] Debug Report Rename UI: Enable Rename in Host Tab (Hongliang Wang) + * [47bddf1] Debug Report Rename UI: Add Rename Page (Hongliang Wang) + * [1aff19f] Debug Report Rename UI: Add API in kimchi.api.js (Hongliang Wang) + * [bfaa81f] Debug Report: Sort Reports by Generated Time Descendingly (Hongliang Wang) + * [b9c54b4] Debug Report: Use Generated Time instead of Most Changed Time (Hongliang Wang) + * [7e6d766] Debug Report Rename: Implement Back-end (Hongliang Wang) + * [d600011] Debug Report Rename: Update API.md (Hongliang Wang) + * [7e7083e] Debug Report Rename: Update API.json (Hongliang Wang) + * [1f2d758] Debug Report UI: Generate Report Doesn't Work with Mock Model (Hongliang Wang) + * [377fd70] MockModel: Can't Generate Report if Name is not Given (Hongliang Wang) + * [aef9d42] Add option to add/remove fonts files in rpm packages (ShaoHe Feng) + * [7231a51] Remove useless fonts (Aline Manera) + * [2f319d3] Change ISO stream feature test and kvm user test for PPC (Rodrigo Trujillo) + * [ad655c4] Update API.md to reflect /host/users and /host/groups API (Aline Manera) + * [07f037f] Translation updates for underscore in debug report (Christy Perez) + * [d206f4c] UI changes to allow underscore in debug report name. (Christy Perez) + * [b482880] Add SUSE's products (Dinar Valeev) + +#### [kimchi-1.2.1] #### + * [31e0c0b] Update Changelog and po files for 1.2.1 release (Aline Manera) + * [fcd407e] bugfix: Add policycoreutils-python as Kimchi dependency (Aline Manera) + * [e475bfa] Add translation for vm disk attach exceptions (Royce Lv) + * [593c420] Add testcase for vmstorages create (Royce Lv) + * [954185e] Make sure path and volume will not be specified at same time (Royce Lv) + * [a93aa45] Add mockmodel for vm disk attach (Royce Lv) + * [fff58c2] issue#382: Validate form for adding guest cdrom (Royce Lv) + * [e5333d7] issue#382 :Change false default value (Royce Lv) + * [0599241] update case for root.get redirection (ShaoHe Feng) + * [eed4f36] remove kimchisession hook and add the same logic to root.get (ShaoHe Feng) + * [c13d53d] bug fix: redirect to the protected page after login (ShaoHe Feng) + * [88affbe] Issue #380: Loading icon message splitted into two lines in Chinese (Wen Wang) + * [5afa07f] bug fix: UI set the network persistent attribute. (ShaoHe Feng) + * [4197f3a] Bugfix: Minor i18n updates(Chinese) (Wen Wang) + * [9136f8d] add firewalld to debian Install Dependencies (ShaoHe Feng) + * [0890b7a] bug fix: Set charset to help pages (Aline Manera) + * [5ce667a] Show remote Ubuntu 14.04 x86_64 in new Template window (ShaoHe Feng) + * [000149e] Update i18n package scripts(Chinese) (Wen Wang) + * [e0a6643] Add missing translation entries in pt_BR (Cr��stian Viana) + * [93784be] Add empty translation entries in English (Cr��stian Viana) + * [45703ec] Help translation to zh_CN. (Paulo Vital) + * [c29f1e2] Help translation to pt_BR. (Paulo Vital) + * [b430576] Show remote Ubuntu 14.04 in new Template window (Rodrigo Trujillo) + * [b5425f8] escape special characters for jQuery selector. (ShaoHe Feng) + * [7b65e7b] escape < > and & in in xml for network name. (ShaoHe Feng) + * [df9a017] network name support unicode. (ShaoHe Feng) + * [2fabc33] bug fix: network name can be any characters except " and / (ShaoHe Feng) + * [7167f31] Host info: Add support to Power. (Paulo Vital) + * [4b096f2] Fix Bug: Actions Menu Disappears after Refresh in Guests Tab (Hongliang Wang) + * [234c198] Bug fix: Do not require login for simple resources (Cr��stian Viana) + * [14bc6fc] Typo: Rename function create_defautl_network (Cr��stian Viana) + * [ba96997] Bug Fix: Fix network list layout. (Wen Wang) + * [4a91e74] Issue#348: Fix UI for nfs mount (Royce Lv) + * [3c6c5c5] List iSCSI targets available for initiator while creating iSCSI Pool (ShaoHe Feng) + * [35050bf] List iSCSI server for initiator while creating iSCSI Pool (ShaoHe Feng) + * [3f61acb] Issue #361: Bugfix disable the action button content when creating network (Hongliang Wang) + * [7467feb] Fix i18n packaging scripts (Zhou Zheng Sheng) + * [19b3c4a] Keep User from Generating a Report with an Existing Name (Hongliang Wang) + * [a1bc654] Add progress Event Handler for Asynchronized Tasks (Hongliang Wang) + * [5ea8e8f] Add License Statement in kimchi.report_add_main.js (Hongliang Wang) + * [464d3d0] Add Name Existence Check for Debug Report when Create (Hongliang Wang) + * [c89c2e0] Bug fix: Display the username on the header bar (Cr��stian Viana) + * [8ce46e6] Add doc and test case for dedicate iso pool (Royce Lv) + * [e3ab2ce] Store qemu user name in class attribute (Royce Lv) + * [5dc4dd2] Dedicated ISO pool: create an out of box ISO pool (Royce Lv) + * [ff92786] Reword 'isolated' network description (Christy Perez) + * [9aeac73] Disable cache for help page (Royce Lv) + * [27bd99f] Create pool UI: making 'Create' button disable when forms not filled. (Daniel Henrique Barboza) + * [b7c518c] bug fix: Make rpm failed (ssdxiao) + * [bd98489] update ui/pages/Makefile.am to let i18n.json.tmpl be added to the package. (ShaoHe Feng) + * [578ab29] add some sample plugin generated files to .gitignore (ShaoHe Feng) + * [26582d8] skip plugins test, when sample plugin is not enabled (ShaoHe Feng) + * [de177c8] generate the translation files for plugins/sample (ShaoHe Feng) + * [3ce13b5] add an option to toggle the sample plugin (ShaoHe Feng) + * [38bee60] Issue #342: load i18n.html of the plugin (ShaoHe Feng) + * [45b16d0] Add JS API for fetching i18n JSON (ShaoHe Feng) + * [947bce5] Update the i18n tmpl to produce JSON (ShaoHe Feng) + * [3205117] Update root.py to make Cheetah render the JSON template. (ShaoHe Feng) + * [3d52774] Add Minimal UI Page for the Sample Plugin (Zhou Zheng Sheng) + * [d8c2ea1] Bugfix: List inactive network interface while editing template (Wen Wang) + * [cf015d4] login: update test config case (ShaoHe Feng) + * [df4749b] login page prompts error when session timeout (ShaoHe Feng) + * [ba0cf6e] login page prompts error when username or password is wrong (ShaoHe Feng) + * [d7e828e] when login successfully, redirect to the last page. (ShaoHe Feng) + * [85e3837] redirect the URL to login page when session timeout or first login (ShaoHe Feng) + * [8f86568] create a new login page (ShaoHe Feng) + * [a556578] Bugfix: Multiple progress indicator during debug report generating (Wen Wang) + * [54e6bfa] Issue#305: Redesign bridged network UI section tempstorage (Wen Wang) + * [fe23558] Add Ubuntu as modern distro to Power guests. (Paulo Vital) + * [8c50cc8] Added the generating progress indicator (Wang Wen) + * [250cc3d] Remove the first column of debug report grid (Wang Wen) + * [c81314f] Add testcase for cdrom eject (Royce Lv) + * [2768515] Update model to support cdrom eject (Royce Lv) + * [3282020] Change doc and controllor to support cdrom eject (Royce Lv) + * [cd67617] Adding test case for updating flags (Royce Lv) + * [a48518b] Fix wrong create/update/delete flags for vmstorages (Royce Lv) + * [5fee8c2] Fix Bug: Template Tab Broken in Chrome due to Code Error (Hongliang Wang) + * [08a9c00] Bug Fix - Save Button Behaves Incorrectly in Guest Edit Window (Hongliang Wang) + * [f2f137e] Remove Unused Files (Hongliang Wang) + * [c4117ab] Adjust Guest Edit Storage Tab Styles (Hongliang Wang) + * [339c1aa] show template is local or remote (ShaoHe Feng) + * [7835e16] Update API.md (Hongliang Wang) + * [6741700] Add Unit (MB) to Memory in Template Edit Window (Hongliang Wang) + * [b558fd9] bug fix: decode volume name in IsoVolumesModel. (ShaoHe Feng) + * [ef7e8e3] novnc does not work in IE (Adam King) + * [8b6405f] Code Refector: Extract Variables in kimchi.login_window.js (Hongliang Wang) + * [892238e] Disable metadata log output in every guest refresh (Cr��stian Viana) + * [785920b] Repository Grid Column Resizing Issue (Hongliang Wang) + * [76629f6] StoragePool Edit: Add Disk to Logical Pool (Royce Lv) + * [5ee2b93] Exception: fix exception details when not specified (Royce Lv) + * [7ca9ade] Remove cdrom '.iso' suffix checking from add template js (Rodrigo Trujillo) + * [7e5f8b2] Remove '.iso' extension checking from json schema (Rodrigo Trujillo) + * [a1e7364] model.host: avoid redundant libvirt lookupByName API invocation (Zhou Zheng Sheng) + * [f7ec8f0] Rename kimchi.template to kimchi.substitute (Hongliang Wang) + * [bd866e1] Remove unused listDeepScanIsos function (Rodrigo Trujillo) + * [4448948] Update README with the correct FF ESR version. (Adam King) + * [68d4d6c] VM template: add disk size error message (Zhou Zheng Sheng) + * [0e165c4] adjust the width of host info-container (ShaoHe Feng) + * [d65b8e5] UI: Fix VM Delete Confirmation Dialog Box Title (Zhou Zheng Sheng) + * [96c19c6] Fix text alignment on storage pool type combo boxes (Cr��stian Viana) + * [c5329c2] Remove button "Cancel" from modal dialog (Cr��stian Viana) + * [0666eee] Fix Text Truncated Problem of Login Button (Hongliang Wang) + * [ff7f991] bug fix: Allow changing default ports (Aline Manera) + * [96f3248] bug fix: Update test cases to use HTTPS (Aline Manera) + * [1d8476b] host/partitions: avoid calling disks.get_partitions_names() for each partition (Zhou Zheng Sheng) + * [1d56572] Correct the ID String of Disk Size in Template Edit Window (Hongliang Wang) + * [5c2a584] Issue #369: Fix config_dir assignment (Aline Manera) + * [cc3b5b5] Revert "Host Tab: Add Widths for Repository Grid Columns" (Aline Manera) + * [5dc3195] Fix Text Wrapping Problem in Template Edit (Hongliang Wang) + * [9ececcf] Fix Text Wrapping in Tab Bar (Hongliang Wang) + * [4128392] Github #368: Removing 'resend' tag from getHostStats JSON (Daniel Henrique Barboza) + * [44ec020] Set IE edge mode for VNC/Spice web pages (Adam King) + * [73e524c] bug fix: Properly set the listen IP to SPICE console (Aline Manera) + * [58017f4] websockets: Disallow non-encrypted client connections (Aline Manera) + * [381864f] UI: Redirect user to console page after logging (Aline Manera) + * [be9b967] backend: Redirect 401 error to default page (Aline Manera) + * [e1760d8] Enable Kimchi authentication in console pages (Aline Manera) + * [74ad9b4] Make use of the mini Web server in the websockify (Aline Manera) + * [9116d53] Enable encryption in vm console connection (Mark Wu) + * [6ddf6a9] Revert "Enable encryption in vm VNC console connection" (Aline Manera) + * [dc6c28e] vmiface update support: update test case (ShaoHe Feng) + * [b813d6c] vmiface update support: update mockmodel (ShaoHe Feng) + * [309aa71] vmiface update support: update model. (ShaoHe Feng) + * [51820c4] vmiface update support: update API.md (ShaoHe Feng) + * [c356a75] Display all disk types in storage edit view (Royce Lv) + * [010aaac] UI: Support add guest disk (Royce Lv) + * [b2d1217] Fix select menu data append (Royce Lv) + * [3c294a5] Guest disks: Update testcase (Royce Lv) + * [5df01ab] Multiple pep8 fixes (Royce Lv) + * [2360f7c] Guest disk: deals with disk attachment (Royce Lv) + * [1bc8aa6] Guest disks: Abstract vm disk functions (Royce Lv) + * [7770a11] Guest disks: Choose proper bus for device (Royce Lv) + * [4e7a17c] Guest disks: Update api definition and error reporting (Royce Lv) + * [9c0e2a1] Guest disks: Update doc to support manage guest disks (Royce Lv) + * [9328079] Return info from run_command on exception. (Christy Perez) + * [781b331] write the template OS info to vm metadata (ShaoHe Feng) + * [8566599] update test case to set/get user and group when VM is running (ShaoHe Feng) + * [2617373] bug fix: get user and group when vm is living. (ShaoHe Feng) + * [d7e7017] manually manage the metadata element (ShaoHe Feng) + * [2c176c0] Add two function to set and get domain xml metadata (ShaoHe Feng) + * [1f1dcc3] add method to test libvirt metadata api are available (ShaoHe Feng) + * [d777a02] bug fix: call a method should be followed by "()" (ShaoHe Feng) + * [06238f2] Enable encryption in vm VNC console connection (Mark Wu) + * [6bf630c] Change the default tab to "Guests" (Cr��stian Viana) + * [9e85e59] Define the default tab more clearly (Cr��stian Viana) + * [976db87] Refactor code to trim file extension (Cr��stian Viana) + * [37a1e1b] bug fix: Redirect 3xx responses through proxy (Aline Manera) + * [a7f083c] Set default storage pool to autostart and make persistent (Christy Perez) + * [6f5d0d9] Fix PEP8 in scan.py (Rodrigo Trujillo) + * [5de2ca8] security: Prevent XSS attacks (Aline Manera) + * [9d3bb9c] bug fix: Use secure cookies (Aline Manera) + * [def7c67] security: Redirect all HTTP requests to HTTPS (Aline Manera) + * [819cc2a] Fix Bug: Invalid URL at 404 Not Found Page (Hongliang Wang) + * [7132f75] Changes to use 2048 bit public key for self-signed certificate (Mark Wu) + * [6bac3ec] Display historical host statistical info on the host tab (Adam King) + * [217858c] Host stats history: Update test cases (Aline Manera) + * [9d2bf5c] Add API to return host stats history (Aline Manera) + * [9b2eafb] repository: Remove full stop symbol from checkbox's label (Cr��stian Viana) + * [087e739] repository: Make checkbox clickable (Cr��stian Viana) + * [f2d6ff4] repository: Place checkbox to the left of its label (Cr��stian Viana) + * [b4f84dd] Modify edit guest help info (Rodrigo Trujillo) + * [4a8d603] User action menu overflows when actions with names longer than a few chars a.. (Adam King) + * [1ef1561] Regenerate PO files (Adam King) + * [82c1181] Update po/POTFILES.in (Adam King) + * [3acf6c3] UI: Edit Guest Network Interface (Yu Xin Huo) + * [19011c7] Github #329: .gitignore, spec, control.in and readme (Daniel Henrique Barboza) + * [117cd5a] Github #329: changes in mockmodel, model/config and tests (Daniel Henrique Barboza) + * [152d820] Github #329: Kimchid, config.py.in and server.py changes (Daniel Henrique Barboza) + * [6883533] Github #329: Proxy module and template file (Daniel Henrique Barboza) + * [775e630] New domain state pmsuspended (ShaoHe Feng) + * [177a147] VM shutdown support in UI (ShaoHe Feng) + * [d242e30] VM shutdown support in backend (ShaoHe Feng) + * [44e545e] Fix error storage pool lookup usage in deep scan (Royce Lv) + * [2271eeb] Clarify the meaning of an empty vm user or group list (Christy Perez) + * [c01d983] VM Edit: CPU and memory (Adam King) + * [b31a134] VM Edit CPU/Memory: (Backend) Changes mockmodel and tests (Rodrigo Trujillo) + * [ac2c7de] VM Edit CPU/Memory: (Backend) Changes VM control and model (Rodrigo Trujillo) + * [5ea7626] VM Edit CPU/Memory: (Backend) Changes API.md, API.json and i18n.py (Rodrigo Trujillo) + * [ecaf9a8] Update test cases (Aline Manera) + * [f04f67f] Remove unused code (Aline Manera) + * [17fd157] Update users/groups verification based on new API (Aline Manera) + * [fe2fd1d] Add API to list system users and groups (Aline Manera) + * [5641e5e] Create a new common collection named SimpleCollection (Aline Manera) + * [ce2bbbd] Bug fix: add PYTHONPATH for contrib/check_i18n.py (ShaoHe Feng) + * [5c2013d] packaging: ship kimchi with plugins/__init__.py (Zhou Zheng Sheng) + * [361cae4] Display version/build number in UI (Adam King) + * [a67fe54] Host Tab: Add Widths for Repository Grid Columns (Hongliang Wang) + * [88c190a] Issue#364: UI - Column Resizing Function Broken in Host Tab (Hongliang Wang) + * [257d0ff] config version API support in backend. (ShaoHe Feng) + * [698b101] config version API support: add a method to get kimchi version (ShaoHe Feng) + * [4c7c402] Add/remove users and groups to VMs (Aline Manera) + * [ca0bfd9] Return users and groups when fetching VM info (Aline Manera) + * [0a38dc9] Add functions to check if a user/group exists (Aline Manera) + * [021d4d1] Use proper term "user name" instead of "user id" (Aline Manera) + * [0348f4a] Override only the updated "User" methods in "patch_auth" (Cr��stian Viana) + * [548f894] Set virt_use_nfs when NFS pool is added. (Christy Perez) + * [767a34e] Issue #363: Fix data/information consistence in edit template window (Rodrigo Trujillo) + * [16659a5] Issue #363: Add new rest api function - getStoragePoolVolume (Rodrigo Trujillo) + * [4266218] add a method to check the i18n strings are obsolete (ShaoHe Feng) + * [89411f9] remove obsolete i18n strings which are no longer in use (ShaoHe Feng) + * [3b11219] add a make check-local command to verify the i18n string formatting (ShaoHe Feng) + * [04d2d73] Choose available address for ide disk (Royce Lv) + * [5c487da] add confirmation for reset a VM (ShaoHe Feng) + * [074f7c5] reset vm in UI (ShaoHe Feng) + * [86f1afa] reset VM in backend. (ShaoHe Feng) + * [6fe5997] reset VM: update API.md (ShaoHe Feng) + * [9f626cb] Bug fix #357 - Error when creating template from ISO (Ramon Medeiros) + * [d8617eb] Fix backend error when creating multiple templates (Rodrigo Trujillo) + * [767e486] Fix typo while processing request data (Aline Manera) + * [7c3bb7b] Fix kimchi vlan tagged bridge name (Mark Wu) + * [3bf0173] error when editing repository entry with no mirrorlist. (Paulo Vital) + * [de1d0f6] kimchi.disks: Ignore unsupported partition table (Zhou Zheng Sheng) + * [68d86c5] Fix get_storageservers API and UI retrieval of storage servers. (Christy Perez) + * [e19383c] help pages: Set default index file to /help URI (Aline Manera) + * [23042dd] help pages: Update .gitignore file (Aline Manera) + * [65051df] help pages: Adjust css url (Aline Manera) + * [61d619e] help pages: Remove former .dita files (Aline Manera) + * [a8f8abd] Update build process to generate html pages for each help subdir (Aline Manera) + * [4e548cb] Replicate help pages for pt_BR and zh_CN (Aline Manera) + * [aab8764] Bug fix #360: Support i686 architecture (Ramon Medeiros) + * [42f7771] Fix volume not found error message (Rodrigo Trujillo) + * [4a34cbf] Fix debugreports download issue (Mark Wu) + * [c7e4707] objectstore: support sorting by a key in get_list() (Zhou Zheng Sheng) + * [58efd8f] add confirmation for power off a VM (ShaoHe Feng) + * [250565d] change the stop to power off for VM in UI (ShaoHe Feng) + * [82fa8d1] change the stop to power off for VM in backend (ShaoHe Feng) + * [70dc729] Try to activate physical interface when create a network on it (Mark Wu) + * [6e19ac4] Software Update: Make Update Progress Area Collapsible (Hongliang Wang) + * [c012f81] Issue #365: Preventing duplicate Bridged VLAN tagged network. (Paulo Vital) + * [11b2c7f] improve Chinese translation (ShaoHe Feng) + * [3a2ed85] Make use of the new forms handling capabilities (Adam King) + * [eadacde] Extend jQuery form (Adam King) + * [229710a] Extend base classes to support form processing (Adam King) + * [0e555f5] Fix hardcoded storage bus assignment in vmstorage (Rodrigo Trujillo) + * [58c9025] kimchi.exception: Properly Decode All Kinds of Exception Arguments (Zhou Zheng Sheng) + * [25bd8e0] Sort device paths shown when creating a logical storage pool (Rodrigo Trujillo) + * [02807f8] Add template clone support (Adam King) + * [15b0e43] Fix pep8: add files to whitelist of Makefile.am (Rodrigo Trujillo) + * [5252d7a] Fix pep8 issues in src/kimchi/objectstore.py (Rodrigo Trujillo) + * [75542bd] Fix pep8 in src/kimchi/template.py (Rodrigo Trujillo) + * [b81f7bc] Fix pep8 in src/kimchi/vmtemplate.py (Rodrigo Trujillo) + * [f2c436b] Plugins UI: Correctly Load Plugin Tabs (Zhou Zheng Sheng) + * [e057827] Fix 'disk full' issue: Fix vms/screenshot db store/delete error handling (Rodrigo Trujillo) + * [42a9072] Fix 'disk full' issue: Fix storagepool and asynctasks error handling (Rodrigo Trujillo) + * [fa0b991] Fix 'disk full' issue: Fix storage volume error handling (Rodrigo Trujillo) + * [b787cba] Fix 'disk full' issue: Fix Templates db store/delete error handling (Rodrigo Trujillo) + * [dc2174e] Fix 'disk full' issue: Change objectstore exception handling (Rodrigo Trujillo) + * [e851d99] Add the command to run_command error and debug logging (Christy Perez) + * [833125c] bug fix: we should pass str to cherrpy HTTPError (ShaoHe Feng) + * [f5c517a] Issue #343 & #353: Improve & Correct UI Init Logic Flow (Hongliang Wang) + * [bd80b70] AsyncTask: Propagate cherrypy request information to worker threads (Zhou Zheng Sheng) + * [0ea1f4b] UI: change some code of storage add page (ShaoHe Feng) + * [d5fd304] Fix non persistent network handling (mockmodel/tests) (Rodrigo Trujillo) + * [f3f55a8] Fix non persistent network handling (frontend) (Rodrigo Trujillo) + * [cc87c6a] Fix non persistent network handling (backend) (Rodrigo Trujillo) + +#### [kimchi-1.2.0] #### + * [335ee71] Update Changelog for 1.2 release (Aline Manera) + * [015ebb3] Remove LUN assignment in VM (Aline Manera) + * [103e87b] Update po and pot files for 1.2 release (Aline Manera) + * [002ec76] Translate pt_BR.po file (Ramon Medeiros) + * [35c3000] Chinese translation for release 1.2 (ShaoHe Feng) + * [1add01e] bug fix: fix the string format %(pool). (ShaoHe Feng) + * [58da428] Add error handling for repo management (Adam King) + * [2e4a46a] Logical Storage Pool: Detect and Enumerate Multipath Block Devices (Zhou Zheng Sheng) + * [179bf14] validate the volume parameter when the pool of template is iscsi or scsi (ShaoHe Feng) + * [31fa6b8] Fix swupdate listing (Royce Lv) + * [9259c90] error message fix. (ShaoHe Feng) + * [b056903] Fix a typo. (Leonardo Garcia) + * [b31e125] bug fix: fix the string format. (ShaoHe Feng) + * [429d370] Add lock in swupdate (Royce Lv) + * [a144b90] fix lock for apt package manager (Royce Lv) + * [1e3e121] Properly display YUM exception (Aline Manera) + * [074e265] UI: template edit page support scsi lun (ShaoHe Feng) + * [1060f98] create a VM from an scsi pool template (ShaoHe Feng) + * [81bc75e] create a VM from an iscsi pool template. (ShaoHe Feng) + * [0671de3] generate a iscsi volume disk for a guest (ShaoHe Feng) + * [6ac343a] add a method to get iscsi storage pool auth information. (ShaoHe Feng) + * [f4db0d6] Help for scsi fibre channel (Kersten Richter) + * [e1e7baa] Fibre Channel SCSI Storage Pool UI (Yu Xin Huo) + * [5f43812] Added help for repositories (Kersten Richter) + * [5b14926] Repository Management - Integrate into Host Tab (Hongliang Wang) + * [7999102] Repository Management - Edit Repository Support (Hongliang Wang) + * [55c426b] Repository Management - Add Repository Support (Hongliang Wang) + * [057f2d4] Repository Management - Add API Support (Hongliang Wang) + * [66b1573] Repository Management - Add i18n Strings (Hongliang Wang) + * [f18b0bc] Update grid widget to populate fields from deeply nested objects (Adam King) + * [afea547] Update form.serializeObject method to handle deep object serialization (Adam King) + * [0d51a2f] Adds 'in_use' info to API.md (Rodrigo Trujillo) + * [622781d] Template: Check if the host supports Spice (Zhou Zheng Sheng) + * [a8f9f16] but fix: show the content of combobox and filterselect in storage add page (ShaoHe Feng) + * [24cfe69] Bug fix: specify the class attribute when change pool state dot. (ShaoHe Feng) + * [281d35c] Optimize return code check. (Leonardo Garcia) + * [ddd588d] Show error message from debug report generation async task (Rodrigo Trujillo) + * [3d47c5c] bug fix: Lock YUM operations (Aline Manera) + * [ace80fe] bug fix: Display update progress on real time (Aline Manera) + * [413e36b] bug fix: Allow user specifies the repository name when adding a new YUM repo (Aline Manera) + * [ad283ee] bug fix: Instantiate the apt-get manager when update the apt-get packages list (Aline Manera) + * [e94903a] Issue#349: Software Update Grid Keeps Loading when Error Returns (Hongliang Wang) + * [81c16b4] run pyflakes when make check (ShaoHe Feng) + * [f4cbe91] add template_delete to rollback after create a template (ShaoHe Feng) + * [2fa81bf] make pyflakes happly, remove unused availables (ShaoHe Feng) + * [8b64eb1] make pyflakes happly, remove the unused import module (ShaoHe Feng) + * [be5c57d] Remove debug report's file path from UI (Mark Wu) + * [4fa40e1] partitions: Fix when disk does not have extended partition (Royce Lv) + * [c177cae] bug fix: instantiate the Yum manager when update the yum packages list (ShaoHe Feng) + * [4a43a7c] Issue#352: Debug Report Section NOT Hidden for Non-root User (Hongliang Wang) + * [50a373a] bug fix: Lock yum/apt operations (Aline Manera) + * [bc72f1c] Update test cases to reflect the repositories changes (Aline Manera) + * [d369c91] bug fix: Do not store internal repository information (Aline Manera) + * [8536141] bug fix: Let package manager tool create the repository ID (Aline Manera) + * [ca77c50] bug fix: Sort repositories (Aline Manera) + * [5e6300e] bug fix: Raise exception comming from backend (Aline Manera) + * [384dbec] Update messages used in the repositories management feature (Aline Manera) + * [340e4f5] mockmodel: Move specific repository data under 'config' (Aline Manera) + * [7d5fad5] bug fix: Reorganize repository information (Aline Manera) + * [81e5440] bug fix: Expose repository management tool name (Aline Manera) + * [9b40f58] VLAN: Do not allow bridge to be the trunk device (Zhou Zheng Sheng) + * [24c4319] Fix iso streaming functions and feature tests (Rodrigo Trujillo) + * [c44b238] sudo: run sudo with a pseudo controlling terminal (Zhou Zheng Sheng) + * [e609efa] Display the error code when displaying error msgs (Cr��stian Viana) + * [f39dfe4] Apply Kimchi standard error message (Cr��stian Viana) + * [cb1ece8] Do not show success messages (Cr��stian Viana) + * [6a45ad0] Doc: add work around to handle NFS root squash problem (Royce Lv) + * [13819ab] Fix issue 348: NFS pool creation times out (Christy Perez) + * [6d6c816] Software Update: Enable "Update All" Button when Task Fails (Hongliang Wang) + * [6888a72] Changes to help (Kersten Richter) + * [38d8f1a] Remove bridge and vlan interface unconditionally on removing vlan network (Mark Wu) + * [01c4035] Fix Bug - Text Overlapped in Template Add Window (Hongliang Wang) + * [9c2b766] Fix multiple pep8 (Royce Lv) + * [a37e0bd] Grid Loading Mask - Some Elements are Missing (Hongliang Wang) + * [58ab016] Skip 'screendump' for vms no video device configured (Mark Wu) + * [cfd29f8] Controller: Improve Kimchi Specific Exception Reporting (Zhou Zheng Sheng) + * [4523b3e] Grid widget presently interprets displays null values as null strings (Adam King) + * [22dc2af] mockmodel: Reset packages after updating system (Aline Manera) + * [e6806e4] UI: Disable stop/undefine buttons when network is in use (Aline Manera) + * [b590cd5] Do not allow user disable/delete a network used by VM or template (Aline Manera) + * [31f7bbf] Software Update Support in Host Tab (Hongliang Wang) + * [95bd616] Software Update - APIs in kimchi.api.js (Hongliang Wang) + * [3182653] Software Update - i18n Translation Strings (Hongliang Wang) + * [4f2b234] Supplement to [PATCH v6 0/3] UI: Software Update Support (Adam King) + * [e9ab744] bug fix: encode the args in KimchiException when is is unicode. (ShaoHe Feng) + * [8a6db10] Grid Enhancement - Show Message when Loading Data (Hongliang Wang) + * [c700997] Correct the Repositories parameter name of is_mirror (Adam King) + * [9a54667] Start up Kimchi even if no repo management tool was identified (Aline Manera) + * [aee1318] Expose repo_mngt_tool to /config/capabilities (Aline Manera) + * [0b811f6] bug fix: Identify repository management tool based on available system tools (Aline Manera) + * [e3338e2] bug fix: Identify update tool based on available system tools (Aline Manera) + * [96a0235] Changed xsl file to include stylesheet (Kersten Richter) + * [acde6c7] Added a style sheet to make the html look pretty (Kersten Richter) + * [35033c6] Commit changes to templates and storage.dita files (Kersten Richter) + * [34cd66f] Added help for host and network tab. (Kersten Richter) + * [681ac87] Grid Enhancement - "title" Attribute for Long Values (Hongliang Wang) + * [5b921e0] ISO Scan: Use volume set id instead of volume id for some wrong images. (Mark Wu) + * [e7c6426] Issue #302: let 'create' attr of networks model to create default network (ShaoHe Feng) + * [42008ee] add a new function to get an available network address (ShaoHe Feng) + * [39a2ba8] move _default_network_check from top model to networks model (ShaoHe Feng) + * [3df47fe] Update guest action menu (Adam King) + * [626081f] Pass ajaxError information on to original requester on ajaxError event (Adam King) + * [b113780] Issue 292 Logical Storage Pool Returning "extended" Partitions as Possible P.. (Zhou Zheng Sheng) + * [5ed36d6] bug fix: remove the hard code of disk_path (ShaoHe Feng) + * [378eb45] probe iso permission: update test case (ShaoHe Feng) + * [84a28fb] Don't allow templates to be created with ISOs that won't be usable. (ShaoHe Feng) + * [af51f27] qemu user tests: probe the username of qemu process started by libvirt (ShaoHe Feng) + * [baed491] add a method to probe the permission as qemu user (ShaoHe Feng) + * [de0400b] Attach/Replace/Detach a CDROM to/in/from a VM (Hongliang Wang) + * [474e774] Add/Edit CDROM Support (Hongliang Wang) + * [505409f] Add i18n Variables for CDROM-related Function (Hongliang Wang) + * [f392c6d] Add CDROM-related APIs (Hongliang Wang) + * [9cfb638] kimchi.message - Enhancement (Hongliang Wang) + * [23b5850] Adjust CSS for Window (Hongliang Wang) + * [87a6eec] Issue 294 The auto logout leaves action menu on page - update JS (Adam King) + * [28419d8] Issue 294 The auto logout leaves action menu on page - add classes (Adam King) + * [f8ac146] Fix formatting of the requestJSON function (Adam King) + * [9f91334] pep8 clean for osinfo.py (ShaoHe Feng) + * [82a743b] bug fix: add an icon distros list. (ShaoHe Feng) + * [8c3ce5f] Build help index page only once (Cr��stian Viana) + * [2c7dbf8] fix: Build new DITA pages when running "make" (Cr��stian Viana) + * [11e871c] Multiple pep8 fixes (Royce Lv) + * [2ab54c1] Add volume ref_cnt: Update test (Royce Lv) + * [3f0e775] Add volume ref_cnt: Add model and mockmodel implementation (Royce Lv) + * [757a254] Add volume ref_cnt: Update controller and json schema (Royce Lv) + * [d55e72a] Add volume ref_cnt: update api.md (Royce Lv) + * [bb89241] Fix vm disk path when it does not have source element (Royce Lv) + * [86a9b4d] Export list vms functionality (Royce Lv) + * [dfccd65] Allocate enough space for logical volume (Royce Lv) + * [a815850] Window Widget Enhancement - Allow onClose Listener (Hongliang Wang) + * [834e48b] Bug fix: Kimchi could not start guest with iscsi lun assigned as disk (Rodrigo Trujillo) + * [c092436] issue #200: Rebuild .mo files when running "make" (Cr��stian Viana) + * [57f9f9f] Do not show a success msg when creating a template (Cr��stian Viana) + * [7dc503d] Window - Correct Footer Height (Hongliang Wang) + * [0c840f0] logical pool: Fix logical pool target path (Royce Lv) + * [75f31dc] Fix storage volume format on logical pool for vm (Royce Lv) + * [3fdbb1c] Use a pool of threads to valid all remote ISOs in parallel (Aline Manera) + * [456018a] bug fix: "sudo: sorry, you must have a tty to run sudo". (Paulo Vital) + * [389b13c] Update distros JSON files to always point to a valid URL (Aline Manera) + * [7b69dfa] issue #301: Add a loading message while listing default remote ISOs (Aline Manera) + * [db72242] issue #301: Only list remote ISOs with valid URL (Aline Manera) + * [33a9257] Increase memory size for vm template on ppc platform (Mark Wu) + * [5747b58] Fix issue #339: Change mock and add test to check persistent variable (Rodrigo Trujillo) + * [88bb4a7] Fix issue #339: Changes UI to handle deactivation of non-persistent pools (Rodrigo Trujillo) + * [596ddb1] Fix issue #339: Enable backend to handle not persistent pools (Rodrigo Trujillo) + * [f11beaa] Fix rollback order (Rodrigo Trujillo) + * [6d234f1] bug fix: Set default flags for virDomain.state() function (Aline Manera) + * [00a60b3] Issue #222: add python-xml to suse require list (ShaoHe Feng) + * [34a6073] storage volume: fix xml parsing of logical volume format type (Zhou Zheng Sheng) + * [4be19f9] Support ppc64 isos in Templates: Fix test cases (Rodrigo Trujillo) + * [6a81c0e] Support ppc64 isos in Templates: Filter remote isos and change UI (Rodrigo Trujillo) + * [01d338b] Support ppc64 isos in Templates: Add arch and urls to distro jsons (Rodrigo Trujillo) + * [0ef900c] issue #330: Make sure exception argument is a string to convert it to unicode (Aline Manera) + * [e9a5071] issue #312: Check volume group exists while creating a logical pool (Aline Manera) + * [186a2ad] Refreshing an inactive pool causes exception (Shu Ming) + * [853908a] session expire: update test case (ShaoHe Feng) + * [2907055] UI: set kimchi robot header for some request. (ShaoHe Feng) + * [ad459df] auth enhancement: expire the session when the request access periodically (ShaoHe Feng) + * [fa350f6] add timeout for sessions (ShaoHe Feng) + * [eb37a50] Issue #333: do not encode error.html when the cherrpy version less than '3.2.. (ShaoHe Feng) + * [707aee0] bug fix: setup disks to use cache=none to support live migration. (Paulo Vital) + * [6779b95] While trying to extend a logical pool I got the following error message: (Aline Manera) + * [008e76f] template integrity verification: update test case to verify storagepool (ShaoHe Feng) + * [2ec01d5] template integrity verification: verify storagepool in backend (ShaoHe Feng) + * [ae3b81b] template integrity verification: verify storagepool, update API.md (ShaoHe Feng) + * [5f28f72] Github bug #307: storage pool type list - html and string changes (Daniel Henrique Barboza) + * [a7ea3d2] Github bug #307: add storage pool type list - JS changes (Daniel Henrique Barboza) + * [d977d18] remove unused InvalidOperation instance (ShaoHe Feng) + * [7869c19] Add test case for kimchi server configuration. (Mark Wu) + * [e65d00a] Add static directory configurations for plugin's ui (Mark Wu) + * [668f522] UI: Grid Widget - Enable/Disable Row Selection (Hongliang Wang) + * [e9f67dc] Bug Fix #282: Handle toggleNetwork error returns (Rodrigo Trujillo) + * [41ac09c] Bug Fix #282: Disable Start/Stop network buttons while wait backend lag (Rodrigo Trujillo) + * [ee36b1f] Clear pep8 failure in make check (Royce Lv) + * [4175f76] Prevent volume create and delete for certain pool types (Royce Lv) + * [20568e2] Fix vm creation storage rollback clean (Royce Lv) + * [729d15b] UI: template support spice, update po (ShaoHe Feng) + * [6a17215] UI: template support spice (ShaoHe Feng) + * [a9d94a7] Fix debug report UI: Error handling and line selection (Rodrigo Trujillo) + * [e1ed6cd] issue #66: Auto generate template name in backend when none is provided (Aline Manera) + * [bd47f5a] bug fix: Only check for ISO images in active pools (Aline Manera) + * [74614bd] bug fix: Do not probe ISO file while checking template integrity (Aline Manera) + * [be2122d] vmtemplate: Remove useless imports (Aline Manera) + * [276c13a] Fix typo on KCHAPI6005E message (Aline Manera) + * [c835175] bug fix: Enable NFS path field when a NFS server is provided (Aline Manera) + * [31c4398] Fix software update action into Host resource (Paulo Vital) + * [793e2c6] Fix test_osinfo.py to use new modern distro version dict. (Paulo Vital) + * [1a05317] Fix VM's network model template for Power systems. (Paulo Vital) + * [9abfad4] kimchi.control.utils: fix request parsing in generate_action_handler() (Zhou Zheng Sheng) + * [5d82241] Issue 299 Inactive storage pools are listed while editing template (Adam King) + * [279a710] Can not create a VM from a template with disks['volume'] parameters. #181 (Shu Ming) + * [3100c0c] Fix Kimchi vm tests according to new messages sent from backend (Rodrigo Trujillo) + * [5e902bf] Delete unsed _vm_exists funtion (Rodrigo Trujillo) + * [9178089] Fix VM delete error message handling (UI/Backend) (Rodrigo Trujillo) + * [d58edad] Fix VM reset (UI) error messages hnadling (Rodrigo Trujillo) + * [82b80e3] Fix VM stop error messages handling (backend/UI) (Rodrigo Trujillo) + * [96f5457] Fix vm start UI error return message (Rodrigo Trujillo) + * [f8c9c60] Fix Add Network window (Rodrigo Trujillo) + * [eb8347e] Add another way to download the debugreport file in the test (Shu Ming) + * [632c3ca] Have a meaningful description for the exception test #81 (Shu Ming) + * [7ee1b09] bug fix: check all Red Hat distributions for yum package management (ShaoHe Feng) + * [8931da1] Set default combo box style to storage pool type list (Aline Manera) + * [c4c093e] issue #242: Do not allow user deactivate/delete storage pool used by a templ.. (Aline Manera) + * [26631c0] bug fix: Make URI parameter is not None before encoding it (Aline Manera) + * [d58f453] Authors cleanup (Paulo Vital) + * [e3ea028] run_command: log error messages using higher log level when return code is n.. (Zhou Zheng Sheng) + * [c6e8212] Fix screenshots and debug reports paths. (Leonardo Garcia) + * [3514d3b] Fix tests: restore the monkey patch after testing Paths (Mark Wu) + * [ca04f30] Issue # 303 The password of iSCSI Authentication should be masked (Adam King) + * [e5cf383] issue #325: Use RamSession instead of FileSession (Aline Manera) + * [e10177e] Github bug #327: NFS pool workaround: model changes (Daniel Henrique Barboza) + * [5c38855] Github bug #327: NFS pool workaround: timeout adjustments (Daniel Henrique Barboza) + * [5076c7d] Github bug #327: NFS pool workaround: i18n changes (Daniel Henrique Barboza) + * [948445f] Packaging: removed start of kimchid from RPM and DEB files (Paulo Vital) + * [d83510c] bug fix: Properly display missing parameter (Aline Manera) + * [19f6fcf] Clear out the guests list properly using jQuery (Adam King) + * [baff478] issue #316: Only verify if path starts with '/' (Aline Manera) + * [ad1ecbc] Add help to user menu (Adam King) + * [346d50d] Fix debug report naming problem (UI) (Rodrigo Trujillo) + * [f1d433b] Fix debug report naming problem (backend) (Rodrigo Trujillo) + * [cde51be] Github bug #326: run_command: killing all children processes (Daniel Henrique Barboza) + * [0a34570] allow user to create a storagepool with name in his local language (ShaoHe Feng) + * [c580e08] Issue #243: start/stop/display a VM whose name with "?" (ShaoHe Feng) + * [7cb61c0] Clear unused reference in vmstorages of 'kargs' (Royce Lv) + * [667a6b2] Issue #289: catch the libvirtError when failed to start a vm (ShaoHe Feng) + * [c35c318] Fix Kimchi UI issues on IE11 (Adam King) + * [5a044d9] Fix typo on API.json and add missing error messages (Aline Manera) + * [68988c3] cdrom: update model test for media update (Royce Lv) + * [cbab49f] cdrom: fix cdrom change media (Royce Lv) + * [a319343] Undefined lable in template buttons. (adriano) + * [30c383a] Issue #315: edit/delete templates that contains slashes in their names (ShaoHe Feng) + * [243dd85] Remove tabs in ui/pages/storagepool-add.html.tmpl (Aline Manera) + * [0af44e3] Change guests tab to update the VM List by DOM manipulation (Adam King) + * [8e7ef05] Update the guest.html.tmpl to use the new circleGauge widget (Adam King) + * [6db93c8] Create a reusable jQuery circleGauge widget (Adam King) + * [b47595d] Update (mock)model to generate proper JSON (Adam King) + * [3be6341] PEP8 for mockmodel.py (Adam King) + * [977e772] Fix PEP8 in test files (Aline Manera) + * [92d04e3] Fix ui/js/Makefile.am (Aline Manera) + * [09366f0] Implement integrity verification: update test case (ShaoHe Feng) + * [9988128] Implement integrity verification: verify template integrity in backend (ShaoHe Feng) + * [ef8222b] add a new method to get iso info for VMTemplate class (ShaoHe Feng) + * [f8bdc13] Implement integrity verification: verify template integrity, update API.md (ShaoHe Feng) + * [8c0ad96] issue #324 Improve error messages of creating a storage pool named "kimchi_i.. (Mark Wu) + * [2e93bbd] Use $(wildcard) to list files in Makefile (Aline Manera) + * [c0ffb52] Fix duplicate dev names in host with multipath storage (Rodrigo Trujillo) + * [898f3bd] Return 403 Forbidden when user does not have permission to access kimchi (Aline Manera) + * [88b01a0] Removing extra word from kimchi description (Christy Perez) + * [a4a64f9] add libxml2 to BuildRequires list (ShaoHe Feng) + * [af31ad1] Host's repositories management: Update error exception messages. (Paulo Vital) + * [1057a2f] Host's repositories management: Update test-cases. (Paulo Vital) + * [c33ab87] Host's repositories management: Update Makefile (Paulo Vital) + * [f27bcdb] Host's repositories management: Update backend. (Paulo Vital) + * [fcb7c68] Host's repositories management: Update REST API (Paulo Vital) + * [b7b2ab3] Host's repositories management: Update API.md (Paulo Vital) + * [5eb9bd8] Block access for non-root users (Aline Manera) + * [23df447] Add one more case to network tests (Ramon Medeiros) + * [10a2ed4] Bug fix #318 Kimchi fails creating new network (Ramon Medeiros) + * [4091825] bug fix: Properly check if there running vms before rebooting system (Aline Manera) + * [ba7dea2] Bug fix: methods signature in storagetargets.py (Daniel Henrique Barboza) + * [7e4588e] Add software update action to Host resource (Aline Manera) + * [a695185] Remove unused vms reference in VMModel (Royce Lv) + * [c53b3ea] Fix encode and decode in storagevolumes.py (Royce Lv) + * [391befb] ui: Add tooltip when hovering long names (Cr��stian Viana) + * [91bab78] doc: Generate index.html to join all help pages (Aline Manera) + * [0b7d861] bug fix: Package doc html files into deb package (Aline Manera) + * [400f3d8] Setup VM's input and output template for Power systems. (Paulo Vital) + * [13d610b] Fix exception for model test (Royce Lv) + * [db954e9] Implement integrity verification: don't disable network used by guest (ShaoHe Feng) + * [ff94a34] Fix Software Update rebase issue. (Paulo Vital) + * [f5506b9] clone template: update test case (ShaoHe Feng) + * [31dff43] clone template: update model and mockmodel (ShaoHe Feng) + * [a4be3c0] clone template: update controller (ShaoHe Feng) + * [0f0c991] Enhance generate_action_handler to redirect a new resource (ShaoHe Feng) + * [50f8272] clone template: update API.md (ShaoHe Feng) + * [a823e20] Bug fix #309 - network: Unable to create vlan tagged on Ubuntu (Ramon Medeiros) + * [f5502f7] doc: Ignore the generated files (Cr��stian Viana) + * [1b3310d] doc: Export the help pages to cherrypy (Cr��stian Viana) + * [5257e69] doc: Add help files to dist packages (Cr��stian Viana) + * [31d9ccf] doc: Add DITA help pages (Cr��stian Viana) + * [5c80111] Enhance UrlSubNode decorator and kimchiauth tool to check for sudo rights. (Leonardo Garcia) + * [1ca8c6f] Find out user groups and sudo status during login. (Leonardo Garcia) + * [cd65d8f] Code cleanup. (Leonardo Garcia) + * [382105c] CDROM Management: changes in tests/test_model.py (Daniel Henrique Barboza) + * [68f8784] CDROM Management: Guest vm storage devices mockmodel and rest api test cases (Rodrigo Trujillo) + * [9ce2615] CDROM Management: Devices management model implementation (Rodrigo Trujillo) + * [68701c2] CDROM Management: Update controller and API.json for guest storages (Rodrigo Trujillo) + * [56a6d9a] CDROM Management: API.md and externalized error messages (Aline Manera) + * [cbf7a89] bug fix: display kimchi icon instead of cherrypy icon (ShaoHe Feng) + * [82f1b82] Setup VM's boot order. (Paulo Vital) + * [c58465d] host update: Expose update tool (Aline Manera) + * [dae3830] host update: Update po files (Aline Manera) + * [d23ed36] Host's software update: Update test cases. (Paulo Vital) + * [002cb04] Host's software update: Update Makefile (Paulo Vital) + * [216db4f] Host's software update: Update backend. (Paulo Vital) + * [c29a36f] Host's software update: Update REST API (Paulo Vital) + * [3714aae] Host's software update: Update API.md (Paulo Vital) + * [8e6fc17] bug fix: fix python syntax error (ShaoHe Feng) + * [a9c80ac] bug fix: make install miss ifaces.py (ShaoHe Feng) + * [bfb5608] Fix host debug report for Fedora 20 (Rodrigo Trujillo) + * [c74e1db] Storagepool SCSI/FC: Modifies mockmodel and implements tests for FC pool (Rodrigo Trujillo) + * [7c0fc12] Storagepool SCSI/FC: Backend implementation (Rodrigo Trujillo) + * [ecb4d6c] Storagepool SCSI/FC: API.md entries related to host pci devices (Rodrigo Trujillo) + * [e4d08f3] Storagepool SCSI/FC: Implement node devices API backend (Rodrigo Trujillo) + * [57ece7a] Add mailing list information. (Leonardo Garcia) + * [3907474] Limit README.md to 80 columns. (Leonardo Garcia) + * [79abe0b] Add hypervisor information on README.md. (Leonardo Garcia) + * [a3f157e] refactor exception: Update all po files (Aline Manera) + * [0ee16b4] refactor exception: Update UI references (Aline Manera) + * [ce3953b] refactor exception: Update gen-pot script to get messages from i18n.py (Aline Manera) + * [f137c23] refactor exception: Update all exceptions (Aline Manera) + * [8d19059] refator exception: Update control to raise the exception message (Aline Manera) + * [715152c] refactor exception: Set error messages for jsonschema validation (Aline Manera) + * [26020a5] refactor exception: Add messages to be translated on backend (Aline Manera) + * [e13997a] refactor exception: Create a common Exception to translate error messages (Aline Manera) + * [b94d36c] Fix path of plugins dir (Mark Wu) + * [41ba026] pass params to create method of all Collections. (ShaoHe Feng) + * [9644c05] Fix wrong "Failed to list guest" message (Rodrigo Trujillo) + * [2f6ac7b] Add disks to LVM pool: API.json changes (Daniel Henrique Barboza) + * [61945fd] Add disks to LVM pool: mockmodel changes (Daniel Henrique Barboza) + * [0a54dab] Add disks to LVM pool: API.md changes (Daniel Henrique Barboza) + * [b500a90] Add disks to LVM pool: control and model changes (Daniel Henrique Barboza) + * [d7458e7] Fix missing report-add html page in rpm (Rodrigo Trujillo) + * [db829ac] Fix controller base code: Update function is not using model_args (Rodrigo Trujillo) + * [2fed3f5] change the vm name in test case (ShaoHe Feng) + * [0adea83] update test case for updating vm with unicode name (ShaoHe Feng) + * [60f3da3] bug fix: failed to update vm with unicode name (ShaoHe Feng) + * [3f5cdd2] update test case for storage pool support unicode (ShaoHe Feng) + * [4f3d489] Firewall: Adding WebSocket port in firewall rules (Paulo Vital) + * [8cac63d] Storage pool support unicode correctly (ShaoHe Feng) + * [cc11627] bug fix: Set full path to guest page file in guest tab (Aline Manera) + * [9f33184] bug fix: Fix shallow scan broken after model refactoring (Aline Manera) + * [b9c0594] Make sure ISO files have read permission while starting VM (Aline Manera) + * [461452a] Remove kvmusertests.py (Aline Manera) + * [0e25ad2] Add a method to fix read permission on ISO files (ShaoHe Feng) + * [0368afa] Avoid useless libvirt error log produced by featuretests (apporc) + * [f84b4d5] Packaging: add the basemodel.py to src/kimchi/Makefile.am (Paulo Vital) + * [02d94f5] Fix get vms list function name (Rodrigo Trujillo) + * [0d7d89c] Add test cases for BaseModel (Mark Wu) + * [4a5ede7] Break the 'sample' plugin's monolithic model into several smaller ones (Zhou Zheng Sheng) + * [78443ae] refactor model: Update makefile and specs files (Aline Manera) + * [a0a4dc0] Delete former model.py and rename model_ to model (Aline Manera) + * [17d1014] Update mockmodel imports (Aline Manera) + * [d0ff3f9] Update tests to use the new model (Aline Manera) + * [dd2b2f4] Update server to use the new model (Aline Manera) + * [a87ab93] refactor model: Create a separated model for host resource (Aline Manera) + * [8a93e68] refactor model: Create a separated model for vm interface resource (Aline Manera) + * [5e34a52] refactor model: Create a separated model for vm resource (Aline Manera) + * [41f0cc7] refactor model: Create a separated model for template resource (Aline Manera) + * [977c267] refactor model: Create a separated model for storage target resource (Aline Manera) + * [e67c3be] refactor model: Create a separated model for storage server resource (Aline Manera) + * [b1d2c63] refactor model: Create a separated model for storage volume resource (Aline Manera) + * [f7001ca] refactor model: Create a separated model for storage pool resource (Aline Manera) + * [8d004e1] refactor model: Create a separated model for interface resource (Aline Manera) + * [3bf22b3] refactor model: Create a separated model for network resource (Aline Manera) + * [39d1b7b] refactor model: Create a separated model for config resource (Aline Manera) + * [9c38e1f] refactor model: Create a separated model for debug report resource (Aline Manera) + * [e79ebaa] refactor model: Create a separated model for plugins resource (Aline Manera) + * [c08c091] refactor model: Create a separated model for task resource (Aline Manera) + * [a22d932] Create a model to join all model resources implementation (Aline Manera) + * [4b00cab] refactor model: Create a common model builder (Aline Manera) + * [f96d5e5] refactor model: Move StoragePooldef from model to libvirtstoragepools.py (Aline Manera) + * [e2008c5] refactor model: Separate libvirtconnection from model.py (Aline Manera) + * [b77935b] Allow plugin use kimchi's ui handler (Mark Wu) + * [44be0d2] Add test cases for paths generation code (Mark Wu) + * [8bc4dde] Reorganize the kimchi's paths gereneration code (Mark Wu) + * [fce2030] Move resource config's info fetching to model level (Mark Wu) + * [2ab9785] CSS: Change all CSS files indentation to 4 spaces (Cr��stian Viana) + * [ab999de] CSS: Do not allow lines longer than 79 characters (Cr��stian Viana) + * [84df5f7] HTML: Make the form element's labels clickable (Cr��stian Viana) + * [29e17e4] Update README to direct users to the oVirt mailing list (Adam King) + * [9057ae1] Use Autoconf macros AC_PROG_MKDIR_P and MKDIR_P (ShaoHe Feng) + * [21f099f] GET /plugins failed, fix it (ShaoHe Feng) + * [b1bf105] get vms list by listAllDomains (ShaoHe Feng) + * [6bcbb3f] Make guests template handling more robust like host template handling (Adam King) + * [fdbd2a8] Remove the unnecessary 'exposed' (Mark Wu) + * [de892cb] bug fix: Expose /storageservers (Aline Manera) + * [a6a4999] bug fix: remove decode for resouce ident when use cherrypy's default dispatc.. (ShaoHe Feng) + * [b67aa7b] fix: Add missing license copyright to css files (Aline Manera) + * [8989283] PEP8 cleanup and bug fix for src/kimchi/utils.py (Mark Wu) + * [7410a58] support create/delete VMIface: update testcase (ShaoHe Feng) + * [9072f67] support create/delete VMIface: update API.json (ShaoHe Feng) + * [4cf2b6e] support create/delete VMIface: update mockmodel (ShaoHe Feng) + * [c66c675] support create/delete VMIface: update model (ShaoHe Feng) + * [f4942a0] bug fix: guest iface does not return model if no model is found (ShaoHe Feng) + * [dd5bf4a] bug fix: Use cherrypy host to run feature tests instead of localhost (Aline Manera) + * [6ded2ab] VM supports interfaces: update testcase (ShaoHe Feng) + * [e2e5aab] VM supports interfaces: update mockmodel (ShaoHe Feng) + * [d90f38e] VM supports interfaces: update controller (ShaoHe Feng) + * [5825943] VM supports interfaces: update model (ShaoHe Feng) + * [398a171] VM supports interfaces: update API (ShaoHe Feng) + * [304217b] Add a control.vm module (ShaoHe Feng) + * [b4fe1dc] bug fix: test case can not find plugin, fix it (ShaoHe Feng) + * [b0aed86] improve controller: set authentication automatically (ShaoHe Feng) + * [18b68ea] improve controller: Root loads collections/resouces automatically (ShaoHe Feng) + * [5b82bdf] improve controller: tag the collections/resouces of root with @UrlSubNode (ShaoHe Feng) + * [c7d2856] improve controller: add a method to load root sub collections/resouces autom.. (ShaoHe Feng) + * [f68a3bc] add gettext to package require list (ShaoHe Feng) + * [7cff21e] Modify bug in spice UI (zhoumeina) + * [2ef94b9] Add nfs server and target UI in create storage pool (zhoumeina) + * [504213f] Fix libvirt nfs target probe problem (Royce Lv) + * [881361f] Add showmount function and feature test for libvirt target probe (Royce Lv) + * [e024dd3] storage target: Add model support (Royce Lv) + * [d60c4b8] storage target: Update controller and json schema (Royce Lv) + * [4be609a] storage target: Update API.md (Royce Lv) + * [2e1657e] storage server: Update model and mockmodel (Royce Lv) + * [e976b78] storage server: update controller.py (Royce Lv) + * [545ec78] Storage server: Update API.md (Royce Lv) + * [1740a25] Add testcase for GET param (Royce Lv) + * [478d01d] Support params for GET method (Royce Lv) + * [4750f33] Remove 'encoding=iso-8859-1' from json.dumps() (Mark Wu) + * [7dfb3e4] Integrate nfs path check before create nfs pool (Royce Lv) + * [f575b52] utils: Add nfs prevalication (Royce Lv) + * [0a02212] storagepool: Use callback functions when deleting a pool (Cr��stian Viana) + * [41e4c8c] storagepool: Do not assume different 'else' values in pool type (Cr��stian Viana) + * [7606325] Issue #310: Query correct name to validate logical devices (Cr��stian Viana) + * [7813c63] storagepool: Add missing msg when no logical device is selected (Cr��stian Viana) + * [3a49821] Ubuntu: Add the LVM dependency package to README (Cr��stian Viana) + * [c69fa0f] Use cherrypy's default dispatcher for subcollection (Mark Wu) + * [43618b0] UI bug fix: Set vlan_id value only if 'Enable VLAN' is checked (Aline Manera) + * [5e829c2] Add the iSCSI dependency packages to README (Cr��stian Viana) + * [6ae06e9] add a synchronous function with timeout to execute command (ShaoHe Feng) + * [f060c18] Add jquery widget dropDown button (zhoumeina) + * [a2e7b35] Modify vnc_proxy_port to display_proxy_port (zhoumeina) + * [19ae1dd] Add the front end support for SPICE (zhoumeina) + * [b605432] RollbackContext: Make it complied with Python Standard (Zhou Zheng Sheng) + * [1a2d326] UI: Remove Unused Label Room for Debug Report (Hongliang Wang) + * [0dbfe20] host.css: Change Indent to 4 Spaces (Hongliang Wang) + * [5289d02] Add a timeout tuning environment variable for debug report test (Shu Ming) + * [f51dbbc] Skip the debug report test if there is no tool avaible (Shu Ming) + * [88553a8] Issue #308: Use correct iSCSI package for openSUSE (Cr��stian Viana) + * [1567cbb] spec: Open 8000 and 8001 port by default (Eli Qiao) + * [31ef97f] Add support to RHEL 7 (Adriano Botega) + * [342334e] Deep scan: listing 'unknown' bootable isos after deep scan (Daniel Henrique Barboza) + * [c3a548e] UI: template supports networks (Xin Ding) + * [7b608a0] Add graphics parameters description in API.md (apporc) + * [655f03d] Update test case for graphics support (apporc) + * [4951d3c] Update mockmodel for spice support (apporc) + * [6c3bc68] Validate graphics parameters input by users (apporc) + * [88ddc57] Add spice backend support for kimchi (apporc) + * [5ab77d3] Fix break of deep scanning (Royce Lv) + * [f5b4740] network improvement: update test case to support vms field (ShaoHe Feng) + * [866e836] network improvement: update mockmodel to support vms field (ShaoHe Feng) + * [dff73d0] network improvement: add vms field (ShaoHe Feng) + * [2f54aab] UI: All user to specify a vlan ID for a virtual network. (Mark Wu) + * [6b339da] Support creating vlan tagged virtual network (Mark Wu) + * [69edfe9] Generate libvirt's interface XML definition for vlan tagged bridge (Mark Wu) + * [b656d4d] Fix qemu-io option in featuretests (Mark Wu) + * [dff7038] Add Fedora 20 and Ubuntu 13.10 to distros.d (Mark Wu) + * [319a83b] Github issue #300: hardcoded server port fix (Daniel Henrique Barboza) + * [e57b07e] Update the po files (Shu Ming) + * [99808b2] Remove the legacy files (Shu Ming) + * [641ace2] Remove the legacy files from automake and package configurations (Shu Ming) + * [90b61f0] Remove jquery-ui customization in network (Yu Xin Huo) + * [af8cac4] Customize jquery-ui dialog (Yu Xin Huo) + * [762c522] Customize jquery-ui menu (Yu Xin Huo) + * [5ba06d7] Customize jquery-ui button (Yu Xin Huo) + * [9882732] Remove vnc related code in mockmodel (Mark Wu) + * [f1234b1] Use one weksockify instance as all vms' vnc proxy. (Mark Wu) + * [8480365] Add a configuration for vnc websocket proxy (Mark Wu) + * [47e64e7] Move configuration parsing to config.py (Mark Wu) + * [212dc33] Add the ISCSI translation po files (zhoumeina) + * [4997624] Add UI support of iscsi (zhoumeina) + * [618035a] Support VM template for Power machine (Mark Wu) + * [177c2a0] Dynamically generate template parameters for different distros (Mark Wu) + * [b4ca2a8] Fix: Storagepool json schema has not been tested when create new SP (Rodrigo Trujillo) + * [0b507ff] pep8 cleanup for isoinfo.py (Aline Manera) + * [b5d80d8] isoinfo: Move _probe_iso() to IsoImage() (Aline Manera) + * [e885f0b] Move ISO path validation to IsoImage() (Aline Manera) + * [ff79ea8] Move IsoFormatError() from isoinfo.py to exception.py (Aline Manera) + * [1eb47bf] isoinfo: Use absolute path only for local ISO files (Aline Manera) + * [e0b2d83] isoinfo: Add default value for ignore_list paramter (Aline Manera) + * [6722758] template supports networks: update test case (ShaoHe Feng) + * [6f7fda8] template supports networks: update mockmodel (ShaoHe Feng) + * [51c1af4] template supports networks: update model (ShaoHe Feng) + * [e777c77] template supports networks: update controller and json schema (ShaoHe Feng) + * [7d03a1c] template supports networks: update API (ShaoHe Feng) + * [601d140] template supports networks: fix test case (ShaoHe Feng) + * [ee3377f] template supports networks: let template xml support more networks (ShaoHe Feng) + * [1a0fd41] pep8 cleanup for exception.py (Aline Manera) + * [be26ed4] pep8 cleanup for distroloader.py (Aline Manera) + * [170709e] qemu user tests: probe the username of qemu process started by libvirt (ShaoHe Feng) + * [8a7aca2] plugin: fix dynamic import mechanism (Zhou Zheng Sheng) + * [05f999f] test_model: test creating iSCSI storage pool (Zhou Zheng Sheng) + * [f163d22] storagepool: Support Creating iSCSI storagepool in model.py (Zhou Zheng Sheng) + * [53e1d40] storagepool: rename and consolidate arguments of creating (front-end) (Zhou Zheng Sheng) + * [265de8d] storagepool: rename and consolidate arguments of creating (back-end) (Zhou Zheng Sheng) + * [ab63bba] storagepool: refactor _get_pool_xml() (Zhou Zheng Sheng) + * [08ff87d] Issue #293: Resizing Issue When There Are Multiple Grids (Hongliang Wang) + * [5e5a6a6] touch 4 files when move RollbackContext, fix pep8 on them (ShaoHe Feng) + * [7c98d3b] move RollbackContext from tests/utils to src/kimchi/rollbackcontext (ShaoHe Feng) + * [cb7c355] Move all resources related to tasks to control/tasks.py (Aline Manera) + * [423e9bb] Move all resources related to plugins to control/plugins.py (Aline Manera) + * [ae9cc6b] Move all resources related to host to control/host.py (Aline Manera) + * [ceff362] Move all resources related to config to control/config.py (Aline Manera) + * [0d44ed9] Move all resources related to networks to control/networks.py (Aline Manera) + * [cd5d5bc] Move all resources related to interfaces to control/interfaces.py (Aline Manera) + * [8a7a5f6] Move all resources related to storage volume to control/storagevolumes.py (Aline Manera) + * [05ce4dd] Move all resources related to storage pools to control/storagepools.py (Aline Manera) + * [69a241a] Move all resources related to debug reports to control/debugreports.py (Aline Manera) + * [6ea6d32] Move all resources related to templates to control/templates.py (Aline Manera) + * [1a23ce1] Move all resources related to vms to control/vms.py (Aline Manera) + * [f824fa2] Move basic controller resources to control/base.py (Aline Manera) + * [cae61e6] Move login() and logout() functions from controller.py to root.py (Aline Manera) + * [9cf0c0f] Move common functions for Resource and Collection to control/utils.py (Aline Manera) + * [2d6d1f5] Move generate_action_handler() function to Resource() class (Aline Manera) + * [817d3ad] Simplify domain xml in featuretests.py (Aline Manera) + * [b44e658] pep8 cleanup for featuretests.py (Aline Manera) + * [07c25db] fix whitespace in test_mockmodel (ShaoHe Feng) + * [c56582e] logical pool: list unused physical volume (Zhou Zheng Sheng) + * [2553e21] logical pool fixes: only list leaf devices, and read file instead of run "cat" (Zhou Zheng Sheng) + * [e467b32] Organize python imports (Rodrigo Trujillo) + * [1410acd] Add support for Gentoo Linux (Cr��stian Viana) + * [320fd13] PEP 8: Fix an alignment issue in src/kimchi/auth.py (Zhou Zheng Sheng) + * [7cead00] pep8 cleanup for root.py (Aline Manera) + * [de1867a] pep8 cleanup for cachebust.py (Aline Manera) + * [508ada2] pep8 cleanup for auth.py (Aline Manera) + * [c0b9d57] Bug fix: Kimchi will try to create directory for 'DIR' storagepool (Rodrigo Trujillo) + * [f70d34f] Replace tab to 4 spaces (Aline Manera) + * [8698173] Issue #290: correct the log usage (ShaoHe Feng) + * [5831b4d] screenshot: fix problem on Power of truncated picture (Royce Lv) + * [acbcf04] Return source information for storage pool (Royce Lv) + +#### [kimchi-1.1.0] #### + * [88e5ec6] Update changelog and version files for 1.1 release (Aline Manera) + * [bf6d929] Issue #276, logical pool: a quick fix for the device listing rules, front-end (Zhou Zheng Sheng) + * [902d295] Issue #276: logical pool: a quick fix for the device listing rules, back-end (Zhou Zheng Sheng) + * [b555f83] PEP 8: cleanup src/kimchi/disks.py (Zhou Zheng Sheng) + * [85d16e1] Add some brazilian portuguese lang translations (Alexandre Tanaka Hirata) + * [f2de42c] do Chinese translation for release 1.1 (ShaoHe Feng) + * [3c7f2d7] issue #287: Confirm box will be hidden by the window dialog (Xin Ding) + * [bf1d443] Use spacewalk repo to get python-ethtool on suse. (ShaoHe Feng) + * [1773214] Add confirm box to create logical pool,and modify device path number (zhoumeina) + * [0faa902] bug fix: Make sure to use string with os.walk (Aline Manera) + * [b12167b] bug fix: Add authentication to host tab (Aline Manera) + * [0e274b8] bug fix: Update openSUSE instructions in README file (Aline Manera) + * [d5fe662] bug fix: Don't display vlan interfaces while creating network bridge (Aline Manera) + * [a6ddab1] Issue #283: Fix memory leak caused by libvirt connection wrapper (Mark Wu) + * [7c62e72] Templates: Remote ISO Image page aligning mess (Xin Ding) + * [07111ae] Meaningless text "Default Settings" in the templates tab page (Xin Ding) + * [8b41a3f] create template in batch don't show success detail message (Xin Ding) + * [d2f4951] Bug fix:251 template edit page disk unit with no unit and make cdrom disable (zhoumeina) + * [a4b412c] Incosistent pages when no guests or templates available (Xin Ding) + * [3a44881] Update test_model to compare distro name using unicode (Ramon Medeiros) + * [af05155] Set autostart value for logical storagepool (Shu Ming) + * [3cf5330] Issue #259: vm create: fail msg need to be more specific (Hongliang Wang) + * [1a97be6] Fix emulator path in feature tests (Mark Wu) + * [428fce5] Issue #279: some plugins/sample files are missing in dist. (ShaoHe Feng) + * [be5969d] Tests: Generate UUID and use as temp report file name (Zhou Zheng Sheng) + * [1d15833] sosreport: fix name matching of the generated report file (Zhou Zheng Sheng) + * [c8a760a] Support unicode on Host Basic Information page (Ramon Medeiros) + * [d57226d] Issue #278: add iso_gen.py to Makefile EXTRA_DIST list (ShaoHe Feng) + * [0d63a80] Issue 277, Disable 'bridged' option when no interface available (Yu Xin Huo) + * [97139d8] Issue #271, add address space for bridged nework (Yu Xin Huo) + * [842f72b] Issue #241: require python-psutil version (ShaoHe Feng) + * [ed971d1] Issue #262: Switch tab lose default network type selection (Yu Xin Huo) + * [9a22f75] bug fix: set the network ip as bridge ip instead of subnet IP (ShaoHe Feng) + * [d43e538] Bug #260 fix: Makes UI show missing storage volume information (Rodrigo Trujillo) + * [c8a25fd] Bug Fix: Wrong host available memory value (Rodrigo Trujillo) + * [37f4d8c] Issue #273: unittest.TestCase has no attribute 'assertLessEqual' (ShaoHe Feng) + * [e12b93e] bug fix #254: Reset guest statistics when vm is powered off (Aline Manera) + * [1dd695d] bug fix #257: Specify the mime type for debugreports static dir (Aline Manera) + * [01d72ca] bug fix: Don't use shell=True in subprocess.Popen while running qemu-io test (Aline Manera) + * [175869d] Issue #263: network: bridge network shows network/prefix (ShaoHe Feng) + * [89d4766] Packaging: add host.html.tmpl to ui/pages/tabs/Makefile.am (Paulo Vital) + * [ce43d08] Add build in localdisk back-end (zhoumeina) + * [92d81c6] Add logical pool UI support (zhoumeina) + * [97a5e81] Packaging: add the disks.py to src/kimchi/Makefile.am (Zhou Zheng Sheng) + * [55f5fa0] Nit fix of scan_dir_prepare (Royce Lv) + * [2f4de5f] Deduplication: deduplication in shallow scan (Royce Lv) + * [b44c66a] Deep scan: Adding scan ignore path (Royce Lv) + * [8d55a0d] Deep scan result deduplication (Royce Lv) + * [e3cf2c2] interface bug fix: only expose the unused interfaces to the front end (ShaoHe Feng) + * [e9b8deb] Tests: fix test_model.ModelTests.test_debug_reports (Zhou Zheng Sheng) + * [612b8e3] UI: Enhancement & Fixes for Host Monitoring (Hongliang Wang) + * [1bf51f9] Issue #240: The bridge address of nat and isolated network is invalid, fix it (ShaoHe Feng) + * [b1dd7b4] Interface: Fix status return (Rodrigo Trujillo) + * [132bfc5] Logical StoragePool: changes in API.md (Daniel Henrique Barboza) + * [59a0976] Logical StoragePool: changes in controller.py (Daniel Henrique Barboza) + * [343f3d1] Logical StoragePool: changes in model and mockmodel (Daniel Henrique Barboza) + * [d9a2013] Logical StoragePool: adding disks.py module (Daniel Henrique Barboza) + * [2686b5f] PEP8 cleanup for server.py (Mark Wu) + * [8e488ff] Add deep scan test (Royce Lv) + * [6b2f43a] ISSUE #236: Fix break of deep scanning (Royce Lv) + * [02192e5] Add pseudo iso_gen for deep scan test (Royce Lv) + * [64c541a] Template: Enable update Disk size and CDROM path (UI) (Rodrigo Trujillo) + * [d7b1be8] Add dependency of nfs client (Royce Lv) + * [a7223e0] Concatenate ISO URL correctly with port number (Cr��stian Viana) + * [ebac998] UI: Host Monitoring (Hongliang Wang) + * [f684b36] Issue #235: changetoProperUnit Returns Wrong Result (Hongliang Wang) + * [0164098] change the unit of host disk and net IO rate from kb/s to B/s (ShaoHe Feng) + * [006f773] Fix test cases according to new Templates Schema validation (Rodrigo Trujillo) + * [46e9b94] Enable template data verification against json schema (Rodrigo Trujillo) + * [c57da0d] Json schema for templates (Rodrigo Trujillo) + * [b9b4359] Host reboot and shutdown backend implementation (Rodrigo Trujillo) + * [76f8d5d] ui: Adjust storage pool window layout (Aline Manera) + * [2ad5768] po files: NFS pool (Pradeep K Surisetty) + * [e62ff62] Add/delete NFS pool (Pradeep K Surisetty) + * [76653ec] bug fix: remove wlans from nics. (ShaoHe Feng) + * [33f487e] bug fix: assert list append successfully when get all network interfaces (ShaoHe Feng) + * [f793d3a] Fix minor issue in import order (Rodrigo Trujillo) + * [3ddb97d] Add Network UI Files to Makefile (Yu Xin Huo) + * [f7a0fa8] network UI: update po files (Yu Xin Huo) + * [dc0fc09] create/delete network (Yu Xin Huo) + * [f2cf0b6] List/Start/Stop Network (Yu Xin Huo) + * [e6b0afc] Center the storage pool "Actions" button (Cr��stian Viana) + * [842e55b] Use consistent padding in storage pool details (Cr��stian Viana) + * [4e2748a] Use jQuery to load xml to make code consistent (zhoumeina) + * [8e23fef] host net-io: update test case (ShaoHe Feng) + * [c4721df] host net-io: update model and mockmodel (ShaoHe Feng) + * [80bcbcb] host net-io: update API.md (ShaoHe Feng) + * [b0bc8ba] Authentication is required to access networks (ShaoHe Feng) + * [853cdf1] network: update test case (ShaoHe Feng) + * [df2b66e] network: update mockmodel (ShaoHe Feng) + * [3e0d05b] network: update makefile, spec file and README (ShaoHe Feng) + * [9070d60] network: update model (ShaoHe Feng) + * [d30ca35] network: generate network xml and testcast for it (ShaoHe Feng) + * [26ee208] network: update controller (ShaoHe Feng) + * [dbe31d3] network: update API.md (ShaoHe Feng) + * [e7c9ce7] Add license to scan.py file (Aline Manera) + * [65f6ad3] Organize imports in all .py files (Aline Manera) + * [0048f33] fix disk unit: 1K bytes is 1024 bytes instead of 1000 bytes (ShaoHe Feng) + * [ad75a6f] Add test cases for plugin support (Mark Wu) + * [2abc251] Add a sample kimchi plugin (Mark Wu) + * [9fb6a09] Move API schema loading to the initialization of application (Mark Wu) + * [f879390] Add a plugin mechanism for Kimchi server (Mark Wu) + * [ce3e182] Add the missing Makefiles for plugins support (Mark Wu) + * [f22dd25] Add a helper function to get kimchi python package directory (Mark Wu) + * [302f186] host disk-io: update test case (ShaoHe Feng) + * [f987fb5] host disk-io: update model and mockmodel (ShaoHe Feng) + * [76f3f5b] host disk-io: update API.md (ShaoHe Feng) + * [940742a] Fix kimchi make rpm fail error (zhoumeina) + * [e293010] Authentication is required to access debugreports (Shu Ming) + * [f2fce9d] Add the front-end support of tabs (zhoumeina) + * [ebf366f] Add the back-end support of tabs (zhoumeina) + * [b45e709] Template update UI return 'cpus' and 'memory' as numbers (Rodrigo Trujillo) + * [277bd3b] UI: deep scan (Xin Ding) + * [a83f2ee] Use "dropdown" CSS class on the Edit Template page (Cr��stian Viana) + * [11f78db] Format template and storage pool details (Cr��stian Viana) + * [7cb6c2a] deep scan: Probe iso information (Aline Manera) + * [00d01a7] Add sos/sosreport package as Kimchi dependency (Aline Manera) + * [af1de8e] Expose if the host has at least one system report tool (Aline Manera) + * [c75d773] Fix low version libvirt bug when get cpuinfo (malcolm yu) + * [df327bb] VM Edit UI (Hongliang Wang) + * [81a7b87] vm-rename fix: return domain after static config change (Royce Lv) + * [89b7631] Sort the storage pool list (Cr��stian Viana) + * [09f9ee0] Update storage pool list after activate/deactivate (Cr��stian Viana) + * [722c5a8] vm-rename: Update testcases for vm-rename (Royce Lv) + * [bb895c6] vm-rename: Update mockmodel for vm edit (Royce Lv) + * [b2953fc] vm-rename: Update model for vm edit (Royce Lv) + * [edaa063] vm-rename: Update controller (Royce Lv) + * [a0223e2] vm-rename: Update API.md for vm rename (Royce Lv) + * [ceb4ca3] host memory stats: update test case (ShaoHe Feng) + * [e225c83] host memory stats: update model and mockmodel (ShaoHe Feng) + * [95dda58] host memory stats: update API.md (ShaoHe Feng) + * [63f6f77] support recrusive probe in iso scanning (Royce Lv) + * [ab7518f] Fix session locking issue (Mark Wu) + * [59a8a08] amend API.md (ShaoHe Feng) + * [cdb9023] host info: update test case (ShaoHe Feng) + * [f0f069c] host info: update mockmodel (ShaoHe Feng) + * [371dcdc] host info: update model (ShaoHe Feng) + * [4843de7] host info: update controller (ShaoHe Feng) + * [cd1d545] host info: update API.md (ShaoHe Feng) + * [45df370] interface: update makefile, spec file and README (ShaoHe Feng) + * [2036b2c] interface: update test case (ShaoHe Feng) + * [6f22e4e] interface: update mockmodel (ShaoHe Feng) + * [9054bf9] interface: update model (ShaoHe Feng) + * [c47ba91] interface: update controller (ShaoHe Feng) + * [5ced3ef] interface: update API (ShaoHe Feng) + * [1bd987c] interface: some new utils to get the interface info (ShaoHe Feng) + * [76515ed] Add json schema for API's request parameters (Mark Wu) + * [8ceadbe] Extend the action decorator into an action handler generator (Mark Wu) + * [da4f395] host cpu usage: update test case (ShaoHe Feng) + * [f84e32d] host cpu usage: update mockmodel (ShaoHe Feng) + * [ca7648b] host cpu usage: update model (ShaoHe Feng) + * [1f558d7] host cpu usage: update controller (ShaoHe Feng) + * [18b24b3] host cpu usage: update API.md (ShaoHe Feng) + * [8ef7b15] Use socket.getservbyname() to get the default port of a protocol (Aline Manera) + * [4c05423] Expose the number of CPUs assigned to a VM (Aline Manera) + * [e40d237] Make the report tool silent in the background (Shu Ming) + * [1c807b6] DebugReports: Downloading the archives (Shu Ming) + * [cd74bb8] DebugReports: Implement the real backend (Shu Ming) + * [b01b9f4] DebugReports: Implement the mock model (Shu Ming) + * [bb59b46] DebugReports: Add collection and Resource (Shu Ming) + * [b81fce3] DebugReports: Define the APIs (Shu Ming) + * [31f60d7] Add testcase of template storagepool customise (Royce Lv) + * [aa77a7a] pre-create validate: validate for mockmodel vm create (Royce Lv) + * [94b3b65] pre-create validate: Add iso/storage/network availabilty check (Royce Lv) + * [623135f] test storage pool not changed after vm customization (Royce Lv) + * [24b4c23] model: aggregate vm config customization when creating (Royce Lv) + * [02aa5eb] mockmodel: generate customised temporary template when create vm (Royce Lv) + * [549da65] Customise template storage: Report 'storagepool' info in controller (Royce Lv) + * [1a090d6] Customise template storage: Update API.md (Royce Lv) + * [e2e5892] Set a custom pool for a template (Xin Ding) + * [226f6f7] deep scan: add model support (Royce Lv) + * [0469f1e] Deep scan: Add functions for deep scan preparation (Royce Lv) + * [c359641] Deep scan: update controller (Royce Lv) + * [c71a5a6] Deep scan: Update API.md (Royce Lv) + * [b5e5bc2] Deep scan: Fix isoinfo.py for iso can't be reported (Royce Lv) + * [0c603c5] Adding "python-psutil" package to Kimchi (Daniel Henrique Barboza) + * [fe82184] Issue #227: Misunderstood labels and error messages in templates tab. (Paulo Vital) + * [39dae67] Fix text wrap in template and guest (zhoumeina) + * [1d30644] issue #228: Use SIGKILL to kill proc in featuretests (ShaoHe Feng) + * [0e50096] close libvirt connection in featuretests (ShaoHe Feng) + * [e74728c] Add gen-pot to .gitignore list (Aline Manera) + * [7d86a64] Add missing ui files to spec file (Mark Wu) + * [c339575] Distribute po/get-pot.in instead of po/get-pot (Mark Wu) + * [0bd8245] bug fix: put distroloader.py in Makefile dist list (ShaoHe Feng) + * [50a37a4] Remove 'config.py' from the distribution (Mark Wu) + * [07d9a85] Bug fix:153 Drop kimchi-iso from storagepool list (zhoumeina) + * [2ee72ce] bug fix: Use vm uuid to properly get vm statistics (Aline Manera) + * [a276aff] bug fix: correct to use float when calculate guest net and disk IO (ShaoHe Feng) + * [38bb3bd] iso streaming: Add default port for all protocols (Aline Manera) + * [b4e0122] ISO streaming: Enable UI (Aline Manera) + * [620618b] iso streaming: QEMU workaround (Aline Manera) + * [29c7338] iso streaming: Libvirt workaround (Aline Manera) + * [93d3ccc] Expose QEMU ISO streaming functionality to host capabilities (Aline Manera) + * [03aa2e9] feature tests: Verify QEMU can properly work with hostname while streaming I.. (Aline Manera) + * [9e1eae2] feature tests: Verify QEMU supports ISO streaming (Aline Manera) + * [e14dec1] feature tests: Rename libvirt test to express what it does (Aline Manera) + * [99331be] distros: update testcase in test_rest and rest_model (ShaoHe Feng) + * [8a2980a] distros: add mockmodel and model implementation (ShaoHe Feng) + * [d8b067a] distros: update Controller to add Distros collection and Distro resource (ShaoHe Feng) + * [7e2a5ac] distros: update API document (ShaoHe Feng) + * [7add3d9] distros: add a DistroLoader to load distros (ShaoHe Feng) + * [185cad1] distros: add new distros files (ShaoHe Feng) + * [0e3cb34] Drop IE8 support in README (zhoumeina) + * [cbcbd5d] pep8 cleanup for asynctask.py (Mark Wu) + * [cafab09] Enable pep8 code style checking (Mark Wu) + * [ad793e0] Display error message on template delete failure (Cr��stian Viana) + * [a138304] Choose right icon for centos iso (Royce Lv) + * [949fc69] Add jquery-ui files to dist data list. (Yu Xin Huo) + * [b1d5002] isoinfo: Allow the main program probe a single ISO file (remote or local) (Aline Manera) + * [193ab1a] templates: Try to identify distro and version from remote ISO file (Aline Manera) + * [e7f3337] isoinfo: Add support to identify distro and version from remote ISO file (Aline Manera) + * [26f1688] StoragePool: Pool name error message (Pradeep K Surisetty) + * [e9599d5] Add jquery-ui (Yu Xin Huo) + * [00536ab] Remove redundant interface in api.js (zhoumeina) + * [8f3e38c] Issue #199: Update templates list only after success of deleteTemplate (Aline Manera) + * [cbafe92] vm-uuid: Update testcases (Royce Lv) + * [053fa95] vm-uuid: Report uuid in controller (Royce Lv) + * [d44883e] vm-uuid: make vm stats indexed in uuid (Royce Lv) + * [b0bbc20] vm-uuid: store vm extra information indexed in uuid (Royce Lv) + * [d022fff] vm-uuid: Use uuid in screenshot generation (Royce Lv) + * [8d70b27] vm-uuid: Using uuid in vmtemplate (Royce Lv) + * [51e9766] Use "font-weight: bold" in header texts (Cr��stian Viana) + * [ec381bb] No HttpOnly is set to the cookie for session id (Xin Ding) + * [18567d7] Use libvirt api to implement find_qemu_binary (apporc) + * [ce12235] eliminate messages keys from all po files (ShaoHe Feng) + * [1e164ca] bug fix: make gen-pot scan multi lines (ShaoHe Feng) + * [765887d] Add the three translation for Chinese (zhoumeina) + +#### [kimchi-1.0.1] #### + * [1726c5b] Update ChangeLog for the 1.0.1 release (Adam Litke) + * [9d0c89c] Do not generate ChangeLog when outside a Git repo (Cr��stian Viana) + * [c44d03b] Add VERSION file with Kimchi version (Aline Manera) + * [51d365f] Get the appropriate Kimchi version from Git tag (Cr��stian Viana) + * [d9d4cdd] Fix variable name "iptype" (Cr��stian Viana) + * [564babe] Issue #97: "Make distclean" does not remove all the intermediate files (Paulo Vital) + * [4a6edb2] Issue #180: Singular/plural noun agreement on "Templates" (Cr��stian Viana) + +#### [kimchi-1.0.0] #### + * [d665854] Update ChangeLog for the 1.0.0 release (Adam Litke) + * [0448a5a] opensuse: Start kimchid automatically (Adam Litke) + * [5db3d20] Issue #173: set the correct mime type of Content-Type in HTTP respose header (ShaoHe Feng) + * [665406d] Bugfix: Issue #182 int object has no attribute isdigit (apporc) + * [0654104] Encode parameters in URL generated by the server (Xin Ding) + * [f7fa1d8] Encode parameters in URL When calling REST APIs (Xin Ding) + * [4fdc708] Make header text sizes equal (Cr��stian Viana) + * [3c88c7f] build: Generate ChangeLog (Adam Litke) + * [51f15c6] issue #183: Display all template information in pt_BR on Firefox (Aline Manera) + * [adb065f] i18n: Update translation catalogue (Adam Litke) + * [f4d7f5b] Fix typo in English translation (Aline Manera) + * [65bdf9e] Issue #183: Adjust Template Tile Layout (Hongliang Wang) + * [916344a] Fug fix:Chinese tooltip will wrap in storage (zhoumeina) + * [045c506] change the storage arrow style, and make arrow disable when inactive (zhoumeina) + * [b45b62c] i18n: Update pt_BR translations (Aline Manera) + * [27cebf6] Issue #154: Prompt User When Creating VM and There is NO Template (Hongliang Wang) + * [85195d6] Issue #191: Log-in Name Disappears after Restarting Browser (Hongliang Wang) + * [4cf0113] Issue #190: Language Selector Value NOT Match Page Content (Hongliang Wang) + * [6c85531] Bug fix: login window will have scroll bar when putted wrong password (zhoumeina) + * [111494a] Drop the handle in storage,fix the position error of the navbar arrow (zhoumeina) + * [917d120] The icon image for unknown os is not suitable (Xin Ding) + * [aea983c] issue #166: Destroy storage when vm define fails (Royce Lv) + * [3269670] The size unit of scanned ISOs is wrong (Xin Ding) + * [66be273] kimchid: Fix default for 'host' parameter (Adam Litke) + * [1fd2284] Add the translation of English and Chinese (zhoumeina) + * [832a270] bug fix: 404 error in debugger network tab when creating new VM (Aline Manera) + * [457afa8] Apply Kimchi style to login screen (Aline Manera) + * [26f8b50] model: Handle libvirt connection failures (Adam Litke) + * [b97428f] MockModel: fix mock_environment (Adam Litke) + * [e7c976e] Issue#93 UI Not updated after deleting the last guest (fix) (Adam King) + * [e515426] issue #171: Adjust template box style to avoid text overlapping (Aline Manera) + * [3d4d209] Fix bug:145 Make a util to change the storage unit (zhoumeina) + * [318a183] update test case after a series unit bug fixed (ShaoHe Feng) + * [385a1b0] bug fix: keep the default value of storage info from libvirt (ShaoHe Feng) + * [8171fcc] bug fix: set the capacity unit to MB when pass it the storagevolumes_create. (ShaoHe Feng) + * [508cbdb] bug fix: mockmodel set the storage volume size to MB according to the API.md (ShaoHe Feng) + * [aee9ebe] bug fix: Update API for storage volume resize (ShaoHe Feng) + * [5eb9b8b] Issue: #177: iso storage volume get wrong allocation value (ShaoHe Feng) + * [8976efd] Add spaces around words on "Templates" (Cr��stian Viana) + * [4ed3db9] tests: Add tests to verify data validation when editing a template (Aline Manera) + * [cf817b9] issue #75: Validate parameters when updating a Template (Aline Manera) + * [71a3a88] Create default network if it does not exist (Aline Manera) + * [59efe0c] bug fix: Fix log error message when kimchi can not create default pool (Aline Manera) + * [c20106f] bug fix: Fix typo while logging information to cherrypy handlers (Aline Manera) + * [e97498a] bug fix: Import missing modules (Aline Manera) + * [6d8d739] doc: Restart libvirt after installing packages (Adam Litke) + * [5387198] tests: Add assertIn and assertNotIn for python2.6 (Adam Litke) + * [7498532] Update README and packaging files for release (Adam Litke) + * [f8ef624] Fix typo on Storage Tab (Aline Manera) + * [f6a60ff] change the login window css to make language selector in the head (zhoumeina) + * [0509118] Issue #174: error page can not be translated, fix it. (ShaoHe Feng) + * [de3cc14] UI Template Edit: Hide Unsupported Items (Hongliang Wang) + * [87b2930] Fix bug Regex in checking url (zhoumeina) + * [149f12d] Align storage header in Storage tab (Aline Manera) + * [e7e8c61] Autostart storagepools created from kimchi (apporc) + * [d41f4f5] UI: Enable Language Selection (Hongliang Wang) + * [87049d1] Enable the template_create test with non-root account (Shu Ming) + * [ba5fbc3] Streamline template creation flows - update (Xin Ding) + * [0abccf7] bug fix: Recognize openSUSE 12.3 ISO file (Aline Manera) + * [a8c5430] Fixed the regx pattern (Shu Ming) + * [d244cb6] bug fix: Recognize Fedora 19 ISO file (Aline Manera) + * [488784e] Issue #133: mv make_dirs from kimchid.in to server.py (ShaoHe Feng) + * [ac1d7c2] Streamline template creation flows (Xin Ding) + * [436ce3e] doc: Update images in README (Adam Litke) + * [4ea86e3] Issue #167: Duplicate Requests for HTML Fragment when Switching Pages (Hongliang Wang) + * [657bb3b] Issue #161: Firefox Doesn't Take Correct Favicon for Kimchi (Hongliang Wang) + * [0ba88f8] bug fix: remove ordereddict from suse spec require list (ShaoHe Feng) + * [768441a] Style of uneditable fileds in template edit (Xin Ding) + * [26a9427] Change the ico of iso (zhoumeina) + * [6f74c37] Bug fix:137 UI: When expanding an empty pool, show a message in the drawer (zhoumeina) + * [827f3b2] Issue #151: No Message when User Opens http://kimchi:port/#i18n (Hongliang Wang) + * [316565c] issue#149: fix relative symlink path error in iso scan (Royce Lv) + * [cb7b5e5] Issue #131: Wrong Arrow Position after Error Page (Hongliang Wang) + * [87fdfb8] Add test for refresh and vol number display (Royce Lv) + * [0c7900a] Update model to support refresh and 'nr_volumes' info (Royce Lv) + * [fa3ffc2] Change mockmodel to refresh pool volumes (Royce Lv) + * [2391429] Update Controller to add 'nr_volumes' into its info (Royce Lv) + * [8c4fedc] Update the description StoragePool and StorageVolume in API.md (Royce Lv) + * [868db8e] Add testcase for create volume for active pool (Royce Lv) + * [7657947] Prevent mockmodel from creating volumes for deactive pool (Royce Lv) + * [45c6769] Activate default pool for mockmodel (Royce Lv) + * [78f18e7] Create default pool and activate in model (Royce Lv) + * [3a33f1c] Issue #112: Guest reboot and power buttons do not have hover text (Hongliang Wang) + * [b8ad3fd] Issue #147: Storage UI NOT List Storage Automatically After Logging in (Hongliang Wang) + * [d514ac6] KPI: Updates model and mockmodel tests (Aline Manera) + * [c2dcfa9] KPI: Update API documentation (Aline Manera) + * [8e6448e] Display disk I/O rate instead of storage usage (Aline Manera) + * [f6c1daf] Display network I/O rate instead of memory usage (Aline Manera) + * [dd1b604] Create new thread to collect Kimchi statistics (Aline Manera) + * [9e20380] Fix Log-in Window Redrawn after 401 Returned (Hongliang Wang) + * [5539156] tests: Fix auth tests (Adam Litke) + * [87dc322] tests: Add authentication tests (Adam Litke) + * [3d993d3] Issue #125: Switching Page Tabs Breaks Pop-up Menu Disappearing (Hongliang Wang) + * [f00ee09] i18n: Correct storage pool create error message (Adam Litke) + * [adf3ac3] issue #143: Add missing parameter while calling the request error handler (Aline Manera) + * [a915292] Add the globalization translation in English/Chinese (zhoumeina) + * [8ccaf94] Fix bug: Storage pool name will wrap when it contains - and white-space (zhoumeina) + * [b27d1f4] issue #141: Fix regex responsible to check if an URL is valid or not (Aline Manera) + * [e9a8723] fix issue #136 about mockmodel iso pool type (Royce Lv) + * [d412d20] There will be two goto homepage button at the #tag nonexistent page (zhoumeina) + * [d894fc1] Aggregate read for iso to improve scan efficiency (Royce Lv) + * [6ffb568] Add a go to homepage button at the error page (zhoumeina) + * [cd1b23d] capabilities: Update REST API tests (Aline Manera) + * [f5089e8] capabilities: Update API.md (Aline Manera) + * [8f54df9] Capabilities detection (Aline Manera) + * [b0a0c73] screenshot: Expose stream test result (Aline Manera) + * [99f9d9e] Update Test Code (Hongliang Wang) + * [d00782c] Edit Template API: Change HTTP Code to 303 (Hongliang Wang) + * [cfc30c8] UI: Update Template (Hongliang Wang) + * [f12ebc0] UI:[Storage support]Add the html of Storage support (zhoumeina) + * [53cad8d] UI:[Storage support]Add the js files of storage (zhoumeina) + * [59f07ab] UI:[Storage support]Add the css style of the storage page (zhoumeina) + * [3d9a7ff] UI:[Storage support]Add the po files of storage ui design (zhoumeina) + * [e806e87] UI:[Storage support]Add the png files for storage ui design (zhoumeina) + * [6d72c82] tests: Disable auth debug (Adam Litke) + * [740ae82] tests: Fix unit tests after auth was merged (Adam Litke) + * [c8876e3] auth: Prevent HTTBA in browser with FF Poster (Adam Litke) + * [114d52e] Enable UI (Hongliang Wang) + * [e13434a] Enable Cookie Manipulating in Client Side (Hongliang Wang) + * [bd1367b] Enable REST API (Hongliang Wang) + * [d69d14c] authentication (ShaoHe Feng) + * [f2949fa] Raise exception when cdrom URl does not match any criteria (Aline Manera) + * [ec0dd6a] Create sanity test to verify libvirt supports iso streaming (Aline Manera) + * [2a0504d] Adjust VM xml to support iso streaming (Aline Manera) + * [2d9ee88] bug fix: Use unitdir macro when creating directory for systemd units (ShaoHe Feng) + * [706a277] Create templates by shallow scan, deep scan and distros (Xin Ding) + * [50a5f26] shallow scan: Update testcases (Royce Lv) + * [0ef2130] Shallow scan: Add mockmodel implementation (Royce Lv) + * [e652eaf] shallow scan: Add model support (Royce Lv) + * [451c006] shallow scan: Change controller to be compatible with virtual pool (Royce Lv) + * [e2dd533] shallow scan: return unknown distro and version rather than none (Royce Lv) + * [3bceeaf] shallow scan: Report path info to storage volume (Royce Lv) + * [fac0794] shallow scan: extend API.md to make volume report iso information (Royce Lv) + * [0453992] Create template iso path needs to check (zhoumeina) + * [f1594e4] Fix bug:119 Action will be closed after refresh each 5 s (zhoumeina) + * [9e7ccba] No html escape in the kimchi.template function (Xin Ding) + * [a3b4891] Add browser support in README (zhoumeina) + * [78ba75c] Remove the msg check in test_exception.py (Bing Bu Cao) + * [d64c1fb] Catch the libvirt exceptions when accessing storage objects (Bing Bu Cao) + * [0ca05c1] Return abspath for iso scanning (Royce Lv) + * [7a01840] Add parentheses around dependency version in deb control file (Aline Manera) + * [781ba1d] issue#110: Fix list storage volume for inactive pool (Royce Lv) + * [b53bb35] Add testcase for InvalidOperation (Royce Lv) + * [a21aaeb] Catch InvalidOperation in collection (Royce Lv) + * [99638de] tests: Test the REST API using an SSL connection (Adam Litke) + * [2f26f37] server: Support SSL connections (Adam Litke) + * [a92de0d] api: Add an API to retrieve application configuration (Adam Litke) + * [8aac0d1] bug fix: add two dependencies in README. (apporc) + * [7dd1243] bug fix: two python souce missing in distribution (apporc) + * [1e46730] build: Include extra top-level files in dist (Adam Litke) + * [e8f27d8] Issue #76 - ImportError: No module named discover (Bing Bu Cao) + * [270a971] adopt a single log convention (ShaoHe Feng) + * [fff1bdf] IE8: The arrow indicator of dropdown menus can't be displayed (Xin Ding) + * [c73d9e6] A module to check the pam authenticate (ShaoHe Feng) + * [a724d98] set expires for static content caching (ShaoHe Feng) + * [c89a1ed] cacheBust parameter for static content caching (ShaoHe Feng) + * [ce1ad9c] add a cachebust module to generate href with cacheBust (ShaoHe Feng) + * [253a894] IE8: No background style for items in the template list page (Xin Ding) + * [0ea6333] IE8: No selected style for items in the main (Xin Ding) + * [44202b0] Fix indent of the js files (zhoumeina) + * [4d78ca5] template-update: real model support implement update method (ShaoHe Feng) + * [d3f864b] template-update: add the test case for update (ShaoHe Feng) + * [d3c4cb2] template-update: mock model support implement update method (ShaoHe Feng) + * [7d924e6] template-update: resouce support update method (ShaoHe Feng) + * [f67cf47] template-update: define an update method in API.md document (ShaoHe Feng) + * [dab2688] codingstyle: Fix indent for templates.html.tmpl (Adam Litke) + * [d12b474] IE8: The template list page can't be displayed (Xin Ding) + * [d24d1d5] Add delete confirm message box (zhoumeina) + * [40f0d9d] issues #95: Added files generated by build to .gitignore (ShaoHe Feng) + * [6528b11] IE8: Very long guest names cause column misalignment (Xin Ding) + * [8b6f92f] issue #82: convert from svg image to png image (ShaoHe Feng) + * [41206f4] Add Portuguese (Brazil) translation (Aline Manera) + * [e1eb228] Remove magic directories from config.py.in (Adam Litke) + * [9bc6ba2] i18n: Stop adding location comments to po files (Adam Litke) + * [c873867] Issue #39: Animate Button Clicks to Provide User Feedback (Hongliang Wang) + * [692cdd6] ui: Rename tab pages (Adam Litke) + * [eb1c6a3] python2.6 do not support dict key iteration (ShaoHe Feng) + * [c59b7d6] Using absolute path in error page (Royce Lv) + * [5f04ac0] test case for creating a vm with unicode name (ShaoHe Feng) + * [1797fe8] mockmodel support a VM with ww language name (ShaoHe Feng) + * [af8014d] support create a vm with unicode name (ShaoHe Feng) + * [a4c99eb] sqlite3 support unicode (ShaoHe Feng) + * [ae358e4] Passing the options from autogen.sh to configure (Shu Ming) + * [ff869d5] remove the translation keys in i18n.thml and update the po files (ShaoHe Feng) + * [afb3a77] UI: update some labels of template edit page (ShaoHe Feng) + * [04395d5] All templates translate all languages no exceptions for English (ShaoHe Feng) + * [49a02da] Issue #72: Make Pages Be Bookmark-able (Hongliang Wang) + * [a5fceb2] fix bug:35 GUEST 'VNC' do not work which graphic type is 'spice' (zhoumeina) + * [bfd91d8] ui: Keep image ratio while displaying VM icon and screenshot image (Aline Manera) + * [1846daa] Exception: Add UI support (Royce Lv) + * [431d554] Exception: Add testcase to test error reporting (Royce Lv) + * [55d84e1] Exception: Distinguish development mode and production mode in kimchi server (Royce Lv) + * [1463303] Exception: reporting error in controller.py in details (Royce Lv) + * [dc8881f] Exception: Customise error page handler (Royce Lv) + * [b8c6eee] Exception: move exceptions from model (Royce Lv) + * [3e86f3f] ui: Disable 'Create' button on create guest without required input (Aline Manera) + * [c5e3951] Update Banner image for Kimchi rename (Adam King) + * [551a564] Issue #43: UI Reports Error When Pressing Enter Key in Creating VM Form (Hongliang Wang) + * [75ce907] fix bug:#51 guest tab contains 404 file not find error (zhoumeina) + * [2086de3] Bug fix:#67 add M for template memory (zhoumeina) + * [831160b] update UI to get connect graphics (ShaoHe Feng) + * [a196235] add graphics in mockmodel (ShaoHe Feng) + * [091af9b] add an attribute to get graphics of vm in model and update test case (ShaoHe Feng) + * [9d17820] bug fix: Add graphics of vm in API.md document (ShaoHe Feng) + * [4c227f5] Add ignore_missing parameter to ObjectStoreSession.delete() method (Aline Manera) + * [7c5b4d3] add automake and autoconf to dependencies (zhoumeina) + * [895f18c] add i18n.html.tmpl in dist_html_DATA list (ShaoHe Feng) + * [e67e479] doc: Update README.md with new build steps (Adam Litke) + * [91746b7] Rename burnet to kimchi (Adam Litke) + * [da6bc2c] build: Set install prefix using autoconf (Adam Litke) + * [0eba7d3] build: remove old distutils build files (Adam Litke) + * [818f184] build: Add support for building distro packages (Adam Litke) + * [544d8bd] build: Add gettext i18n support (Adam Litke) + * [b868785] build: Compile, distribute and install files (Adam Litke) + * [3529c60] build: Add basic autotools infrastructure (Adam Litke) + * [fff5167] screenshot: Add timeout to screenshot creation (Aline Manera) + * [5bebdc2] bug fix:#49 404 in debugger network tab when opening kimchi templates tab (zhoumeina) + * [30bc539] tests: Fix test_server_start (Adam Litke) + * [6228dee] ui: Ensure i18n.html loads (Adam Litke) + * [7e963fe] Remove obsolete data used in rendering page (Royce Lv) + * [cc89b1e] add js globalization method (ShaoHe Feng) + * [0c1cdcb] Asynctask: add logging to async task (Royce Lv) + * [37b87ab] Remove 'path' which should not be specified when creating volume (Bing Bu Cao) + * [95b7446] Use #unicode instead of #encoding in Cheetah templates (Aline Manera) + * [cbd5afa] fix bug: xmlutils get node context by context attribute (ShaoHe Feng) + * [80df676] issue34: add handling invalid iso file (Royce Lv) + * [5380105] issue60: Avoid using default database file in test (Royce Lv) + * [56b6e67] Issue #59: Make the popup menu entirely visible in browser (Hongliang Wang) + * [8796558] template: add rhel to osinfo (Royce Lv) + * [e05096c] bug: fix list vm name in unicode for mockmodel (Royce Lv) + * [de4d8b4] bug fix: kimchi supports to show VM with Chinese name (ShaoHe Feng) + * [b5fa8c2] Fix the exception caused by IE8 (Shu Ming) + * [4a8fcfd] fix-bug: remove the useless mini-line (ShaoHe Feng) + * [130d98b] UI:Add Template button should be disable but not hide before input the iSO (Xin Ding) + * [7c4c1b5] fix-bug: issues30 UI:Add Template contains js errors (Xin Ding) + * [a747f74] Hidden the VNC button when VM is stopped (Bing Bu Cao) + * [f17e101] #32 template name too long make page abnarmally (zhoumeina) + * [2477c0c] Fix Issue #10: Very long guest names cause column misalignment (Hongliang Wang) + * [1b33ded] Remove useless text in template-add.html.tmpl (Xin Ding) + * [868abd7] doc: Update README.md with more package dependencies (ShaoHe Feng) + * [5cda59c] Need root privilege to run test_vm_list_sorted test (Shu Ming) + * [69669a1] test: change testcase to allow running single test (Royce Lv) + +#### [v0.1.0] #### + + +#### [kimchi-0.1.0] #### + * [3efcaa2] Enable the usage of test:///default (Eduardo Elias Ferreira) + * [96f604f] Ordered guest list (Eduardo Elias Ferreira) + * [7c06d1d] Convert VM list to unicode (Eduardo Elias Ferreira) + * [7212590] Cannot delete a VM that is powered on (Eduardo Elias Ferreira) + * [85927b0] Check if VM exists before stopping or deleting (Eduardo Elias Ferreira) + * [dcabdcb] ui: overwrite vm start and stop click event to fix multi-click bug. (ShaoHe Feng) + * [03cbce4] ui: add a vm load icon for multi-click bug. (ShaoHe Feng) + * [90e586e] Change test filename to a standard format (Eduardo Elias Ferreira) + * [0e2801e] fix bug: UI displays abnormal follow the README (ShaoHe Feng) + * [61332e7] fix bug: let i18n_files depends on po files instead of mo files. (ShaoHe Feng) + * [98c0373] Bug Fix: Get correct exception info when run unittest on Python2.6 (Bing Bu Cao) + * [811c10e] Raise an exception in skipUnless() to abort the test on Python2.6 (Bing Bu Cao) + * [2ac7290] mockmodel: Use ps|grep to find open VNC port (Aline Manera) + * [acfa9f2] Add another path for SLES11 to find the qemu binary (Bing Bu Cao) + * [329a4c3] ui: Fix screenshot flicker (Royce Lv) + * [9ed459c] fix: Remove extra import statement in objectstore.py (Aline Manera) + * [41ab0c0] Tasks: Implement the backend (Shu Ming) + * [0968b5c] Tasks: Implement mock model (Shu Ming) + * [41f107e] Tasks: Splitting ObjectStore from model file (Shu Ming) + * [bf3501f] Tasks: Define the APIs (Shu Ming) + * [7343783] Correct License file to correctly cite ASL2 (Adam King) + * [5983108] Bug 94806 screenshot can not display from design UI. JS Updates (Adam King) + * [5e6ebea] Bug 94806 Screenshot live tile gets 404 on initial load. Refactor html (Adam King) + * [9a23263] Update setup.py make_po task to be verbose (Adam King) + * [34f1f3e] Remove unused rule .template-drop in template list CSS (Hongliang Wang) + * [75a4e4f] Update the Rest and MockModel tests to account for the server no longer redi.. (Adam King) + * [0cf1d00] Update controller.py to prefer InternalRedirect to HTTPRedirect (Adam King) + * [4b65b20] Add RHEL6 support (Eduardo Elias Ferreira) + * [f2149f4] Merge pull request #3 from crobinso/fedora-pil-fix (Adam Litke) + * [163c3cd] Fix Image imports on Fedora 19 (Cole Robinson) + * [6fbc8ed] ui: Display template icons (Adam Litke) + * [9fc1789] templates: Scan ISO to determine os_distro and os_version (Adam Litke) + * [68baf7a] Identify Operating System from ISO file (Adam Litke) + * [7ee068d] osinfo: Fix osinfo to use the correct distro shortnames and versions (Adam Litke) + * [8fafad1] Refactor osinfo/VMTemplate parameter handling (Adam Litke) + * [365e6e5] Update design ui html template to use favorites icon (Adam) + * [2becd3a] Add icon file for use as favorites icon (Adam) + * [c8c0eb7] Make logging level configurable (Aline Manera) + * [b59ab8a] Separate burnet logs into access log and error log (Aline Manera) + * [ff5d076] tests: Screenshot is not available until vm is started (Adam Litke) + * [c812468] Add improved README with screenshots (Anthony Liguori) + * [59a94c8] ui: remove the mocked up username (Anthony Liguori) + * [48b6efb] UI: Support Edit a Template (Hong Liang L Wang) + * [e7b69fe] ui: template creation without iso scan support (xinding@cn.ibm.com) + * [2783ce9] UI: Support List Templates & Delete a Template (Hong Liang L Wang) + * [0f18271] new ui: Display a VM's icon when it is powered off (Aline Manera) + * [47f5c52] Revert 5a9ff5d61fa03c19c71c1d22e0f841ca1377a423 This patch is part of the fu.. (Adam Litke) + * [5a9ff5d] add template navigation title (zhoumeina) + * [40c1eaa] change button styles according to the latest ui design (Xin BJ Ding) + * [d364d02] Bug Fix: this patch fix the bug 95350 (Bing Bu Cao) + * [ed4ec60] Added additional patterns to .gitignore (Adam King) + * [07d906d] Add cpu_stats field to ModelTests (Aline Manera) + * [0f094b1] Generate the cdrom XML based on template config. (Tony Breeds) + * [fc6e2b9] Move bus_to_dev into the VMTemplate class. (Tony Breeds) + * [30515ef] bug: using whitespace when probing qemu process with vnc option (Bing Bu Cao) + * [c44dfaf] UI: remove red exclamation point before the vm name (ShaoHe Feng) + * [70db7f4] burnet: relicense source tree (Anthony Liguori) + * [0ecc1a3] Assume guest arch is the same as host, rather than x86_64. (Tony Breeds) + * [1a8bc2f] Display percentage of CPU usage for each virtual machine (Aline Manera) + * [d14d2d5] ui: Display a warning if the UI needs to be built (Adam Litke) + * [9603514] packaging: python-polib is required (Adam Litke) + * [61a170a] dev-ui: Fix vnc linkage (Adam Litke) + * [1df0364] Fix screenshot stream resource leak (Royce Lv) + * [d7c586b] ui: Update the build process and server configuration (Adam Litke) + * [2a91a9d] ui: Import pages and i18n (Adam Litke) + * [f852fa3] ui: Import javascript files (Adam Litke) + * [b3502a3] ui: import modernizr (Adam Litke) + * [21a2354] ui: Import jquery-1.10.0.min.js (Adam Litke) + * [4ca183a] ui: Import the default theme images (Adam Litke) + * [67bef51] ui: Import css files for the default theme (Adam Litke) + * [df49b71] ui: Namespace the dev ui (Adam Litke) + * [9789650] ui: Filter all requests for html pages through cheetah (Adam Litke) + * [40e5b6b] Move noVNC files into new directory structure (Adam Litke) + * [975bfa4] Reorganize UI files (Adam Litke) + * [40a538f] ui: Let the UI pick the default icon for a VM (Adam Litke) + * [3d414ed] i18n: Fix install paths of gettext .mo files (Adam Litke) + * [ffa826c] Revert b8cfa245b868d4778c68f407fcf3180dde895673 I applied a patch to fix fli.. (Adam Litke) + * [313b52d] ui: Increase screenshot refresh frequency (Adam Litke) + * [4552ca5] ui: Allow scrollbars on the VNC window if necessary (Adam Litke) + * [b8cfa24] Fix screenshot image flicker (Royce Lv) + * [77b1177] do not translate en_US (ShaoHe Feng) + * [0a83bd7] add README for i18n (ShaoHe Feng) + * [096f512] check pygettext.py is available (ShaoHe Feng) + * [16b259a] install the i18n files correctly (ShaoHe Feng) + * [983e140] info_po command to show the summary infomation of po files (ShaoHe Feng) + * [f222a31] add make_po command to generate or update po files (ShaoHe Feng) + * [28b5875] give gettext another nickname ' _t' (ShaoHe Feng) + * [beee18c] trim index.tmpl to make pygettext.py happy (ShaoHe Feng) + * [26d56d7] translate burnet home page to Chinese (ShaoHe Feng) + * [2c0af9f] initialize the language select on the URL loading (ShaoHe Feng) + * [8a40004] i18n the title 'hostname' of index.tmpl (ShaoHe Feng) + * [d099fb3] define a dummy _() function to defer actual translation (ShaoHe Feng) + * [8a36c45] generate mo files during build time (ShaoHe Feng) + * [574833a] configure the gettext of Cheetah template to support i18n (ShaoHe Feng) + * [cb38be8] add po files for i18n (ShaoHe Feng) + * [90ab55c] get language that the client prefers (ShaoHe Feng) + * [5e04efc] ui: Add button to delete a templete (ShaoHe Feng) + * [f3eb2ed] tests: Fix expected result in test_vm_info (Adam Litke) + * [aa6101f] tests: Add required logfile variable to server options (Adam Litke) + * [87964ad] Fix websockify.py permission after installation (Royce Lv) + * [bd387ce] browser report start VM error, fix it (ShaoHe Feng) + * [6ca43a6] Set default log directory according to burnet root directory (Aline Manera) + * [12ea4a3] Create build process for Debian distributions (Aline Manera) + * [d2e5514] Create build process for SLES-based distributions (Aline Manera) + * [4d43935] Create build process for RHEL-based distributions (Aline Manera) + * [674e129] Add sysvinit support (Aline Manera) + * [972c689] Add upstart support (Aline Manera) + * [9e191e6] Add systemd support (Aline Manera) + * [c969f03] Create log file to burnet server (Aline Manera) + * [d357d37] Replace argparse with optparse (Adam Litke) + * [b086e2b] Import OrderedDict across multiple distros (Adam Litke) + * [3f72977] fix the prefix of burnet date path (ShaoHe Feng) + * [23815be] add the static files into data_files list (ShaoHe Feng) + * [74d31b2] Display a VM's icon when it is powered off (Adam Litke) + * [fe48e63] resize no_VNC window dynamically (ShaoHe Feng) + * [3f1a915] Use ps instead of pgrep to search for VNC qemu port (Aline Manera) + * [b9daead] Update vm-toolbar on each vm selection (Aline Manera) + * [a0511aa] Make storage*s_create() return the name of the resource (Bing Bu Cao) + * [d7e8a53] Open VNC port for MockModel only once (Aline Manera) + * [77c5fca] Fix mock backend vm delete error (Royce Lv) + * [7850b3b] Hide dialog-delete-confirm div in Burnet main page (Aline Manera) + * [261cc99] Enable folder navigation for Templates in the UI (Aline Manera) + * [2c774f9] Add bread-crumbs style to burnet template (Aline Manera) + * [088ba06] Add folder field to Template Resource (Aline Manera) + * [0e8c94b] screenshot: libvirt backend screenshot (Royce Lv) + * [0a607da] screenshot: Nit fix of mockmodel (Royce Lv) + * [a27afd2] screenshot: minor change to common screenshot class (Royce Lv) + * [c08bab9] Add libvirt backend StoragePool(s) and StorageVolume(s) unitTest (Bing Bu Cao) + * [dc8952d] Add libvirt backend StoragePool(s) and StorageVolume(s) support to Burnet (Bing Bu Cao) + * [ed4bda5] Remove useless 'pass' in mockmodel.py added before (Bing Bu Cao) + * [0dc3293] ui: Add button to delete a VM (Adam Litke) + * [a1e335f] ui: Create a new VM from a Template (Adam Litke) + * [1b147fc] API: Make VM name optional (Adam Litke) + * [ded4a86] Provision storage when creating a VM from a Template (Adam Litke) + * [e421821] objectstore: rollback transactions on error (Adam Litke) + * [830d4e4] osinfo: Add osinfo for some popular operating systems (Adam Litke) + * [b7562ae] Add 'vnc_port' key (Bing Bu Cao) + * [40f4b45] Add screenshot directory to data/ directory (Royce Lv) + * [e402a07] merge-fail: Add the file 'src/burnet/vnc.py' When taking the patch: [PATCH 0.. (Adam Litke) + * [4b9a62c] Handle the 'Display' link (Aline Manera) + * [7ccfed2] Restore 'Display' link state after performing power on/off (Aline Manera) + * [1688f15] Enable 'Display' link only if a running virtual machine is selected (Aline Manera) + * [9c3778a] Deselect virtual machines after performing power on/off (Aline Manera) + * [5c9a736] Implement real backend to start VNC session (Aline Manera) + * [0000eb6] Handle 'connect' action to virtual machine in MockModel (Aline Manera) + * [19be36f] Open vnc port in MockModel (Aline Manera) + * [ee197f6] Make static/ directory available in the web server (Aline Manera) + * [5ab68de] Import noVNC files (Aline Manera) + * [65e2312] Import python WebSocket library as it is (Aline Manera) + * [30a4503] screenshot: Add time-based screenshot refresh testcase (Royce Lv) + * [e95a007] screenshot: Change mock backend to support screenshot generation (Royce Lv) + * [03682f3] screenshot: Add screenshot sub resource (Royce Lv) + * [aadc37c] screenshot: Add common screenshot class (Royce Lv) + * [cbcf002] screenshot: expose screenshot path (Royce Lv) + * [5ebada4] doc: Add screenshot resource definition (Royce Lv) + * [f30e4c2] images: Import some icons for popular operating systems (Adam Litke) + * [7194621] api: Return HTTP:404 when deleting a non-existent resource (Adam Litke) + * [cbb8396] add a select to setup a language cookie (ShaoHe Feng) + * [24e76c3] ui: Refresh UI at a 5 second interval (Adam Litke) + * [c70b03f] Make sure the data/ directory exists in the source tree (Adam Litke) + * [19f8c02] Add a simple object persistence mechanism (Adam Litke) + * [d335aa1] Implement the real backend using libvirt (Adam Litke) + * [36ca77c] Create VM from a template (Adam Litke) + * [6135a15] templates: Implement the mock model (Adam Litke) + * [ff6ae73] templates: Add osinfo dictionary (Adam Litke) + * [068ea78] templates: Add Collection and Resource (Adam Litke) + * [90cf130] doc: Define the template APIs (Adam Litke) + * [f93dde3] Add Rest API test cases (Bing Bu Cao) + * [44ff829] Add the Collection and Resource (Bing Bu Cao) + * [94dc894] Define the StoragePool(s) and StorageVolume(s) APIs (Bing Bu Cao) + * [0fd434f] Enable power off virtual machines in UI (Aline Manera) + * [8f94ee5] Enable power on virtual machines in UI (Aline Manera) + * [09a75ce] Enable virtual machine selection in UI (Aline Manera) + * [50b4937] Setting the code encoding of cheetah template as UTF-8 (ShaoHe Feng) + * [212add9] Add screenshot field to VM Resource (Adam Litke) + * [2c48de8] doc: Document the desired REST API (Adam Litke) + * [25d9887] UI: Load VM information from the actual REST API (Adam Litke) + * [b0e36f7] Add basic VM operations (Adam Litke) + * [dbdb61a] Remove GPL license (Anthony Liguori) + * [8dc800d] Add basic Virtual Machine support (agl@linux.vnet.ibm.com) + * [f5f8f85] Add basic model/controller support (agl@linux.vnet.ibm.com) + * [a2d2085] template: Fix the separators for json rendering (agl@linux.vnet.ibm.com) + * [bee9ca0] tests: Correct test_server_start expected result (agl@linux.vnet.ibm.com) + * [2ed1745] template: Don't forget to import json (agl@linux.vnet.ibm.com) + * [50dbe22] ui: expose the js/css/images directory and the index template (Anthony Liguori) + * [ae3d4f7] ui: add javascript, css, and template for main page (Anthony Liguori) + * [7a563b4] ui: add external resources (jquery, etc.) (Anthony Liguori) + * [2610749] burnet: add template module (Anthony Liguori) + * [7d0c7d6] burnet: add config file (Anthony Liguori) + * [980b749] setup.py: use package instead of py_modules (Anthony Liguori) + * [4e982f9] docs: add CONTRIBUTE.md to the top-level (Anthony Liguori) + * [d60a085] tests: Introduce basic unit testing infrastructure (v2) (agl@linux.vnet.ibm.com) + * [5e9b7aa] Initial import of code base (Anthony Liguori) \ No newline at end of file -- 2.4.3
Hi Paulo, I was not able to apply this patch set: alinefm@alinefm-ThinkPad-T440:~/kimchi$ git am -3 ../mail-patches/\[PATCH\ * fatal: cannot convert from y to UTF-8 Press ENTER (instead of y) when the UTF-8 question is prompted. Regards, Aline Manera
participants (2)
-
Aline Manera -
pvital@linux.vnet.ibm.com