Compare commits

..

1 Commits

Author SHA1 Message Date
Nicolas Arenas f8390cc9be Modify jenkinsfile to upload packages
ogclone-engine/pipeline/head This commit looks good Details
2025-03-19 14:58:11 +01:00
126 changed files with 964 additions and 439 deletions

View File

@ -1,158 +1,12 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. ## [0.1.1] - 2025-02-28
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Changed - 2025-03-19
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.8.0] - 2025-04-23
### Added
- Have the oglive agent send /stopped on poweroff or restart
## [0.7.2] - 2025-04-21
### Fixed
- Have the partitioning functions return a meaningful rc
## [0.7.1] - 2025-04-15
### Fixed
- getConfiguration.py: don't fail if NTFS filesystems are mounted ro
## [0.7.0] - 2025-04-15
### Removed
- Removed references to ogGlobals.OGLOG in python code
## [0.6.1] - 2025-04-15
### Fixed
- Fixed capturing of partclone output and management of return value
## [0.6.0] - 2025-04-15
### Changed
- ogGetIpAddress() is no longer required in ogGlobals--move it back into NetLib
## [0.5.0] - 2025-04-15
### Changed
- Log to /var/log/clone-engine.log and clone-engine.json.log
## [0.4.1] - 2025-04-10
### Fixed
- restoreImage.py: return negated rc to the shell
## [0.4.0] - 2025-04-10
### Changed
- Make /opt/opengnsys writable in clients, just like it used to be
## [0.3.6] - 2025-04-09
### Fixed
- Fixed ogReduceFs
## [0.3.5] - 2025-04-09
### Fixed
- Fixed syntax
## [0.3.4] - 2025-04-09
### Fixed
- Fixed usage of ogEcho in FileSystemLib
## [0.3.3] - 2025-04-09
### Fixed
- Kill coproc'ed browser in all execution branches in Configurar.py
## [0.3.2] - 2025-04-07
### Fixed
- Handle invalid number of arguments pass to functions/ogCopyFile
## [0.3.1] - 2025-04-03
### Fixed
- Fixed invocation to ogCheckIpAddress in interfaceAdm/CrearImagen.py
## [0.3.0] - 2025-04-03
### Removed
- Removed burg and rsync 3.1
## [0.2.6] - 2025-03-31
### Fixed
- Restore qt4 browser
## [0.2.5] - 2025-03-31
### Fixed
- Don't require protoopts in interfaceAdm/RestaurarImagen.py
## [0.2.4] - 2025-03-28
### Removed
- Removed burg, QT4 stuff, rsync 3.1 and the old browser
## [0.2.3] - 2025-03-28
### Fixed
- Fixed some errors in Configurar.py, ogCreateCache, ogCreatePartitions and initCache.py
## [0.2.2] - 2025-03-26
### Fixed
- Prevent EjecutarScript.py from capturing the output of the script
## [0.2.1] - 2025-03-26
### Fixed
- Run scripts with bash to avoid errno 8 "Exec format error"
## [0.2.0] - 2025-03-25
### Added
- getConfiguration.py now collects the firmware type
- Configurar.py now creates partition tables of the right type (MSDOS/GPT) for each machine
## [0.1.1] - 2025-03-19
### Added
- Missing functions in BootLib
- Some interfaceAdm python scripts
## [0.1.0] - 2025-02-28 ## [0.1.0] - 2025-02-28
### Added ### Addded
- Merge pull request 'Include all client files, build debian package' (#2) from deb-package into main - Merge pull request 'Include all client files, build debian package' (#2) from deb-package into main

View File

@ -19,7 +19,7 @@ pipeline {
stage('Prepare Workspace') { stage('Prepare Workspace') {
steps { steps {
script { script {
env.BUILD_DIR = "${WORKSPACE}/ogclient" env.BUILD_DIR = "${WORKSPACE}/oggui"
sh "mkdir -p ${env.BUILD_DIR}" sh "mkdir -p ${env.BUILD_DIR}"
} }
} }
@ -48,22 +48,16 @@ pipeline {
} }
} }
} }
stage('Generate Changelog (Nightly)'){
when {
branch 'main'
}
steps {
script {
def devName = params.DEV_NAME ? params.DEV_NAME : env.DEFAULT_DEV_NAME
def devEmail = params.DEV_EMAIL ? params.DEV_EMAIL : env.DEFAULT_DEV_EMAIL
generateDebianChangelog(env.BUILD_DIR, devName, devEmail,"nightly")
}
}
}
stage('Build') { stage('Build') {
steps { steps {
script { dir("${env.BUILD_DIR}") {
construirPaquete(env.BUILD_DIR, "../artifacts", "172.17.8.68", "/var/tmp/opengnsys/debian-repo/ogclient") sh '''
dpkg-buildpackage -us -uc
mkdir -p ../artifacts && mv ../*.deb ../*.changes ../*.buildinfo ../artifacts/
ssh aptly@172.17.8.68 "rm -rf /var/tmp/opengnsys/debian-repo/ogclient && mkdir -p /var/tmp/opengnsys/debian-repo/ogclient"
scp -r ../artifacts/* aptly@172.17.8.68:/var/tmp/opengnsys/debian-repo/ogclient
'''
} }
} }
} }
@ -75,24 +69,7 @@ pipeline {
} }
agent { label 'debian-repo' } agent { label 'debian-repo' }
steps { steps {
script { sh "aptly repo add opengnsys-devel /var/tmp/opengnsys/debian-repo/ogclient/*.deb"
// Construir el patrón de versión esperado en el nombre del paquete
def versionPattern = "${env.TAG_NAME}-${env.BUILD_NUMBER}"
publicarEnAptly('/var/tmp/opengnsys/debian-repo/ogclient', 'opengnsys-devel', versionPattern)
}
}
}
stage ('Publish to Debian Repository (Nightly)') {
when {
branch 'main'
}
agent { label 'debian-repo' }
steps {
script {
// Construir el patrón de versión esperado en el nombre del paquete
def versionPattern = "-${env.BUILD_NUMBER}~nightly"
publicarEnAptly('/var/tmp/opengnsys/debian-repo/ogclient', 'nightly', versionPattern)
}
} }
} }
} }

