Compare commits
	
		
			4 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2641a3b3d8 | |||
| b45039a813 | |||
| 04b105ab38 | |||
| 80388c0042 | 
							
								
								
									
										44
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										44
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -59,9 +59,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "cc"
 | 
			
		||||
version = "1.0.67"
 | 
			
		||||
version = "1.0.66"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
 | 
			
		||||
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap"
 | 
			
		||||
@ -76,9 +76,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "dtoa"
 | 
			
		||||
version = "0.4.8"
 | 
			
		||||
version = "0.4.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
 | 
			
		||||
checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "fragile"
 | 
			
		||||
@ -265,9 +265,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "libc"
 | 
			
		||||
version = "0.2.94"
 | 
			
		||||
version = "0.2.82"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
 | 
			
		||||
checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "linked-hash-map"
 | 
			
		||||
@ -326,18 +326,18 @@ checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "proc-macro2"
 | 
			
		||||
version = "1.0.26"
 | 
			
		||||
version = "1.0.24"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
 | 
			
		||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "unicode-xid",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "quote"
 | 
			
		||||
version = "1.0.9"
 | 
			
		||||
version = "1.0.8"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
 | 
			
		||||
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
]
 | 
			
		||||
@ -353,9 +353,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "regex-syntax"
 | 
			
		||||
version = "0.6.25"
 | 
			
		||||
version = "0.6.22"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
 | 
			
		||||
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rs"
 | 
			
		||||
@ -380,18 +380,18 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde"
 | 
			
		||||
version = "1.0.126"
 | 
			
		||||
version = "1.0.118"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
 | 
			
		||||
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde_derive",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_derive"
 | 
			
		||||
version = "1.0.126"
 | 
			
		||||
version = "1.0.118"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
 | 
			
		||||
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
@ -400,9 +400,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_yaml"
 | 
			
		||||
version = "0.8.17"
 | 
			
		||||
version = "0.8.15"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
 | 
			
		||||
checksum = "971be8f6e4d4a47163b405a3df70d14359186f9ab0f3a3ec37df144ca1ce089f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "dtoa",
 | 
			
		||||
 "linked-hash-map",
 | 
			
		||||
@ -412,9 +412,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "syn"
 | 
			
		||||
version = "1.0.72"
 | 
			
		||||
version = "1.0.58"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
 | 
			
		||||
checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
@ -438,9 +438,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "unicode-xid"
 | 
			
		||||
version = "0.2.2"
 | 
			
		||||
version = "0.2.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
 | 
			
		||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi"
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,7 @@ if out_path:
 | 
			
		||||
    i = args.index(out_path)
 | 
			
		||||
    args.pop(i)    
 | 
			
		||||
 | 
			
		||||
subprocess.run(['sh', "{}/cargo.sh".format(source_dir.as_posix()), 'build']
 | 
			
		||||
subprocess.run(['sh', "{}/cargo.sh".format(shlex.quote(source_dir.as_posix())), 'build']
 | 
			
		||||
    + args,
 | 
			
		||||
    check=True)
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ if out_path:
 | 
			
		||||
    out_basename = out_path.name
 | 
			
		||||
    filename = filename or out_basename
 | 
			
		||||
    subprocess.run(['cp', '-a',
 | 
			
		||||
        './{}/{}'.format(binary_dir, filename),
 | 
			
		||||
        './{}/{}'.format(shlex.quote(binary_dir), shlex.quote(filename)),
 | 
			
		||||
        out_path],
 | 
			
		||||
        check=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -438,7 +438,7 @@ buttons:
 | 
			
		||||
                unlock_view: "カタカナ"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        label: "。"
 | 
			
		||||
    # Buttons for Latin characters
 | 
			
		||||
    # Buttons for Latin charachters
 | 
			
		||||
    RSYM1:
 | 
			
		||||
        action:
 | 
			
		||||
            locking:
 | 
			
		||||
 | 
			
		||||
@ -438,7 +438,7 @@ buttons:
 | 
			
		||||
                unlock_view: "カタカナ"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        label: "。"
 | 
			
		||||
    # Buttons for Latin characters
 | 
			
		||||
    # Buttons for Latin charachters
 | 
			
		||||
    RSYM1:
 | 
			
		||||
        action:
 | 
			
		||||
            locking:
 | 
			
		||||
 | 
			
		||||
@ -147,6 +147,9 @@ buttons:
 | 
			
		||||
    Pause:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Pause"
 | 
			
		||||
    Menu:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Menu"
 | 
			
		||||
    Break:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Break"
 | 
			
		||||
@ -198,3 +201,4 @@ buttons:
 | 
			
		||||
        modifier: "Alt"
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        label: "Alt"
 | 
			
		||||
 | 
			
		||||
@ -1,220 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
outlines:
 | 
			
		||||
    action:    { width: 59,    height: 46 }
 | 
			
		||||
    small:     { width: 50,    height: 22 }
 | 
			
		||||
    default:   { width: 35.33, height: 46 }
 | 
			
		||||
    altline:   { width: 48,    height: 46 }
 | 
			
		||||
    wide:      { width: 50,    height: 46 }
 | 
			
		||||
    spaceline: { width: 110,   height: 46 }
 | 
			
		||||
    special:   { width: 44,    height: 46 }
 | 
			
		||||
 | 
			
		||||
views:
 | 
			
		||||
    base:
 | 
			
		||||
        - "Ctrl Alt Tabsmall ↑ ↓ ← →"
 | 
			
		||||
        - "a z e r t y u i o p"
 | 
			
		||||
        - "q s d f g h j k l m"
 | 
			
		||||
        - "Shift_L   w x c v b n period   BackSpace"
 | 
			
		||||
        - "show_numbers preferences         space        show_eschars show_actions Return"
 | 
			
		||||
    upper:
 | 
			
		||||
        - "Ctrl Alt Tabsmall PgUp PgDn Home End"
 | 
			
		||||
        - "A Z E R T Y U I O P"
 | 
			
		||||
        - "Q S D F G H J K L M"
 | 
			
		||||
        - "Shift_L   W X C V B N ,  BackSpace"
 | 
			
		||||
        - "show_numbers preferences         space        show_eschars show_actions Return"
 | 
			
		||||
    numbers:
 | 
			
		||||
        - "Ctrl Alt Tabsmall ↑ ↓ ← →"
 | 
			
		||||
        - "1 2 3 4 5 6 7 8 9 0"
 | 
			
		||||
        - "@ # € % & - _ + ( )"
 | 
			
		||||
        - "show_symbols   , \" ' colon ; ! ?  BackSpace"
 | 
			
		||||
        - "show_letters preferences         space        show_eschars show_actions Return"
 | 
			
		||||
    symbols:
 | 
			
		||||
        - "Ctrl Alt Tabsmall ↑ ↓ ← →"
 | 
			
		||||
        - "~ ` | · √ π τ ÷ × ¶"
 | 
			
		||||
        - "© ® £ $ ¥ ^ ° * { }"
 | 
			
		||||
        - "show_numbers_from_symbols   \\ / < > = [ ]  BackSpace"
 | 
			
		||||
        - "show_letters preferences         space        show_eschars show_actions Return"
 | 
			
		||||
    eschars:
 | 
			
		||||
        - "Ctrl Alt Tabsmall ↑ ↓ ← →"
 | 
			
		||||
        - "à â ç é è ê î ô ù û"
 | 
			
		||||
        - "À Â Ç É È Ê Î Ô Ù Û"
 | 
			
		||||
        - "show_numbers_from_symbols  æ œ ä ë ï ö ü  BackSpace"
 | 
			
		||||
        - "show_letters preferences         space        show_eschars show_actions Return"
 | 
			
		||||
    actions:
 | 
			
		||||
        - "Ctrl Alt PgUp PgDn Home End"
 | 
			
		||||
        - "F1  F2  F3  F4  F5  F6"
 | 
			
		||||
        - "F7  F8  F9  F10 F11 F12"
 | 
			
		||||
        - "Esc Tab Pause Insert Up Del"
 | 
			
		||||
        - "show_letters Menu Break Left Down Right"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
buttons:
 | 
			
		||||
    F1:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F1"
 | 
			
		||||
    F2:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F2"
 | 
			
		||||
    F3:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F3"
 | 
			
		||||
    F4:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F4"
 | 
			
		||||
    F5:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F5"
 | 
			
		||||
    F6:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F6"
 | 
			
		||||
    F7:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F7"
 | 
			
		||||
    F8:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F8"
 | 
			
		||||
    F9:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F9"
 | 
			
		||||
    F10:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F10"
 | 
			
		||||
    F11:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F11"
 | 
			
		||||
    F12:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F12"
 | 
			
		||||
    Esc:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Escape"
 | 
			
		||||
    Tab:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Tab"
 | 
			
		||||
    Tabsmall:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Tab"
 | 
			
		||||
        label: "Tab"
 | 
			
		||||
    Del:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Delete"
 | 
			
		||||
    Insert:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Insert"
 | 
			
		||||
    Menu:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Menu"
 | 
			
		||||
    Pause:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Pause"
 | 
			
		||||
    Break:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Break"
 | 
			
		||||
    Home:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Home"
 | 
			
		||||
    End:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "End"
 | 
			
		||||
    PgUp:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Page_Up"
 | 
			
		||||
    PgDn:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Page_Down"
 | 
			
		||||
    "↑":
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Up"
 | 
			
		||||
    "↓":
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Down"
 | 
			
		||||
    "←":
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Left"
 | 
			
		||||
    "→":
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Right"
 | 
			
		||||
    Up:
 | 
			
		||||
        label: "↑"
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Up"
 | 
			
		||||
    Left:
 | 
			
		||||
        label: "←"
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Left"
 | 
			
		||||
    Down:
 | 
			
		||||
        label: "↓"
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Down"
 | 
			
		||||
    Right:
 | 
			
		||||
        label: "→"
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Right"
 | 
			
		||||
    Ctrl:
 | 
			
		||||
        modifier: "Control"
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        label: "Ctrl"
 | 
			
		||||
    Alt:
 | 
			
		||||
        modifier: "Alt"
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        label: "Alt"
 | 
			
		||||
    period:
 | 
			
		||||
        outline: "special"
 | 
			
		||||
        text: "."
 | 
			
		||||
    show_actions:
 | 
			
		||||
        action:
 | 
			
		||||
            set_view: "actions"
 | 
			
		||||
        outline: "special"
 | 
			
		||||
        label: ">_"
 | 
			
		||||
    Shift_L:
 | 
			
		||||
        action:
 | 
			
		||||
            locking:
 | 
			
		||||
                lock_view: "upper"
 | 
			
		||||
                unlock_view: "base"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        icon: "key-shift"
 | 
			
		||||
    BackSpace:
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        icon: "edit-clear-symbolic"
 | 
			
		||||
        action: erase
 | 
			
		||||
    preferences:
 | 
			
		||||
        action: "show_prefs"
 | 
			
		||||
        outline: "special"
 | 
			
		||||
        icon: "keyboard-mode-symbolic"
 | 
			
		||||
    show_numbers:
 | 
			
		||||
        action:
 | 
			
		||||
            set_view: "numbers"
 | 
			
		||||
        outline: "wide"
 | 
			
		||||
        label: "123"
 | 
			
		||||
    show_numbers_from_symbols:
 | 
			
		||||
        action:
 | 
			
		||||
            set_view: "numbers"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        label: "123"
 | 
			
		||||
    show_letters:
 | 
			
		||||
        action:
 | 
			
		||||
            set_view: "base"
 | 
			
		||||
        outline: "wide"
 | 
			
		||||
        label: "abc"
 | 
			
		||||
    show_symbols:
 | 
			
		||||
        action:
 | 
			
		||||
            set_view: "symbols"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        label: "*/="
 | 
			
		||||
    show_eschars:
 | 
			
		||||
        action:
 | 
			
		||||
            locking:
 | 
			
		||||
                lock_view: "eschars"
 | 
			
		||||
                unlock_view: "base"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        label: "âÂ"
 | 
			
		||||
    space:
 | 
			
		||||
        outline: "spaceline"
 | 
			
		||||
        text: " "
 | 
			
		||||
    Return:
 | 
			
		||||
        outline: "wide"
 | 
			
		||||
        icon: "key-enter"
 | 
			
		||||
        keysym: "Return"
 | 
			
		||||
    colon:
 | 
			
		||||
        text: ":"
 | 
			
		||||
    "\"":
 | 
			
		||||
        keysym: "quotedbl"
 | 
			
		||||
@ -1,223 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
outlines:
 | 
			
		||||
    action:    { width: 90,   height: 37 }
 | 
			
		||||
    small:     { width: 67.4, height: 22 }
 | 
			
		||||
    default:   { width: 54,  height: 37 }
 | 
			
		||||
    altline:   { width: 81,  height: 37 }
 | 
			
		||||
    wide:      { width: 100, height: 37 }
 | 
			
		||||
    spaceline: { width: 110, height: 37 }
 | 
			
		||||
    special:   { width: 54,  height: 37 }
 | 
			
		||||
 | 
			
		||||
views:
 | 
			
		||||
    base:
 | 
			
		||||
        - "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
 | 
			
		||||
        - "a z e r t y u i o p"
 | 
			
		||||
        - "q s d f g h j k l m"
 | 
			
		||||
        - "Shift_L   w x c v b n period   BackSpace"
 | 
			
		||||
        - "show_numbers preferences         space        show_eschars show_actions Return"
 | 
			
		||||
    upper:
 | 
			
		||||
        - "EscSmall TabSmall Ctrl Alt PgUp PgDn Home End"
 | 
			
		||||
        - "A Z E R T Y U I O P"
 | 
			
		||||
        - "Q S D F G H J K L M"
 | 
			
		||||
        - "Shift_L   W X C V B N ,  BackSpace"
 | 
			
		||||
        - "show_numbers preferences         space        show_eschars show_actions Return"
 | 
			
		||||
    numbers:
 | 
			
		||||
        - "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
 | 
			
		||||
        - "1 2 3 4 5 6 7 8 9 0"
 | 
			
		||||
        - "@ # € % & - _ + ( )"
 | 
			
		||||
        - "show_symbols   , \" ' colon ; ! ?  BackSpace"
 | 
			
		||||
        - "show_letters preferences         space        show_eschars show_actions Return"
 | 
			
		||||
    symbols:
 | 
			
		||||
        - "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
 | 
			
		||||
        - "~ ` | · √ π τ ÷ × ¶"
 | 
			
		||||
        - "© ® £ $ ¥ ^ ° * { }"
 | 
			
		||||
        - "show_numbers_from_symbols   \\ / < > = [ ]  BackSpace"
 | 
			
		||||
        - "show_letters preferences         space        show_eschars show_actions Return"
 | 
			
		||||
    eschars:
 | 
			
		||||
        - "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
 | 
			
		||||
        - "à â ç é è ê î ô ù û"
 | 
			
		||||
        - "À Â Ç É È Ê Î Ô Ù Û"
 | 
			
		||||
        - "show_numbers_from_symbols  æ œ ä ë ï ö ü  BackSpace"
 | 
			
		||||
        - "show_letters preferences         space        show_eschars show_actions Return"
 | 
			
		||||
    actions:
 | 
			
		||||
        - "EscSmall TabSmall Ctrl Alt PgUp PgDn Home End"
 | 
			
		||||
        - "F1  F2  F3  F4  F5  F6"
 | 
			
		||||
        - "F7  F8  F9  F10 F11 F12"
 | 
			
		||||
        - "Esc Tab Pause Insert Up Del"
 | 
			
		||||
        - "show_letters Menu Break Left Down Right"
 | 
			
		||||
 
 | 
			
		||||
buttons:
 | 
			
		||||
    F1:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F1"
 | 
			
		||||
    F2:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F2"
 | 
			
		||||
    F3:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F3"
 | 
			
		||||
    F4:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F4"
 | 
			
		||||
    F5:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F5"
 | 
			
		||||
    F6:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F6"
 | 
			
		||||
    F7:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F7"
 | 
			
		||||
    F8:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F8"
 | 
			
		||||
    F9:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F9"
 | 
			
		||||
    F10:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F10"
 | 
			
		||||
    F11:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F11"
 | 
			
		||||
    F12:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "F12"
 | 
			
		||||
    Esc:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Escape"
 | 
			
		||||
    EscSmall:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Escape"
 | 
			
		||||
        label: "Esc"
 | 
			
		||||
    Tab:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Tab"
 | 
			
		||||
    TabSmall:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Tab"
 | 
			
		||||
        label: "Tab"
 | 
			
		||||
    Del:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Delete"
 | 
			
		||||
    Insert:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Insert"
 | 
			
		||||
    Menu:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Menu"
 | 
			
		||||
    Pause:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Pause"
 | 
			
		||||
    Break:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Break"
 | 
			
		||||
    Home:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Home"
 | 
			
		||||
    End:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "End"
 | 
			
		||||
    PgUp:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Page_Up"
 | 
			
		||||
    PgDn:
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Page_Down"
 | 
			
		||||
    "↑":
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Up"
 | 
			
		||||
    "↓":
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Down"
 | 
			
		||||
    "←":
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Left"
 | 
			
		||||
    "→":
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        keysym: "Right"
 | 
			
		||||
    Up:
 | 
			
		||||
        label: "↑"
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Up"
 | 
			
		||||
    Left:
 | 
			
		||||
        label: "←"
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Left"
 | 
			
		||||
    Down:
 | 
			
		||||
        label: "↓"
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Down"
 | 
			
		||||
    Right:
 | 
			
		||||
        label: "→"
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Right"
 | 
			
		||||
    Ctrl:
 | 
			
		||||
        modifier: "Control"
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        label: "Ctrl"
 | 
			
		||||
    Alt:
 | 
			
		||||
        modifier: "Alt"
 | 
			
		||||
        outline: "small"
 | 
			
		||||
        label: "Alt"
 | 
			
		||||
    period:
 | 
			
		||||
        outline: "special"
 | 
			
		||||
        text: "."
 | 
			
		||||
    show_actions:
 | 
			
		||||
        action:
 | 
			
		||||
            set_view: "actions"
 | 
			
		||||
        outline: "special"
 | 
			
		||||
        label: ">_"
 | 
			
		||||
    Shift_L:
 | 
			
		||||
        action:
 | 
			
		||||
            locking:
 | 
			
		||||
                lock_view: "upper"
 | 
			
		||||
                unlock_view: "base"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        icon: "key-shift"
 | 
			
		||||
    BackSpace:
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        icon: "edit-clear-symbolic"
 | 
			
		||||
        action: erase
 | 
			
		||||
    preferences:
 | 
			
		||||
        action: "show_prefs"
 | 
			
		||||
        outline: "special"
 | 
			
		||||
        icon: "keyboard-mode-symbolic"
 | 
			
		||||
    show_numbers:
 | 
			
		||||
        action:
 | 
			
		||||
            set_view: "numbers"
 | 
			
		||||
        outline: "wide"
 | 
			
		||||
        label: "123"
 | 
			
		||||
    show_numbers_from_symbols:
 | 
			
		||||
        action:
 | 
			
		||||
            set_view: "numbers"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        label: "123"
 | 
			
		||||
    show_letters:
 | 
			
		||||
        action:
 | 
			
		||||
            set_view: "base"
 | 
			
		||||
        outline: "wide"
 | 
			
		||||
        label: "abc"
 | 
			
		||||
    show_symbols:
 | 
			
		||||
        action:
 | 
			
		||||
            set_view: "symbols"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        label: "*/="
 | 
			
		||||
    show_eschars:
 | 
			
		||||
        action:
 | 
			
		||||
            locking:
 | 
			
		||||
                lock_view: "eschars"
 | 
			
		||||
                unlock_view: "base"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        label: "âÂ"
 | 
			
		||||
    space:
 | 
			
		||||
        outline: "spaceline"
 | 
			
		||||
        text: " "
 | 
			
		||||
    Return:
 | 
			
		||||
        outline: "wide"
 | 
			
		||||
        icon: "key-enter"
 | 
			
		||||
        keysym: "Return"
 | 
			
		||||
    colon:
 | 
			
		||||
        text: ":"
 | 
			
		||||
    "\"":
 | 
			
		||||
        keysym: "quotedbl"
 | 
			
		||||
@ -155,6 +155,9 @@ buttons:
 | 
			
		||||
    Pause:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Pause"
 | 
			
		||||
    Menu:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Menu"
 | 
			
		||||
    Break:
 | 
			
		||||
        outline: "action"
 | 
			
		||||
        keysym: "Break"
 | 
			
		||||
							
								
								
									
										540
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										540
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@ -1,94 +1,508 @@
 | 
			
		||||
squeekboard (1.14.0-1pureos1) byzantium; urgency=medium
 | 
			
		||||
squeekboard (1.12.0pureos0~amber0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * debian: New upstream release
 | 
			
		||||
  * docs: Correct Cargo update instructions
 | 
			
		||||
  * visibility: Centralize keyboard panel visibility policy and handling
 | 
			
		||||
  * build: Fix release
 | 
			
		||||
  * tests: Prefer the env var for finding test layouts
 | 
			
		||||
  * tests: Explicitly pass source directory to tests
 | 
			
		||||
  * debian: Build reproducibly
 | 
			
		||||
  * tests: Allow legacy mode to have much longer tests.
 | 
			
		||||
  * build: Enable unused warnings in C
 | 
			
		||||
  * build: Enable wformat to remove warnings about missing wformat
 | 
			
		||||
  * build: Fail on any C warnings when strict
 | 
			
		||||
  * data: Made data flow in fallback clearer
 | 
			
		||||
  * data: Flattened layout fallback function
 | 
			
		||||
  * layouts: Use base as fallback for alternative layouts
 | 
			
		||||
  * layouts: Simplify the main flow of source list
 | 
			
		||||
  * tests: Add some description to the list of tested layouts
 | 
			
		||||
  * layout_names: Unmess the list of builtin layouts
 | 
			
		||||
  * dbus: Reset hints if text input missing
 | 
			
		||||
  * visibility: Stop calling GTK functions from the visibility manager
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Sat, 22 May 2021 14:19:27 +0000
 | 
			
		||||
  [ Wannaphong Phatthiyaphaibun ]
 | 
			
		||||
  * Add thai keyboard
 | 
			
		||||
  * Update resources.rs
 | 
			
		||||
  * Update meson.build
 | 
			
		||||
  * escape " on thai keyboard
 | 
			
		||||
 | 
			
		||||
squeekboard (1.13.0-1pureos1) byzantium; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * debian: New upstream release
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Mon, 12 Apr 2021 10:50:32 +0000a
 | 
			
		||||
 | 
			
		||||
squeekboard (1.12.0-1pureos1) byzantium; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * debian: New Byzantium release
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Thu, 28 Jan 2021 14:36:20 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.12.0-1) unstable; urgency=medium
 | 
			
		||||
  [ clonex10100 ]
 | 
			
		||||
  * Added US Colemak Keyboard Layout
 | 
			
		||||
 | 
			
		||||
  [ Henry-Nicolas Tourneur ]
 | 
			
		||||
  * d/rules: fix an FTBFS on mips64el with GOT > 64kb
 | 
			
		||||
  * d/rules: export RUSTFLAGS only on architecture that needs it
 | 
			
		||||
  * d/rules: export RUSTFLAGS only on architecture that needs it
 | 
			
		||||
 | 
			
		||||
  [ Jiří Stránský ]
 | 
			
		||||
  * Add Czech keyboard layouts
 | 
			
		||||
 | 
			
		||||
  [ Stefan Grotz ]
 | 
			
		||||
  * Esperanto keyboard
 | 
			
		||||
 | 
			
		||||
  [ Vladimir ]
 | 
			
		||||
  * Bulgarian language keyboard layout
 | 
			
		||||
 | 
			
		||||
  [ Vladimir Stoilov ]
 | 
			
		||||
  * bulgarian add translation and to needed lists
 | 
			
		||||
  * Fix bulgarian layout size
 | 
			
		||||
 | 
			
		||||
  [ Andreas Rönnquist ]
 | 
			
		||||
  * no: Use wide button switching between numbers, symbols and base
 | 
			
		||||
 | 
			
		||||
  [ jranaraki ]
 | 
			
		||||
  * Farsi/Persian keyboard layout
 | 
			
		||||
  * Farsi/Persian keyboard layout
 | 
			
		||||
  * Added requirements to resources.rs and meson.build
 | 
			
		||||
  * Updated the layout to provide more convenient and faster typing experience
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Sun, 10 Jan 2021 09:43:42 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.11.1) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Mark Müller ]
 | 
			
		||||
  * keyboard: Fix semicolon in German layout
 | 
			
		||||
  * keyboard: Move semicolon in German layout to numbers view replacing redundant comma key
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * debian: Build reproducibly
 | 
			
		||||
  * imservice: Set up UI according to current needs when it shows up
 | 
			
		||||
  * UI: Keep visibility factors in a central place
 | 
			
		||||
  * cargo: Update deps
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Sat, 21 Nov 2020 11:08:06 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.11.0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * UI: Delay hiding only when leaving a text field
 | 
			
		||||
  * ui: Cancel hiding delay when activity requested again
 | 
			
		||||
  * Update dependencies
 | 
			
		||||
 | 
			
		||||
  [ Fabio Tomat ]
 | 
			
		||||
  * Update fur-IT.txt fix typo for Spanish
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Sat, 14 Nov 2020 06:46:28 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.10.0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * virtual_keyboard: Fix desynced modifiers state
 | 
			
		||||
  * rust: Fix deprecation warnings
 | 
			
		||||
  * docs: Tutorial syntax cleanups
 | 
			
		||||
  * docs: Reorganize tutorial
 | 
			
		||||
  * build: Error on repeating declarations
 | 
			
		||||
  * keymap: Generate from symbol map, not layout
 | 
			
		||||
  * data: Restore testability of action->keysym conversion
 | 
			
		||||
  * syntax: Let older rustc understand symbolmap's lifetime
 | 
			
		||||
  * debian: Insert a "breaks" for librem5-base < 24
 | 
			
		||||
  * keymap: Keep keymap fd management in one place
 | 
			
		||||
  * vkeyboard: Use a generic slice instead of a vector
 | 
			
		||||
  * tests: Check for missing return in builtin layouts except emoji
 | 
			
		||||
  * keymap: Concentrate special handling of BackSpace, which is implicit in Erase action
 | 
			
		||||
  * keymaps: Use multiple key maps, each within the limit of what Xorg can accept.
 | 
			
		||||
  * build: Avoid MaybeUninit on older Debian
 | 
			
		||||
  * tests: Fix bad field access
 | 
			
		||||
  * cargo: Update dependencies
 | 
			
		||||
 | 
			
		||||
  [ Guido Günther ]
 | 
			
		||||
  * eekboard-context-service: Return early if schema is unavailable
 | 
			
		||||
  * treewide: Use new style function definitions
 | 
			
		||||
  * build: Enable '-Wold-style-definition' '-Wstrict-prototypes'
 | 
			
		||||
  * build: Enable '-Wunused-function'
 | 
			
		||||
  * eekboard-context-service: Drop EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE
 | 
			
		||||
  * keyboard: Fix warning
 | 
			
		||||
  * layout: Fix warning
 | 
			
		||||
  * gitlab-ci: Enable --Werror
 | 
			
		||||
  * eek-keyboard: Don't ignore return value
 | 
			
		||||
  * build: Enable -Winit-self
 | 
			
		||||
  * build: Enable -Wformat-security
 | 
			
		||||
  * build: Enable -Wmaybe-uninitialized
 | 
			
		||||
  * treewide: Drop redundant declarations
 | 
			
		||||
  * build: Enable -Wredundant-declarations
 | 
			
		||||
  * ServerContextService: Drop GObject boilerplate
 | 
			
		||||
  * build: Enable '-Wformat-nonliteral'
 | 
			
		||||
  * eekboad-context-service: Drop signal class handler
 | 
			
		||||
  * eekboard-context-service: Drop docstrings for inexistent functions
 | 
			
		||||
  * eekboard-context-service: Drop the GObject boilerplate
 | 
			
		||||
  * eekboard-context-service: Drop private struct
 | 
			
		||||
  * server-context-service: Consistenty name self argument 'self'
 | 
			
		||||
  * server-context-service: swap signal arguments
 | 
			
		||||
  * server-context-service: Don't show keyboard when disabled (Closes: #222)
 | 
			
		||||
 | 
			
		||||
  [ Nazarii Kretovych ]
 | 
			
		||||
  * Add Ukrainian keyboard layout.
 | 
			
		||||
 | 
			
		||||
  [ Benjamin Schaaf ]
 | 
			
		||||
  * Fix spelling mistakes in doc/hacking.md
 | 
			
		||||
  * Expand the development documentation in the readme
 | 
			
		||||
  * Expand key press detection to the edges of the view's bounding box
 | 
			
		||||
  * Sort layouts by type before sorting by name
 | 
			
		||||
  * Fix leak in level_keyboard_new
 | 
			
		||||
  * Fix leak endlessly adding a resource path to the default theme
 | 
			
		||||
  * Add settings option to popover
 | 
			
		||||
 | 
			
		||||
  [ Al ]
 | 
			
		||||
  * proposal for belgian layout (copy of fr)
 | 
			
		||||
  * alphabetical order for src/resources.rs tests/meson.build
 | 
			
		||||
 | 
			
		||||
  [ Arnaud Ferraris ]
 | 
			
		||||
  * New upstream version 1.12.0
 | 
			
		||||
  * eek-gtk-keyboard: use virtual resolution to check arrangement kind
 | 
			
		||||
  * server-context-service: optimize height calculation
 | 
			
		||||
  * keyboards: add wide French layout
 | 
			
		||||
  * keyboards: add wide Belgian layout
 | 
			
		||||
  * keyboards: add wide terminal layout
 | 
			
		||||
 | 
			
		||||
 -- Arnaud Ferraris <arnaud.ferraris@gmail.com>  Tue, 26 Jan 2021 18:19:42 +0100
 | 
			
		||||
  [ Fabio Tomat ]
 | 
			
		||||
  * Revert "Add friulian keyboard"
 | 
			
		||||
 | 
			
		||||