View File

@ -23,7 +23,13 @@ case "$1" in
cp -a "$OLD_FILE" "$NEW_FILE" cp -a "$OLD_FILE" "$NEW_FILE"
# Append our configuration # Append our configuration
echo "include = /etc/samba/smb-ogclient.conf" >> "$OLD_FILE" echo "include = /etc/samba/smb-ogclient.conf" >> "$NEW_FILE"
# Use ucf to handle the file update
ucf --debconf-ok "$NEW_FILE" "$OLD_FILE"
# Clean up
rm -f "$NEW_FILE"
# Reload Samba # Reload Samba
if command -v systemctl >/dev/null 2>&1; then if command -v systemctl >/dev/null 2>&1; then
@ -42,8 +48,6 @@ case "$1" in
;; ;;
esac esac
chown -R opengnsys:opengnsys /opt/opengnsys/ogclient
chown -R opengnsys:opengnsys /opt/opengnsys/ogclient_log
#DEBHELPER# #DEBHELPER#
exit 0 exit 0

View File

@ -1,15 +0,0 @@
#!/bin/bash
set -e
# Asegurarse de que el usuario exista
USER="opengnsys"
HOME_DIR="/opt/opengnsys"
if id "$USER" &>/dev/null; then
echo "El usuario $USER ya existe."
else
echo "Creando el usuario $USER con home en $HOME_DIR."
useradd -m -d "$HOME_DIR" -s /bin/bash "$USER"
fi
exit 0

View File

@ -1,7 +1,7 @@
[ogclient] [ogclient]
comment = OpenGnsys Client comment = OpenGnsys Client
browseable = no browseable = no
writeable = yes writeable = no
locking = no locking = no
path = /opt/opengnsys/ogclient path = /opt/opengnsys/ogclient
guest ok = no guest ok = no

Binary file not shown.

View File

@ -55,9 +55,6 @@ elif 6 == len (sys.argv):
args = parser.parse_args() args = parser.parse_args()
src = { 'container': args.src_container, 'file': args.src_file } src = { 'container': args.src_container, 'file': args.src_file }
dst = { 'disk': args.dst_disk, 'par': args.dst_par, 'file': args.dst_file } dst = { 'disk': args.dst_disk, 'par': args.dst_par, 'file': args.dst_file }
else:
ogHelp ('ogCopyFile', 'ogCopyFile [ str_repo | int_ndisk int_npartition ] path_source [ str_repo | int_ndisk int_npartition ] path_target', ['ogCopyFile REPO newfile.txt 1 2 /tmp/newfile.txt'])
sys.exit (1)
ret = ogCopyFile (src, dst) ret = ogCopyFile (src, dst)
if ret is not None: if ret is not None:

View File

@ -2,9 +2,6 @@
import os import os
import sys import sys
import time
os.system ('pkill -f OGAgent')
time.sleep (3)
os.system ('poweroff') os.system ('poweroff')
sys.exit (0) sys.exit (0)

View File

@ -9,7 +9,6 @@ import SystemLib
import CacheLib import CacheLib
import FileSystemLib import FileSystemLib
import DiskLib import DiskLib
import InventoryLib
#Load engine configurator from engine.cfg file. #Load engine configurator from engine.cfg file.
#Carga el configurador del engine desde el fichero engine.cfg #Carga el configurador del engine desde el fichero engine.cfg
@ -62,24 +61,23 @@ sparam = tbprm[1] # Partitioning and formatting parameters
# Toma valores de disco y caché, separados por "*". # Toma valores de disco y caché, separados por "*".
# Los valores están en las variables $dis: disco, $che: existe cache (1, 0), $tch: Tamaño de la cache. # Los valores están en las variables $dis: disco, $che: existe cache (1, 0), $tch: Tamaño de la cache.
tbprm = pparam.split ('*') tbprm = pparam.split ('*')
dis = tch = None dis = ptt = tch = None
for item in tbprm: for item in tbprm:
if '=' not in item: continue if '=' not in item: continue
k, v = item.split ('=', 1) k, v = item.split ('=', 1)
if k not in ['dis', 'tch']: if k not in ['dis', 'tch', 'ptt']: ## 'ptt' added, unused 'che' removed
print (f'ignoring unknown disk parameter ({k})') print (f'ignoring unknown disk parameter ({k})')
continue continue
if 'dis' == k: dis = int (v) if 'dis' == k: dis = int (v)
elif 'ptt' == k: ptt = v
elif 'tch' == k: tch = v elif 'tch' == k: tch = v
# Error si no se define el parámetro de disco (dis). # Error si no se define el parámetro de disco (dis).
if dis is None: if dis is None: sys.exit (ogGlobals.OG_ERR_FORMAT)
coproc.kill() if ptt is None: ptt = 'MSDOS'
sys.exit (ogGlobals.OG_ERR_FORMAT) if tch is None: tch = '0'
if tch is None:
tch = '0'
# Toma valores de distribución de particiones, separados por "%". # Toma valores de distribución de particiones, separados por "%".
tbp = [] # Valores de configuración (parámetros para ogCreatePartitions) tbp = [] # Valores de configuración (parámetros para ogCreatePartitions)
@ -114,7 +112,6 @@ for item in tbprm:
if tam is None: missing_params.append ('tam') if tam is None: missing_params.append ('tam')
if missing_params: if missing_params:
print (f'partition data ({item}) missing required parameters ({' '.join (missing_params)})') print (f'partition data ({item}) missing required parameters ({' '.join (missing_params)})')
coproc.kill()
sys.exit (1) sys.exit (1)
# Componer datos de particionado. # Componer datos de particionado.
@ -141,21 +138,18 @@ CacheLib.ogUnmountCache()
# Elimina la tabla de particiones # Elimina la tabla de particiones
cur_ptt = DiskLib.ogGetPartitionTableType (dis) cur_ptt = DiskLib.ogGetPartitionTableType (dis)
ptt = 'GPT' if InventoryLib.ogIsEfiActive() else 'MSDOS'
if not cur_ptt or ptt != cur_ptt: if not cur_ptt or ptt != cur_ptt:
DiskLib.ogDeletePartitionTable (dis) DiskLib.ogDeletePartitionTable (dis)
SystemLib.ogExecAndLog ('command', DiskLib.ogUpdatePartitionTable) SystemLib.ogExecAndLog ('command', DiskLib.ogUpdatePartitionTable)
# Crea tabla de particiones MSDOS (NOTA: adaptar para tablas GPT).
DiskLib.ogCreatePartitionTable (dis, ptt) DiskLib.ogCreatePartitionTable (dis, ptt)
# Inicia la cache. # Inicia la cache.
if 'CACHE' in sparam: if 'CACHE' in sparam:
SystemLib.ogEcho (['session', 'log'], None, f'[30] {ogGlobals.lang.MSG_HELP_ogCreateCache}') SystemLib.ogEcho (['session', 'log'], None, f'[30] {ogGlobals.lang.MSG_HELP_ogCreateCache}')
SystemLib.ogEcho (['session', 'log'], None, f' initCache {tch}') SystemLib.ogEcho (['session', 'log'], None, f' initCache {tch}')
rc = SystemLib.ogExecAndLog ('command', CacheLib.initCache, tch) SystemLib.ogExecAndLog ('command', CacheLib.initCache, tch)
if rc:
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_CACHE, f'initCache failed')
coproc.kill()
sys.exit (1)
# Definir particionado. # Definir particionado.
SystemLib.ogEcho (['session', 'log'], None, f'[50] {ogGlobals.lang.MSG_HELP_ogCreatePartitions}') SystemLib.ogEcho (['session', 'log'], None, f'[50] {ogGlobals.lang.MSG_HELP_ogCreatePartitions}')