squeekboard (1.11.1-1) unstable; urgency=medium
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Mon, 19 Oct 2020 14:07:01 +0000
 | 
			
		||||
 | 
			
		||||
  * New upstream version 1.11.1
 | 
			
		||||
squeekboard (1.9.3) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
 -- Arnaud Ferraris <arnaud.ferraris@gmail.com>  Tue, 24 Nov 2020 11:52:41 +0100
 | 
			
		||||
  [ Björn Tantau ]
 | 
			
		||||
  * Show more useful keys at the same time.
 | 
			
		||||
  * Add Ctrl and Alt modifier keys.
 | 
			
		||||
  * Add missing Ê key.
 | 
			
		||||
  * Make f-keys slightly wider.
 | 
			
		||||
  * Add Menu key.
 | 
			
		||||
 | 
			
		||||
squeekboard (1.11.0-1) unstable; urgency=medium
 | 
			
		||||
  [ Guido Günther ]
 | 
			
		||||
  * d/rules: Only remove Cargo.lock if it exists
 | 
			
		||||
  * eek: Drop libcanberra usage
 | 
			
		||||
  * debian: Build-depend on libfeedback
 | 
			
		||||
  * eek-gtk-keyboard: Trigger event feedback on button press (Closes: #166)
 | 
			
		||||
 | 
			
		||||
  * New upstream release 1.11.0
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * build: Add missing gio-unix dependency
 | 
			
		||||
  * build: Make compatible with Debian Bullseye
 | 
			
		||||
  * debian: Add amber to legacy distro list
 | 
			
		||||
  * ci: Add amber job
 | 
			
		||||
  * debian: Require lsb-release
 | 
			
		||||
  * size: Hardcode size to work around screen rotation
 | 
			
		||||
  * ci: Re-add x64 Buster build
 | 
			
		||||
  * italian: Fix space and period
 | 
			
		||||
 | 
			
		||||
 -- Arnaud Ferraris <arnaud.ferraris@gmail.com>  Mon, 16 Nov 2020 11:17:23 +0100
 | 
			
		||||
  [ Sebastian Krzyszkowiak ]
 | 
			
		||||
  * Revert "Merge branch 'btantau-master-patch-76686' into 'master'"
 | 
			
		||||
  * Terminal layout: another approach
 | 
			
		||||
 | 
			
		||||
squeekboard (1.10.0-2) unstable; urgency=medium
 | 
			
		||||
  [ Luís Fernando Stürmer da Rosa ]
 | 
			
		||||
  * Brazilian Portuguese Keyboard Layout.
 | 
			
		||||
 | 
			
		||||
  * Team upload.
 | 
			
		||||
  * d/rules: set RUSTFLAGS to avoid an FTBFS on mips64el (Closes: #974036)
 | 
			
		||||
 -- Sebastian Krzyszkowiak <sebastian.krzyszkowiak@puri.sm>  Wed, 05 Aug 2020 16:16:08 +0200
 | 
			
		||||
 | 
			
		||||
 -- Henry-Nicolas Tourneur <debian@nilux.be>  Tue, 10 Nov 2020 18:40:50 +0000
 | 
			
		||||
squeekboard (1.9.2) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
squeekboard (1.10.0-1) unstable; urgency=medium
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * keyboard: Remove unused code
 | 
			
		||||
  * gsettings: Don't crash when unavailable
 | 
			
		||||
  * dbus: Don't crash if can't make a connection
 | 
			
		||||
  * gsettings: Don't crash on switching when unavailable
 | 
			
		||||
  * layout: Split out choice to a struct on its own
 | 
			
		||||
  * renderer: Simplify by dropping gobjectness
 | 
			
		||||
  * levelkeyboard: Rearrange to make future conversion easier
 | 
			
		||||
  * layout: Minor generalizations
 | 
			
		||||
  * Remove unused code
 | 
			
		||||
  * sizing: Create a standalone UI shape manager
 | 
			
		||||
  * sizing: Ignore scaling factor for layout selection
 | 
			
		||||
  * CI: Fix typo
 | 
			
		||||
  * Update rust deps for release
 | 
			
		||||
 | 
			
		||||
  * New upstream release 1.10.0
 | 
			
		||||
  * d/control: build-depend on libfeedbackd-dev and set team maintainership
 | 
			
		||||
  * d/control: fix dependency name
 | 
			
		||||
  * d/copyright: add missing entries
 | 
			
		||||
  * d/copyright: add entries for new keyboard files and remove duplicate
 | 
			
		||||
    `src/meson.build` appeared in 2 different paragraphs, remove the
 | 
			
		||||
    duplicate entry.
 | 
			
		||||
  * d/gbp.conf: fix debian version number
 | 
			
		||||
  [ Andreas Rönnquist ]
 | 
			
		||||
  * Swedish keyboard, wide button switching between numbers, symbols and base
 | 
			
		||||
  * More fixes of button sizes
 | 
			
		||||
  * Folder is doc, not docs
 | 
			
		||||
 | 
			
		||||
 -- Arnaud Ferraris <arnaud.ferraris@gmail.com>  Fri, 23 Oct 2020 13:18:43 +0200
 | 
			
		||||
  [ uzanto ]
 | 
			
		||||
  * Add new file
 | 
			
		||||
  * Replace duplicated show_symbols by show_eschars and removed "Delete" button that it's doing nothing
 | 
			
		||||
 | 
			
		||||
squeekboard (1.9.3-1) experimental; urgency=medium
 | 
			
		||||
  [ Arnaud Ferraris ]
 | 
			
		||||
  * keyboards: fr: fix keyboard layout
 | 
			
		||||
  * keyboards: fr: make sure the layout fits the screen
 | 
			
		||||
  * resources: include French keyboard layout
 | 
			
		||||
  * keyboards: fr: improve consistency with other layouts
 | 
			
		||||
  * keyboards: fr: improve diacritics layout
 | 
			
		||||
  * tests: add french layout
 | 
			
		||||
 | 
			
		||||
  * Upload to experimental
 | 
			
		||||
  * Update upstream source from tag 'v1.9.3'
 | 
			
		||||
    Update to upstream version '1.9.3'
 | 
			
		||||
    with Debian dir 7a3f8b82779759ba288b75755ba54500250b0ff4
 | 
			
		||||
  * d/control: Use librust-xkbcommon-dev
 | 
			
		||||
    This one avoids the empty feature package.
 | 
			
		||||
  * Ship sm.puri.OSK0.desktop.
 | 
			
		||||
    This is needed to fulfill phosh's session dependencies
 | 
			
		||||
  * Conflict with phosh-osk-stub.
 | 
			
		||||
    They're not useful at the same time and we'll drop phosh-osk-stub from
 | 
			
		||||
    Debian once squeekboard is in.
 | 
			
		||||
  * Drop pathes no longer required due to upstream changes
 | 
			
		||||
    - 0001-Cargo.toml-update-to-Debian-dependencies-versions.patch
 | 
			
		||||
    - 0002-popover.rs-fix-build-with-gtk-rs-0.7.0.patch
 | 
			
		||||
  * d/gbp.conf: Don't use patch numbers.
 | 
			
		||||
    Ordering is defined via the series file and patch numbers just
 | 
			
		||||
    cause manual work.
 | 
			
		||||
  [ Vlad ]
 | 
			
		||||
  * Fresh Russian layout
 | 
			
		||||
 | 
			
		||||
 -- Guido Günther <agx@sigxcpu.org>  Sat, 26 Sep 2020 13:01:18 +0200
 | 
			
		||||
  [ Jordi Masip ]
 | 
			
		||||
  * Removed unused dependency 'libcroco'
 | 
			
		||||
 | 
			
		||||
squeekboard (1.9.2-1) UNRELEASED; urgency=medium
 | 
			
		||||
  [ Florian Klink ]
 | 
			
		||||
  * sm.puri.Squeekboard.desktop: make path to Exec= absolute
 | 
			
		||||
 | 
			
		||||
  * Initial Debian release (Closes: #956960)
 | 
			
		||||
  [ Ole Guldberg ]
 | 
			
		||||
  * Danish keyboard layout
 | 
			
		||||
  * Danish keyboard layout
 | 
			
		||||
  * add test for danish layout
 | 
			
		||||
 | 
			
		||||
 -- Arnaud Ferraris <arnaud.ferraris@gmail.com>  Tue, 09 Jun 2020 23:29:19 +0200
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Mon, 01 Jun 2020 09:39:12 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.9.1) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * layout: Improve press handling
 | 
			
		||||
  * settings: Handle empty settings
 | 
			
		||||
  * Variant: Use proper pointer conversion between C and Rust
 | 
			
		||||
  * meta: Add doap file
 | 
			
		||||
  * modifiers: Support Control and Alt
 | 
			
		||||
  * CI: Test that any bump to changelog has a corresponding tag
 | 
			
		||||
  * docs: Add the guiding principle
 | 
			
		||||
  * hacking: Move into docs/
 | 
			
		||||
 | 
			
		||||
  [ &t ]
 | 
			
		||||
  * Fix minor comment typos
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * cargo: Bump package versions before release
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Sun, 08 Mar 2020 10:04:29 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.9.0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * imservice: Add commit_string method
 | 
			
		||||
  * submission: Handle submitting strings
 | 
			
		||||
  * input_method: Use for erasing
 | 
			
		||||
  * logging: Use in merged functions
 | 
			
		||||
  * translations: Remove redundant ones
 | 
			
		||||
  * translations: Translate builtin layouts
 | 
			
		||||
  * greek: Rename to gr which is used by gnome settings
 | 
			
		||||
 | 
			
		||||
  [ Sebastian Krzyszkowiak ]
 | 
			
		||||
  * layouts: Add Polish layouts
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * locks: Draw based on current view
 | 
			
		||||
  * locking: Lock keys statelessly
 | 
			
		||||
  * layouts: Better accented uppercase in PL
 | 
			
		||||
  * emoji: Add more choices
 | 
			
		||||
  * row: Eliminate angle
 | 
			
		||||
  * layout: Center views relative to each other and the layout bounds
 | 
			
		||||
  * drawing: Generalized foreach_visible_button
 | 
			
		||||
  * variant: Fix double-free
 | 
			
		||||
  * variant: Fix leak
 | 
			
		||||
  * keyboard_layout: Fix leak
 | 
			
		||||
  * layout: Improve scoping of locked variable
 | 
			
		||||
  * terminal: Make */ easier to reach
 | 
			
		||||
 | 
			
		||||
  [ Sebastian Krzyszkowiak ]
 | 
			
		||||
  * layouts: terminal: Use altline outline for dot key
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * text input: Disable erasing
 | 
			
		||||
  * cargo: Update deps
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Wed, 19 Feb 2020 14:32:39 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.8.1) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * action: Rename Level to View
 | 
			
		||||
  * keyboard: Introduce a KeyCode type wrapping u32
 | 
			
		||||
  * layout: Centralize handling key releases
 | 
			
		||||
  * layout: Make handling presses uniform
 | 
			
		||||
  * UI: Drop indirection for show/hide functions
 | 
			
		||||
  * managers: Move visible flag to UI manager
 | 
			
		||||
  * dbus_service: Remove unused function
 | 
			
		||||
  * dbus: Remove unneeded gobjectness
 | 
			
		||||
  * dbus: Rename handler from eekboard_service
 | 
			
		||||
  * context: Moved keymap setting together with its generation
 | 
			
		||||
  * key-emitter: Remove unused
 | 
			
		||||
  * eekboard_context_service: Drop unused enable property
 | 
			
		||||
  * services: Split out layout management from EekboardContextService
 | 
			
		||||
  * submission: Move away from virtual-keyboard
 | 
			
		||||
  * submission: Create a new wrapper over imservice
 | 
			
		||||
  * imservice: Limited scope of unsafe
 | 
			
		||||
  * EekGtkKeyboard: Use a direct reference to EekboardContext
 | 
			
		||||
  * submission: Take over virtual_keyboard handling
 | 
			
		||||
  * keyboard: Cleanups of unused code
 | 
			
		||||
  * levelkeyboard: Drop unused manager references
 | 
			
		||||
  * keyboard: Gather up keymap handling, drop layout
 | 
			
		||||
  * submission: Remove wildcard reexport
 | 
			
		||||
  * imservice: Rename commit_state to done to match protocol
 | 
			
		||||
  * ci: Clean up `..` before it's searched for artifacts
 | 
			
		||||
  * dbus: Log error on dbus exit
 | 
			
		||||
  * logging: Try to improve common operations
 | 
			
		||||
  * imservice: Return something more resembling an Error on failure
 | 
			
		||||
  * logging: Unified to remove random eprint calls
 | 
			
		||||
  * press_key: Use proper logging
 | 
			
		||||
  * number: Fix keysym for Return
 | 
			
		||||
  * build: Strip clap of optional features
 | 
			
		||||
  * layouts: Fix segfault on switching to wide
 | 
			
		||||
  * font: Use font from style context
 | 
			
		||||
  * font: Only pass relevant data to label renderer
 | 
			
		||||
 | 
			
		||||
  [ Sebastian Krzyszkowiak ]
 | 
			
		||||
  * layout: terminal: Swap positions of preferences and actions button
 | 
			
		||||
  * layout: terminal: Show actions button on all views
 | 
			
		||||
  * layout: terminal: Replace actions button with period on symbols view
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * setup: Connect ui to the state manager
 | 
			
		||||
  * debian: Add missing commas
 | 
			
		||||
 | 
			
		||||
  [ David Boddie ]
 | 
			
		||||
  * Tidy build file and docs
 | 
			
		||||
  * Use pip to install recommonmark
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Fri, 31 Jan 2020 09:59:12 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.8.0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * translations: Use gnome-desktop's xkb info database for layout names
 | 
			
		||||
  * translations: Make the code cleaner
 | 
			
		||||
  * overlay: Add terminal
 | 
			
		||||
  * eek-layout: Remove unused
 | 
			
		||||
  * pre-release: Update deps
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Tue, 14 Jan 2020 13:55:00 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.7.0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * New terminal layout appearing on terminal input hint
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Wed, 08 Jan 2020 11:53:07 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.7.0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * New terminal layout appearing on terminal input hint
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Wed, 08 Jan 2020 11:53:07 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.6.0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * tools: Move entry.py
 | 
			
		||||
  * build: Move building of squeekboard-test-layout to tools
 | 
			
		||||
  * packaging: Install entty.py as squeekboard-entry
 | 
			
		||||
  * Remove unused build dependencies
 | 
			
		||||
  * Remove unused header generator
 | 
			
		||||
  * logging: Move all facilities to one file
 | 
			
		||||
  * logging: Described the design
 | 
			
		||||
  * logging: Add described log levels
 | 
			
		||||
  * popover: Install emoji layout
 | 
			
		||||
  * popover: Show overlays as selected
 | 
			
		||||
  * Fix old Rust woes
 | 
			
		||||
  * emoji: Add a passable layout
 | 
			
		||||
  * Fix g_ and stdlib allocation/free mismatches
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Thu, 02 Jan 2020 12:02:50 +0000
 | 
			
		||||
 
 | 
			
		||||
squeekboard (1.5.0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * keycodes: Sort to eliminate runtime indeterminism
 | 
			
		||||
  * switcher: Switch layout on menu item click
 | 
			
		||||
  * Drop squeek_key
 | 
			
		||||
  * renderer: Remove some unneeded vars
 | 
			
		||||
  * renderer: Simplified outline rendering
 | 
			
		||||
  * renderer: Drop row from button rendering
 | 
			
		||||
  * renderer: Drop unused params
 | 
			
		||||
  * renderer: Simplify surface rendering
 | 
			
		||||
  * rendering: Simplify Cairo context usage, remove unneeded calls.
 | 
			
		||||
  * rendering: Remove unneeded redraw after button release
 | 
			
		||||
  * renderer: Remove unused locked key render function
 | 
			
		||||
  * renderer: Simply cut off when painting outside bounds
 | 
			
		||||
  * renderer: Render whole keyboard the same way as pressed buttons
 | 
			
		||||
 | 
			
		||||
  [ Mark Müller ]
 | 
			
		||||
  * layout: add German wide layout
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * renderer: Remove unused functions
 | 
			
		||||
  * cleanup: Remove references to squeek_view
 | 
			
		||||
  * cleanup: Unbox View and Row
 | 
			
		||||
  * cleanup: Remove unused single frame draw
 | 
			
		||||
  * positioning: Calculate sizes instead of storing, move position out of widgets
 | 
			
		||||
  * positioning: Clean up unused code
 | 
			
		||||
  * Fix old Rust woes
 | 
			
		||||
 | 
			
		||||
  [ Mark Müller ]
 | 
			
		||||
  * layout: add Japanese Kana wide layout
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * Entry test: Add Terminal input purpose
 | 
			
		||||
  * readme: Add note about Cargo dependencies
 | 
			
		||||
  * Create a library/UI module separation
 | 
			
		||||
  * hacking: Add DCO and licensing requirement
 | 
			
		||||
  * Fix internal .md link
 | 
			
		||||
 | 
			
		||||
  [ Mark Müller ]
 | 
			
		||||
  * squeekboard-test-layout: add argument parsing and some more output
 | 
			
		||||
 | 
			
		||||
  [ Dorota Czaplejewicz ]
 | 
			
		||||
  * Use clap in the lockfile
 | 
			
		||||
  * parsing: Remove bounds which weren't used anyway
 | 
			
		||||
  * layout: Respect margins
 | 
			
		||||
  * CI: Build arm64 .deb
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Mon, 23 Dec 2019 11:58:57 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.4.0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * "text" property in layouts
 | 
			
		||||
  * Adjusts to user's color scheme
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Mon, 02 Dec 2019 19:37:01 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.3.2) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Make sure all key presses get accepted by the compositor
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Tue, 26 Nov 2019 15:36:27 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.3.1) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Update and fix layouts and languages
 | 
			
		||||
  * Make tests less likely to fail
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Wed, 20 Nov 2019 22:10:48 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.3.0) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Language selection popup
 | 
			
		||||
  * Swedish and Finnish layouts
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Sat, 16 Nov 2019 15:38:14 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.2.2) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Landscape mode
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Wed, 30 Oct 2019 12:38:39 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.2.1) amber-phone; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Use different distribution
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Tue, 08 Oct 2019 10:56:10 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.2.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Use Cargo-based dependencies
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Tue, 24 Sep 2019 10:42:15 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.1.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Use new keyboard layout format
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Mon, 02 Sep 2019 10:12:02 +0000
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
squeekboard (1.0.10) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Use a shared DBus definition
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Tue, 02 Jul 2019 20:12:02 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.0.9) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Initial release.
 | 
			
		||||
 | 
			
		||||
 -- David Boddie <david.boddie@puri.sm>  Tue, 25 Jun 2019 19:33:00 +0200
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							@ -1 +1 @@
 | 
			
		||||
10
 | 
			
		||||
12
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@ -31,8 +31,6 @@ Build-Depends:
 | 
			
		||||
 wayland-protocols (>= 1.14),
 | 
			
		||||
Standards-Version: 4.1.3
 | 
			
		||||
Homepage: https://source.puri.sm/Librem5/squeekboard
 | 
			
		||||
Vcs-Browser: https://source.puri.sm/pureos/squeekboard
 | 
			
		||||
Vcs-Git: https://source.puri.sm/pureos/squeekboard.git
 | 
			
		||||
 | 
			
		||||
Package: squeekboard
 | 
			
		||||
Architecture: linux-any
 | 
			
		||||
@ -43,6 +41,7 @@ Depends:
 | 
			
		||||
 ${misc:Depends},
 | 
			
		||||
Breaks:
 | 
			
		||||
 librem5-base (<< 24),
 | 
			
		||||
 phosh (<= 0.10),
 | 
			
		||||
Description: On-screen keyboard for Wayland
 | 
			
		||||
 Virtual keyboard supporting Wayland, built primarily for the Librem 5 phone.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								debian/gbp.conf
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								debian/gbp.conf
									
									
									
									
										vendored
									
									
								
							@ -1,7 +0,0 @@
 | 
			
		||||
[DEFAULT]
 | 
			
		||||
debian-branch = pureos/byzantium
 | 
			
		||||
debian-tag = pureos/%(version)s
 | 
			
		||||
debian-tag-msg = %(pkg)s %(version)s
 | 
			
		||||
 | 
			
		||||
[tag]
 | 
			
		||||
sign-tags = true
 | 
			
		||||
							
								
								
									
										29
									
								
								debian/librem5-ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								debian/librem5-ci.yml
									
									
									
									
										vendored
									
									
								
							@ -1,29 +0,0 @@
 | 
			
		||||
include:
 | 
			
		||||
 - 'https://source.puri.sm/Librem5/librem5-ci/raw/master/librem5-pipeline-definitions.yml'
 | 
			
		||||
 - 'https://source.puri.sm/Librem5/librem5-ci/raw/master/librem5-pipeline-byzantium-jobs.yml'
 | 
			
		||||
 | 
			
		||||
stages:
 | 
			
		||||
 - package
 | 
			
		||||
 - test-package
 | 
			
		||||
 | 
			
		||||
.tags: &tags
 | 
			
		||||
  tags:
 | 
			
		||||
    - librem5
 | 
			
		||||
 | 
			
		||||
check_release:
 | 
			
		||||
  <<: *tags
 | 
			
		||||
  stage: test-package
 | 
			
		||||
  only:
 | 
			
		||||
    refs:
 | 
			
		||||
      - pureos/byzantium
 | 
			
		||||
  script:
 | 
			
		||||
    - apt-get -y install git python3
 | 
			
		||||
    - (head -n 1 ./debian/changelog && git tag) | ./debian/check_release.py
 | 
			
		||||
 | 
			
		||||
# check-tarball relies on the contents of other branches,
 | 
			
		||||
# which are irrelevant for MRs. It's similar to checking tags in this way.
 | 
			
		||||
check-tarball:
 | 
			
		||||
  extends: .l5-check-tarball
 | 
			
		||||
  only:
 | 
			
		||||
    refs:
 | 
			
		||||
        - pureos/byzantium
 | 
			
		||||
							
								
								
									
										2
									
								
								debian/source/format
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/source/format
									
									
									
									
										vendored
									
									
								
							@ -1 +1 @@
 | 
			
		||||
3.0 (quilt)
 | 
			
		||||
3.0 (native)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								debian/squeekboard.install
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/squeekboard.install
									
									
									
									
										vendored
									
									
								
							@ -1,2 +1,2 @@
 | 
			
		||||
tools/squeekboard-restyled usr/bin
 | 
			
		||||
usr/bin/squeekboard /usr/bin
 | 
			
		||||
usr/share/applications/sm.puri.Squeekboard.desktop
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								debian/squeekboard.user.service
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								debian/squeekboard.user.service
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Squeekboard - a Wayland virtual keyboard
 | 
			
		||||
PartOf=graphical-session.target
 | 
			
		||||
# Don't stop restarting the program
 | 
			
		||||
StartLimitIntervalSec=0
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Environment="GTK_THEME=Adwaita:dark"
 | 
			
		||||
ExecStart=/usr/bin/squeekboard
 | 
			
		||||
 | 
			
		||||
Restart=on-failure
 | 
			
		||||
RestartSec=3s
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=graphical-session.target
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,6 @@ Contents
 | 
			
		||||
 | 
			
		||||
* [Tutorial](tutorial.md)
 | 
			
		||||
* [Contributing](hacking.md)
 | 
			
		||||