View File

@ -66,7 +66,7 @@ repo = arg_repo
if not repo: repo = 'REPO' if not repo: repo = 'REPO'
if repo == ogGetIpAddress(): repo = 'CACHE' if repo == ogGetIpAddress(): repo = 'CACHE'
# Si es una ip y es distinta a la del recurso samba cambiamos de REPO. # Si es una ip y es distinta a la del recurso samba cambiamos de REPO.
if 'REPO' == repo or ogCheckIpAddress (repo): if 'REPO' == repo or StringLib.ogCheckIpAddress (repo):
# Si falla el cambio -> salimos con error repositorio no valido # Si falla el cambio -> salimos con error repositorio no valido
if not ogChangeRepo (repo): if not ogChangeRepo (repo):
ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, repo) ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, repo)

View File

@ -34,7 +34,7 @@ with open (ogGlobals.OGLOGFILE, 'a') as logfd:
os.chmod (script_path, 0o755) os.chmod (script_path, 0o755)
# Si mandamos la salida a OGLOGCOMMAND reescribimos lo que manda el comando. # Si mandamos la salida a OGLOGCOMMAND reescribimos lo que manda el comando.
RETVAL = subprocess.run (['bash', script_path]).returncode RETVAL = subprocess.run (script_path, capture_output=True, text=True).returncode
TIME = time.time() - TIME1 TIME = time.time() - TIME1

View File

@ -2,9 +2,6 @@
import os import os
import sys import sys
import time
os.system ('pkill -f OGAgent')
time.sleep (3)
os.system ('reboot') os.system ('reboot')
sys.exit (0) sys.exit (0)

View File

@ -19,11 +19,11 @@ import ogGlobals
if __name__ == '__main__': if __name__ == '__main__':
prog = sys.argv[0] prog = sys.argv[0]
if len (sys.argv) < 6: if len (sys.argv) < 7:
print (f'Usage: {prog} <disk> <partition> <image_name> <repo_ip> <protocol> [protocol_options] [additional_args...]') print (f'Usage: {prog} <disk> <partition> <image_name> <repo_ip> <protocol> <protocol_options> [additional_args...]')
sys.exit (1) sys.exit (1)
disk, par, imgname, repo, proto, *extra = sys.argv[1:] disk, par, imgname, repo, proto, protoopt, *extra = sys.argv[1:]
rc = subprocess.run ([f'{ogGlobals.OGSCRIPTS}/deployImage.py', repo, imgname, disk, par, proto] + extra).returncode rc = subprocess.run ([f'{ogGlobals.OGSCRIPTS}/deployImage.py', repo, imgname, disk, par, proto, protoopt] + extra).returncode
sys.exit (rc) sys.exit (rc)

View File