* [Switching views](views.md)
 | 
			
		||||
 | 
			
		||||
Introduction
 | 
			
		||||
------------
 | 
			
		||||
@ -22,8 +21,6 @@ Layouts are created using a text-based format, based on YAML.
 | 
			
		||||
 | 
			
		||||
TODO: Provide a description of the format.
 | 
			
		||||
 | 
			
		||||
Squeekboard layouts are separated into *views* and use a *room metaphor* to [switch views](views.md).
 | 
			
		||||
 | 
			
		||||
Contributions
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										594
									
								
								doc/latching.svg
									
									
									
									
									
								
							
							
						
						
									
										594
									
								
								doc/latching.svg
									
									
									
									
									
								
							@ -1,594 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="177.92439mm"
 | 
			
		||||
   height="88.144363mm"
 | 
			
		||||
   viewBox="0 0 177.92439 88.144364"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   id="svg8"
 | 
			
		||||
   sodipodi:docname="latching.svg"
 | 
			
		||||
   inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs2">
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Mend"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Mend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.4,0,0,-0.4,-4,0)"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1098" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow2Sstart"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow2Sstart"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(0.3,0,0,0.3,-0.69,0)"
 | 
			
		||||
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
 | 
			
		||||
         id="path1119" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow2Mstart"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow2Mstart"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="scale(0.6)"
 | 
			
		||||
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
 | 
			
		||||
         id="path1113" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-5" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect848" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-1" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect848-1" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-9" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect848-8" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-10" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect916" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-4" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect951" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-10-1" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect986" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect1061" />
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-5"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-7" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2-1" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect1549" />
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-8"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#101010;fill-opacity:1;fill-rule:evenodd;stroke:#101010;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-8" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2-3" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect1845" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2-38" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect1960" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2-3-9" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect2304" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2-3-4" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect2304-7" />
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-2"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:#6c6c6c;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-89" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-2-6"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-89-8" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-21" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect2574" />
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-2-6-1"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-89-8-0" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-2-6-6"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-89-8-2" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-10-1-8" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect3021" />
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-8-3"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#101010;fill-opacity:1;fill-rule:evenodd;stroke:#101010;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-8-5" />
 | 
			
		||||
    </marker>
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="1.3358025"
 | 
			
		||||
     inkscape:cx="212.63846"
 | 
			
		||||
     inkscape:cy="105.21093"
 | 
			
		||||
     inkscape:document-units="mm"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     inkscape:document-rotation="0"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     fit-margin-top="4"
 | 
			
		||||
     fit-margin-left="4"
 | 
			
		||||
     fit-margin-right="4"
 | 
			
		||||
     fit-margin-bottom="4"
 | 
			
		||||
     lock-margins="true"
 | 
			
		||||
     inkscape:window-width="1298"
 | 
			
		||||
     inkscape:window-height="708"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="0"
 | 
			
		||||
     inkscape:window-maximized="1" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata5">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
        <dc:title />
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     transform="translate(-72.097892,-53.326191)">
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#101010;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-8-3)"
 | 
			
		||||
       d="m 134.9616,86.141869 c 17.5759,-11.622767 35.93283,0 35.93283,0"
 | 
			
		||||
       id="path1087-1-6" />
 | 
			
		||||
    <g
 | 
			
		||||
       id="g2948">
 | 
			
		||||
      <circle
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         id="path1065-6"
 | 
			
		||||
         cx="129.67093"
 | 
			
		||||
         cy="92.793152"
 | 
			
		||||
         r="7.8844509" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-0"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(46.071199,-1.2662626)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>A</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <rect
 | 
			
		||||
       style="color:#000000;overflow:visible;fill:#f8f8f8;fill-opacity:1;stroke:#000000;stroke-width:0.555679;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
       id="rect2066"
 | 
			
		||||
       width="1.4562259"
 | 
			
		||||
       height="10.90563"
 | 
			
		||||
       x="81.767418"
 | 
			
		||||
       y="75.519585"
 | 
			
		||||
       ry="0.9693895" />
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905"
 | 
			
		||||
       transform="translate(0,-0.85044703)">
 | 
			
		||||
      <circle
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         id="path1065"
 | 
			
		||||
         cx="83.154755"
 | 
			
		||||
         cy="93.6436"
 | 
			
		||||
         r="7.8844509" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan
 | 
			
		||||
             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none">a</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-3-7"
 | 
			
		||||
       transform="translate(92.82116,-0.85044861)">
 | 
			
		||||
      <circle
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         id="path1065-6-7"
 | 
			
		||||
         cx="83.557831"
 | 
			
		||||
         cy="93.6436"
 | 
			
		||||
         r="7.8844509" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-0-5"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>Ą</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-1"
 | 
			
		||||
       transform="translate(68.838914,-17.67039)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-8"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="78.878532"
 | 
			
		||||
         y="85.920006"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-7"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.2686286,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan> ̨̂ ̈</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#101010;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-8)"
 | 
			
		||||
       d="m 88.446425,85.89509 c 17.575895,-11.622767 35.932835,0 35.932835,0"
 | 
			
		||||
       id="path1087-1" />
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="99.186691"
 | 
			
		||||
       y="66.221436"
 | 
			
		||||
       id="text1035-89"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan1033-6"
 | 
			
		||||
         x="99.186691"
 | 
			
		||||
         y="66.221436"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">locking</tspan></text>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-1-4"
 | 
			
		||||
       transform="translate(22.423434,-17.67039)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-8-3"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="78.878532"
 | 
			
		||||
         y="85.920006"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-7-3"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-3);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>⇧</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.5, 0.5;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
       d="m 83.251484,76.550079 c -0.31498,0 -0.944941,-0.314981 -0.944941,0 0,0.31498 0.770221,0.262079 0.944941,0 0.212555,-0.318834 0.08197,-0.862973 -0.188988,-1.133929 -0.132651,-0.13265 -1.931144,0.354037 -2.078869,0.944941 -0.108038,0.432149 0.877467,-0.188989 1.322916,-0.188989 0.339244,0 0.626121,0.262042 0.944941,0.377977 0.374434,0.136158 0.777569,0.199796 1.133928,0.377976 0.113894,0.05695 -0.0037,0.439732 0.944941,0.755952 0.544156,0.181385 1.78847,0.275251 2.267857,0.377976 0.448438,0.09609 0.881944,0.251984 1.322917,0.377977 0.063,0.188988 0.388199,0.566964 0.188988,0.566964 -0.195153,0 -0.745291,-0.93961 0,-0.566964 0.281726,0.140863 0.485859,0.404908 0.755952,0.566964 1.460327,0.876196 3.039871,1.714659 4.346726,2.834821 0.966187,0.828161 1.495207,2.006597 2.645833,2.645834 2.876101,1.597834 5.000414,0.287454 7.370534,1.133929 0.4783,0.170821 0.85136,0.567325 1.32292,0.755952 1.8557,0.74228 0.94424,0.230907 2.26785,0.377976 1.47287,0.16365 2.67387,1.06159 4.15774,0.566965 1.22233,-0.407443 3.2674,-1.377519 4.15774,-2.267858 0.39842,-0.398422 0.42845,-1.053404 0.75595,-1.511905 0.50136,-0.70189 1.27041,-1.107171 1.7009,-1.889881 2.28615,-4.156632 0.41931,-1.931216 3.2128,-4.724702 0.18898,-0.188988 0.33491,-0.434362 0.56696,-0.566964 0.864,-0.493714 5.11938,-0.281812 6.04762,-0.188989 0.34449,0.03445 3.71968,0.978261 3.96875,1.133929 0.35339,0.220868 1.41179,1.650838 1.88988,1.889881 0.80324,0.40162 2.22057,0.354332 3.02381,0.755952 1.24832,0.624162 -0.45041,0.669376 -0.18899,1.322917 0.1193,0.298244 0.64418,0.0762 0.94494,0.188988 0.28702,0.107634 1.48279,1.113549 1.5119,1.133929 2.56034,1.792236 -0.96522,-0.855663 2.26786,1.133928 1.61516,0.993946 2.82802,2.547938 4.53572,3.401785 2.03418,1.017093 4.38487,-0.122885 6.42559,-0.377975 1.6791,-0.209886 3.23813,0.06137 4.91369,-0.566965 0.50424,-0.18909 1.82709,-1.701063 2.26786,-2.078869 0.45926,-0.393653 1.0853,-0.707329 1.5119,-1.133928 0.81561,-0.815609 1.44764,-1.826091 2.45685,-2.456845 0.28768,-0.179799 0.65726,-0.198178 0.94494,-0.377977 0.28791,-0.179945 0.60349,-0.774216 0.94494,-0.94494 0.23232,-0.116159 0.51479,-0.09252 0.75595,-0.188988 0.21089,-0.08436 0.33983,-0.377976 0.56697,-0.377976 0.14086,0 0.23711,0.188988 0.37797,0.188988 0.0891,0 0.126,-0.125992 0.18899,-0.188988 0.18899,-0.063 0.36976,-0.217161 0.56696,-0.188988 0.77174,0.110248 1.92711,0.94494 3.02381,0.94494 0.16785,0 0.94189,-0.862638 1.13393,-0.94494 0.19546,-0.08377 1.57981,-0.364523 1.7009,-0.377977 0.72233,-0.08026 2.11645,0.340388 2.64583,-0.188988"
 | 
			
		||||
       id="path2010" />
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="73.802078"
 | 
			
		||||
       y="72.354546"
 | 
			
		||||
       id="text2091"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan2089"
 | 
			
		||||
         x="73.802078"
 | 
			
		||||
         y="72.354546"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">SAVED</tspan></text>
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="164.55956"
 | 
			
		||||
       y="72.354546"
 | 
			
		||||
       id="text2091-8"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan2089-8"
 | 
			
		||||
         x="164.55956"
 | 
			
		||||
         y="72.354546"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">CURRENT</tspan><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         x="164.55956"
 | 
			
		||||
         y="79.410095"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
 | 
			
		||||
         id="tspan3432" /></text>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g2259"
 | 
			
		||||
       transform="matrix(1.0856157,0,0,0.94777147,-19.677062,6.4360598)">
 | 
			
		||||
      <path
 | 
			
		||||
         id="rect2111-9"
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         d="m 179.53502,72.72924 h 5.84717 l -1.37074,1.931346 h -3.04292 z"
 | 
			
		||||
         sodipodi:nodetypes="ccccc" />
 | 
			
		||||
      <path
 | 
			
		||||
         id="rect2111-9-0"
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         d="m 179.4049,80.846668 h 5.84717 l -1.23711,-1.931347 h -3.17655 z"
 | 
			
		||||
         sodipodi:nodetypes="ccccc" />
 | 
			
		||||
      <g
 | 
			
		||||
         id="g2247"
 | 
			
		||||
         transform="translate(-0.04032786,-0.04319387)">
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,75.343053 2.96688,-0.19452"
 | 
			
		||||
           id="path2145"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,76.112065 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-3"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,76.881078 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-0"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,77.65009 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-2"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,78.419102 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-4"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
      </g>
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-0"
 | 
			
		||||
       transform="translate(157.32586,-0.83970203)" />
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="145.70187"
 | 
			
		||||
       y="66.221436"
 | 
			
		||||
       id="text1035-89-2"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan1033-6-9"
 | 
			
		||||
         x="145.70187"
 | 
			
		||||
         y="66.221436"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">locking</tspan></text>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 26 KiB  | 
@ -1,631 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="169.9455mm"
 | 
			
		||||
   height="98.072433mm"
 | 
			
		||||
   viewBox="0 0 169.94549 98.072434"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   id="svg8"
 | 
			
		||||
   sodipodi:docname="latching_return.svg"
 | 
			
		||||
   inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs2">
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-10-1" />
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-5"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-7" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2-38" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2-3-9" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2-3-4" />
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-2-6"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-89-8" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-21" />
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-2-6-1"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-89-8-0" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-2-6-6"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-89-8-2" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-10-1-8" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-12" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-10-7" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="0.94455498"
 | 
			
		||||
     inkscape:cx="314.8465"
 | 
			
		||||
     inkscape:cy="213.42055"
 | 
			
		||||
     inkscape:document-units="mm"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     inkscape:document-rotation="0"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     fit-margin-top="4"
 | 
			
		||||
     fit-margin-left="4"
 | 
			
		||||
     fit-margin-right="4"
 | 
			
		||||
     fit-margin-bottom="4"
 | 
			
		||||
     lock-margins="true"
 | 
			
		||||
     inkscape:window-width="1298"
 | 
			
		||||
     inkscape:window-height="708"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="0"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     showguides="false" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata5">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
        <dc:title></dc:title>
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     transform="translate(-70.551731,-46.47634)">
 | 
			
		||||
    <g
 | 
			
		||||
       id="g3858"
 | 
			
		||||
       transform="translate(1.354821,1.4005714)">
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
         x="204.75821"
 | 
			
		||||
         y="130.07979"
 | 
			
		||||
         id="text2293-4"><tspan
 | 
			
		||||
           sodipodi:role="line"
 | 
			
		||||
           id="tspan2291-1"
 | 
			
		||||
           x="204.75821"
 | 
			
		||||
           y="130.07979"
 | 
			
		||||
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">✄</tspan></text>
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
         x="194.54915"
 | 
			
		||||
         y="128.70164"
 | 
			
		||||
         id="text2293-0-5-8"><tspan
 | 
			
		||||
           sodipodi:role="line"
 | 
			
		||||
           id="tspan2291-6-7-5"
 | 
			
		||||
           x="194.54915"
 | 
			
		||||
           y="128.70164"
 | 
			
		||||
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">cuts</tspan></text>
 | 
			
		||||
      <path
 | 
			
		||||
         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         d="m 210.34971,123.9389 c 0.0233,0.14006 0.07,0.27818 0.07,0.42017 0,0.0738 -0.07,0.13627 -0.07,0.21009 0,0.11902 0.0582,0.23171 0.07,0.35014 0.049,0.49035 0.0857,0.98109 0.14006,1.4706 0.018,0.1624 -0.0269,0.32902 0,0.4902 0.0435,0.26077 0.11166,0.3369 0,0.56023 -0.0209,0.0418 0.033,0.10705 0,0.14006 -0.0369,0.0369 -0.10315,0.0331 -0.14006,0.07"
 | 
			
		||||
         id="path3816-9" />
 | 
			
		||||
      <path
 | 
			
		||||
         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         d="m 209.9819,128.43627 c -0.12445,0.48957 -0.1295,0.98859 -0.0743,1.48553 0.0118,0.10583 0.01,0.21643 0.0248,0.32186 -0.002,0.0627 0.0396,0.11405 0.0495,0.17332 0.0144,0.0866 -0.0193,0.077 0,0.17331 0.0124,0.0621 0.20619,0.18971 0.24759,0.22283"
 | 
			
		||||
         id="path3820-7" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-2-6-1)"
 | 
			
		||||
       d="m 180.7405,85.345284 c 21.77006,-11.52723 44.50758,0 44.50758,0"
 | 
			
		||||
       id="path1087-3-0-8" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="color:#000000;overflow:visible;fill:#f8f8f8;fill-opacity:1;stroke:#000000;stroke-width:0.555679;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
       id="rect2066"
 | 
			
		||||
       width="1.4562259"
 | 
			
		||||
       height="10.90563"
 | 
			
		||||
       x="81.767418"
 | 
			
		||||
       y="75.519585"
 | 
			
		||||
       ry="0.9693895" />
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-3-7"
 | 
			
		||||
       transform="translate(92.629263,-0.8504468)">
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-0-5"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>Ą</tspan></tspan></text>
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-4-9"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="78.266167"
 | 
			
		||||
         y="86.745537"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.4em;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="174.86499"
 | 
			
		||||
       y="130.79413"
 | 
			
		||||
       id="text1035-8"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         x="174.86499"
 | 
			
		||||
         y="130.79413"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
 | 
			
		||||
         id="tspan2277">locking</tspan><tspan
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         x="174.86499"
 | 
			
		||||
         y="135.11462"
 | 
			
		||||
         id="tspan1606" /></text>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-1-6"
 | 
			
		||||
       transform="translate(90.668095,26.90725)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-8-0"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="78.878532"
 | 
			
		||||
         y="85.920006"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-7-4"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-38);fill:#f8f8f8;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.2686286,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan
 | 
			
		||||
             style="fill:#f8f8f8;fill-opacity:1"> ̨̂ ̈</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.5, 0.5;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
       d="m 83.251484,76.550079 c -0.31498,0 -0.944941,-0.314981 -0.944941,0 0,0.31498 0.770221,0.262079 0.944941,0 0.212555,-0.318834 0.08197,-0.862973 -0.188988,-1.133929 -0.132651,-0.13265 -1.931144,0.354037 -2.078869,0.944941 -0.108038,0.432149 0.877467,-0.188989 1.322916,-0.188989 0.339244,0 0.626121,0.262042 0.944941,0.377977 0.374434,0.136158 0.777569,0.199796 1.133928,0.377976 0.113894,0.05695 -0.0037,0.439732 0.944941,0.755952 0.544156,0.181385 1.78847,0.275251 2.267857,0.377976 0.448438,0.09609 0.881944,0.251984 1.322917,0.377977 0.063,0.188988 0.388199,0.566964 0.188988,0.566964 -0.195153,0 -0.745291,-0.93961 0,-0.566964 0.281726,0.140863 0.485859,0.404908 0.755952,0.566964 1.460327,0.876196 3.039871,1.714659 4.346726,2.834821 0.966187,0.828161 1.495207,2.006597 2.645833,2.645834 2.876101,1.597834 5.000414,0.287454 7.370534,1.133929 0.4783,0.170821 0.85136,0.567325 1.32292,0.755952 1.8557,0.74228 0.94424,0.230907 2.26785,0.377976 1.47287,0.16365 2.67387,1.06159 4.15774,0.566965 1.22233,-0.407443 3.2674,-1.377519 4.15774,-2.267858 0.39842,-0.398422 0.42845,-1.053404 0.75595,-1.511905 0.50136,-0.70189 1.27041,-1.107171 1.7009,-1.889881 2.28615,-4.156632 0.41931,-1.931216 3.2128,-4.724702 0.18898,-0.188988 0.33491,-0.434362 0.56696,-0.566964 0.864,-0.493714 5.11938,-0.281812 6.04762,-0.188989 0.34449,0.03445 3.71968,0.978261 3.96875,1.133929 0.35339,0.220868 1.41179,1.650838 1.88988,1.889881 0.80324,0.40162 2.22057,0.354332 3.02381,0.755952 1.24832,0.624162 -0.45041,0.669376 -0.18899,1.322917 0.1193,0.298244 0.64418,0.0762 0.94494,0.188988 0.28702,0.107634 1.48279,1.113549 1.5119,1.133929 2.56034,1.792236 -0.96522,-0.855663 2.26786,1.133928 1.61516,0.993946 2.82802,2.547938 4.53572,3.401785 2.03418,1.017093 4.38487,-0.122885 6.42559,-0.377975 1.6791,-0.209886 3.23813,0.06137 4.91369,-0.566965 0.50424,-0.18909 1.82709,-1.701063 2.26786,-2.078869 0.45926,-0.393653 1.0853,-0.707329 1.5119,-1.133928 0.81561,-0.815609 1.44764,-1.826091 2.45685,-2.456845 0.28768,-0.179799 0.65726,-0.198178 0.94494,-0.377977 0.28791,-0.179945 0.60349,-0.774216 0.94494,-0.94494 0.23232,-0.116159 0.51479,-0.09252 0.75595,-0.188988 0.21089,-0.08436 0.33983,-0.377976 0.56697,-0.377976 0.14086,0 0.23711,0.188988 0.37797,0.188988 0.0891,0 0.126,-0.125992 0.18899,-0.188988 0.18899,-0.063 0.36976,-0.217161 0.56696,-0.188988 0.77174,0.110248 1.92711,0.94494 3.02381,0.94494 0.16785,0 0.94189,-0.862638 1.13393,-0.94494 0.19546,-0.08377 1.57981,-0.364523 1.7009,-0.377977 0.72233,-0.08026 2.11645,0.340388 2.64583,-0.188988"
 | 
			
		||||
       id="path2010" />
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="74.331245"
 | 
			
		||||
       y="71.825378"
 | 
			
		||||
       id="text2091"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan2089"
 | 
			
		||||
         x="74.331245"
 | 
			
		||||
         y="71.825378"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">SAVED</tspan></text>
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="164.23172"
 | 
			
		||||
       y="70.186089"
 | 
			
		||||
       id="text2091-8"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan2089-8"
 | 
			
		||||
         x="164.23172"
 | 
			
		||||
         y="70.186089"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">CURRENT</tspan><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         x="164.23172"
 | 
			
		||||
         y="77.241638"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
 | 
			
		||||
         id="tspan3432" /></text>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g2259"
 | 
			
		||||
       transform="matrix(1.0856157,0,0,0.94777147,-20.206229,4.319393)">
 | 
			
		||||
      <path
 | 
			
		||||
         id="rect2111-9"
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         d="m 179.53502,72.72924 h 5.84717 l -1.37074,1.931346 h -3.04292 z"
 | 
			
		||||
         sodipodi:nodetypes="ccccc" />
 | 
			
		||||
      <path
 | 
			
		||||
         id="rect2111-9-0"
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         d="m 179.4049,80.846668 h 5.84717 l -1.23711,-1.931347 h -3.17655 z"
 | 
			
		||||
         sodipodi:nodetypes="ccccc" />
 | 
			
		||||
      <g
 | 
			
		||||
         id="g2247"
 | 
			
		||||
         transform="translate(-0.04032786,-0.04319387)">
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,75.343053 2.96688,-0.19452"
 | 
			
		||||
           id="path2145"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,76.112065 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-3"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,76.881078 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-0"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,77.65009 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-2"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,78.419102 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-4"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
      </g>
 | 
			
		||||
    </g>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-5)"
 | 
			
		||||
       d="m 173.01207,99.691217 c 0,0 -8.37295,13.367043 -0.26038,13.813423 9.36786,0.51544 7.89797,-9.16673 6.50059,-13.41252"
 | 
			
		||||
       id="path2269"
 | 
			
		||||
       sodipodi:nodetypes="csc" />
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="176.93353"
 | 
			
		||||
       y="138.21815"
 | 
			
		||||
       id="text2293"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan2291"
 | 
			
		||||
         x="176.93353"
 | 
			
		||||
         y="138.21815"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">✄</tspan></text>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-2-6)"
 | 
			
		||||
       d="m 181.46685,99.71436 c 21.61425,11.51564 44.18902,0 44.18902,0"
 | 
			
		||||
       id="path1087-3-0" />
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="195.7271"
 | 
			
		||||
       y="122.96945"
 | 
			
		||||
       id="text1035-89-7"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan1033-6-5"
 | 
			
		||||
         x="195.7271"
 | 
			
		||||
         y="122.96945"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">set_view</tspan></text>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-1-4-4"
 | 
			
		||||
       transform="translate(120.23594,18.477932)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-8-3-8"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="78.878532"
 | 
			
		||||
         y="85.920006"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-7-3-1"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-3-4);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>⇧</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.36em;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="196.99921"
 | 
			
		||||
       y="61.359337"
 | 
			
		||||
       id="text1035-89-4"><tspan
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan3987"
 | 
			
		||||
         x="196.99921"
 | 
			
		||||
         y="61.359337">locking</tspan><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         x="196.99921"
 | 
			
		||||
         y="65.362335"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
 | 
			
		||||
         id="tspan3985">pops: false</tspan></text>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-1-4-9"
 | 
			
		||||
       transform="translate(120.23594,-18.828317)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-8-3-2"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="78.878532"
 | 
			
		||||
         y="85.920006"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-7-3-2"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-3-9);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>⇧</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-0"
 | 
			
		||||
       transform="translate(147.8008,-0.83970203)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-5"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="77.863091"
 | 
			
		||||
         y="86.745537"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-1"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-21);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>ą</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-2-6-6)"
 | 
			
		||||
       d="m 170.49256,99.691217 c -49.40563,31.667983 -82.046134,0 -82.046134,0"
 | 
			
		||||
       id="path1087-3-0-5"
 | 
			
		||||
       sodipodi:nodetypes="cc" />
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-3-7-6"
 | 
			
		||||
       transform="translate(45.925334,26.134402)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-4-9-8"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="78.266167"
 | 
			
		||||
         y="86.745537"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-0-5-2"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1-8);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>Ą</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.4em;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="129.60217"
 | 
			
		||||
       y="131.30838"
 | 
			
		||||
       id="text1035-8-4"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         x="129.60217"
 | 
			
		||||
         y="131.30838"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
 | 
			
		||||
         id="tspan2277-2">text</tspan><tspan
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         x="129.60217"
 | 
			
		||||
         y="135.62888"
 | 
			
		||||
         id="tspan1606-4" /></text>
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.58611px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="123.67847"
 | 
			
		||||
       y="136.8163"
 | 
			
		||||
       id="text2293-0"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan2291-6"
 | 
			
		||||
         x="123.67847"
 | 
			
		||||
         y="136.8163"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.58611px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">returns</tspan></text>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905"
 | 
			
		||||
       transform="translate(1.1299757e-7,-0.85044747)">
 | 
			
		||||
      <circle
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         id="path1065"
 | 
			
		||||
         cx="83.154755"
 | 
			
		||||
         cy="93.6436"
 | 
			
		||||
         r="7.8844509" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-12);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan
 | 
			
		||||
             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none">a</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g2948">
 | 
			
		||||
      <circle
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         id="path1065-6"
 | 
			
		||||
         cx="129.67093"
 | 
			
		||||
         cy="92.793152"
 | 
			
		||||
         r="7.8844509" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-0"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-7);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(46.071199,-1.2662626)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>A</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g2259-3"
 | 
			
		||||
       transform="matrix(0.61171471,0,0,0.53404326,8.8050741,94.418409)">
 | 
			
		||||
      <path
 | 
			
		||||
         id="rect2111-9-1"
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         d="m 179.53502,72.72924 h 5.84717 l -1.37074,1.931346 h -3.04292 z"
 | 
			
		||||
         sodipodi:nodetypes="ccccc" />
 | 
			
		||||
      <path
 | 
			
		||||
         id="rect2111-9-0-7"
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         d="m 179.4049,80.846668 h 5.84717 l -1.23711,-1.931347 h -3.17655 z"
 | 
			
		||||
         sodipodi:nodetypes="ccccc" />
 | 
			
		||||
      <g
 | 
			
		||||
         id="g2247-5"
 | 
			
		||||
         transform="translate(-0.04032786,-0.04319387)">
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,75.343053 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-9"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,76.112065 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-3-6"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,76.881078 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-0-2"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,77.65009 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-2-1"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
           d="m 181.02302,78.419102 2.96688,-0.19452"
 | 
			
		||||
           id="path2145-4-7"
 | 
			
		||||
           sodipodi:nodetypes="cc" />
 | 
			
		||||
      </g>
 | 
			
		||||
    </g>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.265;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.06, 0.53;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
       d="m 119.51485,135.86385 c -0.50656,0.62998 -2.26796,0.26701 -2.85105,0.85011 -0.52314,0.52314 2.02401,2.4426 3.96141,3.16913 2.94083,1.1028 4.79827,0.22 7.72476,-0.19807 0.3268,-0.0467 0.66473,0.0543 0.99035,0 1.72749,-0.28792 3.39512,-0.79539 5.14984,-0.99036 1.10207,-0.12245 0.49735,0.0622 1.58457,0.19807 0.91825,0.11479 1.8542,0.0832 2.77299,0.19807 0.86919,0.10865 1.70964,-0.19807 2.57492,-0.19807"
 | 
			
		||||
       id="path3796" />
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="166.72447"
 | 
			
		||||
       y="136.84001"
 | 
			
		||||
       id="text2293-0-5"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan2291-6-7"
 | 
			
		||||
         x="166.72447"
 | 
			
		||||
         y="136.84001"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">cuts</tspan></text>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529166;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
       d="m 182.52503,132.07727 c 0.0233,0.14006 0.07,0.27818 0.07,0.42017 0,0.0738 -0.07,0.13627 -0.07,0.21009 0,0.11902 0.0582,0.23171 0.07,0.35014 0.049,0.49035 0.0857,0.98109 0.14006,1.4706 0.018,0.1624 -0.0269,0.32902 0,0.4902 0.0435,0.26077 0.11166,0.3369 0,0.56023 -0.0209,0.0418 0.033,0.10705 0,0.14006 -0.0369,0.0369 -0.10315,0.0331 -0.14006,0.07"
 | 
			
		||||
       id="path3816" />
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529166;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
       d="m 182.15722,136.57464 c -0.12445,0.48957 -0.1295,0.98859 -0.0743,1.48553 0.0118,0.10583 0.01,0.21643 0.0248,0.32186 -0.002,0.0627 0.0396,0.11405 0.0495,0.17332 0.0144,0.0866 -0.0193,0.077 0,0.17331 0.0124,0.0621 0.20619,0.18971 0.24759,0.22283"
 | 
			
		||||
       id="path3820" />
 | 
			
		||||
    <g
 | 
			
		||||
       id="g3858-9"
 | 
			
		||||
       transform="translate(1.354821,-73.436839)">
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
         x="204.75821"
 | 
			
		||||
         y="130.07979"
 | 
			
		||||
         id="text2293-4-6"><tspan
 | 
			
		||||
           sodipodi:role="line"
 | 
			
		||||
           id="tspan2291-1-4"
 | 
			
		||||
           x="204.75821"
 | 
			
		||||
           y="130.07979"
 | 
			
		||||
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">✄</tspan></text>
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
         x="194.54915"
 | 
			
		||||
         y="128.70164"
 | 
			
		||||
         id="text2293-0-5-8-3"><tspan
 | 
			
		||||
           sodipodi:role="line"
 | 
			
		||||
           id="tspan2291-6-7-5-3"
 | 
			
		||||
           x="194.54915"
 | 
			
		||||
           y="128.70164"
 | 
			
		||||
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">cuts</tspan></text>
 | 
			
		||||
      <path
 | 
			
		||||
         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         d="m 210.34971,123.9389 c 0.0233,0.14006 0.07,0.27818 0.07,0.42017 0,0.0738 -0.07,0.13627 -0.07,0.21009 0,0.11902 0.0582,0.23171 0.07,0.35014 0.049,0.49035 0.0857,0.98109 0.14006,1.4706 0.018,0.1624 -0.0269,0.32902 0,0.4902 0.0435,0.26077 0.11166,0.3369 0,0.56023 -0.0209,0.0418 0.033,0.10705 0,0.14006 -0.0369,0.0369 -0.10315,0.0331 -0.14006,0.07"
 | 
			
		||||
         id="path3816-9-3" />
 | 
			
		||||
      <path
 | 
			
		||||
         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         d="m 209.9819,128.43627 c -0.12445,0.48957 -0.1295,0.98859 -0.0743,1.48553 0.0118,0.10583 0.01,0.21643 0.0248,0.32186 -0.002,0.0627 0.0396,0.11405 0.0495,0.17332 0.0144,0.0866 -0.0193,0.077 0,0.17331 0.0124,0.0621 0.20619,0.18971 0.24759,0.22283"
 | 
			
		||||
         id="path3820-7-8" />
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 39 KiB  | 
@ -1,386 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="70.905495mm"
 | 
			
		||||
   height="78.260262mm"
 | 
			
		||||
   viewBox="0 0 70.905494 78.260262"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   id="svg8"
 | 
			
		||||
   inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
 | 
			
		||||
   sodipodi:docname="switching.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs2">
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Mend"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Mend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.4,0,0,-0.4,-4,0)"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1098" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow2Sstart"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow2Sstart"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(0.3,0,0,0.3,-0.69,0)"
 | 
			
		||||
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
 | 
			
		||||
         id="path1119" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow2Mstart"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow2Mstart"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="scale(0.6)"
 | 
			
		||||
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
 | 
			
		||||
         id="path1113" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-5" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect848" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-1" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect848-1" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-9" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect848-8" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-10" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect916" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-4" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect951" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-10-1" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect986" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect1061" />
 | 
			
		||||
    <marker
 | 
			
		||||
       style="overflow:visible"
 | 
			
		||||
       id="Arrow1Lend-5"
 | 
			
		||||
       refX="0"
 | 
			
		||||
       refY="0"
 | 
			
		||||
       orient="auto"
 | 
			
		||||
       inkscape:stockid="Arrow1Lend"
 | 
			
		||||
       inkscape:isstock="true">
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
 | 
			
		||||
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
 | 
			
		||||
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
 | 
			
		||||
         id="path1092-7" />
 | 
			
		||||
    </marker>
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect835-2-1" />
 | 
			
		||||
    <rect
 | 
			
		||||
       x="80.886902"
 | 
			
		||||
       y="89.202377"
 | 
			
		||||
       width="18.898809"
 | 
			
		||||
       height="20.410713"
 | 
			
		||||
       id="rect1549" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="0.98994949"
 | 
			
		||||
     inkscape:cx="136.49044"
 | 
			
		||||
     inkscape:cy="110.83537"
 | 
			
		||||
     inkscape:document-units="mm"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     inkscape:document-rotation="0"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     fit-margin-top="4"
 | 
			
		||||
     fit-margin-left="4"
 | 
			
		||||
     fit-margin-right="4"
 | 
			
		||||
     fit-margin-bottom="4"
 | 
			
		||||
     lock-margins="true"
 | 
			
		||||
     inkscape:window-width="1298"
 | 
			
		||||
     inkscape:window-height="708"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="0"
 | 
			
		||||
     inkscape:window-maximized="1" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata5">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
        <dc:title></dc:title>
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     transform="translate(-70.899889,-58.974186)">
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.265;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
 | 
			
		||||
       d="m 88.446426,85.895089 c 17.575894,-11.622767 35.932844,0 35.932844,0"
 | 
			
		||||
       id="path1087" />
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905"
 | 
			
		||||
       transform="translate(0,-0.85044703)">
 | 
			
		||||
      <circle
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         id="path1065"
 | 
			
		||||
         cx="83.03434"
 | 
			
		||||
         cy="93.834679"
 | 
			
		||||
         r="7.8844509" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.16231537,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan
 | 
			
		||||
             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none">a</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-3"
 | 
			
		||||
       transform="translate(46.113101,-0.85044703)">
 | 
			
		||||
      <circle
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
 | 
			
		||||
         id="path1065-3"
 | 
			
		||||
         cx="83.557831"
 | 
			
		||||
         cy="93.366959"
 | 
			
		||||
         r="7.8844509" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-0"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>A</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-7"
 | 
			
		||||
       transform="translate(-0.94494048,73.232887)">
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-6"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-4);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>ą</tspan></tspan></text>
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-3"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="77.863091"
 | 
			
		||||
         y="86.745537"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-3-7"
 | 
			
		||||
       transform="translate(49.136911,68.319196)">
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-0-5"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>Ą</tspan></tspan></text>
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-4-9"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="78.266167"
 | 
			
		||||
         y="86.745537"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="90.548096"
 | 
			
		||||
       y="65.654472"
 | 
			
		||||
       id="text1035"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan1033"
 | 
			
		||||
         x="90.548096"
 | 
			
		||||
         y="65.654472"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52778px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">set_view: upper</tspan></text>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-1"
 | 
			
		||||
       transform="translate(22.423437,-17.670388)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-8"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="78.878532"
 | 
			
		||||
         y="85.920006"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-7"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan>⇧</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-5)"
 | 
			
		||||
       d="m 124.74085,99.691217 c -17.5759,11.622773 -35.932849,0 -35.932849,0"
 | 
			
		||||
       id="path1087-4" />
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.4em;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
       x="91.116165"
 | 
			
		||||
       y="123.76147"
 | 
			
		||||
       id="text1035-8"><tspan
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan1033-5"
 | 
			
		||||
         x="91.116165"
 | 
			
		||||
         y="123.76147"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">locking</tspan><tspan
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         id="tspan1604"
 | 
			
		||||
         x="91.116165"
 | 
			
		||||
         y="128.08197">lock_view: upper</tspan><tspan
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
 | 
			
		||||
         sodipodi:role="line"
 | 
			
		||||
         x="91.116165"
 | 
			
		||||
         y="132.40247"
 | 
			
		||||
         id="tspan1606">unlock_view: lower</tspan></text>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g905-1-9"
 | 
			
		||||
       transform="translate(22.423437,17.64464)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;overflow:visible;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
         id="rect900-8-7"
 | 
			
		||||
         width="10.583333"
 | 
			
		||||
         height="13.79613"
 | 
			
		||||
         x="78.878532"
 | 
			
		||||
         y="85.920006"
 | 
			
		||||
         ry="1.937705" />
 | 
			
		||||
      <text
 | 
			
		||||
         xml:space="preserve"
 | 
			
		||||
         id="text833-7-5"
 | 
			
		||||
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-1);fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
 | 
			
		||||
         transform="translate(-0.04189825,-0.41581583)"><tspan
 | 
			
		||||
           x="80.886719"
 | 
			
		||||
           y="96.225952"><tspan
 | 
			
		||||
             style="fill:#ffffff;fill-opacity:1">⇧</tspan></tspan></text>
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 16 KiB  | 
							
								
								
									
										64
									
								
								doc/views.md
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								doc/views.md
									
									
									
									
									
								
							@ -1,64 +0,0 @@
 | 
			
		||||