@ -1,78 +1,80 @@
#!/usr/bin/python3 #!/usr/bin/env python3
import os import os
import glob
import subprocess import subprocess
from InventoryLib import ogGetSerialNumber, ogGetOsVersion, ogIsEfiActive def run_command(command):
from DiskLib import ogDiskToDev, ogGetPartitionsNumber, ogGetPartitionTableType, ogGetDiskSize, ogGetPartitionId, ogGetPartitionSize result = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
from FileSystemLib import ogMount, ogGetMountPoint, ogGetFsType return result.stdout.decode().strip()
ser = ogGetSerialNumber() def main():
fwt = 'UEFI' if ogIsEfiActive() else 'BIOS' # No registrar los errores.
print (f'ser={ser}\nfwt={fwt}') os.environ["DEBUG"] = "no"
ser = run_command("ogGetSerialNumber")
cfg = ""
disks = int(run_command("ogDiskToDev | wc -w"))
disks = len (ogDiskToDev())
if disks:
for dsk in range(1, disks + 1): for dsk in range(1, disks + 1):
# Tipo de tabla de particiones: 1=MSDOS, 2=GPT particiones = run_command(f"ogGetPartitionsNumber {dsk}")
ptt = ogGetPartitionTableType (dsk) particiones = int(particiones) if particiones else 0
ptt = run_command(f"ogGetPartitionTableType {dsk}")
ptt_map = { ptt_map = {
'MSDOS': 1, "MSDOS": 1,
'GPT': 2, "GPT": 2,
'LVM': 3, "LVM": 3,
'ZPOOL': 4, "ZPOOL": 4
} }
ptt = ptt_map.get(ptt, 0) ptt = ptt_map.get(ptt, 0)
# Información de disco (partición 0) cfg += f"{dsk}:0:{ptt}:::{run_command(f'ogGetDiskSize {dsk}')}:0;"
s = ogGetDiskSize (dsk)
print (f'disk={dsk}\tpar=0\tcpt={ptt}\tfsi=\tsoi=\ttam={s}\tuso=0')
particiones = ogGetPartitionsNumber (dsk)
particiones = int (particiones) if particiones else 0
for par in range(1, particiones + 1): for par in range(1, particiones + 1):
# Código del identificador de tipo de partición cod = run_command(f"ogGetPartitionId {dsk} {par} 2>/dev/null")
cod = ogGetPartitionId (dsk, par) fsi = run_command(f"getFsType {dsk} {par} 2>/dev/null") or "EMPTY"
tam = run_command(f"ogGetPartitionSize {dsk} {par} 2>/dev/null") or "0"
soi = ""
uso = 0
# Tipo del sistema de ficheros if fsi not in ["", "EMPTY", "LINUX-SWAP", "LINUX-LVM", "ZVOL"]:
fsi = ogGetFsType (dsk, par) if run_command(f"ogMount {dsk} {par} 2>/dev/null"):
if not fsi: fsi = 'EMPTY' soi = run_command(f"getOsVersion {dsk} {par} 2>/dev/null").split(":")[1]
# Tamaño de la particón
tam = ogGetPartitionSize (dsk, par)
if not tam: tam = '0'
# Sistema operativo instalado y porcentaje de uso
soi = ''
uso = '0'
if fsi not in ['', 'EMPTY', 'LINUX-SWAP', 'LINUX-LVM', 'ZVOL']:
if ogMount (dsk, par):
soi = ogGetOsVersion (dsk, par)
# Hacer un 2º intento para algunos casos especiales.
if not soi: if not soi:
soi = ogGetOsVersion (dsk, par) soi = run_command(f"getOsVersion {dsk} {par} 2>/dev/null").split(":")[1]
if not soi: soi = '' if not soi and fsi not in ["EMPTY", "CACHE"]:
if soi: soi = soi.split (':')[1] soi = "DATA"
# Sistema de archivos para datos (sistema operativo "DATA") uso = int(run_command(f"df $(ogGetMountPoint {dsk} {par}) | awk '{{getline; printf \"%d\",$5}}'") or 0)
if not soi and fsi not in ['EMPTY', 'CACHE']:
soi = 'DATA'
mntpt = ogGetMountPoint (dsk, par)
uso = subprocess.run (['df', mntpt], capture_output=True, text=True).stdout.splitlines()[-1].split()[4].replace ('%', '')
if not uso: uso = '0'
else: else:
soi = '' soi = ""
uso = '0' uso = 0
print (f'disk={dsk}\tpar={par}\tcpt={cod}\tfsi={fsi}\tsoi={soi}\ttam={tam}\tuso={uso}') cfg += f"{dsk}:{par}:{cod}:{fsi}:{soi}:{tam}:{uso};"
if not cfg:
cfg = "1:0:0:::0;"
cfgfile = "/tmp/getconfig"
with open(cfgfile, "w") as f:
f.write(f"{ser + ';' if ser else ''}{cfg}")
run_command("generateMenuDefault &>/dev/null")
with open(cfgfile, "r") as f:
data = f.read()
lines = data.split(";")
for line in lines:
if line:
parts = line.split(":")
if len(parts) == 1:
print(f"ser={parts[0]}")
else: else:
print ('disk=1\tpar=0\tcpt=0\tfsi=\tsoi=\ttam=0\tuso=0') print(f"disk={parts[0]}\tpar={parts[1]}\tcpt={parts[2]}\tfsi={parts[3]}\tsoi={parts[4]}\ttam={parts[5]}\tuso={parts[6]}")
# Crear el menú por defecto a partir del fichero generado (no dar ninguna salida). run_command("rm -f /mnt/*/ogboot.* /mnt/*/*/ogboot.*")
# requiere /tmp/getconfig pero este script ya no lo crea
#subprocess.run ([f'{ogGlobals.OGSCRIPTS}/generateMenuDefault'])
# Borramos marcas de arranque de Windows # Volver a registrar los errores.
for f in glob.glob ('/mnt/*/ogboot.*') + glob.glob ('/mnt/*/*/ogboot.*'): os.environ.pop("DEBUG", None)
try: os.unlink (f)
except: pass if __name__ == "__main__":
main()