Switching views
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
Squeekboard layout files are separated into *views*.
 | 
			
		||||
 | 
			
		||||
What are views?
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
A view is the button arrangement which you see on Squeekboard's panel. The view always spans the entire panel area, so it's not possible to see two views at the same time, even if the layout contains multiple views.
 | 
			
		||||
 | 
			
		||||
Views are useful because they allow to have many more buttons than would fit on the panel at the same time. That works because views can be switched.
 | 
			
		||||
 | 
			
		||||
Views are different from layouts: they can be switched without affecting the active language, and without touching the globe button. Layouts cannot share views, so switching layouts *always* switches views.
 | 
			
		||||
 | 
			
		||||
Switching views
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
The model selected for switching views is less similar to "levels" known from physical keyboards, but closer to "rooms", which may resemble a game map.
 | 
			
		||||
 | 
			
		||||
Buttons don't have states. It's more of a model where each view is a room, and buttons are doors. Switching means moving to the next room, and buttons highlight according to which view/room they lead to or from.
 | 
			
		||||
 | 
			
		||||
There are two basic kinds of switching buttons: one way (`set_view`), and two way (`locking`). `locking` is the more sophisticated one. When placed inside `lock_view`, it is drawn highlighted, and goes to `unlock view`. When placed inside any other view, it behaves like `set_view`.
 | 
			
		||||
 | 
			
		||||
 This diagram shows which buttons can switch between two views. Views are shown as circles, and buttons as rounded rectangles.
 | 
			
		||||
The two buttons are separate, and visible only in the view *from which the switch starts*. Note that the `locking` button is shown highlighted. That's because it's in `upper` view, which matches its `lock_view`.
 | 
			
		||||
 | 
			
		||||
Latching
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
`locking` buttons provide a second mode of operation: latching. It's useful when the target view is needed only for a single button press, like entering a single accent or a single capital letter in Latin scripts.
 | 
			
		||||
 | 
			
		||||
When a latching button is pressed, the keyboard remembers to come back to the current (source) view, and then the view is switched. If another `locking` button is pressed, the source view stays in memory. If a text button is pressed, the view from memory is shown again, and forgotten.
 | 
			
		||||
 | 
			
		||||
 In this diagram, the dashed line connects the view the typist is seeing to the view remembered for unlatching.
 | 
			
		||||
 | 
			
		||||
There are two ways to erase the memory without going back to the remembered view. Pressing the button again will permanently switch to the current view, and `set_view` will permanently switch to its target.
 | 
			
		||||
 | 
			
		||||
In the room metaphor, it's as if tying a thread inside the room before going through the door to the next one. And another `locking` door while holding the thread. Once the Minotaur is slain (text button pressed), the hero follows the thread back to the starting room.
 | 
			
		||||
 | 
			
		||||
The typist hero cuts the thread in two circumstances: when staying longer in the current room (press button again), or when moving through a `set_view` door.
 | 
			
		||||
 | 
			
		||||
 This diagram shows the possible ways to stop latching. One is by pressing a text button, which takes back to the original view. Another is pressing a locking button which appears highlighted (note that it can be any button, what matters is its `lock_view`). Finally, switching to another view using a button that doesn't keep the latch on forgets latching.
 | 
			
		||||
 | 
			
		||||
The layout author should pay attention that `set_view`'s lack of latching does not come as a surprise to typists.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Differences from keyboard levels
 | 
			
		||||
---------------------------------------
 | 
			
		||||
 | 
			
		||||
Views are **not** like keyboard levels.
 | 
			
		||||
 | 
			
		||||
On a physical keyboard, the number of buttons can not change when switching levels. In Squeekboard, they can have any arrangement of buttons you could imagine.
 | 
			
		||||
 | 
			
		||||
When switching levels on a keyboard, for example by pressing Shift, the key press not only affects the meaning of other keys, but also tells the application that it's pressed down. In Squeekboard, pressing buttons to change layouts *does not* do anything but switch the layout. Pressing the switching button especially *does not* tell the application that it was pressed. (This is the reason Shift and AltGr modifiers are not implemented in Squeekboard.)
 | 
			
		||||
 | 
			
		||||
Why not use the "views" model?
 | 
			
		||||
-------------------------------------
 | 
			
		||||
 | 
			
		||||
Squeekboard's goal is to support as many scripts as possible, and the author of the initial design doesn't know a whole lot. There are two problems with using the levels metaphor:
 | 
			
		||||
 | 
			
		||||
Firstly, the levels model assumes that there is a "base" and an "active" level. This does not work well with scripts that have different but equivalent modes of writing. An example is the Kana layout with Katakana and Hiragana, which are both "base".
 | 
			
		||||
Both systems could have been combined, but the view switching designer doesn't have enough experience with different scripts to do that. Some scripts may have different non-hierarchical ways to switch character groups (Balinese?), which could make combining hierarchy with free-form switching even harder.
 | 
			
		||||
 | 
			
		||||
Secondly, when dealing with languages with a hierarchy, we end up with extra work to eliminate nonsensical combinations. With "symbols" and "uppercase" levels, what does it mean to have both engaged? Eliminating that means extra work. Either validating layouts, so that it's not possible to engage "uppercase" from "symbols", or duplicating, so that "uppercase+symbols" is the same as just "symbols". With "accents" in the mix, this could become a challenge to design well.
 | 
			
		||||
@ -287,7 +287,7 @@ eek_renderer_new (LevelKeyboard  *keyboard,
 | 
			
		||||
    }
 | 
			
		||||
    gtk_style_context_add_provider (renderer->view_context,
 | 
			
		||||
        GTK_STYLE_PROVIDER(renderer->css_provider),
 | 
			
		||||
        GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 | 
			
		||||
        GTK_STYLE_PROVIDER_PRIORITY_USER);
 | 
			
		||||
 | 
			
		||||
    /* Create a style context for the buttons */
 | 
			
		||||
    path = gtk_widget_path_new();
 | 
			
		||||