View File

@ -1,5 +1,10 @@
#!/usr/bin/python3 #!/usr/bin/env python3
import socket
from NetLib import ogGetIpAddress def get_ip_address():
hostname = socket.gethostname()
ip_address = socket.gethostbyname(hostname)
return ip_address
print (ogGetIpAddress()) if __name__ == "__main__":
print(get_ip_address())

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -0,0 +1,79 @@
include "theme"
screen {
background = "$$/background.png"
panel {
halign = center
attach_vcenter = 0
height = 19
# Flip so the cursor defaults to the main menu
direction = bottom_to_top
### Main Menu ###
panel {
height = 15
max_width = 120
margin_top = 1
class = container-body
# No need for a min width and centering panel because extended width > min width
direction = left_to_right
anchor = 1
id = __menu__
}
panel {
height = 4
width = 100%
class = container-title
direction = left_to_right
image {
image = "$$/images/txt-select.png"
attach_top = 0
attach_left = 0
}
### Tools Menu ###
image {
attach_right = 2
image = "$$/images/button-tools.png:$$/images/button-tools-hover.png"
command = "menu_popup tools_menu"
}
}
}
### Progress Bar ###
panel {
halign = center
attach_vcenter = 20
width = 80
class = progressbar-background
id = __timeout__
progressbar { }
}
}
template_menuitem {
panel {
width = 40
height = 12
parameters = "class=image.class:title=panel.text.text"
image {
attach_vcenter = 0
attach_hcenter = 0
}
panel {
attach_vcenter = 0
attach_hcenter = 0
class = text-line
text { font = "Helvetica Regular 22" }
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,21 @@
+class
{
-opengnsys { image = "$$/normal_opengnsys.png:$$/hover_opengnsys.png" }
-windows10 { image = "$$/normal_windows10.png:$$/hover_windows10.png" }
-windows7 { image = "$$/normal_windows7.png:$$/hover_windows7.png" }
-windows { image = "$$/normal_windows.png:$$/hover_windows.png" }
-elementary { image = "$$/normal_elementary.png:$$/hover_elementary.png" }
-elementaryos { image = "$$/normal_elementary.png:$$/hover_elementary.png" }
-recovery { image = "$$/normal_recovery.png:$$/hover_recovery.png" }
-shutdown { image = "$$/normal_shutdown.png:$$/hover_shutdown.png" }
-restart { image = "$$/normal_restart.png:$$/hover_restart.png" }
-linux { image = "$$/normal_linux.png:$$/hover_linux.png" }
-ubuntu { image = "$$/normal_ubuntu.png:$$/hover_ubuntu.png" }
-debian { image = "$$/normal_debian.png:$$/hover_debian.png" }
-suse { image = "$$/normal_opensuse.png:$$/hover_opensuse.png" }
-freebsd { image = "$$/normal_freebsd.png:$$/hover_freebsd.png" }
-macosx { image = "$$/normal_osx.png:$$/hover_osx.png" }
-haiku { image = "$$/normal_haiku.png:$$/hover_haiku.png" }
-image { image = "$$/normal_os.png:$$/hover_os.png" }
-os { image = "$$/normal_os.png:$$/hover_os.png" }
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

Some files were not shown because too many files have changed in this diff Show More