@ -303,7 +303,7 @@ eek_renderer_new (LevelKeyboard  *keyboard,
 | 
			
		||||
    gtk_style_context_set_state (renderer->button_context, GTK_STATE_FLAG_NORMAL);
 | 
			
		||||
    gtk_style_context_add_provider (renderer->button_context,
 | 
			
		||||
        GTK_STYLE_PROVIDER(renderer->css_provider),
 | 
			
		||||
        GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 | 
			
		||||
        GTK_STYLE_PROVIDER_PRIORITY_USER);
 | 
			
		||||
    return renderer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -128,22 +128,30 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *state, uint32_t timestamp) {
 | 
			
		||||
    gchar *layout_name = state->layout_name;
 | 
			
		||||
    gchar *overlay_name = state->overlay_name;
 | 
			
		||||
    gchar *layout_name = state->overlay_name;
 | 
			
		||||
 | 
			
		||||
    if (layout_name == NULL) {
 | 
			
		||||
        layout_name = state->layout_name;
 | 
			
		||||
 | 
			
		||||
        switch (state->purpose) {
 | 
			
		||||
        case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER:
 | 
			
		||||
        case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE:
 | 
			
		||||
            layout_name = "number";
 | 
			
		||||
            break;
 | 
			
		||||
        case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL:
 | 
			
		||||
            layout_name = "terminal";
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            ;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    // try to get the best keyboard layout
 | 
			
		||||
        if (layout_name == NULL) {
 | 
			
		||||
            layout_name = "us";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    // overlay is "Normal" for most layouts, we will only look for "terminal" in rust code.
 | 
			
		||||
    // for now just avoid passing a null pointer
 | 
			
		||||
    if (overlay_name == NULL) {
 | 
			
		||||
        overlay_name = "";    // fallback to Normal
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // generic part follows
 | 
			
		||||
    struct squeek_layout *layout = squeek_load_layout(layout_name, state->arrangement, state->purpose, overlay_name);
 | 
			
		||||
    struct squeek_layout *layout = squeek_load_layout(layout_name, state->arrangement);
 | 
			
		||||
    LevelKeyboard *keyboard = level_keyboard_new(layout);
 | 
			
		||||
    // set as current
 | 
			
		||||
    LevelKeyboard *previous_keyboard = context->keyboard;
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
project(
 | 
			
		||||
    'squeekboard',
 | 
			
		||||
    'c', 'rust',
 | 
			
		||||
    version: '1.14.0',
 | 
			
		||||
    version: '1.12.0',
 | 
			
		||||
    license: 'GPLv3',
 | 
			
		||||
    meson_version: '>=0.51.0',
 | 
			
		||||
    default_options: [
 | 
			
		||||
 | 
			
		||||
@ -1,30 +1,32 @@
 | 
			
		||||
/* Copyright (C) 2020-2021 Purism SPC
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0+
 | 
			
		||||
 */
 | 
			
		||||
/**! The parsing of the data files for layouts */
 | 
			
		||||
 | 
			
		||||
/*! Parsing of the data files containing layouts */
 | 
			
		||||
// TODO: find a nice way to make sure non-positive sizes don't break layouts
 | 
			
		||||
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
use std::collections::{ HashMap, HashSet };
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::ffi::CString;
 | 
			
		||||
use std::fmt;
 | 
			
		||||
use std::fs;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
use std::rc::Rc;
 | 
			
		||||
use std::vec::Vec;
 | 
			
		||||
 | 
			
		||||
use xkbcommon::xkb;
 | 
			
		||||
 | 
			
		||||
use super::{ Error, LoadError };
 | 
			
		||||
 | 
			
		||||
use ::action;
 | 
			
		||||
use ::keyboard::{
 | 
			
		||||
    KeyState, PressType,
 | 
			
		||||
    generate_keymaps, generate_keycodes, KeyCode, FormattingError
 | 
			
		||||
};
 | 
			
		||||
use ::layout;
 | 
			
		||||
use ::layout::ArrangementKind;
 | 
			
		||||
use ::logging;
 | 
			
		||||
use ::util::hash_map_map;
 | 
			
		||||
use ::resources;
 | 
			
		||||
use ::util::c::as_str;
 | 
			
		||||
use ::util::hash_map_map;
 | 
			
		||||
use ::xdg;
 | 
			
		||||
 | 
			
		||||
// traits, derives
 | 
			
		||||
use serde::Deserialize;
 | 
			
		||||
@ -32,7 +34,206 @@ use std::io::BufReader;
 | 
			
		||||
use std::iter::FromIterator;
 | 
			
		||||
use ::logging::Warn;
 | 
			
		||||
 | 
			
		||||
// TODO: find a nice way to make sure non-positive sizes don't break layouts
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_load_layout(
 | 
			
		||||
        name: *const c_char,
 | 
			
		||||
        type_: u32,
 | 
			
		||||
    ) -> *mut ::layout::Layout {
 | 
			
		||||
        let type_ = match type_ {
 | 
			
		||||
            0 => ArrangementKind::Base,
 | 
			
		||||
            1 => ArrangementKind::Wide,
 | 
			
		||||
            _ => panic!("Bad enum value"),
 | 
			
		||||
        };
 | 
			
		||||
        let name = as_str(&name)
 | 
			
		||||
            .expect("Bad layout name")
 | 
			
		||||
            .expect("Empty layout name");
 | 
			
		||||
 | 
			
		||||
        let (kind, layout) = load_layout_data_with_fallback(&name, type_);
 | 
			
		||||
        let layout = ::layout::Layout::new(layout, kind);
 | 
			
		||||
        Box::into_raw(Box::new(layout))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FALLBACK_LAYOUT_NAME: &str = "us";
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum LoadError {
 | 
			
		||||
    BadData(Error),
 | 
			
		||||
    MissingResource,
 | 
			
		||||
    BadResource(serde_yaml::Error),
 | 
			
		||||
    BadKeyMap(FormattingError),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for LoadError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        use self::LoadError::*;
 | 
			
		||||
        match self {
 | 
			
		||||
            BadData(e) => write!(f, "Bad data: {}", e),
 | 
			
		||||
            MissingResource => write!(f, "Missing resource"),
 | 
			
		||||
            BadResource(e) => write!(f, "Bad resource: {}", e),
 | 
			
		||||
            BadKeyMap(e) => write!(f, "Bad key map: {}", e),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
enum DataSource {
 | 
			
		||||
    File(PathBuf),
 | 
			
		||||
    Resource(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for DataSource {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            DataSource::File(path) => write!(f, "Path: {:?}", path.display()),
 | 
			
		||||
            DataSource::Resource(name) => write!(f, "Resource: {}", name),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LayoutSource = (ArrangementKind, DataSource);
 | 
			
		||||
 | 
			
		||||
/// Lists possible sources, with 0 as the most preferred one
 | 
			
		||||
/// Trying order: native lang of the right kind, native base,
 | 
			
		||||
/// fallback lang of the right kind, fallback base
 | 
			
		||||
fn list_layout_sources(
 | 
			
		||||
    name: &str,
 | 
			
		||||
    kind: ArrangementKind,
 | 
			
		||||
    keyboards_path: Option<PathBuf>,
 | 
			
		||||
) -> Vec<LayoutSource> {
 | 
			
		||||
    // Just a simplification of often called code.
 | 
			
		||||
    let add_by_name = |
 | 
			
		||||
        mut ret: Vec<LayoutSource>,
 | 
			
		||||
        name: &str,
 | 
			
		||||
        kind: &ArrangementKind,
 | 
			
		||||
    | -> Vec<LayoutSource> {
 | 
			
		||||
        if let Some(path) = keyboards_path.clone() {
 | 
			
		||||
            ret.push((
 | 
			
		||||
                kind.clone(),
 | 
			
		||||
                DataSource::File(
 | 
			
		||||
                    path.join(name.to_owned()).with_extension("yaml")
 | 
			
		||||
                )
 | 
			
		||||
            ))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ret.push((
 | 
			
		||||
            kind.clone(),
 | 
			
		||||
            DataSource::Resource(name.into())
 | 
			
		||||
        ));
 | 
			
		||||
        ret
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Another grouping.
 | 
			
		||||
    let add_by_kind = |ret, name: &str, kind| {
 | 
			
		||||
        let ret = match kind {
 | 
			
		||||
            &ArrangementKind::Base => ret,
 | 
			
		||||
            kind => add_by_name(
 | 
			
		||||
                ret,
 | 
			
		||||
                &name_with_arrangement(name.into(), kind),
 | 
			
		||||
                kind,
 | 
			
		||||
            ),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        add_by_name(ret, name, &ArrangementKind::Base)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    fn name_with_arrangement(name: String, kind: &ArrangementKind) -> String {
 | 
			
		||||
        match kind {    
 | 
			
		||||
            ArrangementKind::Base => name,
 | 
			
		||||
            ArrangementKind::Wide => name + "_wide",
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let ret = Vec::new();
 | 
			
		||||
 | 
			
		||||
    // Name as given takes priority.
 | 
			
		||||
    let ret = add_by_kind(ret, name, &kind);
 | 
			
		||||
 | 
			
		||||
    // Then try non-alternative name if applicable (`us` for `us+colemak`).
 | 
			
		||||
    let ret = {
 | 
			
		||||
        let mut parts = name.splitn(2, '+');
 | 
			
		||||
        match parts.next() {
 | 
			
		||||
            Some(base) => {
 | 
			
		||||
                // The name is already equal to base, so it was already added.
 | 
			
		||||
                if base == name { ret }
 | 
			
		||||
                else {
 | 
			
		||||
                    add_by_kind(ret, base, &kind)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            // The layout's base name starts with a "+". Weird but OK.
 | 
			
		||||
            None => {
 | 
			
		||||
                log_print!(logging::Level::Surprise, "Base layout name is empty: {}", name);
 | 
			
		||||
                ret
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // No other choices left, so give anything.
 | 
			
		||||
    add_by_kind(ret, FALLBACK_LAYOUT_NAME.into(), &kind)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn load_layout_data(source: DataSource)
 | 
			
		||||
    -> Result<::layout::LayoutData, LoadError>
 | 
			
		||||
{
 | 
			
		||||
    let handler = logging::Print {};
 | 
			
		||||
    match source {
 | 
			
		||||
        DataSource::File(path) => {
 | 
			
		||||
            Layout::from_file(path.clone())
 | 
			
		||||
                .map_err(LoadError::BadData)
 | 
			
		||||
                .and_then(|layout|
 | 
			
		||||
                    layout.build(handler).0.map_err(LoadError::BadKeyMap)
 | 
			
		||||
                )
 | 
			
		||||
        },
 | 
			
		||||
        DataSource::Resource(name) => {
 | 
			
		||||
            Layout::from_resource(&name)
 | 
			
		||||
                .and_then(|layout|
 | 
			
		||||
                    layout.build(handler).0.map_err(LoadError::BadKeyMap)
 | 
			
		||||
                )
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn load_layout_data_with_fallback(
 | 
			
		||||
    name: &str,
 | 
			
		||||
    kind: ArrangementKind,
 | 
			
		||||
) -> (ArrangementKind, ::layout::LayoutData) {
 | 
			
		||||
    let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
 | 
			
		||||
        .map(PathBuf::from)
 | 
			
		||||
        .or_else(|| xdg::data_path("squeekboard/keyboards"));
 | 
			
		||||
    
 | 
			
		||||
    for (kind, source) in list_layout_sources(name, kind, path) {
 | 
			
		||||
        let layout = load_layout_data(source.clone());
 | 
			
		||||
        match layout {
 | 
			
		||||
            Err(e) => match (e, source) {
 | 
			
		||||
                (
 | 
			
		||||
                    LoadError::BadData(Error::Missing(e)),
 | 
			
		||||
                    DataSource::File(file)
 | 
			
		||||
                ) => log_print!(
 | 
			
		||||
                    logging::Level::Debug,
 | 
			
		||||
                    "Tried file {:?}, but it's missing: {}",
 | 
			
		||||
                    file, e
 | 
			
		||||
                ),
 | 
			
		||||
                (e, source) => log_print!(
 | 
			
		||||
                    logging::Level::Warning,
 | 
			
		||||
                    "Failed to load layout from {}: {}, skipping",
 | 
			
		||||
                    source, e
 | 
			
		||||
                ),
 | 
			
		||||
            },
 | 
			
		||||
            Ok(layout) => {
 | 
			
		||||
                log_print!(logging::Level::Info, "Loaded layout {}", source);
 | 
			
		||||
                return (kind, layout);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    panic!("No useful layout found!");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The root element describing an entire keyboard
 | 
			
		||||
#[derive(Debug, Deserialize, PartialEq)]
 | 
			
		||||
@ -125,6 +326,37 @@ struct Outline {
 | 
			
		||||
    height: f64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Errors encountered loading the layout into yaml
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum Error {
 | 
			
		||||
    Yaml(serde_yaml::Error),
 | 
			
		||||
    Io(io::Error),
 | 
			
		||||
    /// The file was missing.
 | 
			
		||||
    /// It's distinct from Io in order to make it matchable
 | 
			
		||||
    /// without calling io::Error::kind()
 | 
			
		||||
    Missing(io::Error),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for Error {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            Error::Yaml(e) => write!(f, "YAML: {}", e),
 | 
			
		||||
            Error::Io(e) => write!(f, "IO: {}", e),
 | 
			
		||||
            Error::Missing(e) => write!(f, "Missing: {}", e),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<io::Error> for Error {
 | 
			
		||||
    fn from(e: io::Error) -> Self {
 | 
			
		||||
        let kind = e.kind();
 | 
			
		||||
        match kind {
 | 
			
		||||
            io::ErrorKind::NotFound => Error::Missing(e),
 | 
			
		||||
            _ => Error::Io(e),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn add_offsets<'a, I: 'a, T, F: 'a>(iterator: I, get_size: F)
 | 
			
		||||
    -> impl Iterator<Item=(f64, T)> + 'a
 | 
			
		||||
    where I: Iterator<Item=T>,
 | 
			
		||||
@ -317,7 +549,7 @@ fn create_action<H: logging::Handler>(
 | 
			
		||||
        Text(String),
 | 
			
		||||
        Keysym(String),
 | 
			
		||||
        Modifier(Modifier),
 | 
			
		||||
    }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    let submission = match (
 | 
			
		||||
        &symbol_meta.action,
 | 
			
		||||
@ -544,13 +776,10 @@ fn extract_symbol_names<'a>(actions: &'a [(&str, action::Action)])
 | 
			
		||||
        .map(|named_keysym| named_keysym.0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    use std::env;
 | 
			
		||||
    
 | 
			
		||||
    use ::logging::ProblemPanic;
 | 
			
		||||
 | 
			
		||||
    fn path_from_root(file: &'static str) -> PathBuf {
 | 
			
		||||
@ -700,6 +929,50 @@ mod tests {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn parsing_fallback() {
 | 
			
		||||
        assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME)
 | 
			
		||||
            .map(|layout| layout.build(ProblemPanic).0.unwrap())
 | 
			
		||||
            .is_ok()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn fallbacks_order() {
 | 
			
		||||
        let sources = list_layout_sources("nb", ArrangementKind::Base, None);
 | 
			
		||||
        
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            sources,
 | 
			
		||||
            vec!(
 | 
			
		||||
                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
			
		||||
                (
 | 
			
		||||
                    ArrangementKind::Base,
 | 
			
		||||
                    DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// If layout contains a "+", it should reach for what's in front of it too.
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn fallbacks_order_base() {
 | 
			
		||||
        let sources = list_layout_sources("nb+aliens", ArrangementKind::Base, None);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            sources,
 | 
			
		||||
            vec!(
 | 
			
		||||
                (ArrangementKind::Base, DataSource::Resource("nb+aliens".into())),
 | 
			
		||||
                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
			
		||||
                (
 | 
			
		||||
                    ArrangementKind::Base,
 | 
			
		||||
                    DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn unicode_keysym() {
 | 
			
		||||
        let keysym = xkb::keysym_from_name(
 | 
			
		||||
@ -1,424 +0,0 @@
 | 
			
		||||
/* Copyright (C) 2020-2021 Purism SPC
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0+
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*! Loading layout files */
 | 
			
		||||
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::fmt;
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
use std::convert::TryFrom;
 | 
			
		||||
 | 
			
		||||
use super::{ Error, LoadError };
 | 
			
		||||
use super::parsing;
 | 
			
		||||
 | 
			
		||||
use ::layout::ArrangementKind;
 | 
			
		||||
use ::logging;
 | 
			
		||||
use ::util::c::as_str;
 | 
			
		||||
use ::xdg;
 | 
			
		||||
use ::imservice::ContentPurpose;
 | 
			
		||||
 | 
			
		||||
// traits, derives
 | 
			
		||||
use ::logging::Warn;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_load_layout(
 | 
			
		||||
        name: *const c_char,    // name of the keyboard
 | 
			
		||||
        type_: u32,             // type like Wide
 | 
			
		||||
        variant: u32,          // purpose variant like numeric, terminal...
 | 
			
		||||
        overlay: *const c_char, // the overlay (looking for "terminal")
 | 
			
		||||
    ) -> *mut ::layout::Layout {
 | 
			
		||||
        let type_ = match type_ {
 | 
			
		||||
            0 => ArrangementKind::Base,
 | 
			
		||||
            1 => ArrangementKind::Wide,
 | 
			
		||||
            _ => panic!("Bad enum value"),
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        let name = as_str(&name)
 | 
			
		||||
            .expect("Bad layout name")
 | 
			
		||||
            .expect("Empty layout name");
 | 
			
		||||
 | 
			
		||||
        let variant = ContentPurpose::try_from(variant)
 | 
			
		||||
                    .or_print(
 | 
			
		||||
                        logging::Problem::Warning,
 | 
			
		||||
                        "Received invalid purpose value",
 | 
			
		||||
                    )
 | 
			
		||||
                    .unwrap_or(ContentPurpose::Normal);
 | 
			
		||||
 | 
			
		||||
        let overlay_str = as_str(&overlay)
 | 
			
		||||
                .expect("Bad overlay name")
 | 
			
		||||
                .expect("Empty overlay name");
 | 
			
		||||
        let overlay_str = match overlay_str {
 | 
			
		||||
            "" => None,
 | 
			
		||||
            other => Some(other),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let (kind, layout) = load_layout_data_with_fallback(&name, type_, variant, overlay_str);
 | 
			
		||||
        let layout = ::layout::Layout::new(layout, kind);
 | 
			
		||||
        Box::into_raw(Box::new(layout))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FALLBACK_LAYOUT_NAME: &str = "us";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
enum DataSource {
 | 
			
		||||
    File(PathBuf),
 | 
			
		||||
    Resource(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for DataSource {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            DataSource::File(path) => write!(f, "Path: {:?}", path.display()),
 | 
			
		||||
            DataSource::Resource(name) => write!(f, "Resource: {}", name),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* All functions in this family carry around ArrangementKind,
 | 
			
		||||
 * because it's not guaranteed to be preserved,
 | 
			
		||||
 * and the resulting layout needs to know which version was loaded.
 | 
			
		||||
 * See `squeek_layout_get_kind`.
 | 
			
		||||
 * Possible TODO: since this is used only in styling,
 | 
			
		||||
 * and makes the below code nastier than needed, maybe it should go.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/// Returns ordered names treating `name` as the base name,
 | 
			
		||||
/// ignoring any `+` inside.
 | 
			
		||||
fn _get_arrangement_names(name: &str, arrangement: ArrangementKind)
 | 
			
		||||
    -> Vec<(ArrangementKind, String)>
 | 
			
		||||
{
 | 
			
		||||
    let name_with_arrangement = match arrangement {    
 | 
			
		||||
        ArrangementKind::Base => name.into(),
 | 
			
		||||
        ArrangementKind::Wide => format!("{}_wide", name),
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    let mut ret = Vec::new();
 | 
			
		||||
    if name_with_arrangement != name {
 | 
			
		||||
        ret.push((arrangement, name_with_arrangement));
 | 
			
		||||
    }
 | 
			
		||||
    ret.push((ArrangementKind::Base, name.into()));
 | 
			
		||||
    ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns names accounting for any `+` in the `name`,
 | 
			
		||||
/// including the fallback to the default layout.
 | 
			
		||||
fn get_preferred_names(name: &str, kind: ArrangementKind)
 | 
			
		||||
    -> Vec<(ArrangementKind, String)>
 | 
			
		||||
{
 | 
			
		||||
    let mut ret = _get_arrangement_names(name, kind);
 | 
			
		||||
    
 | 
			
		||||
    let base_name_preferences = {
 | 
			
		||||
        let mut parts = name.splitn(2, '+');
 | 
			
		||||
        match parts.next() {
 | 
			
		||||
            Some(base) => {
 | 
			
		||||
                // The name is already equal to base, so nothing to add
 | 
			
		||||
                if base == name {
 | 
			
		||||
                    vec![]
 | 
			
		||||
                } else {
 | 
			
		||||
                    _get_arrangement_names(base, kind)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            // The layout's base name starts with a "+". Weird but OK.
 | 
			
		||||
            None => {
 | 
			
		||||
                log_print!(logging::Level::Surprise, "Base layout name is empty: {}", name);
 | 
			
		||||
                vec![]
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    ret.extend(base_name_preferences.into_iter());
 | 
			
		||||
    let fallback_names = _get_arrangement_names(FALLBACK_LAYOUT_NAME, kind);
 | 
			
		||||
    ret.extend(fallback_names.into_iter());
 | 
			
		||||
    ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Includes the subdirectory before the forward slash.
 | 
			
		||||
type LayoutPath = String;
 | 
			
		||||
 | 
			
		||||
// This is only used inside iter_fallbacks_with_meta.
 | 
			
		||||
// Placed at the top scope
 | 
			
		||||
// because `use LayoutPurpose::*;`
 | 
			
		||||
// complains about "not in scope" otherwise.
 | 
			
		||||
// This seems to be a Rust 2015 edition problem.
 | 
			
		||||
/// Helper for determining where to look up the layout.
 | 
			
		||||
enum LayoutPurpose<'a> {
 | 
			
		||||
    Default,
 | 
			
		||||
    Special(&'a str),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns the directory string
 | 
			
		||||
/// where the layout should be looked up, including the slash.
 | 
			
		||||
fn get_directory_string(
 | 
			
		||||
    content_purpose: ContentPurpose,
 | 
			
		||||
    overlay: Option<&str>) -> String
 | 
			
		||||
{
 | 
			
		||||
    use self::LayoutPurpose::*;
 | 
			
		||||
 | 
			
		||||
    let layout_purpose = match overlay {
 | 
			
		||||
        None => match content_purpose {
 | 
			
		||||
            ContentPurpose::Number => Special("number"),
 | 
			
		||||
            ContentPurpose::Digits => Special("number"),
 | 
			
		||||
            ContentPurpose::Phone => Special("number"),
 | 
			
		||||
            ContentPurpose::Terminal => Special("terminal"),
 | 
			
		||||
            _ => Default,
 | 
			
		||||
        },
 | 
			
		||||
        Some(overlay) => Special(overlay),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // For intuitiveness,
 | 
			
		||||
    // default purpose layouts are stored in the root directory,
 | 
			
		||||
    // as they correspond to typical text
 | 
			
		||||
    // and are seen the most often.
 | 
			
		||||
    match layout_purpose {
 | 
			
		||||
        Default => "".into(),
 | 
			
		||||
        Special(purpose) => format!("{}/", purpose),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns an iterator over all fallback paths.
 | 
			
		||||
fn to_layout_paths(
 | 
			
		||||
    name_fallbacks: Vec<(ArrangementKind, String)>,
 | 
			
		||||
    content_purpose: ContentPurpose,
 | 
			
		||||
    overlay: Option<&str>,
 | 
			
		||||
) -> impl Iterator<Item=(ArrangementKind, LayoutPath)> {
 | 
			
		||||
    let prepend_directory = get_directory_string(content_purpose, overlay);
 | 
			
		||||
 | 
			
		||||
    name_fallbacks.into_iter()
 | 
			
		||||
        .map(move |(arrangement, name)|
 | 
			
		||||
            (arrangement, format!("{}{}", prepend_directory, name))
 | 
			
		||||
        )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LayoutSource = (ArrangementKind, DataSource);
 | 
			
		||||
 | 
			
		||||
fn to_layout_sources(
 | 
			
		||||
    layout_paths: impl Iterator<Item=(ArrangementKind, LayoutPath)>,
 | 
			
		||||
    filesystem_path: Option<PathBuf>,
 | 
			
		||||
) -> impl Iterator<Item=LayoutSource> {
 | 
			
		||||
    layout_paths.flat_map(move |(arrangement, layout_path)| {
 | 
			
		||||
        let mut sources = Vec::new();
 | 
			
		||||
        if let Some(path) = &filesystem_path {
 | 
			
		||||
            sources.push((
 | 
			
		||||
                arrangement,
 | 
			
		||||
                DataSource::File(
 | 
			
		||||
                    path.join(&layout_path)
 | 
			
		||||
                        .with_extension("yaml")
 | 
			
		||||
                )
 | 
			
		||||
            ));
 | 
			
		||||
        };
 | 
			
		||||
        sources.push((arrangement, DataSource::Resource(layout_path.clone())));
 | 
			
		||||
        sources.into_iter()
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns possible sources, with first as the most preferred one.
 | 
			
		||||
/// Trying order: native lang of the right kind, native base,
 | 
			
		||||
/// fallback lang of the right kind, fallback base
 | 
			
		||||
fn iter_layout_sources(
 | 
			
		||||
    name: &str,
 | 
			
		||||
    arrangement: ArrangementKind,
 | 
			
		||||
    purpose: ContentPurpose,
 | 
			
		||||
    ui_overlay: Option<&str>,
 | 
			
		||||
    layout_storage: Option<PathBuf>,
 | 
			
		||||
) -> impl Iterator<Item=LayoutSource> {
 | 
			
		||||
    let names = get_preferred_names(name, arrangement);
 | 
			
		||||
    let paths = to_layout_paths(names, purpose, ui_overlay);
 | 
			
		||||
    to_layout_sources(paths, layout_storage)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn load_layout_data(source: DataSource)
 | 
			
		||||
    -> Result<::layout::LayoutData, LoadError>
 | 
			
		||||
{
 | 
			
		||||
    let handler = logging::Print {};
 | 
			
		||||
    match source {
 | 
			
		||||
        DataSource::File(path) => {
 | 
			
		||||
            parsing::Layout::from_file(path.clone())
 | 
			
		||||
                .map_err(LoadError::BadData)
 | 
			
		||||
                .and_then(|layout|
 | 
			
		||||
                    layout.build(handler).0.map_err(LoadError::BadKeyMap)
 | 
			
		||||
                )
 | 
			
		||||
        },
 | 
			
		||||
        DataSource::Resource(name) => {
 | 
			
		||||
            parsing::Layout::from_resource(&name)
 | 
			
		||||
                .and_then(|layout|
 | 
			
		||||
                    layout.build(handler).0.map_err(LoadError::BadKeyMap)
 | 
			
		||||
                )
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn load_layout_data_with_fallback(
 | 
			
		||||
    name: &str,
 | 
			
		||||
    kind: ArrangementKind,
 | 
			
		||||
    purpose: ContentPurpose,
 | 
			
		||||
    overlay: Option<&str>,
 | 
			
		||||
) -> (ArrangementKind, ::layout::LayoutData) {
 | 
			
		||||
 | 
			
		||||
    // Build the path to the right keyboard layout subdirectory
 | 
			
		||||
    let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
 | 
			
		||||
        .map(PathBuf::from)
 | 
			
		||||
        .or_else(|| xdg::data_path("squeekboard/keyboards"));
 | 
			
		||||
 | 
			
		||||
    for (kind, source) in iter_layout_sources(&name, kind, purpose, overlay, path) {
 | 
			
		||||
        let layout = load_layout_data(source.clone());
 | 
			
		||||
        match layout {
 | 
			
		||||
            Err(e) => match (e, source) {
 | 
			
		||||
                (
 | 
			
		||||
                    LoadError::BadData(Error::Missing(e)),
 | 
			
		||||
                    DataSource::File(file)
 | 
			
		||||
                ) => log_print!(
 | 
			
		||||
                    logging::Level::Debug,
 | 
			
		||||
                    "Tried file {:?}, but it's missing: {}",
 | 
			
		||||
                    file, e
 | 
			
		||||
                ),
 | 
			
		||||
                (e, source) => log_print!(
 | 
			
		||||
                    logging::Level::Warning,
 | 
			
		||||
                    "Failed to load layout from {}: {}, skipping",
 | 
			
		||||
                    source, e
 | 
			
		||||
                ),
 | 
			
		||||
            },
 | 
			
		||||
            Ok(layout) => {
 | 
			
		||||
                log_print!(logging::Level::Info, "Loaded layout {}", source);
 | 
			
		||||
                return (kind, layout);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    panic!("No useful layout found!");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    use ::logging::ProblemPanic;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn parsing_fallback() {
 | 
			
		||||
        assert!(parsing::Layout::from_resource(FALLBACK_LAYOUT_NAME)
 | 
			
		||||
            .map(|layout| layout.build(ProblemPanic).0.unwrap())
 | 
			
		||||
            .is_ok()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_fallback_basic_builtin() {
 | 
			
		||||
        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, None);
 | 
			
		||||
        
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            sources.collect::<Vec<_>>(),
 | 
			
		||||
            vec!(
 | 
			
		||||
                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
			
		||||
                (
 | 
			
		||||
                    ArrangementKind::Base,
 | 
			
		||||
                    DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Prefer loading from file system before builtin.
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_preferences_order_path() {
 | 
			
		||||
        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, Some(".".into()));
 | 
			
		||||
        
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            sources.collect::<Vec<_>>(),
 | 
			
		||||
            vec!(
 | 
			
		||||
                (ArrangementKind::Base, DataSource::File("./nb.yaml".into())),
 | 
			
		||||
                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
			
		||||
                (
 | 
			
		||||
                    ArrangementKind::Base,
 | 
			
		||||
                    DataSource::File("./us.yaml".into())
 | 
			
		||||
                ),
 | 
			
		||||
                (
 | 
			
		||||
                    ArrangementKind::Base,
 | 
			
		||||
                    DataSource::Resource("us".into())
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// If layout contains a "+", it should reach for what's in front of it too.
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_preferences_order_base() {
 | 
			
		||||
        let sources = iter_layout_sources("nb+aliens", ArrangementKind::Base, ContentPurpose::Normal, None, None);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            sources.collect::<Vec<_>>(),
 | 
			
		||||
            vec!(
 | 
			
		||||
                (ArrangementKind::Base, DataSource::Resource("nb+aliens".into())),
 | 
			
		||||
                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
			
		||||
                (
 | 
			
		||||
                    ArrangementKind::Base,
 | 
			
		||||
                    DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_preferences_order_arrangement() {
 | 
			
		||||
        let sources = iter_layout_sources("nb", ArrangementKind::Wide, ContentPurpose::Normal, None, None);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            sources.collect::<Vec<_>>(),
 | 
			
		||||
            vec!(
 | 
			
		||||
                (ArrangementKind::Wide, DataSource::Resource("nb_wide".into())),
 | 
			
		||||
                (ArrangementKind::Base, DataSource::Resource("nb".into())),
 | 
			
		||||
                (
 | 
			
		||||
                    ArrangementKind::Wide,
 | 
			
		||||
                    DataSource::Resource("us_wide".into())
 | 
			
		||||
                ),
 | 
			
		||||
                (
 | 
			
		||||
                    ArrangementKind::Base,
 | 
			
		||||
                    DataSource::Resource("us".into())
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_preferences_order_overlay() {
 | 
			
		||||
        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, Some("terminal"), None);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            sources.collect::<Vec<_>>(),
 | 
			
		||||
            vec!(
 | 
			
		||||
                (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())),
 | 
			
		||||
                (
 | 
			
		||||
                    ArrangementKind::Base,
 | 
			
		||||
                    DataSource::Resource("terminal/us".into())
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_preferences_order_hint() {
 | 
			
		||||
        let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Terminal, None, None);
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            sources.collect::<Vec<_>>(),
 | 
			
		||||
            vec!(
 | 
			
		||||
                (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())),
 | 
			
		||||
                (
 | 
			
		||||
                    ArrangementKind::Base,
 | 
			
		||||
                    DataSource::Resource("terminal/us".into())
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,65 +0,0 @@
 | 
			
		||||
/* Copyright (C) 2020-2021 Purism SPC
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0+
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*! Combined module for dealing with layout files */
 | 
			
		||||
 | 
			
		||||
mod loading;
 | 
			
		||||
pub mod parsing;
 | 
			
		||||
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::fmt;
 | 
			
		||||
 | 
			
		||||
use ::keyboard::FormattingError;
 | 
			
		||||
 | 
			
		||||
/// Errors encountered loading the layout into yaml
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum Error {
 | 
			
		||||
    Yaml(serde_yaml::Error),
 | 
			
		||||
    Io(io::Error),
 | 
			
		||||
    /// The file was missing.
 | 
			
		||||
    /// It's distinct from Io in order to make it matchable
 | 
			
		||||
    /// without calling io::Error::kind()
 | 
			
		||||
    Missing(io::Error),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for Error {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            Error::Yaml(e) => write!(f, "YAML: {}", e),
 | 
			
		||||
            Error::Io(e) => write!(f, "IO: {}", e),
 | 
			
		||||
            Error::Missing(e) => write!(f, "Missing: {}", e),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<io::Error> for Error {
 | 
			
		||||
    fn from(e: io::Error) -> Self {
 | 
			
		||||
        let kind = e.kind();
 | 
			
		||||
        match kind {
 | 
			
		||||
            io::ErrorKind::NotFound => Error::Missing(e),
 | 
			
		||||
            _ => Error::Io(e),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum LoadError {
 | 
			
		||||
    BadData(Error),
 | 
			
		||||
    MissingResource,
 | 
			
		||||
    BadResource(serde_yaml::Error),
 | 
			
		||||
    BadKeyMap(FormattingError),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for LoadError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        use self::LoadError::*;
 | 
			
		||||
        match self {
 | 
			
		||||
            BadData(e) => write!(f, "Bad data: {}", e),
 | 
			
		||||
            MissingResource => write!(f, "Missing resource"),
 | 
			
		||||
            BadResource(e) => write!(f, "Bad resource: {}", e),
 | 
			
		||||
            BadKeyMap(e) => write!(f, "Bad key map: {}", e),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -31,7 +31,7 @@ struct transformation squeek_layout_calculate_transformation(
 | 
			
		||||
        const struct squeek_layout *layout,
 | 
			
		||||
        double allocation_width, double allocation_size);
 | 
			
		||||
 | 
			
		||||
struct squeek_layout *squeek_load_layout(const char *name, uint32_t type, uint32_t variant_type, const char *overlay_name);
 | 
			
		||||
struct squeek_layout *squeek_load_layout(const char *name, uint32_t type);
 | 
			
		||||
enum squeek_arrangement_kind squeek_layout_get_kind(const struct squeek_layout *);
 | 
			
		||||
void squeek_layout_free(struct squeek_layout*);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -600,7 +600,7 @@ impl View {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The physical characteristic of layout for the purpose of styling
 | 
			
		||||
#[derive(Clone, Copy, PartialEq, Debug)]
 | 
			
		||||
#[derive(Clone, PartialEq, Debug)]
 | 
			
		||||
pub enum ArrangementKind {
 | 
			
		||||
    Base = 0,
 | 
			
		||||
    Wide = 1,
 | 
			
		||||
@ -621,6 +621,12 @@ pub enum LatchedState {
 | 
			
		||||
    Not,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl LatchedState {
 | 
			
		||||
    pub fn is_latched(&self) -> bool {
 | 
			
		||||
        self != &LatchedState::Not
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: split into sth like
 | 
			
		||||
// Arrangement (views) + details (keymap) + State (keys)
 | 
			
		||||
/// State of the UI, contains the backend as well
 | 
			
		||||
@ -771,6 +777,23 @@ impl Layout {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_locked_keys(&self) -> Vec<Rc<RefCell<KeyState>>> {
 | 
			
		||||
        let mut out = Vec::new();
 | 
			
		||||
        let view = self.get_current_view();
 | 
			
		||||
        for (_, row) in view.get_rows() {
 | 
			
		||||
            for (_, button) in &row.buttons {
 | 
			
		||||
                let locked = {
 | 
			
		||||
                    let state = RefCell::borrow(&button.state).clone();
 | 
			
		||||
                    state.action.is_locked(&self.current_view)
 | 
			
		||||
                };
 | 
			
		||||
                if locked {
 | 
			
		||||
                    out.push(button.state.clone());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        out
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    fn apply_view_transition(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        action: &Action,
 | 
			
		||||
 | 
			
		||||
@ -213,16 +213,7 @@ fn set_visible_layout(
 | 
			
		||||
    layout_id: LayoutId,
 | 
			
		||||
) {
 | 
			
		||||
    match layout_id {
 | 
			
		||||
        LayoutId::System { kind, name } => {
 | 
			
		||||
            unsafe {
 | 
			
		||||
                use std::ptr;
 | 
			
		||||
                manager::c::eekboard_context_service_set_overlay(
 | 
			
		||||
                    manager,
 | 
			
		||||
                    ptr::null(),
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            set_layout(kind, name);
 | 
			
		||||
        }
 | 
			
		||||
        LayoutId::System { kind, name } => set_layout(kind, name),
 | 
			
		||||
        LayoutId::Local(name) => {
 | 
			
		||||
            let name = CString::new(name.as_str()).unwrap();
 | 
			
		||||
            let name_ptr = name.as_ptr();
 | 
			
		||||
@ -401,7 +392,6 @@ pub fn show(
 | 
			
		||||
        width: position.width.floor() as i32,
 | 
			
		||||
        height: position.width.floor() as i32,
 | 
			
		||||
    });
 | 
			
		||||
    menu.set_constrain_to(gtk::PopoverConstraint::None);
 | 
			
		||||
 | 
			
		||||
    if let Some(current_layout) = get_current_layout(manager, &system_layouts) {
 | 
			
		||||
        let current_name_variant = choices.iter()
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ use std::iter::FromIterator;
 | 
			
		||||
// and what a convenience layout. "_wide" is not a layout,
 | 
			
		||||
// neither is "number"
 | 
			
		||||
/// List of builtin layouts
 | 
			
		||||
static KEYBOARDS: &[(&'static str, &'static str)] = &[
 | 
			
		||||
const KEYBOARDS: &[(*const str, *const str)] = &[
 | 
			
		||||
    // layouts: us must be left as first, as it is the,
 | 
			
		||||
    // fallback layout.
 | 
			
		||||
    ("us", include_str!("../data/keyboards/us.yaml")),
 | 
			
		||||
@ -80,33 +80,44 @@ static KEYBOARDS: &[(&'static str, &'static str)] = &[
 | 
			
		||||
    ("us+dvorak_wide", include_str!("../data/keyboards/us+dvorak_wide.yaml")),
 | 
			
		||||
 | 
			
		||||
    // Others
 | 
			
		||||
    ("number/us", include_str!("../data/keyboards/number/us.yaml")),
 | 
			
		||||
 | 
			
		||||
    // Terminal
 | 
			
		||||
    ("terminal/fr", include_str!("../data/keyboards/terminal/fr.yaml")),
 | 
			
		||||
 | 
			
		||||
    ("terminal/us", include_str!("../data/keyboards/terminal/us.yaml")),
 | 
			
		||||
    ("terminal/us_wide",   include_str!("../data/keyboards/terminal/us_wide.yaml")),
 | 
			
		||||
    ("number", include_str!("../data/keyboards/number.yaml")),
 | 
			
		||||
 | 
			
		||||
    // layout+overlay
 | 
			
		||||
    ("terminal", include_str!("../data/keyboards/terminal.yaml")),
 | 
			
		||||
    ("terminal_wide", include_str!("../data/keyboards/terminal_wide.yaml")),
 | 
			
		||||
    // Overlays
 | 
			
		||||
    ("emoji/us", include_str!("../data/keyboards/emoji/us.yaml")),
 | 
			
		||||
    ("emoji", include_str!("../data/keyboards/emoji.yaml")),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
pub fn get_keyboard(needle: &str) -> Option<&'static str> {
 | 
			
		||||
    KEYBOARDS.iter().find(|(name, _)| *name == needle).map(|(_, layout)| *layout)
 | 
			
		||||
    // Need to dereference in unsafe code
 | 
			
		||||
    // comparing *const str to &str will compare pointers
 | 
			
		||||
    KEYBOARDS.iter()
 | 
			
		||||
        .find(|(name, _)| {
 | 
			
		||||
            let name: *const str = *name;
 | 
			
		||||
            (unsafe { &*name }) == needle
 | 
			
		||||
        })
 | 
			
		||||
        .map(|(_, value)| {
 | 
			
		||||
            let value: *const str = *value;
 | 
			
		||||
            unsafe { &*value }
 | 
			
		||||
        })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static OVERLAY_NAMES: &[&'static str] = &[
 | 
			
		||||
const OVERLAY_NAMES: &[*const str] = &[
 | 
			
		||||
    "emoji",
 | 
			
		||||
    "terminal",
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
pub fn get_overlays() -> Vec<&'static str> {
 | 
			
		||||
    OVERLAY_NAMES.to_vec()
 | 
			
		||||
    OVERLAY_NAMES.iter()
 | 
			
		||||
        .map(|name| {
 | 
			
		||||
            let name: *const str = *name;
 | 
			
		||||
            unsafe { &*name }
 | 
			
		||||
        }).collect()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Translations of the layout identifier strings
 | 
			
		||||
static LAYOUT_NAMES: &[(&'static str, &'static str)] = &[
 | 
			
		||||
const LAYOUT_NAMES: &[(*const str, *const str)] = &[
 | 
			
		||||
    ("de-DE", include_str!("../data/langs/de-DE.txt")),
 | 
			
		||||
    ("en-US", include_str!("../data/langs/en-US.txt")),
 | 
			
		||||
    ("es-ES", include_str!("../data/langs/es-ES.txt")),
 | 
			
		||||
@ -121,8 +132,14 @@ pub fn get_layout_names(lang: &str)
 | 
			
		||||
    -> Option<HashMap<&'static str, Translation<'static>>>
 | 
			
		||||
{
 | 
			
		||||
    let translations = LAYOUT_NAMES.iter()
 | 
			
		||||
        .find(|(name, _data)| *name == lang)
 | 
			
		||||
        .map(|(_name, data)| *data);
 | 
			
		||||
        .find(|(name, _data)| {
 | 
			
		||||
            let name: *const str = *name;
 | 
			
		||||
            (unsafe { &*name }) == lang
 | 
			
		||||
        })
 | 
			
		||||
        .map(|(_name, data)| {
 | 
			
		||||
            let data: *const str = *data;
 | 
			
		||||
            unsafe { &*data }
 | 
			
		||||
        });
 | 
			
		||||
    translations.map(make_mapping)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -152,7 +169,7 @@ mod test {
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn check_overlays_present() {
 | 
			
		||||
        for name in get_overlays() {
 | 
			
		||||
            assert!(get_keyboard(&format!("{}/us", name)).is_some());
 | 
			
		||||
            assert!(get_keyboard(name).is_some());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -149,7 +149,7 @@ impl Submission {
 | 
			
		||||
                enum Outcome {
 | 
			
		||||
                    Submitted(Result<(), imservice::SubmitError>),
 | 
			
		||||
                    NotSubmitted,
 | 
			
		||||
                }
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                let submit_outcome = match data {
 | 
			
		||||
                    SubmitData::Text(text) => {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
/*! Testing functionality */
 | 
			
		||||
 | 
			
		||||
use ::data::parsing::Layout;
 | 
			
		||||
use ::data::Layout;
 | 
			
		||||
use ::logging;
 | 
			
		||||
use xkbcommon::xkb;
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ pub fn check_layout_file(path: &str) {
 | 
			
		||||
fn check_sym_in_keymap(state: &xkb::State, sym_name: &str) -> bool {
 | 
			
		||||
    let sym = xkb::keysym_from_name(sym_name, xkb::KEYSYM_NO_FLAGS);
 | 
			
		||||
    if sym == xkb::KEY_NoSymbol {
 | 
			
		||||
        panic!("Entered invalid keysym: {}", sym_name);
 | 
			
		||||
        panic!(format!("Entered invalid keysym: {}", sym_name));
 | 
			
		||||
    }
 | 
			
		||||
    let map = state.get_keymap();
 | 
			
		||||
    let range = map.min_keycode()..=map.max_keycode();
 | 
			
		||||
 | 
			
		||||
@ -85,17 +85,13 @@ foreach layout : [
 | 
			
		||||
    'us+colemak', 'us+colemak_wide',
 | 
			
		||||
    'us+dvorak', 'us+dvorak_wide',
 | 
			
		||||
 | 
			
		||||
    # Terminal keyboards
 | 
			
		||||
    'terminal/fr', 
 | 
			
		||||
    'terminal/us',
 | 
			
		||||
    'terminal/us_wide',
 | 
			
		||||
    
 | 
			
		||||
    # Block: Not languages.
 | 
			
		||||
    'emoji/us',
 | 
			
		||||
    'number/us',
 | 
			
		||||
    'emoji',
 | 
			
		||||
    'number',
 | 
			
		||||
    'terminal', 'terminal_wide',
 | 
			
		||||
]
 | 
			
		||||
    extra = []
 | 
			
		||||
    if layout.startswith('emoji/')
 | 
			
		||||
    if layout == 'emoji'
 | 
			
		||||
        extra += ['allow_missing_return']
 | 
			
		||||
    endif
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user