Post sonoptik commit
70
clitools/README.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# Chaining Lasers In Submission Tools for LJ
|
||||||
|
|
||||||
|
Alright everybody, ready for some fun? Here comes The Piping And Plumbing Your Way To The Top Show!
|
||||||
|
|
||||||
|
You're going to push so many points to this laser it will hog and cry...
|
||||||
|
|
||||||
|
BOOM | WIIIIIZ :: PHHHHHRACKRACKRACK ~~ WOOP ~~###~~ WIIT
|
||||||
|
|
||||||
|
|
||||||
|
## The basic loop
|
||||||
|
```
|
||||||
|
python3 generators/dummy.py -f 2 | python3 filters/kaleidoscope.py | python3 exports/toRedis.py -v
|
||||||
|
------------------------------ --------------------- -------------------
|
||||||
|
\/ \/ \/
|
||||||
|
Generator Filter Export
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1. The Generator
|
||||||
|
|
||||||
|
Use it to produce some points in any manner, orderly or total chaos.
|
||||||
|
|
||||||
|
Don't be that boring Sinusoids bugger! Flash Maps of Dooms, Disbitnic sprites, Dismorphic HexaFonts all over the walls!
|
||||||
|
|
||||||
|
### 2. The Filter(s)
|
||||||
|
|
||||||
|
These babies will modify data on the wire by passing around the points and modifying them in sequence.
|
||||||
|
|
||||||
|
Want your Double Heavy Laser Cannons to Bounce Together Like They Been Drinking Jagerbombs For Two Hours? That's the place.
|
||||||
|
|
||||||
|
### 3. The Exporter
|
||||||
|
|
||||||
|
Now, this IS the most boring part. Send your points to whatever output system. Yawn. Are we there yet?
|
||||||
|
|
||||||
|
## Hacking around
|
||||||
|
|
||||||
|
Say what!? Why, this is exactly the place for that!
|
||||||
|
|
||||||
|
Take a seat and copy paste the "dummy.py" files, they present the basic structure you need to play around.
|
||||||
|
|
||||||
|
Just be cautious to use the `debug` method if you're the kind of miss that debugs by outputing data structures (who does not, yah know, sometimes?). Or you'll break the chain.
|
||||||
|
|
||||||
|
### Generators
|
||||||
|
|
||||||
|
They must send list of points to standard out. Don't forget the "flush" argument, or the piping will be breaking, ain't no Mario lazering.
|
||||||
|
|
||||||
|
* dummy.py : sends always the same list of points. The Monomaniac.
|
||||||
|
* @todo : read texts from redis and others
|
||||||
|
|
||||||
|
### Filters
|
||||||
|
|
||||||
|
These do listen and read on STDIN and do the same print'n'flush on STDOUT.
|
||||||
|
|
||||||
|
* kaleidoscope.py : mirrors the points based on a pivot
|
||||||
|
* @todo : fourier analysis and other realtime reaction
|
||||||
|
|
||||||
|
### Export
|
||||||
|
|
||||||
|
Read from STDIN and send to redis mostly
|
||||||
|
|
||||||
|
* toRedis.py : provide a key, server IP, etc.
|
||||||
|
|
||||||
|
### Common parameters
|
||||||
|
|
||||||
|
Every command can be called with a `-h/--help` flag to get some help
|
||||||
|
|
||||||
|
Every command has a `-v/--verbose` flag to send debug info to STDERR.
|
||||||
|
|
||||||
|
Generators have a `-f/--fps` param for FPS, to be fast but not so furious on your machine
|
||||||
|
|
||||||
|
Filters and Exports are their own beasts
|
BIN
clitools/__pycache__/runner_lib.cpython-38.pyc
Normal file
11
clitools/_run.sh
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
killexit(){
|
||||||
|
pkill -9 -s $$
|
||||||
|
}
|
||||||
|
|
||||||
|
trap killexit SIGTERM SIGINT SIGKILL SIGSTOP
|
||||||
|
|
||||||
|
bash -c "$@"
|
||||||
|
|
||||||
|
killbill(){ pkill -9 -s $(awk '{print $6}' /proc/$1/stat) }
|
BIN
clitools/exports/.DS_Store
vendored
Normal file
BIN
clitools/exports/__pycache__/websocket_server.cpython-38.pyc
Normal file
46
clitools/exports/toNull.py
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
The exporter that drops all traffic !
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
A basic exporter
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import redis
|
||||||
|
import time
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="Null exporter LJ")
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
verbose=args.verbose
|
||||||
|
|
||||||
|
name = "exports::toNull"
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line == "":
|
||||||
|
time.sleep(0.01)
|
||||||
|
debug(name,"dumping: "+line)
|
||||||
|
except EOFError:
|
||||||
|
debug("break")# no more information
|
||||||
|
|
63
clitools/exports/toRedis.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
redis exporter
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
A basic exporter
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import redis
|
||||||
|
import time
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="Redis exporter LJ")
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
|
||||||
|
argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=str)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
ip = args.ip
|
||||||
|
port = args.port
|
||||||
|
key = args.key
|
||||||
|
verbose=args.verbose
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
r=redis.StrictRedis(host=ip, port=port, db=0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line == "":
|
||||||
|
time.sleep(0.01)
|
||||||
|
continue
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
line=line[1:-1]
|
||||||
|
line = line.replace("[",'(')
|
||||||
|
line = line.replace("]",')')
|
||||||
|
line = "[{}]".format(line)
|
||||||
|
if line == "[]":
|
||||||
|
line="[(400.0,400.0,0),(400.0,400.0,0),(400.0,400.0,0),(400.0,400.0,0)]"
|
||||||
|
continue
|
||||||
|
if r.set(key,line)==True:
|
||||||
|
debug("exports::redis set("+str(key)+") to "+line)
|
||||||
|
except EOFError:
|
||||||
|
debug("break")# no more information
|
||||||
|
|
84
clitools/exports/toUDP.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
toUDP
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
A basic exporter
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import time
|
||||||
|
import socket
|
||||||
|
import ast
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="toUDP v0.1b help mode")
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP to bind to (0.0.0.0 by default)",default="0.0.0.0",type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="UDP port to bind to (9000 by default)",default="9003",type=str)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
verbose = args.verbose
|
||||||
|
ip = args.ip
|
||||||
|
port = int(args.port)
|
||||||
|
verbose = args.verbose
|
||||||
|
|
||||||
|
|
||||||
|
name = "exports::toUDP"
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
def ClientStart(ip, port):
|
||||||
|
global sockclient
|
||||||
|
|
||||||
|
sockclient = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
|
||||||
|
|
||||||
|
def ClientSend(msgFromClient):
|
||||||
|
|
||||||
|
bytesToSend = str.encode(str(msgFromClient))
|
||||||
|
serverAddressPort = (ip, port)
|
||||||
|
bufferSize = 1024
|
||||||
|
|
||||||
|
# Send to server using created UDP socket
|
||||||
|
sockclient.sendto(bytesToSend, serverAddressPort)
|
||||||
|
|
||||||
|
'''
|
||||||
|
# If reply :
|
||||||
|
msgFromServer = sockclient.recvfrom(bufferSize)
|
||||||
|
|
||||||
|
msg = "Message from Server {}".format(msgFromServer[0])
|
||||||
|
print(msg)
|
||||||
|
'''
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
ClientStart(ip, port)
|
||||||
|
while True:
|
||||||
|
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line == "":
|
||||||
|
time.sleep(0.01)
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
#pointsList = ast.literal_eval(line)
|
||||||
|
debug(name,": "+line)
|
||||||
|
ClientSend(line)
|
||||||
|
|
||||||
|
|
||||||
|
except EOFError:
|
||||||
|
debug("break")# no more information
|
||||||
|
|
115
clitools/exports/toWS.py
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
toWS
|
||||||
|
exporter to LJ via WebSocket
|
||||||
|
v0.1b
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import websocket
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
import traceback
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import thread
|
||||||
|
except ImportError:
|
||||||
|
import _thread as thread
|
||||||
|
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("toWS v0.1b")
|
||||||
|
print ("Arguments parsing if needed...")
|
||||||
|
argsparser = argparse.ArgumentParser(description="toWS v0.1b help mode")
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
argsparser.add_argument("-s","--server",help="WS server IP (127.0.0.1 by default)", type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="WS port to bind to (9001 by default)", type=str)
|
||||||
|
argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=str)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
key = args.key
|
||||||
|
verbose=args.verbose
|
||||||
|
|
||||||
|
name = "exports::toWS"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Server name
|
||||||
|
if args.server:
|
||||||
|
serverIP = args.server
|
||||||
|
else:
|
||||||
|
serverIP = "127.0.0.1"
|
||||||
|
|
||||||
|
# ORCA destination device
|
||||||
|
if args.port:
|
||||||
|
wsPORT = args.port
|
||||||
|
else:
|
||||||
|
wsPORT = 9001
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def GetTime():
|
||||||
|
return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
|
||||||
|
|
||||||
|
|
||||||
|
def on_message(ws, message):
|
||||||
|
debug(message)
|
||||||
|
|
||||||
|
def on_error(ws, error):
|
||||||
|
debug(error)
|
||||||
|
|
||||||
|
def on_close(ws):
|
||||||
|
debug("### closed ###")
|
||||||
|
|
||||||
|
def on_open(ws):
|
||||||
|
|
||||||
|
def run(*args):
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line == "":
|
||||||
|
time.sleep(0.01)
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
line=line[1:-1]
|
||||||
|
line = line.replace("[",'(')
|
||||||
|
line = line.replace("]",')')
|
||||||
|
#debug(line)
|
||||||
|
line = "[{}]".format(line)
|
||||||
|
ws.send(str(key)+' "'+line+'"')
|
||||||
|
debug("exports::ws "+str(key)+" "+line)
|
||||||
|
|
||||||
|
|
||||||
|
except EOFError:
|
||||||
|
debug("break")# no more information
|
||||||
|
|
||||||
|
finally:
|
||||||
|
ws.close()
|
||||||
|
print("sendWS terminating...")
|
||||||
|
|
||||||
|
|
||||||
|
thread.start_new_thread(run, ())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
websocket.enableTrace(True)
|
||||||
|
ws = websocket.WebSocketApp("ws://"+str(serverIP)+":"+str(wsPORT),
|
||||||
|
on_message = on_message,
|
||||||
|
on_error = on_error,
|
||||||
|
on_close = on_close)
|
||||||
|
ws.on_open = on_open
|
||||||
|
ws.run_forever()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
157
clitools/exports/tonano.py
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
tonano
|
||||||
|
exporter to LJ nano
|
||||||
|
v0.1b
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import websocket
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
import traceback
|
||||||
|
import sys
|
||||||
|
import random
|
||||||
|
from websocket_server import WebsocketServer
|
||||||
|
from socket import *
|
||||||
|
|
||||||
|
try:
|
||||||
|
import thread
|
||||||
|
except ImportError:
|
||||||
|
import _thread as thread
|
||||||
|
|
||||||
|
name = "exports::tonano"
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="tonano v0.1b help mode")
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
argsparser.add_argument("-s","--server",help="WS server IP (127.0.0.1 by default)", type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="WS port to bind to (9001 by default)", type=str)
|
||||||
|
argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=str)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
key = args.key
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
verbose = True
|
||||||
|
else:
|
||||||
|
verbose = False
|
||||||
|
|
||||||
|
if args.server:
|
||||||
|
serverIP = args.server
|
||||||
|
else:
|
||||||
|
serverIP = "127.0.0.1"
|
||||||
|
|
||||||
|
if args.port:
|
||||||
|
wsPORT = args.port
|
||||||
|
else:
|
||||||
|
wsPORT = 9001
|
||||||
|
|
||||||
|
debug("")
|
||||||
|
debug("tonano v0.1b")
|
||||||
|
|
||||||
|
points0 = "[(150.0, 230.0, 65280), (170.0, 170.0, 65280), (230.0, 170.0, 65280), (210.0, 230.0, 65280), (150.0, 230.0, 65280)]"
|
||||||
|
points1 = "[(180.0, 230.0, 65280), (200.0, 170.0, 65280), (180.0, 230.0, 65280)]"
|
||||||
|
points2 = "[(170.0, 190.0, 65280), (200.0, 170.0, 65280), (230.0, 190.0, 65280), (230.0, 200.0, 65280), (170.0, 230.0, 65280), (230.0, 230.0, 65280)]"
|
||||||
|
points3 = "[(170.0, 170.0, 65280), (200.0, 170.0, 65280), (230.0, 190.0, 65280), (200.0, 200.0, 65280), (230.0, 210.0, 65280), (200.0, 230.0, 65280), (170.0, 230.0, 65280)]"
|
||||||
|
points = [points0, points1, points2, points3]
|
||||||
|
|
||||||
|
LaserNumber = 1
|
||||||
|
SceneNumber = 0
|
||||||
|
Laser = 0
|
||||||
|
|
||||||
|
def sendbroadcast():
|
||||||
|
|
||||||
|
debug("Sending broadcast")
|
||||||
|
cs = socket(AF_INET, SOCK_DGRAM)
|
||||||
|
cs.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
|
||||||
|
cs.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
|
||||||
|
cs.sendto("LJ tonano 0.1".encode(), ("255.255.255.255", 54545))
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# CLI websocket client -> WS server (nanoLJ) -> webpage
|
||||||
|
#
|
||||||
|
|
||||||
|
def on_message(ws, message):
|
||||||
|
if random.randint(0,100)>95:
|
||||||
|
sendbroadcast()
|
||||||
|
#debug("CLI WS client received and dropped "+message)
|
||||||
|
|
||||||
|
def on_error(ws, error):
|
||||||
|
debug("CLI WS client got error :"+error)
|
||||||
|
|
||||||
|
def on_close(ws):
|
||||||
|
debug("### CLI WS client WS closed ###")
|
||||||
|
|
||||||
|
def on_open(ws):
|
||||||
|
|
||||||
|
def run(*args):
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line == "":
|
||||||
|
time.sleep(0.005)
|
||||||
|
|
||||||
|
#debug("CLI string", line)
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
line=line[1:-1]
|
||||||
|
line = line.replace("[",'(')
|
||||||
|
line = line.replace("]",')')
|
||||||
|
#debug(line)
|
||||||
|
line = "[{}]".format(line)
|
||||||
|
debug("CLI proccess sending : /simul" +" "+ line)
|
||||||
|
#sendWSall("/simul" +" "+ str(points[laserid].decode('ascii')))
|
||||||
|
ws.send("/simul "+line)
|
||||||
|
#debug("exports::tosimuCLIent "+str(key)+" "+line)
|
||||||
|
|
||||||
|
except EOFError:
|
||||||
|
debug("tonano break")# no more information
|
||||||
|
|
||||||
|
finally:
|
||||||
|
ws.close()
|
||||||
|
debug("tonano WS terminating...")
|
||||||
|
|
||||||
|
|
||||||
|
thread.start_new_thread(run, ())
|
||||||
|
|
||||||
|
def handle_timeout(self):
|
||||||
|
self.timed_out = True
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Launch WS CLI client
|
||||||
|
#
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
# CLI Websocket client
|
||||||
|
debug("Launching tosimu CLI websocket client...")
|
||||||
|
#websocket.enableTrace(True)
|
||||||
|
websocket.enableTrace(False)
|
||||||
|
ws = websocket.WebSocketApp("ws://"+str(serverIP)+":"+str(wsPORT),
|
||||||
|
on_message = on_message,
|
||||||
|
on_error = on_error,
|
||||||
|
on_close = on_close)
|
||||||
|
ws.on_open = on_open
|
||||||
|
ws.run_forever()
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
debug("tonano Exception")
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
388
clitools/exports/websocket_server.py
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
# Author: Johan Hanssen Seferidis
|
||||||
|
# License: MIT
|
||||||
|
|
||||||
|
'''
|
||||||
|
Custom version
|
||||||
|
with clients_list()
|
||||||
|
For 2 clients :
|
||||||
|
[{'id': 1, 'handler': <websocket_server.WebSocketHandler object at 0x114d35880>, 'address': ('127.0.0.1', 62718)}, {'id': 2, 'handler': <websocket_server.WebSocketHandler object at 0x114d35d60>, 'address': ('127.0.0.1', 62720)}]
|
||||||
|
|
||||||
|
|
||||||
|
def client_list():
|
||||||
|
|
||||||
|
clients = wserver.clients()
|
||||||
|
for client in clients:
|
||||||
|
print(client['id'])
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
from base64 import b64encode
|
||||||
|
from hashlib import sha1
|
||||||
|
import logging
|
||||||
|
from socket import error as SocketError
|
||||||
|
import errno
|
||||||
|
|
||||||
|
if sys.version_info[0] < 3:
|
||||||
|
from SocketServer import ThreadingMixIn, TCPServer, StreamRequestHandler
|
||||||
|
else:
|
||||||
|
from socketserver import ThreadingMixIn, TCPServer, StreamRequestHandler
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logging.basicConfig()
|
||||||
|
|
||||||
|
'''
|
||||||
|
+-+-+-+-+-------+-+-------------+-------------------------------+
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-------+-+-------------+-------------------------------+
|
||||||
|
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|
||||||
|
|I|S|S|S| (4) |A| (7) | (16/64) |
|
||||||
|
|N|V|V|V| |S| | (if payload len==126/127) |
|
||||||
|
| |1|2|3| |K| | |
|
||||||
|
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|
||||||
|
| Extended payload length continued, if payload len == 127 |
|
||||||
|
+ - - - - - - - - - - - - - - - +-------------------------------+
|
||||||
|
| Payload Data continued ... |
|
||||||
|
+---------------------------------------------------------------+
|
||||||
|
'''
|
||||||
|
|
||||||
|
FIN = 0x80
|
||||||
|
OPCODE = 0x0f
|
||||||
|
MASKED = 0x80
|
||||||
|
PAYLOAD_LEN = 0x7f
|
||||||
|
PAYLOAD_LEN_EXT16 = 0x7e
|
||||||
|
PAYLOAD_LEN_EXT64 = 0x7f
|
||||||
|
|
||||||
|
OPCODE_CONTINUATION = 0x0
|
||||||
|
OPCODE_TEXT = 0x1
|
||||||
|
OPCODE_BINARY = 0x2
|
||||||
|
OPCODE_CLOSE_CONN = 0x8
|
||||||
|
OPCODE_PING = 0x9
|
||||||
|
OPCODE_PONG = 0xA
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------- API ---------------------------------
|
||||||
|
|
||||||
|
class API():
|
||||||
|
|
||||||
|
def run_forever(self):
|
||||||
|
try:
|
||||||
|
logger.info("Listening on port %d for clients.." % self.port)
|
||||||
|
self.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.server_close()
|
||||||
|
logger.info("Server terminated.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(str(e), exc_info=True)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
def new_client(self, client, server):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def client_left(self, client, server):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def message_received(self, client, server, message):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def set_fn_new_client(self, fn):
|
||||||
|
self.new_client = fn
|
||||||
|
|
||||||
|
def set_fn_client_left(self, fn):
|
||||||
|
self.client_left = fn
|
||||||
|
|
||||||
|
def set_fn_message_received(self, fn):
|
||||||
|
self.message_received = fn
|
||||||
|
|
||||||
|
def send_message(self, client, msg):
|
||||||
|
self._unicast_(client, msg)
|
||||||
|
|
||||||
|
def send_message_to_all(self, msg):
|
||||||
|
self._multicast_(msg)
|
||||||
|
|
||||||
|
def clients_list(self):
|
||||||
|
return self.clients
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------- Implementation -----------------------------
|
||||||
|
|
||||||
|
class WebsocketServer(ThreadingMixIn, TCPServer, API):
|
||||||
|
"""
|
||||||
|
A websocket server waiting for clients to connect.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
port(int): Port to bind to
|
||||||
|
host(str): Hostname or IP to listen for connections. By default 127.0.0.1
|
||||||
|
is being used. To accept connections from any client, you should use
|
||||||
|
0.0.0.0.
|
||||||
|
loglevel: Logging level from logging module to use for logging. By default
|
||||||
|
warnings and errors are being logged.
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
clients(list): A list of connected clients. A client is a dictionary
|
||||||
|
like below.
|
||||||
|
{
|
||||||
|
'id' : id,
|
||||||
|
'handler' : handler,
|
||||||
|
'address' : (addr, port)
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
allow_reuse_address = True
|
||||||
|
daemon_threads = True # comment to keep threads alive until finished
|
||||||
|
|
||||||
|
clients = []
|
||||||
|
id_counter = 0
|
||||||
|
|
||||||
|
def __init__(self, port, host='127.0.0.1', loglevel=logging.WARNING):
|
||||||
|
logger.setLevel(loglevel)
|
||||||
|
TCPServer.__init__(self, (host, port), WebSocketHandler)
|
||||||
|
self.port = self.socket.getsockname()[1]
|
||||||
|
|
||||||
|
def _message_received_(self, handler, msg):
|
||||||
|
self.message_received(self.handler_to_client(handler), self, msg)
|
||||||
|
|
||||||
|
def _ping_received_(self, handler, msg):
|
||||||
|
handler.send_pong(msg)
|
||||||
|
|
||||||
|
def _pong_received_(self, handler, msg):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _new_client_(self, handler):
|
||||||
|
self.id_counter += 1
|
||||||
|
client = {
|
||||||
|
'id': self.id_counter,
|
||||||
|
'handler': handler,
|
||||||
|
'address': handler.client_address
|
||||||
|
}
|
||||||
|
self.clients.append(client)
|
||||||
|
self.new_client(client, self)
|
||||||
|
|
||||||
|
def _client_left_(self, handler):
|
||||||
|
client = self.handler_to_client(handler)
|
||||||
|
self.client_left(client, self)
|
||||||
|
if client in self.clients:
|
||||||
|
self.clients.remove(client)
|
||||||
|
|
||||||
|
def _unicast_(self, to_client, msg):
|
||||||
|
to_client['handler'].send_message(msg)
|
||||||
|
|
||||||
|
def _multicast_(self, msg):
|
||||||
|
for client in self.clients:
|
||||||
|
self._unicast_(client, msg)
|
||||||
|
|
||||||
|
def handler_to_client(self, handler):
|
||||||
|
for client in self.clients:
|
||||||
|
if client['handler'] == handler:
|
||||||
|
return client
|
||||||
|
|
||||||
|
|
||||||
|
class WebSocketHandler(StreamRequestHandler):
|
||||||
|
|
||||||
|
def __init__(self, socket, addr, server):
|
||||||
|
self.server = server
|
||||||
|
StreamRequestHandler.__init__(self, socket, addr, server)
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
StreamRequestHandler.setup(self)
|
||||||
|
self.keep_alive = True
|
||||||
|
self.handshake_done = False
|
||||||
|
self.valid_client = False
|
||||||
|
|
||||||
|
def handle(self):
|
||||||
|
while self.keep_alive:
|
||||||
|
if not self.handshake_done:
|
||||||
|
self.handshake()
|
||||||
|
elif self.valid_client:
|
||||||
|
self.read_next_message()
|
||||||
|
|
||||||
|
def read_bytes(self, num):
|
||||||
|
# python3 gives ordinal of byte directly
|
||||||
|
bytes = self.rfile.read(num)
|
||||||
|
if sys.version_info[0] < 3:
|
||||||
|
return map(ord, bytes)
|
||||||
|
else:
|
||||||
|
return bytes
|
||||||
|
|
||||||
|
def read_next_message(self):
|
||||||
|
try:
|
||||||
|
b1, b2 = self.read_bytes(2)
|
||||||
|
except SocketError as e: # to be replaced with ConnectionResetError for py3
|
||||||
|
if e.errno == errno.ECONNRESET:
|
||||||
|
logger.info("Client closed connection.")
|
||||||
|
print("Error: {}".format(e))
|
||||||
|
self.keep_alive = 0
|
||||||
|
return
|
||||||
|
b1, b2 = 0, 0
|
||||||
|
except ValueError as e:
|
||||||
|
b1, b2 = 0, 0
|
||||||
|
|
||||||
|
fin = b1 & FIN
|
||||||
|
opcode = b1 & OPCODE
|
||||||
|
masked = b2 & MASKED
|
||||||
|
payload_length = b2 & PAYLOAD_LEN
|
||||||
|
|
||||||
|
if opcode == OPCODE_CLOSE_CONN:
|
||||||
|
logger.info("Client asked to close connection.")
|
||||||
|
self.keep_alive = 0
|
||||||
|
return
|
||||||
|
if not masked:
|
||||||
|
logger.warn("Client must always be masked.")
|
||||||
|
self.keep_alive = 0
|
||||||
|
return
|
||||||
|
if opcode == OPCODE_CONTINUATION:
|
||||||
|
logger.warn("Continuation frames are not supported.")
|
||||||
|
return
|
||||||
|
elif opcode == OPCODE_BINARY:
|
||||||
|
logger.warn("Binary frames are not supported.")
|
||||||
|
return
|
||||||
|
elif opcode == OPCODE_TEXT:
|
||||||
|
opcode_handler = self.server._message_received_
|
||||||
|
elif opcode == OPCODE_PING:
|
||||||
|
opcode_handler = self.server._ping_received_
|
||||||
|
elif opcode == OPCODE_PONG:
|
||||||
|
opcode_handler = self.server._pong_received_
|
||||||
|
else:
|
||||||
|
logger.warn("Unknown opcode %#x." % opcode)
|
||||||
|
self.keep_alive = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
if payload_length == 126:
|
||||||
|
payload_length = struct.unpack(">H", self.rfile.read(2))[0]
|
||||||
|
elif payload_length == 127:
|
||||||
|
payload_length = struct.unpack(">Q", self.rfile.read(8))[0]
|
||||||
|
|
||||||
|
masks = self.read_bytes(4)
|
||||||
|
message_bytes = bytearray()
|
||||||
|
for message_byte in self.read_bytes(payload_length):
|
||||||
|
message_byte ^= masks[len(message_bytes) % 4]
|
||||||
|
message_bytes.append(message_byte)
|
||||||
|
opcode_handler(self, message_bytes.decode('utf8'))
|
||||||
|
|
||||||
|
def send_message(self, message):
|
||||||
|
self.send_text(message)
|
||||||
|
|
||||||
|
def send_pong(self, message):
|
||||||
|
self.send_text(message, OPCODE_PONG)
|
||||||
|
|
||||||
|
def send_text(self, message, opcode=OPCODE_TEXT):
|
||||||
|
"""
|
||||||
|
Important: Fragmented(=continuation) messages are not supported since
|
||||||
|
their usage cases are limited - when we don't know the payload length.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Validate message
|
||||||
|
if isinstance(message, bytes):
|
||||||
|
message = try_decode_UTF8(message) # this is slower but ensures we have UTF-8
|
||||||
|
if not message:
|
||||||
|
logger.warning("Can\'t send message, message is not valid UTF-8")
|
||||||
|
return False
|
||||||
|
elif sys.version_info < (3,0) and (isinstance(message, str) or isinstance(message, unicode)):
|
||||||
|
pass
|
||||||
|
elif isinstance(message, str):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
logger.warning('Can\'t send message, message has to be a string or bytes. Given type is %s' % type(message))
|
||||||
|
return False
|
||||||
|
|
||||||
|
header = bytearray()
|
||||||
|
payload = encode_to_UTF8(message)
|
||||||
|
payload_length = len(payload)
|
||||||
|
|
||||||
|
# Normal payload
|
||||||
|
if payload_length <= 125:
|
||||||
|
header.append(FIN | opcode)
|
||||||
|
header.append(payload_length)
|
||||||
|
|
||||||
|
# Extended payload
|
||||||
|
elif payload_length >= 126 and payload_length <= 65535:
|
||||||
|
header.append(FIN | opcode)
|
||||||
|
header.append(PAYLOAD_LEN_EXT16)
|
||||||
|
header.extend(struct.pack(">H", payload_length))
|
||||||
|
|
||||||
|
# Huge extended payload
|
||||||
|
elif payload_length < 18446744073709551616:
|
||||||
|
header.append(FIN | opcode)
|
||||||
|
header.append(PAYLOAD_LEN_EXT64)
|
||||||
|
header.extend(struct.pack(">Q", payload_length))
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise Exception("Message is too big. Consider breaking it into chunks.")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.request.send(header + payload)
|
||||||
|
|
||||||
|
def read_http_headers(self):
|
||||||
|
headers = {}
|
||||||
|
# first line should be HTTP GET
|
||||||
|
http_get = self.rfile.readline().decode().strip()
|
||||||
|
assert http_get.upper().startswith('GET')
|
||||||
|
# remaining should be headers
|
||||||
|
while True:
|
||||||
|
header = self.rfile.readline().decode().strip()
|
||||||
|
if not header:
|
||||||
|
break
|
||||||
|
head, value = header.split(':', 1)
|
||||||
|
headers[head.lower().strip()] = value.strip()
|
||||||
|
return headers
|
||||||
|
|
||||||
|
def handshake(self):
|
||||||
|
headers = self.read_http_headers()
|
||||||
|
|
||||||
|
try:
|
||||||
|
assert headers['upgrade'].lower() == 'websocket'
|
||||||
|
except AssertionError:
|
||||||
|
self.keep_alive = False
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
key = headers['sec-websocket-key']
|
||||||
|
except KeyError:
|
||||||
|
logger.warning("Client tried to connect but was missing a key")
|
||||||
|
self.keep_alive = False
|
||||||
|
return
|
||||||
|
|
||||||
|
response = self.make_handshake_response(key)
|
||||||
|
self.handshake_done = self.request.send(response.encode())
|
||||||
|
self.valid_client = True
|
||||||
|
self.server._new_client_(self)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def make_handshake_response(cls, key):
|
||||||
|
return \
|
||||||
|
'HTTP/1.1 101 Switching Protocols\r\n'\
|
||||||
|
'Upgrade: websocket\r\n' \
|
||||||
|
'Connection: Upgrade\r\n' \
|
||||||
|
'Sec-WebSocket-Accept: %s\r\n' \
|
||||||
|
'\r\n' % cls.calculate_response_key(key)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def calculate_response_key(cls, key):
|
||||||
|
GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
|
||||||
|
hash = sha1(key.encode() + GUID.encode())
|
||||||
|
response_key = b64encode(hash.digest()).strip()
|
||||||
|
return response_key.decode('ASCII')
|
||||||
|
|
||||||
|
def finish(self):
|
||||||
|
self.server._client_left_(self)
|
||||||
|
|
||||||
|
|
||||||
|
def encode_to_UTF8(data):
|
||||||
|
try:
|
||||||
|
return data.encode('UTF-8')
|
||||||
|
except UnicodeEncodeError as e:
|
||||||
|
logger.error("Could not encode data to UTF-8 -- %s" % e)
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
raise(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def try_decode_UTF8(data):
|
||||||
|
try:
|
||||||
|
return data.decode('utf-8')
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
raise(e)
|
BIN
clitools/filters/.DS_Store
vendored
Normal file
200
clitools/filters/anaglyph.py
Executable file
@ -0,0 +1,200 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
anaglyph
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
Attempts to create a valid 3D-glasses structure
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import argparse
|
||||||
|
import ast
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
name = "filters::cycle"
|
||||||
|
|
||||||
|
maxDist = 300
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="Redis exporter LJ")
|
||||||
|
argsparser.add_argument("-x","--centerX",help="geometrical center X position",default=400,type=int)
|
||||||
|
argsparser.add_argument("-y","--centerY",help="geometrical center Y position",default=400,type=int)
|
||||||
|
argsparser.add_argument("-m","--min",help="Minimal displacement (default:2) ",default=1,type=int)
|
||||||
|
argsparser.add_argument("-M","--max",help="Maximal displacement (default:20) ",default=5,type=int)
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
|
||||||
|
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
fps = args.fps
|
||||||
|
minVal = args.min
|
||||||
|
maxVal = args.max
|
||||||
|
centerX = args.centerX
|
||||||
|
centerY = args.centerY
|
||||||
|
verbose = args.verbose
|
||||||
|
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
name = "filters::anaglyph"
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
def rgb2int(rgb):
|
||||||
|
#debug(name,"::rgb2int rbg:{}".format(rgb))
|
||||||
|
return int('0x%02x%02x%02x' % tuple(rgb),0)
|
||||||
|
|
||||||
|
def isValidColor( color, intensityColThreshold ):
|
||||||
|
if color[0] + color[1] + color[2] > intensityColThreshold:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
# These are paper colors
|
||||||
|
red = (41,24,24)
|
||||||
|
white = (95,95,95)
|
||||||
|
blue = (0,41,64)
|
||||||
|
|
||||||
|
red = (127,0,0)
|
||||||
|
blue = (0,128,128)
|
||||||
|
white = (128,128,128)
|
||||||
|
def anaglyph( pl ):
|
||||||
|
|
||||||
|
debug(name,'--------------- new loop ------------------')
|
||||||
|
# We will send one list after the other to optimize color change
|
||||||
|
blueList = list()
|
||||||
|
redList = list()
|
||||||
|
whiteList = list()
|
||||||
|
out = []
|
||||||
|
out1 = []
|
||||||
|
out2 = []
|
||||||
|
out3 = []
|
||||||
|
|
||||||
|
# The anaglyphic effect will be optained by :
|
||||||
|
# * having close objects appear as white
|
||||||
|
# * having distant objects appear as blue + red
|
||||||
|
# * having in between objects appear as distanceDecreased(white) + blue + red
|
||||||
|
for i, point in enumerate(pl):
|
||||||
|
ref_x = point[0]-centerX
|
||||||
|
ref_y = point[1]-centerY
|
||||||
|
ref_color = point[2]
|
||||||
|
angle = math.atan2( ref_x , ref_y )
|
||||||
|
dist = ref_y / math.cos(angle)
|
||||||
|
white_rvb = (0,0,0)
|
||||||
|
blue_rvb = (0,0,0)
|
||||||
|
red_rvb = (0,0,0)
|
||||||
|
|
||||||
|
# Calculate the point's spread factor (0.0 to 1.0)
|
||||||
|
# The spread is high if the point is close to center
|
||||||
|
"""
|
||||||
|
dist = 0 : spread = 1.0
|
||||||
|
dist = maxDist spread = 0.0
|
||||||
|
"""
|
||||||
|
if dist == 0:
|
||||||
|
spread = 1.0
|
||||||
|
else :
|
||||||
|
spread =( maxDist - dist ) / maxDist
|
||||||
|
if spread < 0.0:
|
||||||
|
spread = 0.0
|
||||||
|
|
||||||
|
#debug(name,"dist:{} spread:{}".format(dist,spread))
|
||||||
|
|
||||||
|
# White color is high if spread is low, i.e. point away from center
|
||||||
|
"""
|
||||||
|
spread = 1.0 : white_c = 0.0
|
||||||
|
spread = 0.0 : whice_c = 1.0
|
||||||
|
"""
|
||||||
|
if point[2] == 0:
|
||||||
|
white_color = 0
|
||||||
|
else:
|
||||||
|
white_factor = 1.0 - math.pow(spread,0.5)
|
||||||
|
white_rvb = tuple(map( lambda a: int(white_factor* a), white))
|
||||||
|
white_color = rgb2int( white_rvb)
|
||||||
|
#debug(name,"spread:{}\t white_rvb:{}\t white_color:{}".format(spread, white_rvb, white_color))
|
||||||
|
|
||||||
|
# Blue and Red colors are high if spread is high, i.e. close to center
|
||||||
|
"""
|
||||||
|
spread = 1.0 : red_c = 1.0
|
||||||
|
spread = 0.0 : red_c = 0.0
|
||||||
|
"""
|
||||||
|
color_factor = math.pow(spread,1)
|
||||||
|
if point[2] == 0:
|
||||||
|
blue_color = 0
|
||||||
|
red_color = 0
|
||||||
|
else:
|
||||||
|
blue_rvb = tuple(map( lambda a: int(color_factor * a), blue))
|
||||||
|
blue_color = rgb2int( blue_rvb)
|
||||||
|
red_rvb = tuple(map( lambda a: int(color_factor * a), red))
|
||||||
|
red_color = rgb2int( red_rvb)
|
||||||
|
|
||||||
|
#debug(name,"color_factor:{}\t\t blue_color:{}\t\t red_color:{}".format(color_factor,blue_color,red_color))
|
||||||
|
|
||||||
|
# Blue-to-Red spatial spread is high when spread is high, i.e. point close to center
|
||||||
|
"""
|
||||||
|
spread = 1.0 : spatial_spread = maxVal
|
||||||
|
spread = 0.0 : spatial_spread = minVal
|
||||||
|
"""
|
||||||
|
spatial_spread = minVal + spread * (maxVal - minVal)
|
||||||
|
#debug(name,"spatial_spread:{}".format(spatial_spread))
|
||||||
|
red_x = int(point[0] + spatial_spread)
|
||||||
|
blue_x = int(point[0] - spatial_spread )
|
||||||
|
red_y = int(point[1] )
|
||||||
|
blue_y = int(point[1])
|
||||||
|
|
||||||
|
white_point = [point[0], point[1], white_color]
|
||||||
|
blue_point = [blue_x,blue_y,blue_color]
|
||||||
|
red_point = [red_x,red_y,red_color]
|
||||||
|
|
||||||
|
#debug(name,"white[x,y,c]:{}".format(white_point))
|
||||||
|
#debug(name,"blue[x,y,c]:{}".format(blue_point))
|
||||||
|
#debug(name,"red[x,y,c]:{}".format(red_point))
|
||||||
|
# Do not append "black lines" i.e. a color where each composent is below X
|
||||||
|
# if isValidColor(white_rvb, 150):
|
||||||
|
# out1.append(white_point)
|
||||||
|
# if isValidColor(blue_rvb, 50):
|
||||||
|
# out2.append(blue_point)
|
||||||
|
# if isValidColor(red_rvb, 30):
|
||||||
|
# out3.append(red_point)
|
||||||
|
out1.append(white_point)
|
||||||
|
out2.append(blue_point)
|
||||||
|
out3.append(red_point)
|
||||||
|
|
||||||
|
#debug(name,"source pl:{}".format(pl))
|
||||||
|
debug(name,"whiteList:{}".format(out1))
|
||||||
|
debug(name,"blueList:{}".format(out2))
|
||||||
|
debug(name,"redList:{}".format(out3))
|
||||||
|
return out1 + out3 + out2
|
||||||
|
#return out1 + out2 + out3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
start = time.time()
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line == "":
|
||||||
|
time.sleep(0.01)
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
pointsList = ast.literal_eval(line)
|
||||||
|
# Do the filter
|
||||||
|
result = anaglyph( pointsList )
|
||||||
|
print( result, flush=True )
|
||||||
|
looptime = time.time() - start
|
||||||
|
# debug(name+" looptime:"+str(looptime))
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
# debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
except EOFError:
|
||||||
|
debug(name+" break")# no more information
|
||||||
|
|
108
clitools/filters/colorcycle.py
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
colorcycle
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
A simple effect : cycle colors
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
import ast
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
name = "filters::cycle"
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="Redis exporter LJ")
|
||||||
|
argsparser.add_argument("-x","--centerX",help="geometrical center X position",default=300,type=int)
|
||||||
|
argsparser.add_argument("-y","--centerY",help="geometrical center Y position",default=300,type=int)
|
||||||
|
argsparser.add_argument("-m","--min",help="Lowest value in the range 0-255",default=10,type=int)
|
||||||
|
argsparser.add_argument("-M","--max",help="Highest value in the range 0-255",default=255,type=int)
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
|
||||||
|
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
fps = args.fps
|
||||||
|
minVal = args.min
|
||||||
|
maxVal = args.max
|
||||||
|
centerX = args.centerX
|
||||||
|
centerY = args.centerY
|
||||||
|
verbose = args.verbose
|
||||||
|
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
|
||||||
|
UP = 5
|
||||||
|
DOWN = -5
|
||||||
|
currentColor = [0,0,0]
|
||||||
|
composant = 0
|
||||||
|
currentDirection = UP
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
def rgb2int(rgb):
|
||||||
|
return int('0x%02x%02x%02x' % tuple(rgb),0)
|
||||||
|
|
||||||
|
def cycleColor( pl ):
|
||||||
|
|
||||||
|
global composant
|
||||||
|
global currentDirection
|
||||||
|
# debug(name,"pl:{}".format(pl))
|
||||||
|
value = currentColor[composant]
|
||||||
|
if currentDirection == UP:
|
||||||
|
target = maxVal
|
||||||
|
else:
|
||||||
|
target = minVal
|
||||||
|
value += currentDirection
|
||||||
|
currentColor[composant] = value
|
||||||
|
|
||||||
|
debug(name,"currentColor:{}".format(currentColor))
|
||||||
|
for i in range( 0, len(pl)):
|
||||||
|
if pl[i][2] != 0:
|
||||||
|
pl[i][2] = rgb2int( currentColor)
|
||||||
|
|
||||||
|
# change the composant if target reached
|
||||||
|
if value <= target and currentDirection == DOWN or value >= target and currentDirection == UP :
|
||||||
|
composant = random.randint( 0,2)
|
||||||
|
value = currentColor[composant]
|
||||||
|
if value == 0 :
|
||||||
|
currentDirection = UP
|
||||||
|
else:
|
||||||
|
currentDirection = DOWN
|
||||||
|
#debug( "pl:{}".format(pl))
|
||||||
|
return pl
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
start = time.time()
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line == "":
|
||||||
|
time.sleep(0.01)
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
pointsList = ast.literal_eval(line)
|
||||||
|
# Do the filter
|
||||||
|
result = cycleColor( pointsList )
|
||||||
|
print( result, flush=True )
|
||||||
|
looptime = time.time() - start
|
||||||
|
# debug(name+" looptime:"+str(looptime))
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
# debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
except EOFError:
|
||||||
|
debug(name+" break")# no more information
|
||||||
|
|
174
clitools/filters/kaleidoscope.py
Executable file
@ -0,0 +1,174 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
kaleidoscop
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
A simple effect : mirror a quadrant of the input
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by Sam Neurohack
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
import ast
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
ljpath = r'%s' % os.getcwd().replace('\\','/')
|
||||||
|
sys.path.append(ljpath +'/../libs/')
|
||||||
|
sys.path.append(ljpath +'/libs/')
|
||||||
|
|
||||||
|
import time
|
||||||
|
name = "filters::kaleidoscope"
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="Redis exporter LJ")
|
||||||
|
argsparser.add_argument("-x","--centerX",help="geometrical center X position",default=400,type=int)
|
||||||
|
argsparser.add_argument("-y","--centerY",help="geometrical center Y position",default=400,type=int)
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
|
||||||
|
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
fps = args.fps
|
||||||
|
centerX = args.centerX
|
||||||
|
centerY = args.centerY
|
||||||
|
verbose = args.verbose
|
||||||
|
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
def kaleidoscope( pl ):
|
||||||
|
|
||||||
|
# Stage 1: Crop points in single quadrant
|
||||||
|
quad1 = []
|
||||||
|
# Iterate trough the segments
|
||||||
|
for i in range( 0, len(pl) ):
|
||||||
|
|
||||||
|
#debug(name+" point #", i)
|
||||||
|
currentpoint = cp = pl[i]
|
||||||
|
cx,cy,cc = [cp[0],cp[1],cp[2]]
|
||||||
|
|
||||||
|
# Exception: escape early if last point
|
||||||
|
if i == len(pl) - 1:
|
||||||
|
if cx >= centerX and cy >= centerY :
|
||||||
|
quad1.append( currentpoint )
|
||||||
|
break
|
||||||
|
|
||||||
|
# Search for the couple of points
|
||||||
|
nextpoint = pl[i+1]
|
||||||
|
nx,ny,nc = [nextpoint[0],nextpoint[1],nextpoint[2]]
|
||||||
|
rect=[[cx,cy],[cx,ny],[nx,ny],[nx,cy]]
|
||||||
|
|
||||||
|
right = wrong = 0
|
||||||
|
#debug(name+" rect: ", rect,"curr",currentpoint,"next",nextpoint )
|
||||||
|
|
||||||
|
# Enumerate the points in rectangle to see
|
||||||
|
# how many right / wrong there are
|
||||||
|
# either to add or skip early
|
||||||
|
for iterator, p in enumerate(rect):
|
||||||
|
if p[0] >= centerX and p[1] >= centerY:
|
||||||
|
right += 1
|
||||||
|
else:
|
||||||
|
#if p[0] <= centerX and p[1] <= centerY:
|
||||||
|
wrong += 1
|
||||||
|
# If all rectangle points are in the right quadrant, Add and Skip
|
||||||
|
if right == 4:
|
||||||
|
quad1.append(pl[i])
|
||||||
|
#debug(name+" found valid point", pl[i])
|
||||||
|
continue
|
||||||
|
# If all rectangle points in wrong quadrant, Skip
|
||||||
|
if wrong == 4:
|
||||||
|
#debug(name+" found bad point", pl[i])
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Find the (x,y) intersections
|
||||||
|
#
|
||||||
|
#debug(name+" Looking for crossing point between ("+str(cx)+","+str(cy)+") and ("+str(nx)+","+str(ny)+")")
|
||||||
|
delta=[ nx - cx, ny - cy ]
|
||||||
|
#debug(name+" delta:",delta)
|
||||||
|
crossX = None
|
||||||
|
crossY = None
|
||||||
|
absnewX = 0
|
||||||
|
absnewY = 0
|
||||||
|
# If one point has negative x, search y axis crossing
|
||||||
|
if cx < centerX or nx < centerX:
|
||||||
|
if delta[0] == 0 :
|
||||||
|
delta[0] = 0.0000001
|
||||||
|
v=[ delta[0]/abs(delta[0]), delta[1]/abs(delta[0]) ]
|
||||||
|
absnewX = abs( centerX - cx )
|
||||||
|
#print("on y axis, v=",str(v)," and absnewX=",str(absnewX))
|
||||||
|
crossX = [( absnewX*v[0] + cx ),( absnewX*v[1]+cy ), nc]
|
||||||
|
# If one point has negative y, search x axis crossing
|
||||||
|
if cy < centerY or ny < centerY:
|
||||||
|
if delta[1] == 0 :
|
||||||
|
delta[1] = 0.0000001
|
||||||
|
v=[ delta[0]/abs(delta[1]), delta[1]/abs(delta[1])]
|
||||||
|
absnewY = abs( centerY - cy )
|
||||||
|
#print("on x axis, v=",str(v)," and absnewY=",str(absnewY))
|
||||||
|
crossY = [( absnewY*v[0] + cy ),( absnewY*v[1]+cy ), nc]
|
||||||
|
# Inject in order
|
||||||
|
# If current point is the quadrant, add it
|
||||||
|
if cx >= centerX and cy >= centerY :
|
||||||
|
quad1.append( currentpoint )
|
||||||
|
# If absnewX smaller, it is closest to currentPoint
|
||||||
|
if absnewX < absnewY:
|
||||||
|
if None != crossX : quad1.append( crossX )
|
||||||
|
if None != crossY : quad1.append( crossY )
|
||||||
|
else :
|
||||||
|
if None != crossY : quad1.append( crossY )
|
||||||
|
if None != crossX : quad1.append( crossX )
|
||||||
|
# Add a black point at the end
|
||||||
|
#lastQuad1Point = quad1[-1]
|
||||||
|
#quad1.append( [lastQuad1Point[0],lastQuad1Point[1],0] )
|
||||||
|
|
||||||
|
## Stage 2 : Mirror points
|
||||||
|
#
|
||||||
|
quad2 = []
|
||||||
|
# quad2 = vertical symetric of quad1
|
||||||
|
for iterator in range( len(quad1) -1 , -1, -1):
|
||||||
|
point = quad1[iterator]
|
||||||
|
quad2.append([ point[0], 2*centerY - point[1], point[2] ])
|
||||||
|
# quad3 is the merge of 1 and 2
|
||||||
|
quad3 = quad1 + quad2
|
||||||
|
# quad4 is the horizontal symetric of quad3
|
||||||
|
quad4 = []
|
||||||
|
for iterator in range( len(quad3) -1, -1, -1):
|
||||||
|
point = quad3[iterator]
|
||||||
|
quad4.append([ 2*centerX - point[0], point[1], point[2] ])
|
||||||
|
|
||||||
|
#debug(name+" quad1:",quad1)
|
||||||
|
#debug(name+" quad2:", quad2 )
|
||||||
|
#debug(name+" quad3:", quad3 )
|
||||||
|
#debug(name+" quad4:", quad4 )
|
||||||
|
return quad3+quad4
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
start = time.time()
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line == "":
|
||||||
|
time.sleep(0.01)
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
pointsList = ast.literal_eval(line)
|
||||||
|
# Do the filter
|
||||||
|
result = kaleidoscope( pointsList )
|
||||||
|
print( result, flush=True )
|
||||||
|
|
||||||
|
looptime = time.time() - start
|
||||||
|
# debug(name+" looptime:"+str(looptime))
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
# debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
except EOFError:
|
||||||
|
debug(name+" break")# no more information
|
||||||
|
|
300
clitools/filters/redilysis.py
Executable file
@ -0,0 +1,300 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
redilysis
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
A complex effect that depends on redis keys for audio analysis
|
||||||
|
|
||||||
|
see https://git.interhacker.space/teamlase/redilysis for more informations
|
||||||
|
about the redilysis project
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import argparse
|
||||||
|
import ast
|
||||||
|
import os
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
import redis
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
name = "filters::redilysis"
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
def msNow():
|
||||||
|
return time.time()
|
||||||
|
|
||||||
|
# The list of available modes => redis keys each requires to run
|
||||||
|
oModeList = {
|
||||||
|
"rms_noise": ["rms"],
|
||||||
|
"rms_size": ["rms"],
|
||||||
|
"bpm_size": ["bpm"],
|
||||||
|
"bpm_detect_size": ["bpm","bpm_delay","bpm_sample_interval","beats"]
|
||||||
|
}
|
||||||
|
CHAOS = 1
|
||||||
|
REDISLATENCY = 30
|
||||||
|
REDIS_FREQ = 300
|
||||||
|
|
||||||
|
# General Args
|
||||||
|
argsparser = argparse.ArgumentParser(description="Redilysis filter")
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
|
||||||
|
# Redis Args
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
|
||||||
|
argsparser.add_argument("-s","--redis-freq",help="Query Redis every x (in milliseconds). Default:{}".format(REDIS_FREQ),default=REDIS_FREQ,type=int)
|
||||||
|
# General args
|
||||||
|
argsparser.add_argument("-x","--centerX",help="geometrical center X position",default=400,type=int)
|
||||||
|
argsparser.add_argument("-y","--centerY",help="geometrical center Y position",default=400,type=int)
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
# Modes And Common Modes Parameters
|
||||||
|
argsparser.add_argument("-l","--redisLatency",help="Latency in ms to substract. Default:{}".format(REDISLATENCY),default=REDISLATENCY,type=float)
|
||||||
|
argsparser.add_argument("-m","--modelist",required=True,help="Comma separated list of modes to use from: {}".format("i, ".join(oModeList.keys())),type=str)
|
||||||
|
argsparser.add_argument("--chaos",help="How much disorder to bring. High value = More chaos. Default {}".format(CHAOS), default=CHAOS, type=str)
|
||||||
|
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
ip = args.ip
|
||||||
|
port = args.port
|
||||||
|
redisFreq = args.redis_freq / 1000
|
||||||
|
verbose = args.verbose
|
||||||
|
fps = args.fps
|
||||||
|
centerX = args.centerX
|
||||||
|
centerY = args.centerY
|
||||||
|
redisLatency = args.redisLatency
|
||||||
|
chaos = float(args.chaos)
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
|
||||||
|
modeList = args.modelist.split(",")
|
||||||
|
redisKeys = []
|
||||||
|
for mode in modeList:
|
||||||
|
if not mode in oModeList:
|
||||||
|
print("Mode '{}' is invalid. Exiting.".format(mode))
|
||||||
|
sys.exit(2)
|
||||||
|
redisKeys += oModeList[mode]
|
||||||
|
redisKeys = list(set(redisKeys))
|
||||||
|
debug(name,"Redis Keys:{}".format(redisKeys))
|
||||||
|
redisData = {}
|
||||||
|
redisLastHit = msNow() - 99999
|
||||||
|
r = redis.Redis(
|
||||||
|
host=ip,
|
||||||
|
port=port)
|
||||||
|
|
||||||
|
# Records the last bpm
|
||||||
|
tsLastBeat = time.time()
|
||||||
|
|
||||||
|
def gauss(x, mu, sigma):
|
||||||
|
return( math.exp(-math.pow((x-mu),2)/(2*math.pow(sigma,2))/math.sqrt(2*math.pi*math.pow(sigma,2))))
|
||||||
|
|
||||||
|
previousPTTL = 0
|
||||||
|
tsNextBeatsList = []
|
||||||
|
def bpmDetect( ):
|
||||||
|
"""
|
||||||
|
An helper to compute the next beat time in milliseconds
|
||||||
|
Returns True if the cache was updated
|
||||||
|
"""
|
||||||
|
global tsNextBeatsList
|
||||||
|
global previousPTTL
|
||||||
|
global redisLastHit
|
||||||
|
global redisLatency
|
||||||
|
|
||||||
|
# Get the redis PTTL value for bpm
|
||||||
|
PTTL = redisData["bpm_pttl"]
|
||||||
|
|
||||||
|
# Skip early if PTTL < 0
|
||||||
|
if PTTL < 0 :
|
||||||
|
debug(name,"bpmDetect skip detection : PTTL expired for 'bpm' key")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Skip early if the record hasn't been rewritten
|
||||||
|
if PTTL <= previousPTTL :
|
||||||
|
previousPTTL = PTTL
|
||||||
|
#debug(name,"bpmDetect skip detection : {} <= {}".format(PTTL, previousPTTL))
|
||||||
|
return False
|
||||||
|
debug(name,"bpmDetect running detection : {} > {}".format(PTTL, previousPTTL))
|
||||||
|
previousPTTL = PTTL
|
||||||
|
|
||||||
|
# Skip early if beat list is empty
|
||||||
|
beatsList = ast.literal_eval(redisData["beats"])
|
||||||
|
tsNextBeatsList = []
|
||||||
|
if( len(beatsList) == 0 ):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Read from redis
|
||||||
|
bpm = float(redisData["bpm"])
|
||||||
|
msBpmDelay = float(redisData["bpm_delay"])
|
||||||
|
samplingInterval = float(redisData["bpm_sample_interval"])
|
||||||
|
|
||||||
|
# Calculate some interpolations
|
||||||
|
lastBeatTiming = float(beatsList[len(beatsList) - 1])
|
||||||
|
msPTTLDelta = 2 * samplingInterval - float(PTTL)
|
||||||
|
sPerBeat = 60 / bpm
|
||||||
|
lastBeatDelay = msBpmDelay - lastBeatTiming*1000 + msPTTLDelta
|
||||||
|
countBeatsPast = math.floor( (lastBeatDelay / 1000) / sPerBeat)
|
||||||
|
#debug(name,"bpmDetect lastBeatTiming:{}\tmsPTTLDelta:{}\tsPerBeat:{}".format(lastBeatTiming,msPTTLDelta,sPerBeat))
|
||||||
|
#debug(name,"lastBeatDelay:{}\t countBeatsPast:{}".format(lastBeatDelay, countBeatsPast))
|
||||||
|
for i in range( countBeatsPast, 1000):
|
||||||
|
beatTime = i * sPerBeat - lastBeatTiming
|
||||||
|
if beatTime < 0:
|
||||||
|
continue
|
||||||
|
if beatTime * 1000 > 2 * samplingInterval :
|
||||||
|
break
|
||||||
|
#debug(name, "bpmDetect beat add beatTime:{} redisLastHit:{}".format(beatTime, redisLastHit))
|
||||||
|
tsNextBeatsList.append( redisLastHit + beatTime - redisLatency/1000)
|
||||||
|
debug(name, "bpmDetect new tsNextBeatsList:{}".format(tsNextBeatsList))
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def bpm_detect_size( pl ):
|
||||||
|
bpmDetect()
|
||||||
|
|
||||||
|
# Find the next beat in the list
|
||||||
|
tsNextBeat = 0
|
||||||
|
|
||||||
|
now = time.time()
|
||||||
|
msNearestBeat = None
|
||||||
|
msRelativeNextBTList = list(map( lambda a: abs(now - a) * 1000, tsNextBeatsList))
|
||||||
|
msToBeat = min( msRelativeNextBTList)
|
||||||
|
|
||||||
|
#debug(name,"bpm_detect_size msRelativeNextBTList:{} msToBeat:{}".format(msRelativeNextBTList,msToBeat))
|
||||||
|
# Calculate the intensity based on bpm coming/leaving
|
||||||
|
# The curb is a gaussian
|
||||||
|
mu = 15
|
||||||
|
intensity = gauss( msToBeat, 0 , mu)
|
||||||
|
#debug(name,"bpm_size","mu:{}\t msToBeat:{}\tintensity:{}".format(mu, msToBeat, intensity))
|
||||||
|
if msToBeat < 20:
|
||||||
|
debug(name,"bpm_detect_size kick:{}".format(msToBeat))
|
||||||
|
pass
|
||||||
|
for i, point in enumerate(pl):
|
||||||
|
ref_x = point[0]-centerX
|
||||||
|
ref_y = point[1]-centerY
|
||||||
|
#debug(name,"In new ref x:{} y:{}".format(point[0]-centerX,point[1]-centerY))
|
||||||
|
angle=math.atan2( point[0] - centerX , point[1] - centerY )
|
||||||
|
l = ref_y / math.cos(angle)
|
||||||
|
new_l = l * intensity
|
||||||
|
#debug(name,"bpm_size","angle:{} l:{} new_l:{}".format(angle,l,new_l))
|
||||||
|
new_x = math.sin(angle) * new_l + centerX
|
||||||
|
new_y = math.cos(angle) * new_l + centerY
|
||||||
|
#debug(name,"x,y:({},{}) x',y':({},{})".format(point[0],point[1],new_x,new_y))
|
||||||
|
pl[i][0] = new_x
|
||||||
|
pl[i][1] = new_y
|
||||||
|
#debug( name,"bpm_detect_size output:{}".format(pl))
|
||||||
|
return( pl );
|
||||||
|
|
||||||
|
def bpm_size( pl ):
|
||||||
|
global tsLastBeat
|
||||||
|
bpm = float(redisData["bpm"])
|
||||||
|
# msseconds ber beat
|
||||||
|
msPerBeat = int(60 / bpm * 1000)
|
||||||
|
# Calculate the intensity based on bpm coming/leaving
|
||||||
|
# The curb is a gaussian
|
||||||
|
mu = math.sqrt(msPerBeat)
|
||||||
|
msTimeToLastBeat = (time.time() - tsLastBeat) * 1000
|
||||||
|
msTimeToNextBeat = (msPerBeat - msTimeToLastBeat)
|
||||||
|
intensity = gauss( msTimeToNextBeat, 0 , mu)
|
||||||
|
debug(name,"bpm_size","msPerBeat:{}\tmu:{}".format(msPerBeat, mu))
|
||||||
|
debug(name,"bpm_size","msTimeToLastBeat:{}\tmsTimeToNextBeat:{}\tintensity:{}".format(msTimeToLastBeat, msTimeToNextBeat, intensity))
|
||||||
|
if msTimeToNextBeat <= 0 :
|
||||||
|
tsLastBeat = time.time()
|
||||||
|
for i, point in enumerate(pl):
|
||||||
|
ref_x = point[0]-centerX
|
||||||
|
ref_y = point[1]-centerY
|
||||||
|
#debug(name,"In new ref x:{} y:{}".format(point[0]-centerX,point[1]-centerY))
|
||||||
|
angle=math.atan2( point[0] - centerX , point[1] - centerY )
|
||||||
|
l = ref_y / math.cos(angle)
|
||||||
|
new_l = l * intensity
|
||||||
|
#debug(name,"bpm_size","angle:{} l:{} new_l:{}".format(angle,l,new_l))
|
||||||
|
new_x = math.sin(angle) * new_l + centerX
|
||||||
|
new_y = math.cos(angle) * new_l + centerY
|
||||||
|
#debug(name,"x,y:({},{}) x',y':({},{})".format(point[0],point[1],new_x,new_y))
|
||||||
|
pl[i][0] = new_x
|
||||||
|
pl[i][1] = new_y
|
||||||
|
#debug( name,"bpm_noise output:{}".format(pl))
|
||||||
|
return pl
|
||||||
|
|
||||||
|
def rms_size( pl ):
|
||||||
|
rms = float(redisData["rms"])
|
||||||
|
for i, point in enumerate(pl):
|
||||||
|
|
||||||
|
ref_x = point[0]-centerX
|
||||||
|
ref_y = point[1]-centerY
|
||||||
|
debug(name,"In new ref x:{} y:{}".format(point[0]-centerX,point[1]-centerY))
|
||||||
|
angle=math.atan2( point[0] - centerX , point[1] - centerY )
|
||||||
|
l = ref_y / math.cos(angle)
|
||||||
|
debug(name,"angle:{} l:{}".format(angle,l))
|
||||||
|
new_l = l + rms * chaos
|
||||||
|
new_x = math.sin(angle) * new_l + centerX
|
||||||
|
new_y = math.cos(angle) * new_l + centerY
|
||||||
|
debug(name,"x,y:({},{}) x',y':({},{})".format(point[0],point[1],new_x,new_y))
|
||||||
|
pl[i][0] = new_x
|
||||||
|
pl[i][1] = new_y
|
||||||
|
#debug( name,"rms_noise output:{}".format(pl))
|
||||||
|
return pl
|
||||||
|
|
||||||
|
def rms_noise( pl ):
|
||||||
|
rms = float(redisData["rms"])
|
||||||
|
debug(name, "pl:{}".format(pl))
|
||||||
|
for i, point in enumerate(pl):
|
||||||
|
#debug(name,"rms_noise chaos:{} rms:{}".format(chaos, rms))
|
||||||
|
xRandom = random.uniform(-1,1) * rms * chaos
|
||||||
|
yRandom = random.uniform(-1,1) * rms * chaos
|
||||||
|
#debug(name,"rms_noise xRandom:{} yRandom:{}".format(xRandom, yRandom))
|
||||||
|
pl[i][0] += xRandom
|
||||||
|
pl[i][1] += yRandom
|
||||||
|
#debug( name,"rms_noise output:{}".format(pl))
|
||||||
|
return pl
|
||||||
|
|
||||||
|
|
||||||
|
def refreshRedis():
|
||||||
|
global redisLastHit
|
||||||
|
global redisData
|
||||||
|
# Skip if cache is sufficent
|
||||||
|
diff = msNow() - redisLastHit
|
||||||
|
if diff < redisFreq :
|
||||||
|
#debug(name, "refreshRedis not updating redis, {} < {}".format(diff, redisFreq))
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
#debug(name, "refreshRedis updating redis, {} > {}".format(diff, redisFreq))
|
||||||
|
redisLastHit = msNow()
|
||||||
|
for key in redisKeys:
|
||||||
|
redisData[key] = r.get(key).decode('ascii')
|
||||||
|
#debug(name,"refreshRedis key:{} value:{}".format(key,redisData[key]))
|
||||||
|
# Only update the TTLs
|
||||||
|
if 'bpm' in redisKeys:
|
||||||
|
redisData['bpm_pttl'] = r.pttl('bpm')
|
||||||
|
#debug(name,"refreshRedis key:bpm_ttl value:{}".format(redisData["bpm_pttl"]))
|
||||||
|
#debug(name,"redisData:{}".format(redisData))
|
||||||
|
return True
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
refreshRedis()
|
||||||
|
start = time.time()
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line == "":
|
||||||
|
time.sleep(0.01)
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
pointsList = ast.literal_eval(line)
|
||||||
|
# Do the filter
|
||||||
|
for mode in modeList:
|
||||||
|
pointsList = locals()[mode](pointsList)
|
||||||
|
print( pointsList, flush=True )
|
||||||
|
looptime = time.time() - start
|
||||||
|
# debug(name+" looptime:"+str(looptime))
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
# debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
except EOFError:
|
||||||
|
debug(name+" break")# no more information
|
||||||
|
|
186
clitools/filters/redilysis_colors.py
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
redilysis colors
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
A complex effect that depends on redis keys for audio analysis
|
||||||
|
|
||||||
|
see https://git.interhacker.space/teamlase/redilysis for more informations
|
||||||
|
about the redilysis project
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import argparse
|
||||||
|
import ast
|
||||||
|
import os
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
import redis
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
name = "filters::redilysis_colors"
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
def msNow():
|
||||||
|
return time.time()
|
||||||
|
|
||||||
|
# The list of available modes => redis keys each requires to run
|
||||||
|
oModeList = {
|
||||||
|
}
|
||||||
|
|
||||||
|
def rgb2int(rgb):
|
||||||
|
return int('0x%02x%02x%02x' % tuple(rgb),0)
|
||||||
|
|
||||||
|
def int2rgb(intcode):
|
||||||
|
#hexcode = hex(intcode)[2:]
|
||||||
|
hexcode = '{0:06X}'.format(intcode)
|
||||||
|
return tuple(int(hexcode[i:i+2], 16) for i in (0, 2, 4))
|
||||||
|
#return tuple(map(ord,hexcode[1:].decode('hex')))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CHAOS = 1
|
||||||
|
REDIS_FREQ = 100
|
||||||
|
|
||||||
|
# General Args
|
||||||
|
argsparser = argparse.ArgumentParser(description="Redilysis filter")
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
|
||||||
|
# Redis Args
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
|
||||||
|
argsparser.add_argument("-s","--redis-freq",help="Query Redis every x (in milliseconds). Default:{}".format(REDIS_FREQ),default=REDIS_FREQ,type=int)
|
||||||
|
# Modes And Common Modes Parameters
|
||||||
|
#argsparser.add_argument("-m","--modelist",required=False,help="Comma separated list of modes to use from: {}".format("i, ".join(oModeList.keys())),type=str)
|
||||||
|
argsparser.add_argument("-c","--chaos",help="How much disorder to bring. High value = More chaos. Default {}".format(CHAOS), default=CHAOS, type=float)
|
||||||
|
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
fps = args.fps
|
||||||
|
ip = args.ip
|
||||||
|
port = args.port
|
||||||
|
redisFreq = args.redis_freq / 1000
|
||||||
|
verbose = args.verbose
|
||||||
|
chaos = float(args.chaos)
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
|
||||||
|
max_width = 800
|
||||||
|
max_height = 800
|
||||||
|
|
||||||
|
redisKeys = ["rms","spectrum_10","spectrum_120"]
|
||||||
|
|
||||||
|
debug(name,"Redis Keys:{}".format(redisKeys))
|
||||||
|
redisData = {}
|
||||||
|
redisLastHit = msNow() - 99999
|
||||||
|
r = redis.Redis(
|
||||||
|
host=ip,
|
||||||
|
port=port)
|
||||||
|
|
||||||
|
|
||||||
|
def refreshRedis():
|
||||||
|
global redisData
|
||||||
|
for key in redisKeys:
|
||||||
|
try:
|
||||||
|
redisData[key] = ast.literal_eval(r.get(key).decode('ascii'))
|
||||||
|
except :
|
||||||
|
debug("Error when reading redis key '{}".format(key))
|
||||||
|
|
||||||
|
def gauss(x, mu, sigma):
|
||||||
|
return( math.exp(-math.pow((x-mu),2)/(2*math.pow(sigma,2))/math.sqrt(2*math.pi*math.pow(sigma,2))))
|
||||||
|
|
||||||
|
|
||||||
|
spect10Correct = [
|
||||||
|
|
||||||
|
6.0,
|
||||||
|
1.5,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
0.8,
|
||||||
|
0.6,
|
||||||
|
0.5,
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
def default( pl ):
|
||||||
|
global redisData
|
||||||
|
spect = redisData["spectrum_10"]
|
||||||
|
debug(name, "spect:{}".format(spect))
|
||||||
|
new_list = []
|
||||||
|
|
||||||
|
# We want to color points that are on left and right when high is strong
|
||||||
|
# i.e. the farther the distance from spectrum, the higher notes have influence
|
||||||
|
# power = 0-1
|
||||||
|
# x = 800 spec[2]= 6.0 spec[7]=0.0 power=0.0
|
||||||
|
# x = 0 spec[2]= 6.0 spec[7]=0.0 power=0.0
|
||||||
|
# x = 0 spec[2]= 1.0 spec[7]=0.5 power=1.0
|
||||||
|
|
||||||
|
# dist 0 = 1
|
||||||
|
# 400 - 400 : maxW/2 -x
|
||||||
|
# 399 = -1 : x - 400
|
||||||
|
# 401 = 1
|
||||||
|
# x = 400 spec[2]= 6.0 spec[7]=0.0 power=1.0
|
||||||
|
# x = 400 spec[2]= 1.0 spec[7]=0.5 power=0.0
|
||||||
|
|
||||||
|
for i, point in enumerate(pl):
|
||||||
|
ocolor = pl[i][2]
|
||||||
|
if ocolor == 0 :
|
||||||
|
new_list.append(point)
|
||||||
|
continue
|
||||||
|
colorTuple = int2rgb(ocolor)
|
||||||
|
x = point[0]
|
||||||
|
dist = abs(x - max_width/2)
|
||||||
|
key = int(2* dist / max_width * 8)
|
||||||
|
power = spect[key] / spect10Correct[key] * chaos
|
||||||
|
color = []
|
||||||
|
for i in colorTuple:
|
||||||
|
new_color = int(i * power)
|
||||||
|
if new_color > 255 :
|
||||||
|
new_color = 255
|
||||||
|
if new_color < 0 :
|
||||||
|
new_color = 0
|
||||||
|
color.append( new_color )
|
||||||
|
color = rgb2int(tuple(color))
|
||||||
|
|
||||||
|
point[2] = color
|
||||||
|
new_list.append(point)
|
||||||
|
#debug(name,"x:{}\t dist:{}\t key:{}\t power:{}\t ocolor:{}\t color:{}".format(point[0], dist, key,power, ocolor, pl[i][2]))
|
||||||
|
debug( name,"rms_noise output:{}".format(new_list))
|
||||||
|
return new_list
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
refreshRedis()
|
||||||
|
start = time.time()
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if line == "":
|
||||||
|
time.sleep(0.01)
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
pointsList = ast.literal_eval(line)
|
||||||
|
# Do the filter
|
||||||
|
pointsList = default(pointsList)
|
||||||
|
print( pointsList, flush=True )
|
||||||
|
looptime = time.time() - start
|
||||||
|
# debug(name+" looptime:"+str(looptime))
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
# debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
except EOFError:
|
||||||
|
debug(name+" break")# no more information
|
||||||
|
|
BIN
clitools/generators/.DS_Store
vendored
Normal file
2407
clitools/generators/159.gml
Executable file
2791
clitools/generators/160.gml
Executable file
2873
clitools/generators/OSC3.py
Normal file
BIN
clitools/generators/__pycache__/OSC3.cpython-38.pyc
Normal file
BIN
clitools/generators/__pycache__/turtle.cpython-38.pyc
Normal file
53
clitools/generators/blank.py
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
Send only black points
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
Use it to test your filters and outputs
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
name="generator::dummy"
|
||||||
|
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="dummy generator")
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
fps=args.fps
|
||||||
|
verbose=args.verbose
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
debug(name+" optimal looptime "+str(optimal_looptime))
|
||||||
|
|
||||||
|
|
||||||
|
shape = [[400,400,0],[400,400,64],[400,400,0]]
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
start = time.time()
|
||||||
|
print(shape, flush=True);
|
||||||
|
looptime = time.time() - start
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
|
||||||
|
|
BIN
clitools/generators/book2.ild
Executable file
54
clitools/generators/brmlab1.svg
Executable file
@ -0,0 +1,54 @@
|
|||||||
|
<?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"
|
||||||
|
xml:space="preserve"
|
||||||
|
height="53"
|
||||||
|
width="299.96875"
|
||||||
|
version="1.1"
|
||||||
|
id="svg2"
|
||||||
|
inkscape:version="0.48.0 r9654"
|
||||||
|
sodipodi:docname="brmlab1.svg"
|
||||||
|
inkscape:export-filename="/home/prusnak/work/scm/laserdisplay/svglaser/templates/template3.svg.png"
|
||||||
|
inkscape:export-xdpi="200"
|
||||||
|
inkscape:export-ydpi="200"><defs
|
||||||
|
id="defs2988" /><metadata
|
||||||
|
id="metadata78"><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><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1024"
|
||||||
|
inkscape:window-height="689"
|
||||||
|
id="namedview76"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1"
|
||||||
|
inkscape:cx="-2.5851173"
|
||||||
|
inkscape:cy="-55.600814"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="25"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg2"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:snap-global="true"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0" />
|
||||||
|
<path
|
||||||
|
id="path20"
|
||||||
|
style="fill:none;stroke:#000000;stroke-opacity:1"
|
||||||
|
d="m 137.17375,22.4425 c 0,-1.815 5.24,-4.345 13.73375,-4.345 3.94875,0 7.73,0.59 10.37875,1.62 2.085,0.81125 3.32875,1.83 3.32875,2.725 0,9.0725 0.0188,30.05375 0.0188,30.05375 l 5.87245,-0.004 c 0,-10e-4 -0.0175,-20.97875 -0.0175,-30.05 0,-2.035 -0.9175,-5.805 -7.0725,-8.2 -3.35125,-1.3025 -7.7925,-2.01875 -12.50875,-2.01875 -4.71625,0 -9.15875,0.71625 -12.50875,2.01875 -1.7975,0.7 -3.16375,1.50625 -4.175,2.3625 -1.01,-0.8475 -2.3675,-1.66875 -4.15,-2.3625 -3.34875,-1.3025 -7.79125,-2.01875 -12.50875,-2.01875 -4.715,0 -9.15625,0.71625 -12.50625,2.01875 -6.15625,2.395 -7.075,6.165 -7.075,8.2 0,9.8775 -0.0163,30.04875 -0.0163,30.04875 l 5.87375,0.005 c 0,0 0.0175,-20.17375 0.0175,-30.05375 0,-1.815 5.215,-4.345 13.70625,-4.345 3.94875,0 7.73125,0.59 10.38,1.62 2.08375,0.81125 3.32875,1.83 3.32875,2.725 0,9.0725 0.0175,30.0575 0.0175,30.0575 l 5.87375,-0.005 c 0,0 0.009,-20.98125 0.009,-30.0525 M 93.61125,18.3922 c -1.0075,-1.47125 -2.7675,-2.98 -5.79125,-4.15625 -3.35,-1.3025 -7.79375,-2.02 -12.50875,-2.02 -4.715,0 -9.15875,0.7175 -12.5075,2.02 C 56.64875,16.63 55.73,20.4 55.73,22.435 c 0,9.87875 -0.0175,30.04875 -0.0175,30.04875 l 5.87375,0.005 c 0,0 0.0175,-20.17375 0.0175,-30.05375 0,-1.81375 5.21375,-4.345 13.7075,-4.345 3.9475,0 7.73,0.59 10.37875,1.62125 1.58875,0.6175 2.6875,1.355 3.1225,2.0675 l 4.79875,-3.38625 z m 86.2125,34.1 5.874,0 0,-52.0075 -5.874,0 0,52.0075 z m 24.45,-33.325 c -0.89625,0 -1.91375,1.24375 -2.725,3.32875 -1.03,2.64875 -1.62125,6.43125 -1.62125,10.37875 0,8.4925 2.53125,13.7075 4.34625,13.7075 7.19625,0 24.94,0.0225 31.975,0.0313 l 0,-27.44625 -31.975,0 z m 37.84875,33.32875 -2.94,-0.004 c 0,0 -25.83625,-0.035 -34.90875,-0.035 -2.035,0 -5.80625,-0.91875 -8.2,-7.07375 -1.3025,-3.35125 -2.02,-7.7925 -2.02,-12.50875 0,-4.715 0.7175,-9.1575 2.02,-12.5075 2.39375,-6.155 6.165,-7.075 8.2,-7.075 l 34.9125,0 2.91979,0.006 0.0165,39.198 z m 49.85125,-9.24125 c -0.80875,2.085 -1.82875,3.32875 -2.7225,3.32875 -7.1975,0 -24.94125,0.0225 -31.97625,0.0313 l 0,-27.4475 31.97625,0.001 c 1.81375,0 4.345,5.215 4.345,13.7075 0,3.94625 -0.5925,7.73 -1.6225,10.37875 M 297.45,20.3687 c -2.39375,-6.155 -6.165,-7.075 -8.19875,-7.075 l -31.97625,-0.002 0,-12.80625 -5.87375,0 0,52.0125 2.94125,-0.004 c 0,0 25.83625,-0.0362 34.90875,-0.0362 2.03375,0 5.805,-0.9175 8.19875,-7.0725 1.30375,-3.35125 2.02,-7.7925 2.02,-12.50875 0,-4.715 -0.71625,-9.1575 -2.02,-12.5075 M 41.07375,43.255 c -0.80875,2.085 -1.82875,3.32875 -2.725,3.32875 -7.195,0 -24.94,0.0225 -31.97375,0.0313 l 0,-27.4475 31.97375,0.001 c 1.815,0 4.34625,5.215 4.34625,13.7075 0,3.94625 -0.5925,7.73 -1.62125,10.37875 m 5.475,-22.88625 c -2.39375,-6.155 -6.16375,-7.075 -8.2,-7.075 l -31.97375,-0.002 0,-12.80625 -5.875,0 0,52.0125 2.9425,-0.004 c 0,0 25.835,-0.0362 34.90625,-0.0362 2.03625,0 5.80625,-0.9175 8.2,-7.0725 1.30375,-3.35125 2.02,-7.7925 2.02,-12.50875 0,-4.715 -0.71625,-9.1575 -2.02,-12.5075"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.6 KiB |
53
clitools/generators/brmlab2.svg
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
<?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"
|
||||||
|
xml:space="preserve"
|
||||||
|
height="78.96875"
|
||||||
|
width="78.96875"
|
||||||
|
version="1.1"
|
||||||
|
id="svg2"
|
||||||
|
inkscape:version="0.48.0 r9654"
|
||||||
|
sodipodi:docname="brmlab2.svg"
|
||||||
|
inkscape:export-filename="/home/prusnak/work/scm/laserdisplay/svglaser/templates/template4.svg.png"
|
||||||
|
inkscape:export-xdpi="200"
|
||||||
|
inkscape:export-ydpi="200"><defs
|
||||||
|
id="defs2994" /><metadata
|
||||||
|
id="metadata78"><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><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1024"
|
||||||
|
inkscape:window-height="689"
|
||||||
|
id="namedview76"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1"
|
||||||
|
inkscape:cx="25.043829"
|
||||||
|
inkscape:cy="5.6960585"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="25"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg2"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:snap-global="true"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0" />
|
||||||
|
<path
|
||||||
|
id="path3237"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:1"
|
||||||
|
d="m 20.26276,45.39193 c -1.816875,0 -3.293437,-1.4775 -3.293437,-3.29344 0,-1.81593 1.476562,-3.29437 3.293437,-3.29437 1.816875,0 3.294375,1.47844 3.294375,3.29437 0,1.81594 -1.4775,3.29344 -3.294375,3.29344 M 39.480011,0.50605 C 17.985519,0.50605 0.5,17.99425 0.5,39.48874 c 0,10.41205 4.0546519,20.20071 11.416975,27.56304 7.363668,7.36232 17.15099,11.41697 27.563036,11.41697 21.494491,0 38.982697,-17.48686 38.982697,-38.98001 C 78.461408,17.99291 60.974502,0.50605 39.480011,0.50605 m -0.09362,68.75171 c -5.945327,0 -11.681286,-1.74473 -16.588197,-5.04528 l -0.998709,-0.67022 0.765276,-0.92531 c 1.473999,-1.78685 1.350062,-4.36785 -0.289986,-6.0079 -0.844692,-0.84469 -1.96854,-1.31035 -3.163381,-1.31035 -1.037214,0 -2.046752,0.36218 -2.843313,1.01916 l -0.926513,0.76407 -0.670218,-0.9963 C 6.757481,44.32012 8.3000651,28.49238 18.341303,18.45235 c 4.199391,-4.2018 9.490142,-7.02345 15.299501,-8.16174 l 1.179198,-0.22982 0.115514,1.19484 c 0.220197,2.30425 2.13459,4.04176 4.452076,4.04176 2.317487,0 4.23188,-1.73751 4.45328,-4.04176 l 0.115513,-1.19484 1.177996,0.22982 c 5.806952,1.13829 11.098906,3.95994 15.299501,8.15933 10.040034,10.04124 11.583822,25.87018 3.668751,37.63569 l -0.670218,0.9963 -0.92531,-0.76527 c -0.798967,-0.65698 -1.807302,-1.01796 -2.845719,-1.01796 -1.194841,0 -2.317486,0.46446 -3.163381,1.30915 -1.638845,1.64005 -1.762781,4.22225 -0.289986,6.0091 l 0.764072,0.92531 -0.996302,0.67022 c -4.90691,3.30055 -10.644073,5.04528 -16.5894,5.04528 m -7.130784,-26.72605 14.281498,0 0,-6.00112 -14.281498,0 0,6.00112 z M 24.122448,30.11568 c -1.816875,0 -3.294375,-1.4775 -3.294375,-3.29344 0,-1.81593 1.4775,-3.29437 3.294375,-3.29437 1.815937,0 3.293437,1.47844 3.293437,3.29437 0,1.81594 -1.4775,3.29344 -3.293437,3.29344 m 34.387656,15.27625 c -1.815937,0 -3.294375,-1.4775 -3.294375,-3.29344 0,-1.81593 1.478438,-3.29437 3.294375,-3.29437 1.816875,0 3.294375,1.47844 3.294375,3.29437 0,1.81594 -1.4775,3.29344 -3.294375,3.29344 m -26.905937,15.1875 c -1.815938,0 -3.292501,-1.4775 -3.292501,-3.29344 0,-1.81593 1.476563,-3.29437 3.292501,-3.29437 1.816875,0 3.294374,1.47844 3.294374,3.29437 0,1.81594 -1.477499,3.29344 -3.294374,3.29344 M 54.647291,30.11568 c -1.816874,0 -3.294374,-1.4775 -3.294374,-3.29344 0,-1.81593 1.4775,-3.29437 3.294374,-3.29437 1.815938,0 3.292501,1.47844 3.292501,3.29437 0,1.81594 -1.476563,3.29344 -3.292501,3.29344 m -7.474843,30.46375 c -1.816875,0 -3.294375,-1.4775 -3.294375,-3.29344 0,-1.81593 1.4775,-3.29437 3.294375,-3.29437 1.815937,0 3.293437,1.47844 3.293437,3.29437 0,1.81594 -1.4775,3.29344 -3.293437,3.29344 m -7.775,-30.46375 c -1.816875,0 -3.294375,-1.4775 -3.294375,-3.29344 0,-1.81593 1.4775,-3.29437 3.294375,-3.29437 1.815937,0 3.293437,1.47844 3.293437,3.29437 0,1.81594 -1.4775,3.29344 -3.293437,3.29344"
|
||||||
|
inkscape:connector-curvature="0" /></svg>
|
After Width: | Height: | Size: 4.5 KiB |
85
clitools/generators/dummy.py
Executable file
@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
This is the most basic generator you can imagine: straight up static!
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
Use it to test your filters and outputs
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
name="generator::dummy"
|
||||||
|
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="dummy generator")
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-s","--speed",help="point per frame progress",default=3,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
fps=args.fps
|
||||||
|
verbose=args.verbose
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
debug(name+" optimal looptime "+str(optimal_looptime))
|
||||||
|
color = 16777215
|
||||||
|
square = [[100.0, 100.0, color], [100.0, 500.0, color], [500.0, 500.0, color], [500.0, 100.0, color], [100.0, 100.0, color]]
|
||||||
|
line =[]
|
||||||
|
for i in range(00,800,int(800/120)):
|
||||||
|
line.append([i, 400, color])
|
||||||
|
square = [[100.0, 100.0, color], [100.0, 500.0, color], [500.0, 500.0, color], [500.0, 100.0, color], [100.0, 100.0, color]]
|
||||||
|
mire = [
|
||||||
|
[600,600,0],
|
||||||
|
[600,600,color],
|
||||||
|
[700,600,color],
|
||||||
|
[700,700,color],
|
||||||
|
[600,700,color],
|
||||||
|
[600,600,color],
|
||||||
|
[100,100,0],
|
||||||
|
[100,100,color],
|
||||||
|
[200,100,color],
|
||||||
|
[200,200,color],
|
||||||
|
[100,200,color],
|
||||||
|
[100,100,color],
|
||||||
|
[0,0,0],
|
||||||
|
[0,0,color],
|
||||||
|
[800,0,color],
|
||||||
|
[800,800,color],
|
||||||
|
[0,800,color],
|
||||||
|
[0,0,color],
|
||||||
|
[350,400,0],
|
||||||
|
[350,400,color],
|
||||||
|
[450,400,color],
|
||||||
|
[400,350,0],
|
||||||
|
[400,350,color],
|
||||||
|
[400,450,color],
|
||||||
|
]
|
||||||
|
|
||||||
|
shape = mire
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
start = time.time()
|
||||||
|
print(shape, flush=True);
|
||||||
|
looptime = time.time() - start
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
|
||||||
|
|
182
clitools/generators/example.py
Executable file
@ -0,0 +1,182 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
example, based on custom
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
A copy of square.py you can modify to code your plugin.
|
||||||
|
custom1 has necessary hooks in LJ.conf, webui and so on.
|
||||||
|
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by Sam Neurohack
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
ljpath = r'%s' % os.getcwd().replace('\\','/')
|
||||||
|
|
||||||
|
# import from shell
|
||||||
|
sys.path.append(ljpath +'/../../libs/')
|
||||||
|
|
||||||
|
#import from LJ
|
||||||
|
sys.path.append(ljpath +'/libs/')
|
||||||
|
print(ljpath+'/../libs/')
|
||||||
|
|
||||||
|
import lj23layers as lj
|
||||||
|
|
||||||
|
sys.path.append('../libs')
|
||||||
|
import math
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
print ("")
|
||||||
|
print ("Arguments parsing if needed...")
|
||||||
|
argsparser = argparse.ArgumentParser(description="Custom1 example for LJ")
|
||||||
|
argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",default=0,type=int)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
# Useful variables init.
|
||||||
|
white = lj.rgb2int(255,255,255)
|
||||||
|
red = lj.rgb2int(255,0,0)
|
||||||
|
blue = lj.rgb2int(0,0,255)
|
||||||
|
green = lj.rgb2int(0,255,0)
|
||||||
|
|
||||||
|
width = 800
|
||||||
|
height = 600
|
||||||
|
centerX = width / 2
|
||||||
|
centerY = height / 2
|
||||||
|
|
||||||
|
# 3D to 2D projection parameters
|
||||||
|
fov = 256
|
||||||
|
viewer_distance = 2.2
|
||||||
|
|
||||||
|
# Anaglyph computation parameters for right and left eyes.
|
||||||
|
# algorythm come from anaglyph geo maps
|
||||||
|
eye_spacing = 100
|
||||||
|
nadir = 0.5
|
||||||
|
observer_altitude = 30000
|
||||||
|
map_layerane_altitude = 0.0
|
||||||
|
|
||||||
|
# square coordinates : vertices that compose each of the square.
|
||||||
|
vertices = [
|
||||||
|
(- 1.0, 1.0,- 1.0),
|
||||||
|
( 1.0, 1.0,- 1.0),
|
||||||
|
( 1.0,- 1.0,- 1.0),
|
||||||
|
(- 1.0,- 1.0,- 1.0)
|
||||||
|
]
|
||||||
|
|
||||||
|
face = [0,1,2,3]
|
||||||
|
|
||||||
|
#
|
||||||
|
# LJ inits
|
||||||
|
#
|
||||||
|
|
||||||
|
layer = 0
|
||||||
|
|
||||||
|
# Define properties for each drawn "element" : name, intensity, active, xy, color, red, green, blue, layer , closed
|
||||||
|
Leftsquare = lj.FixedObject('Leftsquare', True, 255, [], red, 255, 0, 0, layer , True)
|
||||||
|
Rightsquare = lj.FixedObject('Rightsquare', True, 255, [], green, 0, 255, 0, layer , True)
|
||||||
|
|
||||||
|
# 'Destination' for given layer : name, number, active, layer , scene, laser
|
||||||
|
Dest0 = lj.DestObject('0', 0, True, 0 , 0, 0) # Dest0 will send layer 0 points to scene 0, laser 0
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Anaglyph computation : different X coordinate for each eye
|
||||||
|
#
|
||||||
|
|
||||||
|
def LeftShift(elevation):
|
||||||
|
|
||||||
|
diff = elevation - map_layerane_altitude
|
||||||
|
return nadir * eye_spacing * diff / (observer_altitude - elevation)
|
||||||
|
|
||||||
|
def RightShift(elevation):
|
||||||
|
|
||||||
|
diff = map_layerane_altitude - elevation
|
||||||
|
return (1 - nadir) * eye_spacing * diff / (observer_altitude - elevation)
|
||||||
|
|
||||||
|
|
||||||
|
def Proj(x,y,z,angleX,angleY,angleZ):
|
||||||
|
|
||||||
|
rad = angleX * math.pi / 180
|
||||||
|
cosa = math.cos(rad)
|
||||||
|
sina = math.sin(rad)
|
||||||
|
y2 = y
|
||||||
|
y = y2 * cosa - z * sina
|
||||||
|
z = y2 * sina + z * cosa
|
||||||
|
|
||||||
|
rad = angleY * math.pi / 180
|
||||||
|
cosa = math.cos(rad)
|
||||||
|
sina = math.sin(rad)
|
||||||
|
z2 = z
|
||||||
|
z = z2 * cosa - x * sina
|
||||||
|
x = z2 * sina + x * cosa
|
||||||
|
|
||||||
|
rad = angleZ * math.pi / 180
|
||||||
|
cosa = math.cos(rad)
|
||||||
|
sina = math.sin(rad)
|
||||||
|
x2 = x
|
||||||
|
x = x2 * cosa - y * sina
|
||||||
|
y = x2 * sina + y * cosa
|
||||||
|
|
||||||
|
|
||||||
|
""" Transforms this 3D point to 2D using a perspective projection. """
|
||||||
|
factor = fov / (viewer_distance + z)
|
||||||
|
x = x * factor + centerX
|
||||||
|
y = - y * factor + centerY
|
||||||
|
return (x,y)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Main
|
||||||
|
#
|
||||||
|
|
||||||
|
def Run():
|
||||||
|
Left = []
|
||||||
|
Right = []
|
||||||
|
counter =0
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
Left = []
|
||||||
|
Right = []
|
||||||
|
x = vertices[0][0]
|
||||||
|
y = vertices[0][1]
|
||||||
|
z = vertices[0][2]
|
||||||
|
|
||||||
|
# lj tracers will "move" the laser to this first point in black, then move to the next with second point color.
|
||||||
|
# for more accuracy in dac emulator, repeat this first point.
|
||||||
|
|
||||||
|
# generate all points in square.
|
||||||
|
for point in face:
|
||||||
|
x = vertices[point][0]
|
||||||
|
y = vertices[point][1]
|
||||||
|
z = vertices[point][2]
|
||||||
|
left.append(proj(x+leftshift(z*25),y,z,0,counter,0))
|
||||||
|
right.append(proj(x+rightshift(z*25),y,z,0,counter,0))
|
||||||
|
|
||||||
|
|
||||||
|
lj.polylineonecolor(left, c = leftsquare.color , layer = leftsquare.layer, closed = leftsquare.closed)
|
||||||
|
lj.polylineonecolor(right, c = rightsquare.color , layer = rightsquare.layer, closed = rightsquare.closed)
|
||||||
|
lj.drawdests()
|
||||||
|
time.sleep(0.1)
|
||||||
|
counter += 1
|
||||||
|
if counter > 360:
|
||||||
|
counter = 0
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Gently stop on CTRL C
|
||||||
|
finally:
|
||||||
|
lj.ClosePlugin()
|
||||||
|
|
||||||
|
|
||||||
|
Run()
|
406
clitools/generators/fromGML.py
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
fromGML
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
Display a GML file
|
||||||
|
|
||||||
|
See GML specs at the end.
|
||||||
|
Support the gml spec="1.0 (minimum)"
|
||||||
|
and header/client/name
|
||||||
|
and maybe one day drawing/brush/color
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
by cocoa and Sam Neurohack
|
||||||
|
|
||||||
|
Heavy use of : https://github.com/kgn/pygml
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import time
|
||||||
|
import struct
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as etree
|
||||||
|
#import urllib
|
||||||
|
from datetime import datetime
|
||||||
|
import math, random
|
||||||
|
import ast
|
||||||
|
|
||||||
|
name="generator::fromgml"
|
||||||
|
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="GML file frame generator")
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
argsparser.add_argument("-g","--gml",help=".gml file",default="147.gml",type=str)
|
||||||
|
argsparser.add_argument("-t","--total",help="Total time",default=32,type=int)
|
||||||
|
argsparser.add_argument("-m","--mode",help="once or anim mode",default="anim",type=str)
|
||||||
|
argsparser.add_argument("-s","--skip",help="% of points to skip",default="0.4",type=float)
|
||||||
|
argsparser.add_argument("-r","--rot",help="(angleX, angleY, angleZ) in degree",default="(0,0,270)",type=str)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
fps=args.fps
|
||||||
|
verbose=args.verbose
|
||||||
|
mode = args.mode
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
angles = ast.literal_eval(args.rot)
|
||||||
|
debug(name+" optimal frame time "+str(optimal_looptime))
|
||||||
|
|
||||||
|
|
||||||
|
TOTAL_TIME=float(args.total)
|
||||||
|
TIME_STRETCH = 1
|
||||||
|
ZOOM=1.0
|
||||||
|
DELTA = 7
|
||||||
|
width = 500
|
||||||
|
height = 500
|
||||||
|
centerX = width / 2
|
||||||
|
centerY = height / 2
|
||||||
|
# 3D to 2D projection parameters
|
||||||
|
fov = 200
|
||||||
|
viewer_distance = 2.2
|
||||||
|
|
||||||
|
skip = args.skip
|
||||||
|
#skip is the percentage of points that we ignore in order to render
|
||||||
|
# faster in the laser display. Unfortunately we are not able to render too
|
||||||
|
# complex content in our display without resulting in a lot of blinking.
|
||||||
|
|
||||||
|
# return a list with all points
|
||||||
|
def readGML(filename):
|
||||||
|
|
||||||
|
outputData = []
|
||||||
|
tree = etree.parse(filename)
|
||||||
|
root = tree.getroot()
|
||||||
|
'''
|
||||||
|
if (root.tag.lower() != "gml"):
|
||||||
|
print("Not a GML file.")
|
||||||
|
return
|
||||||
|
'''
|
||||||
|
#~
|
||||||
|
tag = root.find("tag")
|
||||||
|
header = tag.find("header")
|
||||||
|
if header != None:
|
||||||
|
client = header.find("client")
|
||||||
|
if client != None:
|
||||||
|
debug("Graffiti name :", client.find("name").text)
|
||||||
|
drawing = tag.find("drawing")
|
||||||
|
environment = header.find("environment")
|
||||||
|
if not environment:
|
||||||
|
environment = tag.find("environment")
|
||||||
|
#screenBounds = environment.find("screenBounds")
|
||||||
|
#globalScale = (1.0,1.0,1.0)
|
||||||
|
#dim = (float(screenBounds.find("x").text) * globalScale[0], float(screenBounds.find("y").text) * globalScale[1], float(screenBounds.find("z").text) * globalScale[2])
|
||||||
|
#dim = (40.0,40.0,40.0)
|
||||||
|
#~
|
||||||
|
strokes = drawing.findall("stroke")
|
||||||
|
for stroke in strokes:
|
||||||
|
pointsEl = stroke.findall("pt")
|
||||||
|
for pointEl in pointsEl:
|
||||||
|
|
||||||
|
x = float(pointEl.find("x").text) - 0.5
|
||||||
|
y = float(pointEl.find("y").text) - 0.5
|
||||||
|
z = float(pointEl.find("z").text) - 0.5
|
||||||
|
transpoint = Rot(x,y,z,angles[0],angles[1],angles[2])
|
||||||
|
x = (transpoint[0]*ZOOM*width/2) + (width/2)
|
||||||
|
y = (transpoint[1]*ZOOM*height/2) + (height/2)
|
||||||
|
z = transpoint[2]
|
||||||
|
# WIDTH/2 + ZOOM*point[0]*WIDTH/2, HEIGHT/2 + ZOOM*point[1]*HEIGHT/2
|
||||||
|
time = float(pointEl.find("time").text)
|
||||||
|
outputData.append([x,y,z,time])
|
||||||
|
#print(outputData)
|
||||||
|
return outputData
|
||||||
|
|
||||||
|
def Rot(x, y, z, angleX, angleY, angleZ):
|
||||||
|
|
||||||
|
rad = angleX * math.pi / 180
|
||||||
|
cosa = math.cos(rad)
|
||||||
|
sina = math.sin(rad)
|
||||||
|
y2 = y
|
||||||
|
y = y2 * cosa - z * sina
|
||||||
|
z = y2 * sina + z * cosa
|
||||||
|
|
||||||
|
rad = angleY * math.pi / 180
|
||||||
|
cosa = math.cos(rad)
|
||||||
|
sina = math.sin(rad)
|
||||||
|
z2 = z
|
||||||
|
z = z2 * cosa - x * sina
|
||||||
|
x = z2 * sina + x * cosa
|
||||||
|
|
||||||
|
rad = angleZ * math.pi / 180
|
||||||
|
cosa = math.cos(rad)
|
||||||
|
sina = math.sin(rad)
|
||||||
|
x2 = x
|
||||||
|
x = x2 * cosa - y * sina
|
||||||
|
y = x2 * sina + y * cosa
|
||||||
|
|
||||||
|
return (x,y,z)
|
||||||
|
|
||||||
|
|
||||||
|
#[x,y,z,time]
|
||||||
|
def iterPoints():
|
||||||
|
|
||||||
|
for point in gml:
|
||||||
|
yield point
|
||||||
|
|
||||||
|
|
||||||
|
# Play once during total time arg
|
||||||
|
def Once():
|
||||||
|
|
||||||
|
debug(name,"play once mode")
|
||||||
|
shape = []
|
||||||
|
for point in gml:
|
||||||
|
shape.append([point[0],point[1], 65535])
|
||||||
|
debug(name + str(shape))
|
||||||
|
|
||||||
|
t0=datetime.now()
|
||||||
|
deltat=0
|
||||||
|
|
||||||
|
while deltat<TOTAL_TIME:
|
||||||
|
|
||||||
|
start = time.time()
|
||||||
|
print(shape, flush=True);
|
||||||
|
looptime = time.time() - start
|
||||||
|
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
|
||||||
|
delta = datetime.now() - t0
|
||||||
|
deltat = delta.seconds + delta.microseconds/1000000.0
|
||||||
|
deltat = float(deltat)/TIME_STRETCH
|
||||||
|
|
||||||
|
|
||||||
|
# Anim
|
||||||
|
def Anim():
|
||||||
|
|
||||||
|
debug(name+" anim mode")
|
||||||
|
t0=datetime.now()
|
||||||
|
deltat = 0
|
||||||
|
|
||||||
|
while deltat<TOTAL_TIME:
|
||||||
|
|
||||||
|
delta = datetime.now() - t0
|
||||||
|
deltat = delta.seconds + delta.microseconds/1000000.0
|
||||||
|
deltat = float(deltat)/TIME_STRETCH
|
||||||
|
|
||||||
|
if deltat > TOTAL_TIME:
|
||||||
|
t0=datetime.now()
|
||||||
|
|
||||||
|
first=True
|
||||||
|
shape = []
|
||||||
|
for point in iterPoints():
|
||||||
|
if point[3] <= deltat and deltat <= point[3]+DELTA and random.random()<(1-skip):
|
||||||
|
if first:
|
||||||
|
first=False
|
||||||
|
else:
|
||||||
|
#LD.draw_point(WIDTH/2 + ZOOM*point.x*WIDTH/2, HEIGHT/2 + ZOOM*point.y*HEIGHT/2)
|
||||||
|
shape.append([point[0], point[1], 65535])
|
||||||
|
print(shape, flush=True);
|
||||||
|
|
||||||
|
|
||||||
|
debug(name + " Reading : "+args.gml+" in "+mode+" mode.")
|
||||||
|
gml = readGML(args.gml)
|
||||||
|
|
||||||
|
debug(name + " total points : "+ str(len(gml)))
|
||||||
|
|
||||||
|
if mode =="once":
|
||||||
|
Once()
|
||||||
|
else:
|
||||||
|
Anim()
|
||||||
|
|
||||||
|
debug(name + " ends.")
|
||||||
|
exit()
|
||||||
|
'''
|
||||||
|
|
||||||
|
<gml spec="1.0 (minimum)">
|
||||||
|
|
||||||
|
<tag>
|
||||||
|
<drawing>
|
||||||
|
<stroke>
|
||||||
|
<pt>
|
||||||
|
<x>0.0</x>
|
||||||
|
<y>0.0</y>
|
||||||
|
</pt>
|
||||||
|
</stroke>
|
||||||
|
</drawing>
|
||||||
|
</tag>
|
||||||
|
|
||||||
|
</gml>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<gml spec="1.0">
|
||||||
|
|
||||||
|
<tag>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
|
||||||
|
<client> <!-- how, who, what and where -->
|
||||||
|
<name>Laser Tag</name> <!-- application name -->
|
||||||
|
<version>2.0</version> <!-- application version -->
|
||||||
|
<username>MyUserName</username> <!-- user name on 000000book.com, optional -->
|
||||||
|
<permalink>http://000000book.com/data/156/</permalink> <!-- URL to .gml data on 000000book.com, optional -->
|
||||||
|
<keywords>katsu,paris,2010</keywords> <!-- comma-separated -->
|
||||||
|
<uniquekey>28sks922ks992</uniquekey> <!-- iPhone uuid, MAC address, etc -->
|
||||||
|
<ip>192.168.1.1</ip>
|
||||||
|
<time>1928372722</time> <!-- unixtime -->
|
||||||
|
<location>
|
||||||
|
<lon>-39.392922</lon>
|
||||||
|
<lat>53.29292</lat>
|
||||||
|
</location>
|
||||||
|
</client>
|
||||||
|
|
||||||
|
<!-- This is all stuff that relates to the orientation and dimensions of the client -->
|
||||||
|
<!-- So that we know how to re-map the 0.0-1.0 coordinates that come in for each point -->
|
||||||
|
<!-- Also for figuring out the down vector for devices with accelerometers and how that effects drips -->
|
||||||
|
<!-- All numbers should be between 0.0 - 1.0 -->
|
||||||
|
<environment>
|
||||||
|
<offset>
|
||||||
|
<x>0.0</x>
|
||||||
|
<y>0.0</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</offset>
|
||||||
|
<rotation>
|
||||||
|
<x>0.0</x>
|
||||||
|
<y>0.0</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</rotation>
|
||||||
|
<up>
|
||||||
|
<x>0.0</x> <!-- commonly up for iphone apps -->
|
||||||
|
<y>-1.0</y> <!-- most common -->
|
||||||
|
<z>0.0</z>
|
||||||
|
</up>
|
||||||
|
<screenbounds> <!-- use this as your multipler to get 0.0 to 1.0 back to right size - pts should never go off 0.0 to 1.0 -->
|
||||||
|
<x>1024</x>
|
||||||
|
<y>768</y>
|
||||||
|
<z>0</z>
|
||||||
|
</screenbounds>
|
||||||
|
<origin>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<z>0</z>
|
||||||
|
</origin>
|
||||||
|
<realscale> <!-- how these units relate to real world units - good for laser tag -->
|
||||||
|
<x>1000</x>
|
||||||
|
<y>600</y>
|
||||||
|
<z>0</z>
|
||||||
|
<unit>cm</unit>
|
||||||
|
</realscale>
|
||||||
|
<audio>youraudio.mp3</audio> <!-- path to audio file -->
|
||||||
|
<background>yourimage.jpg</background> <!-- path to image file -->
|
||||||
|
</environment>
|
||||||
|
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<drawing>
|
||||||
|
<!-- for all stroke and movement stuff it helps to have everything inside the stroke tag -->
|
||||||
|
<!-- this way it is easy to get a sense of order to events -->
|
||||||
|
|
||||||
|
<stroke isdrawing="false"> <!-- for non drawing mouse movements -->
|
||||||
|
<pt>
|
||||||
|
<x>0.0</x>
|
||||||
|
<y>0.0</y>
|
||||||
|
<z>0.0</z> <!--this is optional -->
|
||||||
|
<t>0.013</t> <!-- time is optional too -->
|
||||||
|
<!-- NOTE: older versions of GML use <time> instead of <t> -->
|
||||||
|
</pt>
|
||||||
|
</stroke>
|
||||||
|
|
||||||
|
<stroke> <!-- by default stroke drawing is true -->
|
||||||
|
|
||||||
|
<!-- each stroke could be drawn with a different brush -->
|
||||||
|
<!-- if no brush tag is found for a stroke then it inherits the previous settings -->
|
||||||
|
<brush>
|
||||||
|
<mode>0</mode> <!-- same as uniqueStyleID but an internal reference -->
|
||||||
|
<uniquestyleid>LaserTagArrowLetters</uniquestyleid> <!-- unique blackbook string for your style -->
|
||||||
|
<!-- see note about spec at the bottom - like unique style but with extra info -->
|
||||||
|
<spec>http://aurltodescribethebrushspec.com/someSpec.xml</spec>
|
||||||
|
<width>10</width>
|
||||||
|
<speedtowidthratio>1.5</speedtowidthratio> <!-- put 0 for fixed width -->
|
||||||
|
<dripamnt>1.0</dripamnt>
|
||||||
|
<dripspeed>1.0</dripspeed>
|
||||||
|
<layerabsolute>0</layerabsolute> <!--Think photoshop layers-->
|
||||||
|
<color>
|
||||||
|
<r>255</r>
|
||||||
|
<g>255</g>
|
||||||
|
<b>255</b>
|
||||||
|
<a>255</a> <!-- optional -->
|
||||||
|
</color>
|
||||||
|
<dripvecrelativetoup> <!-- what angle do our drips go in relation to our up vector -->
|
||||||
|
<x>0</x>
|
||||||
|
<y>1</y>
|
||||||
|
<z>0</z>
|
||||||
|
</dripvecrelativetoup>
|
||||||
|
</brush>
|
||||||
|
|
||||||
|
<pt>
|
||||||
|
<x>0.0</x>
|
||||||
|
<y>0.0</y>
|
||||||
|
<z>0.0</z> <!--this is optional -->
|
||||||
|
<t>0.013</t> <!-- time is optional too -->
|
||||||
|
</pt>
|
||||||
|
|
||||||
|
<pt>
|
||||||
|
<x>0.0</x>
|
||||||
|
<y>0.0</y>
|
||||||
|
<z>0.0</z> <!--this is optional -->
|
||||||
|
<t>0.023</t> <!-- time is optional too -->
|
||||||
|
</pt>
|
||||||
|
|
||||||
|
|
||||||
|
</stroke>
|
||||||
|
|
||||||
|
<!-- this stroke inherits the previous stroke properties -->
|
||||||
|
<!-- but changes color and draws on the layer below -->
|
||||||
|
<stroke>
|
||||||
|
<info> <!-- optional info - more stuff soon-->
|
||||||
|
<curved>true</curved>
|
||||||
|
</info>
|
||||||
|
<brush>
|
||||||
|
<color>
|
||||||
|
<r>255</r>
|
||||||
|
<g>255</g>
|
||||||
|
<b>0</b>
|
||||||
|
</color>
|
||||||
|
<layerrelative> <!-- this means one layer bellow the previous layer -->
|
||||||
|
-1
|
||||||
|
</layerrelative>
|
||||||
|
</brush>
|
||||||
|
|
||||||
|
<pt>
|
||||||
|
<x>0.0</x>
|
||||||
|
<y>0.0</y>
|
||||||
|
</pt>
|
||||||
|
|
||||||
|
<pt>
|
||||||
|
<x>0.0</x>
|
||||||
|
<y>0.0</y>
|
||||||
|
</pt>
|
||||||
|
|
||||||
|
</stroke>
|
||||||
|
|
||||||
|
<stroke>
|
||||||
|
<pt>
|
||||||
|
<pres>0.5</pres> <!-- Optional. Preasure range from 0 to 1 -->
|
||||||
|
<rot>0.5</rot> <!-- Optional. Rotation range from 0 to 1 for 0 to 2*PI -->
|
||||||
|
<dir> <!-- Optional Direction -->
|
||||||
|
<x></x> <!-- range from 0 to 1 -->
|
||||||
|
<y></y> <!-- range from 0 to 1 -->
|
||||||
|
<z></z> <!-- Optional inside direction. Range from 0 to 1 -->
|
||||||
|
</dir>
|
||||||
|
</pt>
|
||||||
|
</stroke>
|
||||||
|
</drawing>
|
||||||
|
|
||||||
|
</tag>
|
||||||
|
|
||||||
|
</gml>
|
||||||
|
'''
|
126
clitools/generators/fromOSC.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
Forward /pl pointlist to cli
|
||||||
|
|
||||||
|
input OSC in END points format : (x,y,color)
|
||||||
|
output CLI in CLI points format : [x,y,color]
|
||||||
|
|
||||||
|
/pl "[(150.0, 230.0, 255), (170.0, 170.0, 255), (230.0, 170.0, 255), (210.0, 230.0, 255), (150.0, 230.0, 255)]"
|
||||||
|
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by Cocoa, Sam Neurohack
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
from OSC3 import OSCServer, OSCClient, OSCMessage
|
||||||
|
import sys
|
||||||
|
from time import sleep
|
||||||
|
import argparse
|
||||||
|
import ast
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="fromOSC generator")
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP to bind to (0.0.0.0 by default)",default="0.0.0.0",type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="OSC port to bind to (9002 by default)",default=9002,type=str)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
verbose = args.verbose
|
||||||
|
ip = args.ip
|
||||||
|
port = int(args.port)
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
oscserver = OSCServer( (ip, port) )
|
||||||
|
oscserver.timeout = 0
|
||||||
|
run = True
|
||||||
|
|
||||||
|
# this method of reporting timeouts only works by convention
|
||||||
|
# that before calling handle_request() field .timed_out is
|
||||||
|
# set to False
|
||||||
|
def handle_timeout(self):
|
||||||
|
self.timed_out = True
|
||||||
|
|
||||||
|
# funny python's way to add a method to an instance of a class
|
||||||
|
import types
|
||||||
|
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
|
||||||
|
|
||||||
|
# RAW OSC Frame available ?
|
||||||
|
def OSC_frame():
|
||||||
|
# clear timed_out flag
|
||||||
|
oscserver.timed_out = False
|
||||||
|
# handle all pending requests then return
|
||||||
|
while not oscserver.timed_out:
|
||||||
|
oscserver.handle_request()
|
||||||
|
|
||||||
|
|
||||||
|
# default handler
|
||||||
|
def OSChandler(oscpath, tags, args, source):
|
||||||
|
|
||||||
|
oscaddress = ''.join(oscpath.split("/"))
|
||||||
|
debug("fromOSC Default OSC Handler got oscpath", oscpath, "from" + str(source[0]), ":", args)
|
||||||
|
#print("OSC address", path)
|
||||||
|
#print("find.. /bhoreal ?", path.find('/bhoreal'))
|
||||||
|
|
||||||
|
if oscpath == "/pl" and len(args)==1:
|
||||||
|
|
||||||
|
debug("correct OSC type :'/pl")
|
||||||
|
|
||||||
|
if validate(args[0]) == True:
|
||||||
|
|
||||||
|
debug("new pl : ", args[0])
|
||||||
|
line = args[0].replace("(",'[')
|
||||||
|
line = line.replace(")",']')
|
||||||
|
line = "[{}]".format(line)
|
||||||
|
print(line, flush=True);
|
||||||
|
|
||||||
|
else:
|
||||||
|
debug("Bad pointlist -> msg trapped.")
|
||||||
|
|
||||||
|
else:
|
||||||
|
debug("BAD OSC Message : " + oscpath +" " +args[0])
|
||||||
|
|
||||||
|
|
||||||
|
oscserver.addMsgHandler( "default", OSChandler )
|
||||||
|
|
||||||
|
|
||||||
|
def validate(pointlist):
|
||||||
|
|
||||||
|
state = True
|
||||||
|
|
||||||
|
if len(pointlist)<9:
|
||||||
|
debug("Not enough characters :", pointlist)
|
||||||
|
state = False
|
||||||
|
|
||||||
|
if pointlist.find("(") == -1:
|
||||||
|
debug("Bad format : use () not [] for points", pointlist)
|
||||||
|
state = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
pl = bytes(pointlist, 'ascii')
|
||||||
|
check = ast.literal_eval(pl.decode('ascii'))
|
||||||
|
|
||||||
|
except:
|
||||||
|
debug("BAD POINTLIST :", pointlist)
|
||||||
|
state = False
|
||||||
|
|
||||||
|
return state
|
||||||
|
|
||||||
|
|
||||||
|
# simulate a "game engine"
|
||||||
|
while run:
|
||||||
|
# do the game stuff:
|
||||||
|
sleep(0.01)
|
||||||
|
# call user script
|
||||||
|
OSC_frame()
|
||||||
|
|
||||||
|
oscserver.close()
|
||||||
|
|
72
clitools/generators/fromRedis.py
Executable file
@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
This generator reads a frame from redis
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
Use it to create feedback loops by writing to the same frame
|
||||||
|
or to copy the frame from someone else
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import ast
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import redis
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
name="generator::fromRedis"
|
||||||
|
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="Dummy generator")
|
||||||
|
argsparser.add_argument("-k","--key",required=True,help="Redis key to look after",default=30,type=str)
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
fps = args.fps
|
||||||
|
verbose = args.verbose
|
||||||
|
key = args.key
|
||||||
|
ip = args.ip
|
||||||
|
port = args.port
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
debug(name+" optimal looptime "+str(optimal_looptime))
|
||||||
|
|
||||||
|
r = redis.Redis(
|
||||||
|
host=ip,
|
||||||
|
port=port)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
start = time.time()
|
||||||
|
# Read from Redis
|
||||||
|
line = r.get(key)
|
||||||
|
# Decode as list of tuples
|
||||||
|
pointsList = ast.literal_eval(line.decode('ascii'))
|
||||||
|
# convert to list of lists
|
||||||
|
pointsList = [list(elem) for elem in pointsList]
|
||||||
|
# Convert to JSON string
|
||||||
|
line = json.dumps( pointsList )
|
||||||
|
debug(name,"Key:{} line:{}".format(key,line))
|
||||||
|
print(line, flush=True);
|
||||||
|
looptime = time.time() - start
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
|
84
clitools/generators/fromUDP.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
fromUDP
|
||||||
|
|
||||||
|
Udp server to cli
|
||||||
|
v0.1b
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import traceback, time
|
||||||
|
import argparse
|
||||||
|
import socket
|
||||||
|
import _thread
|
||||||
|
import sys
|
||||||
|
|
||||||
|
name="generator::fromUDP"
|
||||||
|
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="fromUDP v0.1b help mode")
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP to bind to (0.0.0.0 by default)",default="0.0.0.0",type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="UDP port to bind to (9000 by default)",default=9000,type=str)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
verbose = args.verbose
|
||||||
|
ip = args.ip
|
||||||
|
port = int(args.port)
|
||||||
|
verbose = args.verbose
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def udp_thread():
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
payload, client_address = sock.recvfrom(1024)
|
||||||
|
udpath = payload.decode('utf_8')
|
||||||
|
debug(udpath[0:])
|
||||||
|
print(udpath[0:], flush=True);
|
||||||
|
|
||||||
|
'''
|
||||||
|
# Reply to client
|
||||||
|
bytesToSend = str.encode("ACK :"+str(payload))
|
||||||
|
serverAddressPort = (client_address, port)
|
||||||
|
bufferSize = 1024
|
||||||
|
#sock.sendto(bytesToSend, serverAddressPort)
|
||||||
|
sock.sendto(bytesToSend, client_address)
|
||||||
|
'''
|
||||||
|
|
||||||
|
def StartUDP(serverIP, UDPORT):
|
||||||
|
global sock
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
server = ( serverIP,UDPORT)
|
||||||
|
sock.bind(server)
|
||||||
|
_thread.start_new_thread(udp_thread, ())
|
||||||
|
|
||||||
|
|
||||||
|
StartUDP(ip, port)
|
||||||
|
|
||||||
|
|
||||||
|
# Do something else
|
||||||
|
try:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
time.sleep(0.005)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
319
clitools/generators/fromilda.py
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
fromild
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
Read/display once an .ild animation file and quit ??
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa and Sam Neurohack
|
||||||
|
|
||||||
|
Heavy u-se of :
|
||||||
|
|
||||||
|
ILDA.py
|
||||||
|
|
||||||
|
Python module for dealing with the ILDA Image Data Transfer Format,
|
||||||
|
an interchange format for laser image frames.
|
||||||
|
|
||||||
|
Copyright (c) 2008 Micah Dowty
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import time
|
||||||
|
import struct
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
|
name="generator::fromild"
|
||||||
|
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description=".ild file frame generator")
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
argsparser.add_argument("-i","--ild",help=".ild file",default="book2.ild",type=str)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
fps=args.fps
|
||||||
|
verbose=args.verbose
|
||||||
|
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
debug(name+" optimal looptime "+str(optimal_looptime))
|
||||||
|
|
||||||
|
# Format codes
|
||||||
|
FORMAT_3D = 0
|
||||||
|
FORMAT_2D = 1
|
||||||
|
FORMAT_COLOR_TABLE = 2
|
||||||
|
|
||||||
|
# Mapping from FORMAT_* codes to struct format strings
|
||||||
|
formatTable = (
|
||||||
|
'>hhhH',
|
||||||
|
'>hhH',
|
||||||
|
'>BBB',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Header values
|
||||||
|
HEADER_MAGIC = b"ILDA\0\0\0"
|
||||||
|
HEADER_RESERVED = 0
|
||||||
|
HEADER_FORMAT = ">7sB16sHHHBB"
|
||||||
|
HEADER_LEN = struct.calcsize(HEADER_FORMAT)
|
||||||
|
|
||||||
|
# 64 default colors table : use rgb2int(colors64[ildacolor])
|
||||||
|
colors64 = [[255, 0, 0], [255, 17, 0], [255, 34, 0], [255, 51, 0], [255, 68, 0], [255, 85, 0], [255, 102, 0], [255, 119, 0], [255, 136, 0], [255, 153, 0], [255, 170, 0], [255, 187, 0], [255, 204, 0], [255, 221, 0], [255, 238, 0], [255, 255, 0], [255, 255, 0], [238, 255, 0], [204, 255, 0], [170, 255, 0], [136, 255, 0], [102, 255, 0], [68, 255, 0], [34, 255, 0], [0, 255, 0], [0, 255, 34], [0, 255, 68], [0, 255, 102], [0, 255, 136], [0, 255, 170], [0, 255, 204], [0, 255, 238], [0, 136, 255], [0, 119, 255], [0, 102, 255], [0, 102, 255], [0, 85, 255], [0, 68, 255], [0, 68, 255], [0, 34, 255], [0, 0, 255], [34, 0, 255], [68, 0, 255], [102, 0, 255], [136, 0, 255], [170, 0, 255], [204, 0, 255], [238, 0, 255], [255, 0, 255], [255, 34, 255], [255, 68, 255], [255, 102, 255], [255, 136, 255], [255, 170, 255], [255, 204, 255], [255, 238, 255], [255, 255, 255], [255, 238, 238], [255, 204, 204], [255, 170, 170], [255, 136, 136], [255, 102, 102], [255, 68, 68], [0, 34, 34]]
|
||||||
|
|
||||||
|
|
||||||
|
# 256 default colors table
|
||||||
|
colors256 = [[0, 0, 0], [255, 255, 255], [255, 0, 0], [255, 255, 0], [0, 255, 0], [0, 255, 255], [0, 0, 255], [255, 0, 255], [255, 128, 128], [255, 140, 128], [255, 151, 128], [255, 163, 128], [255, 174, 128], [255, 186, 128], [255, 197, 128], [255, 209, 128], [255, 220, 128], [255, 232, 128], [255, 243, 128], [255, 255, 128], [243, 255, 128], [232, 255, 128], [220, 255, 128], [209, 255, 128], [197, 255, 128], [186, 255, 128], [174, 255, 128], [163, 255, 128], [151, 255, 128], [140, 255, 128], [128, 255, 128], [128, 255, 140], [128, 255, 151], [128, 255, 163], [128, 255, 174], [128, 255, 186], [128, 255, 197], [128, 255, 209], [128, 255, 220], [128, 255, 232], [128, 255, 243], [128, 255, 255], [128, 243, 255], [128, 232, 255], [128, 220, 255], [128, 209, 255], [128, 197, 255], [128, 186, 255], [128, 174, 255], [128, 163, 255], [128, 151, 255], [128, 140, 255], [128, 128, 255], [140, 128, 255], [151, 128, 255], [163, 128, 255], [174, 128, 255], [186, 128, 255], [197, 128, 255], [209, 128, 255], [220, 128, 255], [232, 128, 255], [243, 128, 255], [255, 128, 255], [255, 128, 243], [255, 128, 232], [255, 128, 220], [255, 128, 209], [255, 128, 197], [255, 128, 186], [255, 128, 174], [255, 128, 163], [255, 128, 151], [255, 128, 140], [255, 0, 0], [255, 23, 0], [255, 46, 0], [255, 70, 0], [255, 93, 0], [255, 116, 0], [255, 139, 0], [255, 162, 0], [255, 185, 0], [255, 209, 0], [255, 232, 0], [255, 255, 0], [232, 255, 0], [209, 255, 0], [185, 255, 0], [162, 255, 0], [139, 255, 0], [116, 255, 0], [93, 255, 0], [70, 255, 0], [46, 255, 0], [23, 255, 0], [0, 255, 0], [0, 255, 23], [0, 255, 46], [0, 255, 70], [0, 255, 93], [0, 255, 116], [0, 255, 139], [0, 255, 162], [0, 255, 185], [0, 255, 209], [0, 255, 232], [0, 255, 255], [0, 232, 255], [0, 209, 255], [0, 185, 255], [0, 162, 255], [0, 139, 255], [0, 116, 255], [0, 93, 255], [0, 70, 255], [0, 46, 255], [0, 23, 255], [0, 0, 255], [23, 0, 255], [46, 0, 255], [70, 0, 255], [93, 0, 255], [116, 0, 255], [139, 0, 255], [162, 0, 255], [185, 0, 255], [209, 0, 255], [232, 0, 255], [255, 0, 255], [255, 0, 232], [255, 0, 209], [255, 0, 185], [255, 0, 162], [255, 0, 139], [255, 0, 116], [255, 0, 93], [255, 0, 70], [255, 0, 46], [255, 0, 23], [128, 0, 0], [128, 12, 0], [128, 23, 0], [128, 35, 0], [128, 47, 0], [128, 58, 0], [128, 70, 0], [128, 81, 0], [128, 93, 0], [128, 105, 0], [128, 116, 0], [128, 128, 0], [116, 128, 0], [105, 128, 0], [93, 128, 0], [81, 128, 0], [70, 128, 0], [58, 128, 0], [47, 128, 0], [35, 128, 0], [23, 128, 0], [12, 128, 0], [0, 128, 0], [0, 128, 12], [0, 128, 23], [0, 128, 35], [0, 128, 47], [0, 128, 58], [0, 128, 70], [0, 128, 81], [0, 128, 93], [0, 128, 105], [0, 128, 116], [0, 128, 128], [0, 116, 128], [0, 105, 128], [0, 93, 128], [0, 81, 128], [0, 70, 128], [0, 58, 128], [0, 47, 128], [0, 35, 128], [0, 23, 128], [0, 12, 128], [0, 0, 128], [12, 0, 128], [23, 0, 128], [35, 0, 128], [47, 0, 128], [58, 0, 128], [70, 0, 128], [81, 0, 128], [93, 0, 128], [105, 0, 128], [116, 0, 128], [128, 0, 128], [128, 0, 116], [128, 0, 105], [128, 0, 93], [128, 0, 81], [128, 0, 70], [128, 0, 58], [128, 0, 47], [128, 0, 35], [128, 0, 23], [128, 0, 12], [255, 192, 192], [255, 64, 64], [192, 0, 0], [64, 0, 0], [255, 255, 192], [255, 255, 64], [192, 192, 0], [64, 64, 0], [192, 255, 192], [64, 255, 64], [0, 192, 0], [0, 64, 0], [192, 255, 255], [64, 255, 255], [0, 192, 192], [0, 64, 64], [192, 192, 255], [64, 64, 255], [0, 0, 192], [0, 0, 64], [255, 192, 255], [255, 64, 255], [192, 0, 192], [64, 0, 64], [255, 96, 96], [255, 255, 255], [245, 245, 245], [235, 235, 235], [224, 224, 224], [213, 213, 213], [203, 203, 203], [192, 192, 192], [181, 181, 181], [171, 171, 171], [160, 160, 160], [149, 149, 149], [139, 139, 139], [128, 128, 128], [117, 117, 117], [107, 107, 107], [96, 96, 96], [85, 85, 85], [75, 75, 75], [64, 64, 64], [53, 53, 53], [43, 43, 43], [32, 32, 32], [21, 21, 21], [11, 11, 11], [0, 0, 0]]
|
||||||
|
|
||||||
|
def rgb2int(rgb):
|
||||||
|
return int('0x%02x%02x%02x' % tuple(rgb),0)
|
||||||
|
|
||||||
|
class Table(object):
|
||||||
|
"""Container object for one ILDA table: either a frame (table of points)
|
||||||
|
or a palette (table of colors).
|
||||||
|
|
||||||
|
The 'items' list contains the data within this table. Each item
|
||||||
|
is a tuple, corresponding to the raw values within that row of the
|
||||||
|
table.
|
||||||
|
|
||||||
|
2D frame: (x, y, status)
|
||||||
|
3D frame: (x, y, z, status)
|
||||||
|
Color: (r, g, b)
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, format=FORMAT_2D, name="",
|
||||||
|
length=0, number=0, total=0, scanHead=0):
|
||||||
|
self.__dict__.update(locals())
|
||||||
|
self.items = []
|
||||||
|
self.itemsproducer = None
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return ("<ILDA.Table format=%d name=%r "
|
||||||
|
"length=%d number=%d total=%d scanHead=%d>" %
|
||||||
|
(self.format, self.name, self.length, self.number,
|
||||||
|
self.total, self.scanHead))
|
||||||
|
|
||||||
|
def unpackHeader(self, data):
|
||||||
|
magic, self.format, self.name, self.length, \
|
||||||
|
self.number, self.total, self.scanHead, \
|
||||||
|
reserved = struct.unpack(HEADER_FORMAT, data)
|
||||||
|
print(magic, HEADER_MAGIC)
|
||||||
|
if magic != HEADER_MAGIC:
|
||||||
|
raise ValueError("Bad ILDA header magic. Not an ILDA file?")
|
||||||
|
if reserved != HEADER_RESERVED:
|
||||||
|
raise ValueError("Reserved ILDA field is not zero.")
|
||||||
|
|
||||||
|
def packHeader(self):
|
||||||
|
return struct.pack(HEADER_FORMAT, HEADER_MAGIC, self.format,
|
||||||
|
self.name, self.length, self.number,
|
||||||
|
self.total, self.scanHead, HEADER_RESERVED)
|
||||||
|
|
||||||
|
def readHeader(self, stream):
|
||||||
|
self.unpackHeader(stream.read(HEADER_LEN))
|
||||||
|
|
||||||
|
def writeHeader(self, stream):
|
||||||
|
stream.write(self.packHeader())
|
||||||
|
|
||||||
|
def _getItemFormat(self):
|
||||||
|
try:
|
||||||
|
return formatTable[self.format]
|
||||||
|
except IndexError:
|
||||||
|
raise ValueError("Unsupported format code")
|
||||||
|
|
||||||
|
def read_stream(self, stream):
|
||||||
|
"""Read the header, then read all items in this table."""
|
||||||
|
self.readHeader(stream)
|
||||||
|
if self.length:
|
||||||
|
fmt = self._getItemFormat()
|
||||||
|
itemSize = struct.calcsize(fmt)
|
||||||
|
self.items = [struct.unpack(fmt, stream.read(itemSize))
|
||||||
|
for i in range(self.length)]
|
||||||
|
self.itemsproducer = self.produce()
|
||||||
|
|
||||||
|
def write(self, stream):
|
||||||
|
"""Write the header, then write all items in this table."""
|
||||||
|
self.writeHeader(stream)
|
||||||
|
if self.length:
|
||||||
|
fmt = self._getItemFormat()
|
||||||
|
itemSize = struct.calcsize(fmt)
|
||||||
|
stream.write(''.join([struct.pack(fmt, *item)
|
||||||
|
for item in self.items]))
|
||||||
|
|
||||||
|
def iterPoints(self):
|
||||||
|
"""Iterate over Point instances for each item in this table.
|
||||||
|
Only makes sense if this is a 2D or 3D point table.
|
||||||
|
"""
|
||||||
|
for item in self.items:
|
||||||
|
p = Point()
|
||||||
|
p.decode(item)
|
||||||
|
yield p
|
||||||
|
|
||||||
|
|
||||||
|
def produce(self):
|
||||||
|
"""Iterate over Point instances for each item in this table.
|
||||||
|
Only makes sense if this is a 2D or 3D point table.
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
for item in self.items:
|
||||||
|
p = Point()
|
||||||
|
p.decode(item)
|
||||||
|
yield p.encode()
|
||||||
|
#yield (p.x, p.y, p.z, p.color, p.blanking)
|
||||||
|
|
||||||
|
def read(self, cap):
|
||||||
|
"""yields what dac.play_stream() needs (x, y, z, ?, ?)
|
||||||
|
"""
|
||||||
|
return [next(self.itemsproducer) for i in range(cap)]
|
||||||
|
|
||||||
|
|
||||||
|
class Point:
|
||||||
|
"""Abstraction for one vector point. The Table object, for
|
||||||
|
completeness and efficiency, stores raw tuples for each
|
||||||
|
point. This is a higher level interface that decodes the status
|
||||||
|
bits and represents coordinates in floating point.
|
||||||
|
"""
|
||||||
|
def __init__(self, x=0.0, y=0.0, z=0.0, color=0, blanking=False):
|
||||||
|
self.__dict__.update(locals())
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
|
||||||
|
return "%s, %s, %s, %s, %s" % (
|
||||||
|
self.x, self.y, self.z, self.color, self.blanking)
|
||||||
|
#return "<ILDA.Point (%s, %s, %s) color=%s blanking=%s>" % (
|
||||||
|
# self.x, self.y, self.z, self.color, self.blanking)
|
||||||
|
|
||||||
|
def encode(self):
|
||||||
|
status = self.color & 0xFF
|
||||||
|
if self.blanking:
|
||||||
|
status |= 1 << 14
|
||||||
|
|
||||||
|
return (
|
||||||
|
int( min(0x7FFF, max(-0x7FFF, self.x * 0x7FFF)) ),
|
||||||
|
int( min(0x7FFF, max(-0x7FFF, self.y * 0x7FFF)) ),
|
||||||
|
int( min(0x7FFF, max(-0x7FFF, self.z * 0x7FFF)) ),
|
||||||
|
int( min(0x7FFF, max(-0x7FFF, self.color * 0x7FFF)) ),
|
||||||
|
int( min(0x7FFF, max(-0x7FFF, self.blanking * 0x7FFF)) )
|
||||||
|
)
|
||||||
|
|
||||||
|
def decode(self, t):
|
||||||
|
#print "~~ Decoding, t of len "+ str(len(t)) +" is: " + str(t)
|
||||||
|
self.x = t[0] / 0x7FFF
|
||||||
|
self.y = t[1] / 0x7FFF
|
||||||
|
if len(t) > 3:
|
||||||
|
self.z = t[2] / 0x7FFF
|
||||||
|
# self.color = t[3] & 0xFF
|
||||||
|
# self.blanking = (t[3] & (1 << 14)) != 0
|
||||||
|
else:
|
||||||
|
self.z = 0.0
|
||||||
|
|
||||||
|
self.color = t[-1] & 0xFF
|
||||||
|
self.blanking = (t[-1] & (1 << 14)) != 0
|
||||||
|
|
||||||
|
|
||||||
|
def read(stream):
|
||||||
|
"""Read ILDA data from a stream until we hit the
|
||||||
|
end-of-stream marker. Yields a sequence of Table objects.
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
t = Table()
|
||||||
|
t.read_stream(stream)
|
||||||
|
if not t.length:
|
||||||
|
# End-of-stream
|
||||||
|
break
|
||||||
|
yield t
|
||||||
|
|
||||||
|
|
||||||
|
def write(stream, tables):
|
||||||
|
"""Write a sequence of tables in ILDA format,
|
||||||
|
terminated by an end-of-stream marker.
|
||||||
|
"""
|
||||||
|
for t in tables:
|
||||||
|
t.write(stream)
|
||||||
|
Table().write(stream)
|
||||||
|
|
||||||
|
|
||||||
|
def readFrames(stream):
|
||||||
|
"""Read ILDA data from a stream, and ignore
|
||||||
|
all non-frame tables. Yields only 2D or 3D
|
||||||
|
point tables.
|
||||||
|
"""
|
||||||
|
for t in read(stream):
|
||||||
|
if t.format in (FORMAT_2D, FORMAT_3D):
|
||||||
|
yield t
|
||||||
|
|
||||||
|
|
||||||
|
def readFirstFrame(stream):
|
||||||
|
"""Read only a single frame from an ILDA stream."""
|
||||||
|
for frame in readFrames(stream):
|
||||||
|
return frame
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
f = open(args.ild, 'rb')
|
||||||
|
myframe = readFirstFrame(f)
|
||||||
|
|
||||||
|
while myframe.number +1< myframe.total:
|
||||||
|
|
||||||
|
start = time.time()
|
||||||
|
shape =[]
|
||||||
|
|
||||||
|
if myframe is None:
|
||||||
|
f.close()
|
||||||
|
break
|
||||||
|
|
||||||
|
debug(name,"Frame", myframe.number, "/",myframe.total, "length", myframe.length)
|
||||||
|
|
||||||
|
for p in myframe.iterPoints():
|
||||||
|
p2 = str(p)
|
||||||
|
point = p2.split(',')
|
||||||
|
|
||||||
|
x = float(point[0])
|
||||||
|
y = float(point[1])
|
||||||
|
z = float(point[2])
|
||||||
|
color = int(point[3])
|
||||||
|
blanking = point[4][1:]
|
||||||
|
|
||||||
|
if blanking == "True":
|
||||||
|
shape.append([300+(x*300),300+(-y*300),0])
|
||||||
|
else:
|
||||||
|
shape.append([300+(x*300),300+(-y*300),rgb2int(colors64[color])])
|
||||||
|
|
||||||
|
print(shape, flush=True);
|
||||||
|
myframe = readFirstFrame(f)
|
||||||
|
|
||||||
|
looptime = time.time() - start
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
|
||||||
|
f.close()
|
||||||
|
debug(name + " end of .ild animation")
|
131
clitools/generators/osc2redis.py
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
Forward pointlist to redis key
|
||||||
|
|
||||||
|
END POINT Format : (x,y,color)
|
||||||
|
|
||||||
|
/pl/0/0 "[(150.0, 230.0, 255), (170.0, 170.0, 255), (230.0, 170.0, 255), (210.0, 230.0, 255), (150.0, 230.0, 255)]"
|
||||||
|
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by Cocoa, Sam Neurohack
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from OSC3 import OSCServer, OSCClient, OSCMessage
|
||||||
|
import sys
|
||||||
|
from time import sleep
|
||||||
|
import argparse
|
||||||
|
import ast
|
||||||
|
import redis
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="osc2redis generator")
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP to bind to (0.0.0.0 by default)",default="0.0.0.0",type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="OSC port to bind to (9002 by default)",default=9002,type=str)
|
||||||
|
|
||||||
|
argsparser.add_argument("-r","--rip",help="Redis server IP (127.0.0.1 by default)",default="127.0.0.1",type=str)
|
||||||
|
argsparser.add_argument("-o","--rout",help="Redis port (6379 by default)",default=6379,type=str)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
verbose = args.verbose
|
||||||
|
ip = args.ip
|
||||||
|
port = int(args.port)
|
||||||
|
rip = args.rip
|
||||||
|
rport = int(args.rout)
|
||||||
|
|
||||||
|
|
||||||
|
r = redis.StrictRedis(host=rip, port=rport, db=0)
|
||||||
|
|
||||||
|
|
||||||
|
def debug(msg):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
|
||||||
|
oscserver = OSCServer( (ip, port) )
|
||||||
|
oscserver.timeout = 0
|
||||||
|
run = True
|
||||||
|
|
||||||
|
# this method of reporting timeouts only works by convention
|
||||||
|
# that before calling handle_request() field .timed_out is
|
||||||
|
# set to False
|
||||||
|
def handle_timeout(self):
|
||||||
|
self.timed_out = True
|
||||||
|
|
||||||
|
# funny python's way to add a method to an instance of a class
|
||||||
|
import types
|
||||||
|
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
|
||||||
|
|
||||||
|
|
||||||
|
def validate(pointlist):
|
||||||
|
|
||||||
|
state = True
|
||||||
|
|
||||||
|
if len(pointlist)<9:
|
||||||
|
state = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
pl = bytes(pointlist, 'ascii')
|
||||||
|
check = ast.literal_eval(pl.decode('ascii'))
|
||||||
|
|
||||||
|
except:
|
||||||
|
state = False
|
||||||
|
|
||||||
|
return state
|
||||||
|
|
||||||
|
|
||||||
|
# RAW OSC Frame available ?
|
||||||
|
def OSC_frame():
|
||||||
|
# clear timed_out flag
|
||||||
|
oscserver.timed_out = False
|
||||||
|
# handle all pending requests then return
|
||||||
|
while not oscserver.timed_out:
|
||||||
|
oscserver.handle_request()
|
||||||
|
|
||||||
|
|
||||||
|
# default handler
|
||||||
|
def OSChandler(oscpath, tags, args, source):
|
||||||
|
|
||||||
|
oscaddress = ''.join(oscpath.split("/"))
|
||||||
|
print("fromOSC Default OSC Handler got oscpath :", oscpath, "from :" + str(source[0]), "args :", args)
|
||||||
|
print(oscpath.find("/pl/"), len(oscpath))
|
||||||
|
|
||||||
|
if oscpath.find("/pl/") ==0 and len(args)==1:
|
||||||
|
|
||||||
|
print("correct OSC type :'/pl/")
|
||||||
|
|
||||||
|
if validate(args[0]) == True and len(oscpath) == 7:
|
||||||
|
print("new pl for key ", oscpath, ":", args[0])
|
||||||
|
|
||||||
|
if r.set(oscpath,args[0])==True:
|
||||||
|
debug("exports::redis set("+str(oscpath)+") to "+args[0])
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Bad pointlist -> msg trapped.")
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("BAD OSC Message :", oscpath)
|
||||||
|
|
||||||
|
oscserver.addMsgHandler( "default", OSChandler )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# simulate a "game engine"
|
||||||
|
while run:
|
||||||
|
# do the game stuff:
|
||||||
|
sleep(0.01)
|
||||||
|
# call user script
|
||||||
|
OSC_frame()
|
||||||
|
|
||||||
|
oscserver.close()
|
||||||
|
|
174
clitools/generators/redilysis_lines.py
Executable file
@ -0,0 +1,174 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
redilysis_lines
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
Add a line on every frame and scroll
|
||||||
|
|
||||||
|
see https://git.interhacker.space/teamlaser/redilysis for more informations
|
||||||
|
about the redilysis project
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import argparse
|
||||||
|
import ast
|
||||||
|
import os
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
import redis
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
name = "generator::redilysis_lines"
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
def msNow():
|
||||||
|
return time.time()
|
||||||
|
|
||||||
|
CHAOS = 1
|
||||||
|
REDIS_FREQ = 33
|
||||||
|
|
||||||
|
# General Args
|
||||||
|
argsparser = argparse.ArgumentParser(description="Redilysis filter")
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
|
||||||
|
# Redis Args
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
|
||||||
|
argsparser.add_argument("-F","--redis-freq",help="Query Redis every x (in milliseconds). Default:{}".format(REDIS_FREQ),default=REDIS_FREQ,type=int)
|
||||||
|
# General args
|
||||||
|
argsparser.add_argument("-n","--nlines",help="number of lines on screen",default=60,type=int)
|
||||||
|
argsparser.add_argument("-x","--centerX",help="geometrical center X position",default=400,type=int)
|
||||||
|
argsparser.add_argument("-y","--centerY",help="geometrical center Y position",default=400,type=int)
|
||||||
|
argsparser.add_argument("-W","--max-width",help="geometrical max width",default=800,type=int)
|
||||||
|
argsparser.add_argument("-H","--max-height",help="geometrical max height",default=800,type=int)
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
verbose = args.verbose
|
||||||
|
ip = args.ip
|
||||||
|
port = args.port
|
||||||
|
fps = args.fps
|
||||||
|
centerX = args.centerX
|
||||||
|
centerY = args.centerY
|
||||||
|
redisFreq = args.redis_freq / 1000
|
||||||
|
maxWidth = args.max_width
|
||||||
|
maxHeight = args.max_height
|
||||||
|
nlines = args.nlines
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
|
||||||
|
redisKeys = ["spectrum_120","spectrum_10"]
|
||||||
|
debug(name,"Redis Keys:{}".format(redisKeys))
|
||||||
|
redisData = {}
|
||||||
|
redisLastHit = msNow() - 99999
|
||||||
|
r = redis.Redis(
|
||||||
|
host=ip,
|
||||||
|
port=port)
|
||||||
|
|
||||||
|
white = 16777215
|
||||||
|
lineList = []
|
||||||
|
|
||||||
|
scroll_speed = int(maxHeight / nlines )
|
||||||
|
line_length = int(maxWidth / 10)
|
||||||
|
line_pattern = []
|
||||||
|
|
||||||
|
def rgb2int(rgb):
|
||||||
|
#debug(name,"::rgb2int rbg:{}".format(rgb))
|
||||||
|
return int('0x%02x%02x%02x' % tuple(rgb),0)
|
||||||
|
|
||||||
|
def spectrum_10( ):
|
||||||
|
delList = []
|
||||||
|
spectrum = ast.literal_eval(redisData["spectrum_10"])
|
||||||
|
debug( name, "spectrum:{}".format(spectrum))
|
||||||
|
# scroll lines
|
||||||
|
for i,line in enumerate(lineList):
|
||||||
|
skip_line = False
|
||||||
|
new_y = int(line[0][1] + scroll_speed)
|
||||||
|
if( new_y >= maxHeight ):
|
||||||
|
debug(name,"{} > {}".format(new_y,maxHeight))
|
||||||
|
debug(name,"delete:{}".format(i))
|
||||||
|
delList.append(i)
|
||||||
|
continue
|
||||||
|
|
||||||
|
for j,point in enumerate(line):
|
||||||
|
line[j][1] = new_y
|
||||||
|
lineList[i] = line
|
||||||
|
|
||||||
|
for i in delList:
|
||||||
|
del lineList[i]
|
||||||
|
|
||||||
|
# new line
|
||||||
|
currentLine = []
|
||||||
|
for i in range(0,10):
|
||||||
|
x = int(i * line_length)
|
||||||
|
y = 0
|
||||||
|
# get frequency level
|
||||||
|
level = spectrum[i]
|
||||||
|
# get color
|
||||||
|
comp = int(255*level)
|
||||||
|
color = rgb2int( (comp,comp,comp))
|
||||||
|
# new point
|
||||||
|
currentLine.append( [x,y,color] )
|
||||||
|
|
||||||
|
# add line to list
|
||||||
|
lineList.append( currentLine)
|
||||||
|
|
||||||
|
|
||||||
|
def refreshRedis():
|
||||||
|
global redisLastHit
|
||||||
|
global redisData
|
||||||
|
# Skip if cache is sufficent
|
||||||
|
diff = msNow() - redisLastHit
|
||||||
|
if diff < redisFreq :
|
||||||
|
#debug(name, "refreshRedis not updating redis, {} < {}".format(diff, redisFreq))
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
#debug(name, "refreshRedis updating redis, {} > {}".format(diff, redisFreq))
|
||||||
|
redisLastHit = msNow()
|
||||||
|
for key in redisKeys:
|
||||||
|
redisData[key] = r.get(key).decode('ascii')
|
||||||
|
#debug(name,"refreshRedis key:{} value:{}".format(key,redisData[key]))
|
||||||
|
# Only update the TTLs
|
||||||
|
if 'bpm' in redisKeys:
|
||||||
|
redisData['bpm_pttl'] = r.pttl('bpm')
|
||||||
|
#debug(name,"refreshRedis key:bpm_ttl value:{}".format(redisData["bpm_pttl"]))
|
||||||
|
#debug(name,"redisData:{}".format(redisData))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def linelistToPoints( lineList ):
|
||||||
|
pl = []
|
||||||
|
for i,line in enumerate(lineList):
|
||||||
|
# add a blank point
|
||||||
|
pl.append([ line[0][0], line[0][1], 0 ])
|
||||||
|
# append all the points of the line
|
||||||
|
pl += line
|
||||||
|
#debug(name,"pl:{}".format(pl))
|
||||||
|
debug(name,"pl length:{}".format(len(pl)))
|
||||||
|
return pl
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
refreshRedis()
|
||||||
|
start = time.time()
|
||||||
|
# Do the thing
|
||||||
|
pointsList = spectrum_10()
|
||||||
|
print( linelistToPoints(lineList), flush=True )
|
||||||
|
looptime = time.time() - start
|
||||||
|
# debug(name+" looptime:"+str(looptime))
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
# debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
except EOFError:
|
||||||
|
debug(name+" break")# no more information
|
||||||
|
|
288
clitools/generators/redilysis_particles.py
Executable file
@ -0,0 +1,288 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import redis
|
||||||
|
import ast
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
MAX_PARTICLES = 50
|
||||||
|
MAX_TIME = 500
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="Dummy generator")
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
# Redis Args
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
|
||||||
|
#
|
||||||
|
argsparser.add_argument("-M","--max-particles",help="Max Particles. Default:{}".format(MAX_PARTICLES),default=MAX_PARTICLES,type=int)
|
||||||
|
argsparser.add_argument("-m","--max-time",help="Max Particles. Default:{}".format(MAX_TIME),default=MAX_TIME,type=int)
|
||||||
|
|
||||||
|
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
verbose = args.verbose
|
||||||
|
ip = args.ip
|
||||||
|
port = args.port
|
||||||
|
max_particles = args.max_particles
|
||||||
|
max_time = args.max_time
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def rgb2int(rgb):
|
||||||
|
#debug(name,"::rgb2int rbg:{}".format(rgb))
|
||||||
|
return int('0x%02x%02x%02x' % tuple(rgb),0)
|
||||||
|
|
||||||
|
def spectrum_120( ):
|
||||||
|
return ast.literal_eval(redisData["spectrum_10"])
|
||||||
|
|
||||||
|
|
||||||
|
def rgb2int(rgb):
|
||||||
|
#debug(name,"::rgb2int rbg:{}".format(rgb))
|
||||||
|
return int('0x%02x%02x%02x' % tuple(rgb),0)
|
||||||
|
|
||||||
|
def msNow():
|
||||||
|
return time.time()
|
||||||
|
|
||||||
|
def refreshRedis():
|
||||||
|
global redisData
|
||||||
|
for key in redisKeys:
|
||||||
|
redisData[key] = ast.literal_eval(r.get(key).decode('ascii'))
|
||||||
|
|
||||||
|
name="generator::redilisys_particles"
|
||||||
|
|
||||||
|
class UnpreparedParticle(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Particle(object):
|
||||||
|
def __init__(self, x, y, m):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.m = m
|
||||||
|
self.dx = 0
|
||||||
|
self.dy = 0
|
||||||
|
self.connectedTo = []
|
||||||
|
|
||||||
|
self.decay = random.randint(10,max_time)
|
||||||
|
self.color = (random.randint(128,256) - int(12.8 * self.m),
|
||||||
|
random.randint(128,256) - int(12.8 * self.m),
|
||||||
|
random.randint(128,256) - int(12.8 * self.m))
|
||||||
|
self.color = (255,255,255)
|
||||||
|
#debug( self.color )
|
||||||
|
|
||||||
|
def interact(self, bodies):
|
||||||
|
self.connectedTo = []
|
||||||
|
spec = redisData["spectrum_10"]
|
||||||
|
power = int(sum(spec[4:6]))
|
||||||
|
for other in bodies:
|
||||||
|
if other is self:
|
||||||
|
continue
|
||||||
|
dx = other.x - self.x
|
||||||
|
dy = other.y - self.y
|
||||||
|
dist = math.sqrt(dx*dx + dy*dy)
|
||||||
|
if dist == 0:
|
||||||
|
dist = 1
|
||||||
|
if dist < 100 and random.randint(0,power) > 0.5 :
|
||||||
|
self.connectedTo.append(other)
|
||||||
|
self.decay += 2
|
||||||
|
factor = other.m / dist**2
|
||||||
|
high_power = sum(spec[8:9]) if sum(spec[8:9]) != 0 else 0.01
|
||||||
|
self.dx += (dx * factor * self.m)
|
||||||
|
self.dy += (dy * factor * self.m)
|
||||||
|
#print "factor %f" % (factor,)
|
||||||
|
|
||||||
|
def move(self):
|
||||||
|
spec = redisData["spectrum_10"]
|
||||||
|
x_friction = (2.2-(1+spec[7]/2))
|
||||||
|
y_friction = (2.2-(1+spec[7]/2))
|
||||||
|
#x_friction = 1.02
|
||||||
|
#y_friction = 1.04
|
||||||
|
self.dx /= x_friction if x_friction != 0 else 0.01
|
||||||
|
self.dy /= y_friction if y_friction != 0 else 0.01
|
||||||
|
self.x += self.dx
|
||||||
|
self.y += self.dy
|
||||||
|
if self.x > max_width:
|
||||||
|
self.dx = - self.dx /8
|
||||||
|
self.x = max_width
|
||||||
|
if self.x < 1:
|
||||||
|
self.dx = - self.dx /8
|
||||||
|
self.x = 1
|
||||||
|
if self.y > max_height:
|
||||||
|
self.dy = - self.dy /4
|
||||||
|
self.y = max_height
|
||||||
|
if self.y < 1:
|
||||||
|
self.dy = - self.dy /4
|
||||||
|
self.y = 1
|
||||||
|
#print "(%.2f,%.2f) -> (%.2f,%.2f)" % (ox, oy, self.x, self.y)
|
||||||
|
|
||||||
|
def attractor(self,attractor):
|
||||||
|
spec = redisData["spectrum_10"]
|
||||||
|
power = sum(spec[0:4])/3
|
||||||
|
# If we're going in the direction of center, reverse
|
||||||
|
next_x = self.x + self.dx
|
||||||
|
next_y = self.y + self.dy
|
||||||
|
next_dx = attractor["x"] - self.x
|
||||||
|
next_dy = attractor["y"] - self.y
|
||||||
|
next_dist = math.sqrt(next_dx*next_dx + next_dy*next_dy)
|
||||||
|
|
||||||
|
dx = attractor["x"] - self.x
|
||||||
|
dy = attractor["y"] - self.y
|
||||||
|
dist = math.sqrt(dx*dx + dy*dy)
|
||||||
|
if dist == 0:
|
||||||
|
dist = 1
|
||||||
|
factor = power/ dist**2
|
||||||
|
x_acceleration = (dx * factor * power * power)
|
||||||
|
y_acceleration = (dx * factor * power * power)
|
||||||
|
|
||||||
|
|
||||||
|
if next_dist > dist:
|
||||||
|
self.dx -= x_acceleration * power
|
||||||
|
self.dy -= y_acceleration * power
|
||||||
|
else:
|
||||||
|
self.dx += x_acceleration
|
||||||
|
self.dy += y_acceleration
|
||||||
|
|
||||||
|
|
||||||
|
class Attractor(Particle):
|
||||||
|
def move(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ParticleViewer(object):
|
||||||
|
def __init__(self, particles, size=(800,800)):
|
||||||
|
(self.width, self.height) = size
|
||||||
|
self.size = size
|
||||||
|
self.particles = particles
|
||||||
|
self.xoff = 0
|
||||||
|
self.yoff = 0
|
||||||
|
self.scalefactor = 1
|
||||||
|
|
||||||
|
def redraw(self):
|
||||||
|
|
||||||
|
pl = []
|
||||||
|
drawnVectors = []
|
||||||
|
for p in self.particles:
|
||||||
|
x = int(self.scalefactor * p.x) - self.xoff
|
||||||
|
y = int(self.scalefactor * p.y) - self.yoff
|
||||||
|
if x > max_width:
|
||||||
|
x = max_width
|
||||||
|
if x < 1:
|
||||||
|
x = 1
|
||||||
|
if y > max_height:
|
||||||
|
y = max_height
|
||||||
|
if y < 1:
|
||||||
|
y = 1
|
||||||
|
|
||||||
|
color = rgb2int(p.color)
|
||||||
|
pl.append([x+1,y+1,0])
|
||||||
|
pl.append([x+1,y+1,color])
|
||||||
|
pl.append([x,y,color])
|
||||||
|
|
||||||
|
for other in p.connectedTo:
|
||||||
|
|
||||||
|
if [other,self] in drawnVectors:
|
||||||
|
continue
|
||||||
|
drawnVectors.append([other,self])
|
||||||
|
pl.append([x,y,0])
|
||||||
|
pl.append([x,y,color])
|
||||||
|
pl.append([other.x,other.y,color])
|
||||||
|
|
||||||
|
print(pl,flush = True)
|
||||||
|
|
||||||
|
def decayParticles(self):
|
||||||
|
for i,p in enumerate(self.particles):
|
||||||
|
# Handle positional decay
|
||||||
|
if p.decay == 0:
|
||||||
|
del self.particles[i]
|
||||||
|
continue
|
||||||
|
p.decay = p.decay - 1
|
||||||
|
# Handle color decay
|
||||||
|
n = int(255 * (p.decay / max_time ))
|
||||||
|
p.color = (n,n,n)
|
||||||
|
|
||||||
|
|
||||||
|
def emitParticles(self):
|
||||||
|
spec = redisData["spectrum_10"]
|
||||||
|
power = sum(spec[6:])
|
||||||
|
if len(self.particles ) > math.sqrt(max_particles):
|
||||||
|
if len(self.particles) > max_particles:
|
||||||
|
return
|
||||||
|
if random.random() > power:
|
||||||
|
return
|
||||||
|
# x is either left or right
|
||||||
|
d = 600
|
||||||
|
rx = 100 if random.randint(0,1) else 700
|
||||||
|
#rx = random.randint(1,max_width)
|
||||||
|
ry = random.randint(1,max_height)
|
||||||
|
spec = redisData["spectrum_10"]
|
||||||
|
m = random.randint(1,1+int(10*spec[7]))
|
||||||
|
particles.append(Particle(rx, ry, m))
|
||||||
|
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
self.decayParticles()
|
||||||
|
self.emitParticles()
|
||||||
|
for p in self.particles:
|
||||||
|
p.interact(self.particles)
|
||||||
|
p.attractor({
|
||||||
|
"x":max_width/2,
|
||||||
|
"y":max_height/2
|
||||||
|
})
|
||||||
|
for p in particles:
|
||||||
|
p.move()
|
||||||
|
self.redraw()
|
||||||
|
|
||||||
|
def scale(self, factor):
|
||||||
|
self.scalefactor += factor
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
max_width = 800
|
||||||
|
max_height = 800
|
||||||
|
redisKeys = ["spectrum_120","spectrum_10"]
|
||||||
|
redisData = {}
|
||||||
|
redisLastHit = msNow() - 99999
|
||||||
|
r = redis.Redis(
|
||||||
|
host=ip,
|
||||||
|
port=port)
|
||||||
|
|
||||||
|
white = 16777215
|
||||||
|
|
||||||
|
refreshRedis()
|
||||||
|
if __name__ == "__main__":
|
||||||
|
particles = []
|
||||||
|
# particles.append(Attractor(320, 200, 10))
|
||||||
|
# particles.append(Attractor(100, 100, 10))
|
||||||
|
|
||||||
|
win = ParticleViewer(particles)
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
win.tick()
|
||||||
|
refreshRedis()
|
||||||
|
time.sleep(.03)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
93
clitools/generators/text.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
A text generators using Hershey fonts
|
||||||
|
https://pypi.org/project/Hershey-Fonts/
|
||||||
|
|
||||||
|
pip3 install Hershey-Fonts
|
||||||
|
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
Font list :
|
||||||
|
'futural', 'astrology', 'cursive', 'cyrilc_1', 'cyrillic', 'futuram', 'gothgbt', 'gothgrt',
|
||||||
|
'gothiceng', 'gothicger', 'gothicita', 'gothitt', 'greek', 'greekc', 'greeks', 'japanese',
|
||||||
|
'markers', 'mathlow', 'mathupp', 'meteorology', 'music', 'rowmand', 'rowmans', 'rowmant',
|
||||||
|
'scriptc', 'scripts', 'symbolic', 'timesg', 'timesi', 'timesib', 'timesr', 'timesrb'
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa and Sam Neurohack
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
from HersheyFonts import HersheyFonts
|
||||||
|
|
||||||
|
name="generator::text"
|
||||||
|
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="Text generator")
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
argsparser.add_argument("-t","--text",help="Text to display",default="hello",type=str)
|
||||||
|
argsparser.add_argument("-p","--police",help="Herschey font to use",default="futural",type=str)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
fps=args.fps
|
||||||
|
verbose=args.verbose
|
||||||
|
|
||||||
|
text = args.text
|
||||||
|
fontname = args.police
|
||||||
|
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
debug(name+" optimal looptime "+str(optimal_looptime))
|
||||||
|
|
||||||
|
def rgb2int(rgb):
|
||||||
|
return int('0x%02x%02x%02x' % tuple(rgb),0)
|
||||||
|
|
||||||
|
# Useful variables init.
|
||||||
|
white = rgb2int((255,255,255))
|
||||||
|
red = rgb2int((255,0,0))
|
||||||
|
blue = rgb2int((0,0,255))
|
||||||
|
green = rgb2int((0,255,0))
|
||||||
|
|
||||||
|
color = 65280
|
||||||
|
|
||||||
|
shape =[]
|
||||||
|
|
||||||
|
Allfonts = ['futural', 'astrology', 'cursive', 'cyrilc_1', 'cyrillic', 'futuram', 'gothgbt', 'gothgrt', 'gothiceng', 'gothicger', 'gothicita', 'gothitt', 'greek', 'greekc', 'greeks', 'japanese', 'markers', 'mathlow', 'mathupp', 'meteorology', 'music', 'rowmand', 'rowmans', 'rowmant', 'scriptc', 'scripts', 'symbolic', 'timesg', 'timesi', 'timesib', 'timesr', 'timesrb']
|
||||||
|
|
||||||
|
thefont = HersheyFonts()
|
||||||
|
#thefont.load_default_font()
|
||||||
|
thefont.load_default_font(fontname)
|
||||||
|
thefont.normalize_rendering(120)
|
||||||
|
|
||||||
|
for (x1, y1), (x2, y2) in thefont.lines_for_text(text):
|
||||||
|
shape.append([x1, -y1+400, color])
|
||||||
|
shape.append([x2 ,-y2+400, color])
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
start = time.time()
|
||||||
|
print(shape, flush=True);
|
||||||
|
|
||||||
|
looptime = time.time() - start
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
|
||||||
|
|
||||||
|
#[[14.285714285714286, 100.0, 14.285714285714286, 25.0, 65280], [64.28571428571429, 100.0, 64.28571428571429, 25.0, 65280], [14.285714285714286, 64.28571428571429, 64.28571428571429, 64.28571428571429, 65280], [89.28571428571428, 53.57142857142858, 132.14285714285714, 53.57142857142858, 65280], [132.14285714285714, 53.57142857142858, 132.14285714285714, 60.714285714285715, 65280], [132.14285714285714, 60.714285714285715, 128.57142857142856, 67.85714285714286, 65280], [128.57142857142856, 67.85714285714286, 125.0, 71.42857142857143, 65280], [125.0, 71.42857142857143, 117.85714285714286, 75.0, 65280], [117.85714285714286, 75.0, 107.14285714285714, 75.0, 65280], [107.14285714285714, 75.0, 100.0, 71.42857142857143, 65280], [100.0, 71.42857142857143, 92.85714285714286, 64.28571428571429, 65280], [92.85714285714286, 64.28571428571429, 89.28571428571428, 53.57142857142858, 65280], [89.28571428571428, 53.57142857142858, 89.28571428571428, 46.42857142857143, 65280], [89.28571428571428, 46.42857142857143, 92.85714285714286, 35.714285714285715, 65280], [92.85714285714286, 35.714285714285715, 100.0, 28.571428571428573, 65280], [100.0, 28.571428571428573, 107.14285714285714, 25.0, 65280], [107.14285714285714, 25.0, 117.85714285714286, 25.0, 65280], [117.85714285714286, 25.0, 125.0, 28.571428571428573, 65280], [125.0, 28.571428571428573, 132.14285714285714, 35.714285714285715, 65280]]
|
||||||
|
|
175
clitools/generators/trckr.py
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
A Face tracker
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
Get all points fom redis /trckr/frame/WSclientID points
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa and Sam Neurohack
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
import redis
|
||||||
|
import ast
|
||||||
|
|
||||||
|
name="generator::trckr"
|
||||||
|
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="Face tracking generator")
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
argsparser.add_argument("-i","--id",help="Trckr client ID",default="0",type=str)
|
||||||
|
argsparser.add_argument("-s","--server",help="redis server IP (127.0.0.1 by default)", type=str)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
fps=args.fps
|
||||||
|
verbose=args.verbose
|
||||||
|
idclient = args.id
|
||||||
|
|
||||||
|
if args.server:
|
||||||
|
redisIP = args.server
|
||||||
|
else:
|
||||||
|
redisIP = "127.0.0.1"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
debug(name+" optimal looptime "+str(optimal_looptime))
|
||||||
|
|
||||||
|
color = 65280
|
||||||
|
|
||||||
|
|
||||||
|
def rgb2int(rgb):
|
||||||
|
return int('0x%02x%02x%02x' % tuple(rgb),0)
|
||||||
|
|
||||||
|
# Useful variables init.
|
||||||
|
white = rgb2int((255,255,255))
|
||||||
|
red = rgb2int((255,0,0))
|
||||||
|
blue = rgb2int((0,0,255))
|
||||||
|
green = rgb2int((0,255,0))
|
||||||
|
|
||||||
|
#
|
||||||
|
# Redis functions
|
||||||
|
#
|
||||||
|
|
||||||
|
r = redis.StrictRedis(host=redisIP , port=6379, db=0)
|
||||||
|
|
||||||
|
# read from redis key
|
||||||
|
def fromKey(keyname):
|
||||||
|
|
||||||
|
return r.get(keyname)
|
||||||
|
|
||||||
|
# Write to redis key
|
||||||
|
def toKey(keyname,keyvalue):
|
||||||
|
return r.set(keyname,keyvalue)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Trckr faces
|
||||||
|
#
|
||||||
|
|
||||||
|
TrckrPts = [[159.39, 137.68], [155.12, 159.31], [155.56, 180.13], [159.81, 201.6], [170.48, 220.51], [187.46, 234.81], [208.4, 244.68], [229.46, 248.21], [246.44, 244.91], [259.69, 234.83], [270.95, 221.51], [278.54, 204.66], [283.53, 185.63], [286.27, 165.79], [284.72, 144.84], [280.06, 125.01], [274.35, 118.7], [260.71, 117.23], [249.52, 118.86], [182.04, 121.5], [193.63, 114.79], [210.24, 114.77], [222.35, 117.57], [190.6, 137.49], [203.59, 132.42], [214.75, 137.58], [203.04, 140.46], [203.32, 136.53], [272.45, 141.57], [263.33, 135.42], [250.31, 138.89], [262.15, 143.27], [261.99, 139.37], [235.82, 131.74], [221.87, 156.09], [213.66, 165.88], [219.28, 173.53], [236.3, 175.25], [249.02, 174.4], [254.22, 167.81], [248.83, 157.39], [237.94, 147.51], [227.01, 168.39], [245.68, 170.02], [204.94, 197.32], [217.56, 192.77], [228.27, 190.55], [234.66, 192.19], [240.47, 191.09], [247.96, 193.87], [254.52, 199.19], [249.35, 204.25], [242.74, 207.16], [233.2, 207.87], [222.13, 206.52], [212.44, 203.09], [220.34, 198.74], [233.31, 200.04], [244.0, 199.6], [244.27, 197.8], [233.81, 197.44], [220.88, 196.99], [239.57, 162.69], [196.52, 133.86], [210.2, 133.98], [209.43, 139.41], [196.59, 139.47], [268.99, 137.59], [256.36, 136.02], [255.95, 141.5], [267.9, 142.85]]
|
||||||
|
toKey('/trckr/frame/0',str(TrckrPts))
|
||||||
|
|
||||||
|
# get absolute face position points
|
||||||
|
def getPART(TrckrPts, pose_points):
|
||||||
|
|
||||||
|
dots = []
|
||||||
|
#debug(pose_points)
|
||||||
|
#debug(TrckrPts)
|
||||||
|
for dot in pose_points:
|
||||||
|
dots.append((TrckrPts[dot][0], TrckrPts[dot][1],0))
|
||||||
|
#debug(dots)
|
||||||
|
return dots
|
||||||
|
|
||||||
|
|
||||||
|
# Face keypoints
|
||||||
|
def face(TrckrPts):
|
||||||
|
pose_points = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
def browL(TrckrPts):
|
||||||
|
pose_points = [15,16,17,18]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
def browR(TrckrPts):
|
||||||
|
pose_points = [22,21,20,19]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
def eyeR(TrckrPts):
|
||||||
|
pose_points = [25,64,24,63,23,66,26,65,25]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
def eyeL(TrckrPts):
|
||||||
|
pose_points = [28,67,29,68,30,69,31,28]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
def pupR(TrckrPts):
|
||||||
|
pose_points = [27]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
def pupL(TrckrPts):
|
||||||
|
pose_points = [32]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
|
||||||
|
def nose1(TrckrPts):
|
||||||
|
pose_points = [62,41,33]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
def nose2(TrckrPts):
|
||||||
|
pose_points = [40,39,38,43,37,42,36,35,34]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
def mouth(TrckrPts):
|
||||||
|
pose_points = [50,49,48,47,46,45,44,55,54,53,52,51,50]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
def mouthfull(TrckrPts):
|
||||||
|
pose_points = [50,49,48,47,46,45,44,55,54,53,52,51,50,59,60,61,44,56,57,58,50]
|
||||||
|
return getPART(TrckrPts, pose_points)
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
start = time.time()
|
||||||
|
shape =[]
|
||||||
|
points = ast.literal_eval(fromKey('/trckr/frame/'+idclient).decode('ascii'))
|
||||||
|
shape.append(browL(points))
|
||||||
|
shape.append(eyeL(points))
|
||||||
|
shape.append(browR(points))
|
||||||
|
shape.append(eyeR(points))
|
||||||
|
shape.append(pupL(points))
|
||||||
|
shape.append(pupR(points))
|
||||||
|
shape.append(nose1(points))
|
||||||
|
shape.append(nose2(points))
|
||||||
|
shape.append(mouthfull(points))
|
||||||
|
line = str(shape)
|
||||||
|
line = line.replace("(",'[')
|
||||||
|
line = line.replace(")",']')
|
||||||
|
line = "[{}]".format(line)
|
||||||
|
print(line, flush=True);
|
||||||
|
#debug(shape)
|
||||||
|
#print(shape, flush=True);
|
||||||
|
|
||||||
|
looptime = time.time() - start
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
|
||||||
|
|
194
clitools/generators/tunnel.py
Executable file
@ -0,0 +1,194 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
Woooh! I'm progressing in a tunnel !
|
||||||
|
v0.1.0
|
||||||
|
|
||||||
|
Use it to test your filters and outputs
|
||||||
|
|
||||||
|
LICENCE : CC
|
||||||
|
|
||||||
|
by cocoa
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import argparse
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
name="generator::tunnel"
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="tunnel generator")
|
||||||
|
argsparser.add_argument("-c","--color",help="Color",default=65280,type=int)
|
||||||
|
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
|
||||||
|
argsparser.add_argument("-i","--interval",help="point per shape interval",default=30,type=int)
|
||||||
|
argsparser.add_argument("-m","--max-size",help="maximum size for objects",default=400,type=int)
|
||||||
|
argsparser.add_argument("-r","--randomize",help="center randomization",default=5,type=int)
|
||||||
|
argsparser.add_argument("-s","--speed",help="point per frame progress",default=3,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
argsparser.add_argument("-x","--centerX",help="geometrical center X position",default=400,type=int)
|
||||||
|
argsparser.add_argument("-y","--centerY",help="geometrical center Y position",default=400,type=int)
|
||||||
|
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
centerX = args.centerX
|
||||||
|
centerY = args.centerY
|
||||||
|
color = args.color
|
||||||
|
fps = args.fps
|
||||||
|
interval = args.interval
|
||||||
|
max_size = args.max_size
|
||||||
|
randomize = args.randomize
|
||||||
|
speed = args.speed
|
||||||
|
verbose = args.verbose
|
||||||
|
|
||||||
|
origSpeed = speed
|
||||||
|
optimal_looptime = 1 / fps
|
||||||
|
square = [
|
||||||
|
[-1,1],
|
||||||
|
[1,1],
|
||||||
|
[1,-1],
|
||||||
|
[-1,-1],
|
||||||
|
[-1,1]
|
||||||
|
]
|
||||||
|
|
||||||
|
circle = [[1,0],
|
||||||
|
[0.9238795325112867,0.3826834323650898],
|
||||||
|
[0.7071067811865476,0.7071067811865475],
|
||||||
|
[0.38268343236508984,0.9238795325112867],
|
||||||
|
[0,1.0],
|
||||||
|
[-0.3826834323650897,0.9238795325112867],
|
||||||
|
[-0.7071067811865475,0.7071067811865476],
|
||||||
|
[-0.9238795325112867,0.3826834323650899],
|
||||||
|
[-1.0,0],
|
||||||
|
[-0.9238795325112868,-0.38268343236508967],
|
||||||
|
[-0.7071067811865477,-0.7071067811865475],
|
||||||
|
[-0.38268343236509034,-0.9238795325112865],
|
||||||
|
[0,-1.0],
|
||||||
|
[0.38268343236509,-0.9238795325112866],
|
||||||
|
[0.707106781186548,-0.707106781186547],
|
||||||
|
[0.9238795325112872,-0.3826834323650887],
|
||||||
|
[1,0]]
|
||||||
|
|
||||||
|
shape = circle
|
||||||
|
currentCenter = [centerX, centerY]
|
||||||
|
centerVector= [0,0]
|
||||||
|
# tweak random basis
|
||||||
|
if randomize % 2 == 1:
|
||||||
|
randomize += 1
|
||||||
|
debug(name,"randomize:{}".format(randomize))
|
||||||
|
centerRand = int(math.sqrt(randomize) / 4 ) + 1
|
||||||
|
debug( name, "centerRand:{}".format(centerRand ) )
|
||||||
|
class polylineGenerator( object ):
|
||||||
|
|
||||||
|
def __init__( self ):
|
||||||
|
self.polylineList = [[0,[currentCenter[0],currentCenter[1]]]]
|
||||||
|
self.buf = []
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
finished = False
|
||||||
|
while not finished:
|
||||||
|
finished = self.increment()
|
||||||
|
debug(name,"init done:{}".format(self.polylineList))
|
||||||
|
def draw( self ):
|
||||||
|
self.buf = []
|
||||||
|
for it_pl, infoList in enumerate(self.polylineList):
|
||||||
|
size = infoList[0]
|
||||||
|
center = infoList[1]
|
||||||
|
for it_sqr, point in enumerate(shape):
|
||||||
|
x = int( center[0] + point[0]*size )
|
||||||
|
y = int( center[1] + point[1]*size )
|
||||||
|
# Add an invisible point in first location
|
||||||
|
if 0 == it_sqr:
|
||||||
|
self.buf.append([x,y,0])
|
||||||
|
self.buf.append([x,y,color])
|
||||||
|
#debug( name, "buf size:", str(len(self.buf)) )
|
||||||
|
return self.buf
|
||||||
|
|
||||||
|
def increment(self):
|
||||||
|
global speed
|
||||||
|
self.buffer = []
|
||||||
|
min_size = 9999
|
||||||
|
delList = []
|
||||||
|
if randomize :
|
||||||
|
# Change the vector
|
||||||
|
centerVector[0] += random.randrange( -centerRand,centerRand )
|
||||||
|
centerVector[1] += random.randrange( -centerRand,centerRand )
|
||||||
|
# Modify the vector if it is over the limit
|
||||||
|
if currentCenter[0] + centerVector[0] >= centerX + randomize or currentCenter[0] + centerVector[0] <= centerX - randomize:
|
||||||
|
centerVector[0] = 0
|
||||||
|
if currentCenter[1] + centerVector[1] >= centerY + randomize or currentCenter[1] +centerVector[1] <= centerY - randomize:
|
||||||
|
centerVector[1] = 0
|
||||||
|
currentCenter[0] += centerVector[0]
|
||||||
|
currentCenter[1] += centerVector[1]
|
||||||
|
# Change speed
|
||||||
|
speed += int( random.randrange( int(-origSpeed),origSpeed ) )
|
||||||
|
if speed < origSpeed :
|
||||||
|
speed = origSpeed
|
||||||
|
elif speed > (origSpeed + randomize / 2) :
|
||||||
|
speed = origSpeed + randomize / 2
|
||||||
|
#debug(name, "currentCenter:{} speed:{}".format(currentCenter,speed))
|
||||||
|
|
||||||
|
for i, shapeInfo in enumerate(self.polylineList):
|
||||||
|
size = shapeInfo[0]
|
||||||
|
# Augment speed with size
|
||||||
|
"""
|
||||||
|
size = 0 : += sqrt(speed)
|
||||||
|
size = half max size : +=speed
|
||||||
|
|
||||||
|
"""
|
||||||
|
if size < max_size / 4:
|
||||||
|
size += math.pow(speed, 0.1)
|
||||||
|
elif size < max_size / 3:
|
||||||
|
size += math.pow(speed, 0.25)
|
||||||
|
elif size < max_size / 2:
|
||||||
|
size += math.pow(speed, 0.5)
|
||||||
|
else:
|
||||||
|
size += math.pow(speed, 1.25)
|
||||||
|
if size < min_size : min_size = size
|
||||||
|
if size > max_size : delList.append(i)
|
||||||
|
self.polylineList[i][0] = size
|
||||||
|
for i in delList:
|
||||||
|
del self.polylineList[i]
|
||||||
|
#debug(name, "polyline:",self.polylineList)
|
||||||
|
if min_size >= interval:
|
||||||
|
debug(name, "new shape")
|
||||||
|
self.polylineList.append([0,[currentCenter[0],currentCenter[1]]])
|
||||||
|
|
||||||
|
# Return True if we delete a shape
|
||||||
|
|
||||||
|
if len(delList):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
pgen = polylineGenerator()
|
||||||
|
pgen.init()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
start = time.time()
|
||||||
|
|
||||||
|
# Generate
|
||||||
|
pgen.increment()
|
||||||
|
|
||||||
|
# send
|
||||||
|
pl = pgen.draw()
|
||||||
|
print(pl, flush=True)
|
||||||
|
#debug(name,"output:{}".format(pl))
|
||||||
|
|
||||||
|
looptime = time.time() - start
|
||||||
|
if( looptime < optimal_looptime ):
|
||||||
|
time.sleep( optimal_looptime - looptime)
|
||||||
|
#debug(name+" micro sleep:"+str( optimal_looptime - looptime))
|
||||||
|
|
||||||
|
|
126
clitools/runner.py
Executable file
@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import tty,termios
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import runner_lib as runner
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_help():
|
||||||
|
global bindings
|
||||||
|
print("\nKey\tAction\n--------------------------------------")
|
||||||
|
for i in bindings:
|
||||||
|
print(" {}\t{}".format(bindings[i],i))
|
||||||
|
print("--------------------------------------\n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bindings={
|
||||||
|
"Show playlist" : "l",
|
||||||
|
"Launch [0-x] cmd" : "0-x",
|
||||||
|
"Previous command" : "p",
|
||||||
|
"Next command" : "o",
|
||||||
|
"New command" : "a",
|
||||||
|
"Edit command" : "e",
|
||||||
|
"Delete command" : "d",
|
||||||
|
"Load playlist" : "L",
|
||||||
|
"Save playlist" : "S",
|
||||||
|
"Save as new" : "A",
|
||||||
|
"New playlist" : "N",
|
||||||
|
"Command help" : "H",
|
||||||
|
"Kill process Id" : "K",
|
||||||
|
"Edit Laser Id" : "i",
|
||||||
|
"Edit Laser Scene" : "s",
|
||||||
|
"Information" : "I",
|
||||||
|
"Help" : "h",
|
||||||
|
"Quit" : "q",
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## Init user contact
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Main Loop
|
||||||
|
runner.action_info()
|
||||||
|
action_help()
|
||||||
|
print("\n\nLoad a playlist? [Y/n]: ")
|
||||||
|
if "y" == runner.inkey() :
|
||||||
|
runner.action_loadPlaylist()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Fuck zombies
|
||||||
|
runner._killBill()
|
||||||
|
runner._ok("> Next Action?")
|
||||||
|
k = runner.inkey()
|
||||||
|
|
||||||
|
if bindings["Next command"] == k:
|
||||||
|
runner.action_changeCommand( 1 )
|
||||||
|
runner.action_runCommand()
|
||||||
|
elif bindings["Previous command"] == k:
|
||||||
|
runner.action_changeCommand( -1 )
|
||||||
|
runner.action_runCommand()
|
||||||
|
elif re.match( r'^\d+$',k):
|
||||||
|
runner.action_match(k)
|
||||||
|
runner.action_runCommand()
|
||||||
|
elif bindings["New command"] == k:
|
||||||
|
runner.action_newCommand()
|
||||||
|
continue
|
||||||
|
elif bindings["Show playlist"] == k:
|
||||||
|
runner.action_listAll()
|
||||||
|
continue
|
||||||
|
elif bindings["Delete command"] == k:
|
||||||
|
runner.action_deleteCommand()
|
||||||
|
continue
|
||||||
|
elif bindings["Edit command"] == k:
|
||||||
|
runner.action_listAll()
|
||||||
|
runner.action_edit()
|
||||||
|
continue
|
||||||
|
elif bindings["Load playlist"] == k:
|
||||||
|
if runner.action_loadPlaylist():
|
||||||
|
runner.action_listAll()
|
||||||
|
continue
|
||||||
|
elif bindings["Save playlist"] == k:
|
||||||
|
runner.action_savePlaylist()
|
||||||
|
continue
|
||||||
|
elif bindings["Save as new"] == k:
|
||||||
|
runner.action_savePlaylist()
|
||||||
|
continue
|
||||||
|
elif bindings["New playlist"] == k:
|
||||||
|
runner.action_newPlaylist()
|
||||||
|
continue
|
||||||
|
elif bindings["Command help"] == k:
|
||||||
|
runner.action_commandHelp()
|
||||||
|
continue
|
||||||
|
elif bindings["Edit Laser Id"] == k:
|
||||||
|
runner.action_laserId()
|
||||||
|
continue
|
||||||
|
elif bindings["Edit Laser Scene"] == k:
|
||||||
|
runner.action_laserScene()
|
||||||
|
continue
|
||||||
|
elif bindings["Kill process Id"] == k:
|
||||||
|
runner.action_killPid()
|
||||||
|
continue
|
||||||
|
elif bindings["Help"] == k:
|
||||||
|
action_help()
|
||||||
|
continue
|
||||||
|
elif bindings["Information"] == k:
|
||||||
|
runner.action_info()
|
||||||
|
continue
|
||||||
|
elif bindings["Quit"] == k:
|
||||||
|
runner.action_quit()
|
||||||
|
else:
|
||||||
|
runner._err("Unexpected key:{}".format(k))
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
379
clitools/runner_lib.py
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import tty,termios
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import redis
|
||||||
|
|
||||||
|
|
||||||
|
environ = {
|
||||||
|
# "REDIS_IP" : "127.0.0.1",
|
||||||
|
"REDIS_IP" : "192.168.2.44",
|
||||||
|
"REDIS_PORT" : "6379",
|
||||||
|
"REDIS_KEY" : "/pl/0/0",
|
||||||
|
"REDIS_SCENE" : "0",
|
||||||
|
"REDIS_LASER" : "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
class bcolors:
|
||||||
|
HL = '\033[31m'
|
||||||
|
OKBLUE = '\033[94m'
|
||||||
|
OKGREEN = '\033[92m'
|
||||||
|
ENDC = '\033[0m'
|
||||||
|
BOLD = '\033[1m'
|
||||||
|
UNDERLINE = '\033[4m'
|
||||||
|
|
||||||
|
class _Getch:
|
||||||
|
def __call__(self):
|
||||||
|
fd = sys.stdin.fileno()
|
||||||
|
old_settings = termios.tcgetattr(fd)
|
||||||
|
try:
|
||||||
|
tty.setraw(sys.stdin.fileno())
|
||||||
|
ch = sys.stdin.read(1)
|
||||||
|
finally:
|
||||||
|
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||||
|
return ch
|
||||||
|
inkey = _Getch()
|
||||||
|
|
||||||
|
def intkey():
|
||||||
|
try:
|
||||||
|
i = int( inkey() )
|
||||||
|
return(i)
|
||||||
|
except ValueError:
|
||||||
|
print("Error.")
|
||||||
|
|
||||||
|
current_id = 0
|
||||||
|
current_cmd = ""
|
||||||
|
process = None
|
||||||
|
current_filename = ""
|
||||||
|
currentPlayList = []
|
||||||
|
playlistsDir = Path("./playlists")
|
||||||
|
if not playlistsDir.is_dir() : playlistsDir.mkdir()
|
||||||
|
|
||||||
|
def ask(q):
|
||||||
|
print(q)
|
||||||
|
return inkey()
|
||||||
|
|
||||||
|
def _ok(msg):
|
||||||
|
print( bcolors.BOLD+bcolors.OKBLUE+ msg + bcolors.ENDC)
|
||||||
|
|
||||||
|
def _err(msg):
|
||||||
|
print( bcolors.HL + msg + bcolors.ENDC)
|
||||||
|
|
||||||
|
def _kill(process):
|
||||||
|
if process :
|
||||||
|
try:
|
||||||
|
pid = os.getpgid(process.pid)
|
||||||
|
os.killpg(pid, signal.SIGTERM)
|
||||||
|
os.killpg(pid, signal.SIGKILL)
|
||||||
|
os.kill(pid, signal.SIGTERM)
|
||||||
|
os.kill(pid, signal.SIGKILL)
|
||||||
|
process.terminate()
|
||||||
|
process.kill()
|
||||||
|
except Exception as e:
|
||||||
|
print("woops:{}".format(e))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _killBill():
|
||||||
|
subprocess.run("ps --ppid 1 -fo pid,sess,ppid,cmd | grep 'toRedis.py' | while read pid sid other; do pkill -9 -s $sid; done", shell=True,executable='/bin/bash')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_info():
|
||||||
|
print("""
|
||||||
|
Welcome to LJ playlist manager
|
||||||
|
|
||||||
|
Currently running on
|
||||||
|
|
||||||
|
IP : {}
|
||||||
|
Port : {}
|
||||||
|
Key : {}
|
||||||
|
Scene : {}
|
||||||
|
Laser : {}
|
||||||
|
""".format(
|
||||||
|
environ["REDIS_IP"],
|
||||||
|
environ["REDIS_PORT"],
|
||||||
|
environ["REDIS_KEY"],
|
||||||
|
environ["REDIS_SCENE"],
|
||||||
|
environ["REDIS_LASER"]
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
def action_changeCommand( inc ):
|
||||||
|
global currentPlayList
|
||||||
|
global current_id
|
||||||
|
if 0 == len(currentPlayList):
|
||||||
|
_err("Empty playlist")
|
||||||
|
return False
|
||||||
|
current_id = (current_id + 1) % len(currentPlayList)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def action_match( k ):
|
||||||
|
global current_id, currentPlayList
|
||||||
|
if int(k) > (len(currentPlayList) - 1):
|
||||||
|
print( bcolors.HL + "This key does not exist" + bcolors.ENDC )
|
||||||
|
return False
|
||||||
|
else :
|
||||||
|
_ok("Changed action id to {}.".format(k))
|
||||||
|
current_id = int(k)
|
||||||
|
|
||||||
|
def action_runCommand():
|
||||||
|
global currentPlayList
|
||||||
|
global current_id
|
||||||
|
global process
|
||||||
|
|
||||||
|
# Get new command
|
||||||
|
try:
|
||||||
|
current_cmd = currentPlayList[current_id]
|
||||||
|
except IndexError as e:
|
||||||
|
_err("woops:{}".format(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("\n[!]New command:'{}'\n".format(current_cmd))
|
||||||
|
|
||||||
|
# Start subprocess
|
||||||
|
try :
|
||||||
|
_kill(process)
|
||||||
|
process = subprocess.Popen("./_run.sh '"+current_cmd+" | exports/toRedis.py -i $REDIS_IP -k $REDIS_KEY'", shell=True, executable='/bin/bash', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=environ, preexec_fn=os.setsid)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("woops:{}".format(e))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_newCommand():
|
||||||
|
global currentPlayList
|
||||||
|
print("Enter new command or e(x)it.")
|
||||||
|
k = input()
|
||||||
|
# Exit early
|
||||||
|
if "x" == k:
|
||||||
|
return(False)
|
||||||
|
currentPlayList.append(k)
|
||||||
|
print(bcolors.OKBLUE + "Command added" + bcolors.ENDC)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_deleteCommand():
|
||||||
|
global currentPlayList
|
||||||
|
print("Select sequence to delete or e(x)it.")
|
||||||
|
action_listAll()
|
||||||
|
key = int(input())
|
||||||
|
# Exit early
|
||||||
|
if "x" == key:
|
||||||
|
return(False)
|
||||||
|
del currentPlayList[key]
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_listAll():
|
||||||
|
global currentPlayList, current_cmd, current_id
|
||||||
|
print("\n--------------------------------------")
|
||||||
|
for i,seq in enumerate(currentPlayList):
|
||||||
|
pre=""
|
||||||
|
suf=""
|
||||||
|
if current_cmd == seq :
|
||||||
|
pre = bcolors.HL
|
||||||
|
suf = bcolors.ENDC
|
||||||
|
print( pre + "{}\t{}".format(i,seq) + suf )
|
||||||
|
print("--------------------------------------\n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_edit():
|
||||||
|
print("Enter the command number to edit, or 'x' to abort.")
|
||||||
|
k = intkey()
|
||||||
|
if 'x' == k:
|
||||||
|
return
|
||||||
|
print("Enter the next value, or 'x' to abort.")
|
||||||
|
value = input()
|
||||||
|
if 'x' == value:
|
||||||
|
return
|
||||||
|
currentPlayList[k] = value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_loadPlaylist():
|
||||||
|
|
||||||
|
global playlistsDir
|
||||||
|
global currentPlayList
|
||||||
|
global current_playlist_name
|
||||||
|
# list files
|
||||||
|
i=0
|
||||||
|
file_list = [x for x in playlistsDir.glob("*json")]
|
||||||
|
if 0 == len(file_list ):
|
||||||
|
print( bcolors.HL + "Error. No file in path '{}'\n".format(playlistsDir.name))
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("\n Id\tName")
|
||||||
|
for k,name in enumerate(file_list) :
|
||||||
|
print(" {}\t{}".format(k,name),flush=True)
|
||||||
|
|
||||||
|
# ask file
|
||||||
|
print("\nChoose a file or e(x)it:")
|
||||||
|
k = intkey()
|
||||||
|
if '' == k:
|
||||||
|
print("Invalid choice: '{}'".format(k))
|
||||||
|
return
|
||||||
|
|
||||||
|
# Exit early
|
||||||
|
if "x" == k: return(False)
|
||||||
|
|
||||||
|
# todo : helper for detecting invalid keys
|
||||||
|
try:
|
||||||
|
if k > (len(file_list) - 1):
|
||||||
|
print( bcolors.HL + "This key '{}' does not exist".format(k) + bcolors.ENDC )
|
||||||
|
return False
|
||||||
|
except TypeError:
|
||||||
|
print( bcolors.HL + "This key '{}' is not valid".format(k) + bcolors.ENDC )
|
||||||
|
return False
|
||||||
|
|
||||||
|
# @todo replace with _loadPlaylist
|
||||||
|
playlistFile = Path("./playlists/"+file_list[k].name)
|
||||||
|
currentPlayList = json.loads(playlistFile.read_text())
|
||||||
|
current_playlist_name = file_list[k].name
|
||||||
|
current_id = 0
|
||||||
|
print( bcolors.OKBLUE + "Playlist loaded: {}\n".format(current_playlist_name)+ bcolors.ENDC)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _loadPlaylist( filename ):
|
||||||
|
|
||||||
|
global currentPlayList, current_playlist_name, current_id
|
||||||
|
try:
|
||||||
|
playlistFile = Path(filename)
|
||||||
|
currentPlayList = json.loads(playlistFile.read_text())
|
||||||
|
current_playlist_name = filename
|
||||||
|
current_id = 0
|
||||||
|
_ok("Playlist loaded: {}\n".format(current_playlist_name))
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
_err("_loadPlaylist error when loading '{}':{}".format(filename,e))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_newPlaylist():
|
||||||
|
global playlistsDir
|
||||||
|
global currentPlayList
|
||||||
|
# ask for name
|
||||||
|
print("Enter new playlist name (without.json) or e(x)it question?")
|
||||||
|
k = input()
|
||||||
|
|
||||||
|
# Exit early
|
||||||
|
if "x" == k:
|
||||||
|
return(False)
|
||||||
|
|
||||||
|
# save file
|
||||||
|
currentPlayList = []
|
||||||
|
_savePlaylist( k+".json" )
|
||||||
|
currentPlayList = []
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _savePlaylist( playlistname ):
|
||||||
|
global currentPlayList
|
||||||
|
filepath = Path("playlists/{}".format(playlistname))
|
||||||
|
with filepath.open("w", encoding ="utf-8") as f:
|
||||||
|
f.write(json.dumps(currentPlayList, indent=4, sort_keys=True))
|
||||||
|
return(True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_savePlaylist( name=False ):
|
||||||
|
global current_playlist_name
|
||||||
|
playlist_name = name if name else current_playlist_name
|
||||||
|
if not playlist_name :
|
||||||
|
_err("No name found.")
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
_savePlaylist(playlist_name)
|
||||||
|
print( bcolors.OKBLUE + "\nSaved as '{}'.\n".format(playlist_name) + bcolors.ENDC)
|
||||||
|
except Exception as e:
|
||||||
|
print("woops:{}".format(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_commandHelp():
|
||||||
|
global playlistsDir
|
||||||
|
|
||||||
|
# iterate through files
|
||||||
|
file_list=[]
|
||||||
|
for folder in ["generators","filters","exports"]:
|
||||||
|
p = Path("./"+folder)
|
||||||
|
for plFile in Path("./"+folder).iterdir() :
|
||||||
|
if re.match("^.*py$",plFile.name):
|
||||||
|
file_list.append(os.path.join(folder,plFile.name))
|
||||||
|
print("\n Id\tFile")
|
||||||
|
for k,filename in enumerate(file_list):
|
||||||
|
print(" {}\t{}".format(k,filename))
|
||||||
|
print("\nChoose a file:")
|
||||||
|
k = int(input())
|
||||||
|
print("\n-----------------------------------------------\n")
|
||||||
|
subprocess.run("python3 "+file_list[k]+" -h", shell=True, executable='/bin/bash')
|
||||||
|
print("\n-----------------------------------------------\n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _setKey( laser=0, scene=0 ):
|
||||||
|
global environ
|
||||||
|
laser = laser if laser else environ["REDIS_LASER"]
|
||||||
|
scene = scene if scene else environ["REDIS_SCENE"]
|
||||||
|
new_key = "/pl/{}/{}".format(scene,laser)
|
||||||
|
environ["REDIS_KEY"] = new_key
|
||||||
|
print("Sending new key '{}'".format(new_key))
|
||||||
|
|
||||||
|
|
||||||
|
def action_laserId():
|
||||||
|
k = int(ask("Enter the LJ Laser id [0-3]"))
|
||||||
|
_setKey( laser = k )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_laserScene():
|
||||||
|
k = int(ask("Enter the LJ Scene id [0-3]"))
|
||||||
|
_setKey( scene = k )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def action_killPid():
|
||||||
|
print("Enter pid to kill")
|
||||||
|
kill_pid = input()
|
||||||
|
subprocess.run("pkill -9 -s $(awk '{print $6}' /proc/$kill_pid/stat)", shell=True,executable='/bin/bash', env={"kill_pid":kill_pid})
|
||||||
|
|
||||||
|
|
||||||
|
def action_quit():
|
||||||
|
print("Quit [Y/n]?")
|
||||||
|
global process
|
||||||
|
quit = inkey()
|
||||||
|
if quit != "n":
|
||||||
|
_kill(process)
|
||||||
|
sys.exit(1)
|
87
clitools/runner_midi.py
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import redis
|
||||||
|
import runner_lib as runner
|
||||||
|
import time
|
||||||
|
|
||||||
|
novationRows = [
|
||||||
|
[ 0, 1, 2, 3, 4, 5, 6, 7 ],
|
||||||
|
[ *range(16,24)],
|
||||||
|
[ *range(32,40)],
|
||||||
|
[ *range(48,56)]
|
||||||
|
]
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="Playlist midi")
|
||||||
|
argsparser.add_argument("playlist",help="JSON playlist file ",type=str)
|
||||||
|
argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
|
||||||
|
argsparser.add_argument("-r","--row",help="Row of Novation pad. Default:1 ",default=1,type=str)
|
||||||
|
argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=str)
|
||||||
|
argsparser.add_argument("-l","--laser",help="Laser number. Default:0 ",default=0,type=int)
|
||||||
|
argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
|
||||||
|
argsparser.add_argument("-s","--scene",help="Laser scene. Default:0 ",default=0,type=int)
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
ip = args.ip
|
||||||
|
port = args.port
|
||||||
|
key = args.key
|
||||||
|
verbose=args.verbose
|
||||||
|
laser = args.laser
|
||||||
|
scene = args.scene
|
||||||
|
playlist = args.playlist
|
||||||
|
row = args.row - 1
|
||||||
|
rowKeys = novationRows[row]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Subscriber
|
||||||
|
|
||||||
|
r = redis.StrictRedis(host=ip, port=port, db=0)
|
||||||
|
p = r.pubsub()
|
||||||
|
p.subscribe('/midi/last_event')
|
||||||
|
runner._killBill()
|
||||||
|
|
||||||
|
# Set Laser and scene
|
||||||
|
runner._setKey( laser = laser, scene = scene)
|
||||||
|
|
||||||
|
# Load playlist
|
||||||
|
runner._loadPlaylist( playlist )
|
||||||
|
|
||||||
|
print("Loaded playlist : {}".format(runner.currentPlayList))
|
||||||
|
|
||||||
|
|
||||||
|
runner.action_info()
|
||||||
|
runner.current_id = -1
|
||||||
|
while True:
|
||||||
|
runner._killBill()
|
||||||
|
|
||||||
|
message = p.get_message()
|
||||||
|
if message:
|
||||||
|
#runner._ok ("Subscriber: %s" % message['data'])
|
||||||
|
|
||||||
|
|
||||||
|
# b'/midi/noteon/0/19/127'
|
||||||
|
match = re.match(".*/([0-9]+)/[0-9]+",str(message['data']))
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
key = int(match.group(1))
|
||||||
|
|
||||||
|
# Check if the event is for us
|
||||||
|
if key not in rowKeys:
|
||||||
|
print("key {} not in {} ".format(key,rowKeys))
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
command_id = rowKeys.index(key)
|
||||||
|
cmd = runner.currentPlayList[command_id]
|
||||||
|
|
||||||
|
if command_id != runner.current_id :
|
||||||
|
runner._ok("Launching command #{}\n Previous was {}\n Cmd:{}".format(command_id,runner.current_id,cmd))
|
||||||
|
runner.action_match(command_id)
|
||||||
|
runner.action_runCommand()
|
||||||
|
else :
|
||||||
|
runner._err("Not running {} : already running.".format(command_id))
|
||||||
|
except Exception as e :
|
||||||
|
print("Woops.",e)
|
273
nano.py
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
LJnano
|
||||||
|
|
||||||
|
v0.1b
|
||||||
|
|
||||||
|
Open localhost websocket 9001
|
||||||
|
|
||||||
|
Write Redis keys :
|
||||||
|
|
||||||
|
- '/trckr/frame/WSclientid' : TrckrPts
|
||||||
|
- 'WSclients' : [{'id': 1, 'handler': <websocket_server.WebSocketHandler object at 0x114d35880>, 'address': ('127.0.0.1', 62718)}, {'id': 2, 'handler': <websocket_server.WebSocketHandler object at 0x114d35d60>, 'address': ('127.0.0.1', 62720)}]
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import print_function
|
||||||
|
import websocket
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
import traceback
|
||||||
|
import sys
|
||||||
|
import random
|
||||||
|
from websocket_server import WebsocketServer
|
||||||
|
import redis
|
||||||
|
from socket import *
|
||||||
|
|
||||||
|
try:
|
||||||
|
import thread
|
||||||
|
except ImportError:
|
||||||
|
import _thread as thread
|
||||||
|
|
||||||
|
name = "exports::ljnano"
|
||||||
|
|
||||||
|
def debug(*args, **kwargs):
|
||||||
|
if( verbose == False ):
|
||||||
|
return
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(description="ljnano v0.1b help mode")
|
||||||
|
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
|
||||||
|
argsparser.add_argument("-s","--server",help="WS server IP (127.0.0.1 by default)", type=str)
|
||||||
|
argsparser.add_argument("-p","--port",help="WS port to bind to (9001 by default)", type=str)
|
||||||
|
argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=str)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
|
||||||
|
key = args.key
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
verbose = True
|
||||||
|
else:
|
||||||
|
verbose = False
|
||||||
|
|
||||||
|
if args.server:
|
||||||
|
serverIP = args.server
|
||||||
|
else:
|
||||||
|
serverIP = "127.0.0.1"
|
||||||
|
|
||||||
|
if args.port:
|
||||||
|
wsPORT = args.port
|
||||||
|
else:
|
||||||
|
wsPORT = 9001
|
||||||
|
|
||||||
|
debug("")
|
||||||
|
debug("LJnano v0.1b")
|
||||||
|
|
||||||
|
points0 = "[(150.0, 230.0, 65280), (170.0, 170.0, 65280), (230.0, 170.0, 65280), (210.0, 230.0, 65280), (150.0, 230.0, 65280)]"
|
||||||
|
points1 = "[(180.0, 230.0, 65280), (200.0, 170.0, 65280), (180.0, 230.0, 65280)]"
|
||||||
|
points2 = "[(170.0, 190.0, 65280), (200.0, 170.0, 65280), (230.0, 190.0, 65280), (230.0, 200.0, 65280), (170.0, 230.0, 65280), (230.0, 230.0, 65280)]"
|
||||||
|
points3 = "[(170.0, 170.0, 65280), (200.0, 170.0, 65280), (230.0, 190.0, 65280), (200.0, 200.0, 65280), (230.0, 210.0, 65280), (200.0, 230.0, 65280), (170.0, 230.0, 65280)]"
|
||||||
|
points = [points0, points1, points2, points3]
|
||||||
|
|
||||||
|
LaserNumber = 1
|
||||||
|
SceneNumber = 0
|
||||||
|
Laser = 0
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Redis
|
||||||
|
#
|
||||||
|
|
||||||
|
r = redis.StrictRedis(host=serverIP , port=6379, db=0)
|
||||||
|
|
||||||
|
# read from redis key
|
||||||
|
def fromKey(keyname):
|
||||||
|
|
||||||
|
return r.get(keyname)
|
||||||
|
|
||||||
|
# Write to redis key
|
||||||
|
def toKey(keyname,keyvalue):
|
||||||
|
|
||||||
|
#print(keyname,keyvalue)
|
||||||
|
# Store encoded data in Redis
|
||||||
|
return r.set(keyname,keyvalue)
|
||||||
|
|
||||||
|
# event key can be like "/midi/last_event"
|
||||||
|
# Send en event to eventkey (publish)
|
||||||
|
def toKeyevent(eventkey,eventname):
|
||||||
|
|
||||||
|
print("redis midi event key :", eventname)
|
||||||
|
r.publish(eventkey, eventname)
|
||||||
|
|
||||||
|
# examples
|
||||||
|
#if toKey("/clientkey","/pl/"+str(gstt.SceneNumber)+"/")==True:
|
||||||
|
# print("sent clientkey : /pl/"+str(gstt.SceneNumber)+"/")
|
||||||
|
|
||||||
|
# toKeyevent("/midi/noteon/"+str(MidiChannel)+"/"+str(MidiNote)+"/"+str(MidiVel))
|
||||||
|
|
||||||
|
|
||||||
|
def custom_handler(message):
|
||||||
|
# do_something with the message
|
||||||
|
print(message)
|
||||||
|
'''
|
||||||
|
p.psubscribe(**{'hello*':custom_handler})
|
||||||
|
thread = p.run_in_thread(sleep_time=0.001)
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Change current laser.
|
||||||
|
def NoteOn(note):
|
||||||
|
debug("NoteOn", note)
|
||||||
|
|
||||||
|
# Change laser client
|
||||||
|
if note < 8:
|
||||||
|
|
||||||
|
Laser = note
|
||||||
|
debug("Current Laser switched to", Laser)
|
||||||
|
sendWSall("/status Laser " + str(Laser))
|
||||||
|
sendWSall("/simul" +" "+ points[Laser])
|
||||||
|
|
||||||
|
# Change PL displayed on webui
|
||||||
|
if note > 23 and note < 32:
|
||||||
|
if note - 24 > LaserNumber -1:
|
||||||
|
debug("Only",LaserNumber,"lasers asked, you dum ass !")
|
||||||
|
sendWSall("/redstatus No Laser"+str(note-24))
|
||||||
|
sendWSall("/laser "+str(LaserNumber-1))
|
||||||
|
sendWSall("/simul" +" "+ points[LaserNumber-1])
|
||||||
|
else:
|
||||||
|
Laser = note -24
|
||||||
|
debug("Current Laser switched to", Laser)
|
||||||
|
sendWSall("/status Laser " + str(Laser))
|
||||||
|
sendWSall("/simul" +" "+ points[Laser])
|
||||||
|
|
||||||
|
|
||||||
|
def sendbroadcast():
|
||||||
|
|
||||||
|
debug("Sending broadcast")
|
||||||
|
cs = socket(AF_INET, SOCK_DGRAM)
|
||||||
|
cs.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
|
||||||
|
cs.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
|
||||||
|
cs.sendto("LJ nano 0.1".encode(), ("255.255.255.255", 54545))
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Websocket server
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
def client_list():
|
||||||
|
|
||||||
|
clients = []
|
||||||
|
for client in wserver.clients_list():
|
||||||
|
clients.append(client['id'])
|
||||||
|
#print(clients)
|
||||||
|
return str(clients)
|
||||||
|
|
||||||
|
# Called for every WS client connecting (after handshake)
|
||||||
|
def new_client(client, wserver):
|
||||||
|
|
||||||
|
debug("WS server got new client connected and was given id %d" % client['id'])
|
||||||
|
toKey('WSclients', client_list())
|
||||||
|
sendWSall("/status Hello " + str(client['id']))
|
||||||
|
sendWSall("/laser "+str(0))
|
||||||
|
sendWSall("/lack/" + str(0) + " 3")
|
||||||
|
sendWSall("/lstt/" + str(0) + " 3")
|
||||||
|
sendWSall("/simul" +" "+ points[0])
|
||||||
|
|
||||||
|
|
||||||
|
# Called for every WS client disconnecting
|
||||||
|
def client_left(client, wserver):
|
||||||
|
|
||||||
|
try:
|
||||||
|
debug("WS server had client(%d) disconnected" % client['id'])
|
||||||
|
|
||||||
|
except:
|
||||||
|
debug("Something weird if coming from",client,"on the wire...")
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Called for each WS received message.
|
||||||
|
def message_received(client, wserver, message):
|
||||||
|
|
||||||
|
#if len(message) > 200:
|
||||||
|
# message = message[:200]+'..'
|
||||||
|
|
||||||
|
oscpath = message.split(" ")
|
||||||
|
#print("WS Client", client['id'], "said :", message, "splitted in an oscpath :", oscpath)
|
||||||
|
#if( verbose == True ):
|
||||||
|
# debug("WS server's client", client['id'], "said :", message)
|
||||||
|
|
||||||
|
if message[0:5] == "/simu":
|
||||||
|
debug("WS server sending to simu page :",message)
|
||||||
|
sendWSall(message)
|
||||||
|
|
||||||
|
if message[0:7] == "/noteon":
|
||||||
|
oscpath = message.split(" ")
|
||||||
|
debug("WS server got new laser", int(oscpath[1]))
|
||||||
|
NoteOn(int(oscpath[1]))
|
||||||
|
|
||||||
|
|
||||||
|
# Get WS /aurora/trckr/frame layernumber framenumber points
|
||||||
|
# Set redis /trckr/frame/WSclientID points
|
||||||
|
if message.find('trckr/frame') > 0:
|
||||||
|
|
||||||
|
args = message.split(" ")
|
||||||
|
TrckrPts = []
|
||||||
|
for dot in range(3,len(args)-1,2):
|
||||||
|
TrckrPts.append([float(args[dot]), float(args[dot+1])])
|
||||||
|
|
||||||
|
debug('/trckr/frame/'+str(client['id'])+" "+str(TrckrPts))
|
||||||
|
toKey('/trckr/frame/'+str(client['id']),str(TrckrPts))
|
||||||
|
|
||||||
|
def sendWSall(message):
|
||||||
|
if ( verbose == True ):
|
||||||
|
debug("WS server is sending to all : %s" % (message))
|
||||||
|
wserver.send_message_to_all(message)
|
||||||
|
|
||||||
|
|
||||||
|
def LaunchServer(*args):
|
||||||
|
global wserver
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
# Websocket server
|
||||||
|
wserver = WebsocketServer(wsPORT,host=serverIP)
|
||||||
|
|
||||||
|
debug("Launching Websocket server...")
|
||||||
|
debug("at", serverIP, "port",wsPORT)
|
||||||
|
wserver.set_fn_new_client(new_client)
|
||||||
|
wserver.set_fn_client_left(client_left)
|
||||||
|
wserver.set_fn_message_received(message_received)
|
||||||
|
debug("LJ local server running...")
|
||||||
|
debug("")
|
||||||
|
|
||||||
|
# websocket server loop
|
||||||
|
wserver.run_forever()
|
||||||
|
|
||||||
|
|
||||||
|
except EOFError:
|
||||||
|
debug("break")# no more information
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
debug("sendWS terminating...")
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Launch WS server
|
||||||
|
#
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
LaunchServer()
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
debug("nano Exception")
|
||||||
|
traceback.print_exc()
|
||||||
|
|
374
websocket_server.py
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
# Author: Johan Hanssen Seferidis
|
||||||
|
# License: MIT
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
from base64 import b64encode
|
||||||
|
from hashlib import sha1
|
||||||
|
import logging
|
||||||
|
from socket import error as SocketError
|
||||||
|
import errno
|
||||||
|
|
||||||
|
if sys.version_info[0] < 3:
|
||||||
|
from SocketServer import ThreadingMixIn, TCPServer, StreamRequestHandler
|
||||||
|
else:
|
||||||
|
from socketserver import ThreadingMixIn, TCPServer, StreamRequestHandler
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logging.basicConfig()
|
||||||
|
|
||||||
|
'''
|
||||||
|
+-+-+-+-+-------+-+-------------+-------------------------------+
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-------+-+-------------+-------------------------------+
|
||||||
|
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|
||||||
|
|I|S|S|S| (4) |A| (7) | (16/64) |
|
||||||
|
|N|V|V|V| |S| | (if payload len==126/127) |
|
||||||
|
| |1|2|3| |K| | |
|
||||||
|
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|
||||||
|
| Extended payload length continued, if payload len == 127 |
|
||||||
|
+ - - - - - - - - - - - - - - - +-------------------------------+
|
||||||
|
| Payload Data continued ... |
|
||||||
|
+---------------------------------------------------------------+
|
||||||
|
'''
|
||||||
|
|
||||||
|
FIN = 0x80
|
||||||
|
OPCODE = 0x0f
|
||||||
|
MASKED = 0x80
|
||||||
|
PAYLOAD_LEN = 0x7f
|
||||||
|
PAYLOAD_LEN_EXT16 = 0x7e
|
||||||
|
PAYLOAD_LEN_EXT64 = 0x7f
|
||||||
|
|
||||||
|
OPCODE_CONTINUATION = 0x0
|
||||||
|
OPCODE_TEXT = 0x1
|
||||||
|
OPCODE_BINARY = 0x2
|
||||||
|
OPCODE_CLOSE_CONN = 0x8
|
||||||
|
OPCODE_PING = 0x9
|
||||||
|
OPCODE_PONG = 0xA
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------- API ---------------------------------
|
||||||
|
|
||||||
|
class API():
|
||||||
|
|
||||||
|
def run_forever(self):
|
||||||
|
try:
|
||||||
|
logger.info("Listening on port %d for clients.." % self.port)
|
||||||
|
self.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.server_close()
|
||||||
|
logger.info("Server terminated.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(str(e), exc_info=True)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
def new_client(self, client, server):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def client_left(self, client, server):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def message_received(self, client, server, message):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def set_fn_new_client(self, fn):
|
||||||
|
self.new_client = fn
|
||||||
|
|
||||||
|
def set_fn_client_left(self, fn):
|
||||||
|
self.client_left = fn
|
||||||
|
|
||||||
|
def set_fn_message_received(self, fn):
|
||||||
|
self.message_received = fn
|
||||||
|
|
||||||
|
def send_message(self, client, msg):
|
||||||
|
self._unicast_(client, msg)
|
||||||
|
|
||||||
|
def send_message_to_all(self, msg):
|
||||||
|
self._multicast_(msg)
|
||||||
|
|
||||||
|
def clients_list(self):
|
||||||
|
return self.clients
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------- Implementation -----------------------------
|
||||||
|
|
||||||
|
class WebsocketServer(ThreadingMixIn, TCPServer, API):
|
||||||
|
"""
|
||||||
|
A websocket server waiting for clients to connect.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
port(int): Port to bind to
|
||||||
|
host(str): Hostname or IP to listen for connections. By default 127.0.0.1
|
||||||
|
is being used. To accept connections from any client, you should use
|
||||||
|
0.0.0.0.
|
||||||
|
loglevel: Logging level from logging module to use for logging. By default
|
||||||
|
warnings and errors are being logged.
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
clients(list): A list of connected clients. A client is a dictionary
|
||||||
|
like below.
|
||||||
|
{
|
||||||
|
'id' : id,
|
||||||
|
'handler' : handler,
|
||||||
|
'address' : (addr, port)
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
allow_reuse_address = True
|
||||||
|
daemon_threads = True # comment to keep threads alive until finished
|
||||||
|
|
||||||
|
clients = []
|
||||||
|
id_counter = 0
|
||||||
|
|
||||||
|
def __init__(self, port, host='127.0.0.1', loglevel=logging.WARNING):
|
||||||
|
logger.setLevel(loglevel)
|
||||||
|
TCPServer.__init__(self, (host, port), WebSocketHandler)
|
||||||
|
self.port = self.socket.getsockname()[1]
|
||||||
|
|
||||||
|
def _message_received_(self, handler, msg):
|
||||||
|
self.message_received(self.handler_to_client(handler), self, msg)
|
||||||
|
|
||||||
|
def _ping_received_(self, handler, msg):
|
||||||
|
handler.send_pong(msg)
|
||||||
|
|
||||||
|
def _pong_received_(self, handler, msg):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _new_client_(self, handler):
|
||||||
|
self.id_counter += 1
|
||||||
|
client = {
|
||||||
|
'id': self.id_counter,
|
||||||
|
'handler': handler,
|
||||||
|
'address': handler.client_address
|
||||||
|
}
|
||||||
|
self.clients.append(client)
|
||||||
|
self.new_client(client, self)
|
||||||
|
|
||||||
|
def _client_left_(self, handler):
|
||||||
|
client = self.handler_to_client(handler)
|
||||||
|
self.client_left(client, self)
|
||||||
|
if client in self.clients:
|
||||||
|
self.clients.remove(client)
|
||||||
|
|
||||||
|
def _unicast_(self, to_client, msg):
|
||||||
|
to_client['handler'].send_message(msg)
|
||||||
|
|
||||||
|
def _multicast_(self, msg):
|
||||||
|
for client in self.clients:
|
||||||
|
self._unicast_(client, msg)
|
||||||
|
|
||||||
|
def handler_to_client(self, handler):
|
||||||
|
for client in self.clients:
|
||||||
|
if client['handler'] == handler:
|
||||||
|
return client
|
||||||
|
|
||||||
|
|
||||||
|
class WebSocketHandler(StreamRequestHandler):
|
||||||
|
|
||||||
|
def __init__(self, socket, addr, server):
|
||||||
|
self.server = server
|
||||||
|
StreamRequestHandler.__init__(self, socket, addr, server)
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
StreamRequestHandler.setup(self)
|
||||||
|
self.keep_alive = True
|
||||||
|
self.handshake_done = False
|
||||||
|
self.valid_client = False
|
||||||
|
|
||||||
|
def handle(self):
|
||||||
|
while self.keep_alive:
|
||||||
|
if not self.handshake_done:
|
||||||
|
self.handshake()
|
||||||
|
elif self.valid_client:
|
||||||
|
self.read_next_message()
|
||||||
|
|
||||||
|
def read_bytes(self, num):
|
||||||
|
# python3 gives ordinal of byte directly
|
||||||
|
bytes = self.rfile.read(num)
|
||||||
|
if sys.version_info[0] < 3:
|
||||||
|
return map(ord, bytes)
|
||||||
|
else:
|
||||||
|
return bytes
|
||||||
|
|
||||||
|
def read_next_message(self):
|
||||||
|
try:
|
||||||
|
b1, b2 = self.read_bytes(2)
|
||||||
|
except SocketError as e: # to be replaced with ConnectionResetError for py3
|
||||||
|
if e.errno == errno.ECONNRESET:
|
||||||
|
logger.info("Client closed connection.")
|
||||||
|
print("Error: {}".format(e))
|
||||||
|
self.keep_alive = 0
|
||||||
|
return
|
||||||
|
b1, b2 = 0, 0
|
||||||
|
except ValueError as e:
|
||||||
|
b1, b2 = 0, 0
|
||||||
|
|
||||||
|
fin = b1 & FIN
|
||||||
|
opcode = b1 & OPCODE
|
||||||
|
masked = b2 & MASKED
|
||||||
|
payload_length = b2 & PAYLOAD_LEN
|
||||||
|
|
||||||
|
if opcode == OPCODE_CLOSE_CONN:
|
||||||
|
logger.info("Client asked to close connection.")
|
||||||
|
self.keep_alive = 0
|
||||||
|
return
|
||||||
|
if not masked:
|
||||||
|
logger.warn("Client must always be masked.")
|
||||||
|
self.keep_alive = 0
|
||||||
|
return
|
||||||
|
if opcode == OPCODE_CONTINUATION:
|
||||||
|
logger.warn("Continuation frames are not supported.")
|
||||||
|
return
|
||||||
|
elif opcode == OPCODE_BINARY:
|
||||||
|
logger.warn("Binary frames are not supported.")
|
||||||
|
return
|
||||||
|
elif opcode == OPCODE_TEXT:
|
||||||
|
opcode_handler = self.server._message_received_
|
||||||
|
elif opcode == OPCODE_PING:
|
||||||
|
opcode_handler = self.server._ping_received_
|
||||||
|
elif opcode == OPCODE_PONG:
|
||||||
|
opcode_handler = self.server._pong_received_
|
||||||
|
else:
|
||||||
|
logger.warn("Unknown opcode %#x." % opcode)
|
||||||
|
self.keep_alive = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
if payload_length == 126:
|
||||||
|
payload_length = struct.unpack(">H", self.rfile.read(2))[0]
|
||||||
|
elif payload_length == 127:
|
||||||
|
payload_length = struct.unpack(">Q", self.rfile.read(8))[0]
|
||||||
|
|
||||||
|
masks = self.read_bytes(4)
|
||||||
|
message_bytes = bytearray()
|
||||||
|
for message_byte in self.read_bytes(payload_length):
|
||||||
|
message_byte ^= masks[len(message_bytes) % 4]
|
||||||
|
message_bytes.append(message_byte)
|
||||||
|
opcode_handler(self, message_bytes.decode('utf8'))
|
||||||
|
|
||||||
|
def send_message(self, message):
|
||||||
|
self.send_text(message)
|
||||||
|
|
||||||
|
def send_pong(self, message):
|
||||||
|
self.send_text(message, OPCODE_PONG)
|
||||||
|
|
||||||
|
def send_text(self, message, opcode=OPCODE_TEXT):
|
||||||
|
"""
|
||||||
|
Important: Fragmented(=continuation) messages are not supported since
|
||||||
|
their usage cases are limited - when we don't know the payload length.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Validate message
|
||||||
|
if isinstance(message, bytes):
|
||||||
|
message = try_decode_UTF8(message) # this is slower but ensures we have UTF-8
|
||||||
|
if not message:
|
||||||
|
logger.warning("Can\'t send message, message is not valid UTF-8")
|
||||||
|
return False
|
||||||
|
elif sys.version_info < (3,0) and (isinstance(message, str) or isinstance(message, unicode)):
|
||||||
|
pass
|
||||||
|
elif isinstance(message, str):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
logger.warning('Can\'t send message, message has to be a string or bytes. Given type is %s' % type(message))
|
||||||
|
return False
|
||||||
|
|
||||||
|
header = bytearray()
|
||||||
|
payload = encode_to_UTF8(message)
|
||||||
|
payload_length = len(payload)
|
||||||
|
|
||||||
|
# Normal payload
|
||||||
|
if payload_length <= 125:
|
||||||
|
header.append(FIN | opcode)
|
||||||
|
header.append(payload_length)
|
||||||
|
|
||||||
|
# Extended payload
|
||||||
|
elif payload_length >= 126 and payload_length <= 65535:
|
||||||
|
header.append(FIN | opcode)
|
||||||
|
header.append(PAYLOAD_LEN_EXT16)
|
||||||
|
header.extend(struct.pack(">H", payload_length))
|
||||||
|
|
||||||
|
# Huge extended payload
|
||||||
|
elif payload_length < 18446744073709551616:
|
||||||
|
header.append(FIN | opcode)
|
||||||
|
header.append(PAYLOAD_LEN_EXT64)
|
||||||
|
header.extend(struct.pack(">Q", payload_length))
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise Exception("Message is too big. Consider breaking it into chunks.")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.request.send(header + payload)
|
||||||
|
|
||||||
|
def read_http_headers(self):
|
||||||
|
headers = {}
|
||||||
|
# first line should be HTTP GET
|
||||||
|
http_get = self.rfile.readline().decode().strip()
|
||||||
|
assert http_get.upper().startswith('GET')
|
||||||
|
# remaining should be headers
|
||||||
|
while True:
|
||||||
|
header = self.rfile.readline().decode().strip()
|
||||||
|
if not header:
|
||||||
|
break
|
||||||
|
head, value = header.split(':', 1)
|
||||||
|
headers[head.lower().strip()] = value.strip()
|
||||||
|
return headers
|
||||||
|
|
||||||
|
def handshake(self):
|
||||||
|
headers = self.read_http_headers()
|
||||||
|
|
||||||
|
try:
|
||||||
|
assert headers['upgrade'].lower() == 'websocket'
|
||||||
|
except AssertionError:
|
||||||
|
self.keep_alive = False
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
key = headers['sec-websocket-key']
|
||||||
|
except KeyError:
|
||||||
|
logger.warning("Client tried to connect but was missing a key")
|
||||||
|
self.keep_alive = False
|
||||||
|
return
|
||||||
|
|
||||||
|
response = self.make_handshake_response(key)
|
||||||
|
self.handshake_done = self.request.send(response.encode())
|
||||||
|
self.valid_client = True
|
||||||
|
self.server._new_client_(self)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def make_handshake_response(cls, key):
|
||||||
|
return \
|
||||||
|
'HTTP/1.1 101 Switching Protocols\r\n'\
|
||||||
|
'Upgrade: websocket\r\n' \
|
||||||
|
'Connection: Upgrade\r\n' \
|
||||||
|
'Sec-WebSocket-Accept: %s\r\n' \
|
||||||
|
'\r\n' % cls.calculate_response_key(key)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def calculate_response_key(cls, key):
|
||||||
|
GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
|
||||||
|
hash = sha1(key.encode() + GUID.encode())
|
||||||
|
response_key = b64encode(hash.digest()).strip()
|
||||||
|
return response_key.decode('ASCII')
|
||||||
|
|
||||||
|
def finish(self):
|
||||||
|
self.server._client_left_(self)
|
||||||
|
|
||||||
|
|
||||||
|
def encode_to_UTF8(data):
|
||||||
|
try:
|
||||||
|
return data.encode('UTF-8')
|
||||||
|
except UnicodeEncodeError as e:
|
||||||
|
logger.error("Could not encode data to UTF-8 -- %s" % e)
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
raise(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def try_decode_UTF8(data):
|
||||||
|
try:
|
||||||
|
return data.decode('utf-8')
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
raise(e)
|
316
www/LJ.js
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
//
|
||||||
|
// LJ.js v0.7.1
|
||||||
|
//
|
||||||
|
|
||||||
|
// LJ websocket address. IP will be updated at LJ startup according to LJ.conf wwwIP
|
||||||
|
|
||||||
|
var LJ = websocket_uri
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Central horizontal menu
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
function noMenu() {
|
||||||
|
var x = document.getElementById("align");
|
||||||
|
x.value = 0 ;
|
||||||
|
var x = document.getElementById("run");
|
||||||
|
x.value = 0 ;
|
||||||
|
var x = document.getElementById("simu");
|
||||||
|
x.value = 0 ;
|
||||||
|
var x = document.getElementById("live");
|
||||||
|
x.value = 0 ;
|
||||||
|
|
||||||
|
// Hide all possible main central grids.
|
||||||
|
var x = document.getElementById("mgalign");
|
||||||
|
x.style.display = "none";
|
||||||
|
var x = document.getElementById("mgsimu");
|
||||||
|
x.style.display = "none";
|
||||||
|
var x = document.getElementById("mgrun");
|
||||||
|
x.style.display = "none";
|
||||||
|
var x = document.getElementById("mglive");
|
||||||
|
x.style.display = "none";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAlign() {
|
||||||
|
noMenu();
|
||||||
|
var x = document.getElementById("mgalign");
|
||||||
|
x.style.display = "grid";
|
||||||
|
var x = document.getElementById("align");
|
||||||
|
x.value = 1 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showRun() {
|
||||||
|
noMenu();
|
||||||
|
var x = document.getElementById("mgrun");
|
||||||
|
x.style.display = "grid";
|
||||||
|
var x = document.getElementById("run");
|
||||||
|
x.value = 1 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCanvas() {
|
||||||
|
noMenu();
|
||||||
|
var x = document.getElementById("mgsimu");
|
||||||
|
x.style.display = "grid";
|
||||||
|
var x = document.getElementById("cnvbuttons");
|
||||||
|
x.style.display = "grid";
|
||||||
|
var x = document.getElementById("simu");
|
||||||
|
x.value = 1 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLive() {
|
||||||
|
noMenu();
|
||||||
|
var x = document.getElementById("mglive");
|
||||||
|
x.style.display = "grid";
|
||||||
|
var x = document.getElementById("live");
|
||||||
|
x.value = 1 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// SimuUIs
|
||||||
|
//
|
||||||
|
|
||||||
|
function nosimuUI() {
|
||||||
|
// Hide all possible main central grids.
|
||||||
|
var x = document.getElementById("planetUI");
|
||||||
|
x.style.display = "none";
|
||||||
|
var x = document.getElementById("nozoidUI");
|
||||||
|
x.style.display = "none";
|
||||||
|
var x = document.getElementById("aiUI");
|
||||||
|
x.style.display = "none";
|
||||||
|
var x = document.getElementById("lissaUI");
|
||||||
|
x.style.display = "none";
|
||||||
|
var x = document.getElementById("vjUI");
|
||||||
|
x.style.display = "none";
|
||||||
|
var x = document.getElementById("poseUI");
|
||||||
|
x.style.display = "none";
|
||||||
|
var x = document.getElementById("wordsUI");
|
||||||
|
x.style.display = "none";
|
||||||
|
var x = document.getElementById("pluginsUI");
|
||||||
|
x.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function showplanetUI() {
|
||||||
|
nosimuUI();
|
||||||
|
var x = document.getElementById("planetUI");
|
||||||
|
x.style.display = "grid";
|
||||||
|
_WS.send("/planet/ping");
|
||||||
|
}
|
||||||
|
|
||||||
|
function shownozoidUI() {
|
||||||
|
nosimuUI();
|
||||||
|
var x = document.getElementById("nozoidUI");
|
||||||
|
x.style.display = "grid";
|
||||||
|
_WS.send("/nozoid/ping");
|
||||||
|
}
|
||||||
|
|
||||||
|
function showaiUI() {
|
||||||
|
nosimuUI();
|
||||||
|
var x = document.getElementById("aiUI");
|
||||||
|
x.style.display = "grid";
|
||||||
|
}
|
||||||
|
|
||||||
|
function showlissaUI() {
|
||||||
|
nosimuUI();
|
||||||
|
var x = document.getElementById("lissaUI");
|
||||||
|
x.style.display = "grid";
|
||||||
|
}
|
||||||
|
|
||||||
|
function showvjUI() {
|
||||||
|
nosimuUI();
|
||||||
|
var x = document.getElementById("vjUI");
|
||||||
|
x.style.display = "grid";
|
||||||
|
_WS.send("/bank0/ping");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showposeUI() {
|
||||||
|
nosimuUI();
|
||||||
|
var x = document.getElementById("poseUI");
|
||||||
|
x.style.display = "grid";
|
||||||
|
_WS.send("/pose/ping");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showwordsUI() {
|
||||||
|
nosimuUI();
|
||||||
|
var x = document.getElementById("wordsUI");
|
||||||
|
x.style.display = "grid";
|
||||||
|
_WS.send("/words/ping");
|
||||||
|
}
|
||||||
|
|
||||||
|
function showpluginsUI() {
|
||||||
|
nosimuUI();
|
||||||
|
var x = document.getElementById("pluginsUI");
|
||||||
|
x.style.display = "grid";
|
||||||
|
//_WS.send("/words/ping");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Button clicked
|
||||||
|
//
|
||||||
|
|
||||||
|
function buttonClicked(clicked_id) {
|
||||||
|
|
||||||
|
_WS.send("/" + clicked_id);
|
||||||
|
|
||||||
|
// update Canvas right part of maingrid
|
||||||
|
if (clicked_id === "planet/planetUI") {
|
||||||
|
showplanetUI();
|
||||||
|
}
|
||||||
|
if (clicked_id === "nozoid/nozoidUI") {
|
||||||
|
shownozoidUI();
|
||||||
|
}
|
||||||
|
if (clicked_id === "ai/aiUI") {
|
||||||
|
showaiUI();
|
||||||
|
}
|
||||||
|
if (clicked_id === "lissa/lissaUI") {
|
||||||
|
showlissaUI();
|
||||||
|
}
|
||||||
|
if (clicked_id === "bank0/vjUI") {
|
||||||
|
showvjUI();
|
||||||
|
}
|
||||||
|
if (clicked_id === "pose/poseUI") {
|
||||||
|
showposeUI();
|
||||||
|
}
|
||||||
|
if (clicked_id === "words/wordsUI") {
|
||||||
|
showwordsUI();
|
||||||
|
}
|
||||||
|
if (clicked_id === "lj/pluginsUI") {
|
||||||
|
showpluginsUI();
|
||||||
|
}
|
||||||
|
if (clicked_id === "nozoid/down 50") {
|
||||||
|
var x = document.getElementById("nozoid/down 50");
|
||||||
|
x.value = 0 ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Matrix selection
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
function MatrixSelect(clicked_value) {
|
||||||
|
|
||||||
|
console.log("/" + clicked_value);
|
||||||
|
_WS.send("/" + clicked_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Forms submits
|
||||||
|
//
|
||||||
|
|
||||||
|
function onSubmit(clicked_id) {
|
||||||
|
var input = document.getElementById(clicked_id);
|
||||||
|
console.log("/" + clicked_id + " " + input.value);
|
||||||
|
_WS.send("/" + clicked_id + " " + input.value);
|
||||||
|
_WS.showout("/" + clicked_id + " " + input.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Websocket handler
|
||||||
|
//
|
||||||
|
|
||||||
|
var pl = "";
|
||||||
|
var pl2 = new Array();
|
||||||
|
var _WS = {
|
||||||
|
uri: LJ,
|
||||||
|
ws: null,
|
||||||
|
|
||||||
|
init : function (e) {
|
||||||
|
_WS.s = new WebSocket(_WS.uri);
|
||||||
|
_WS.s.onopen = function (e) { _WS.onOpen(e); };
|
||||||
|
_WS.s.onclose = function (e) { _WS.onClose(e); };
|
||||||
|
_WS.s.onmessage = function (e) { _WS.onMessage(e); };
|
||||||
|
_WS.s.onerror = function (e) { _WS.onError(e); };
|
||||||
|
},
|
||||||
|
|
||||||
|
onOpen: function () {
|
||||||
|
_WS.showout(_WS.uri);
|
||||||
|
_WS.showout('CONNECTED');
|
||||||
|
document.getElementById("on").value = 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
onClose: function () {
|
||||||
|
_WS.showout('DISCONNECTED');
|
||||||
|
document.getElementById("on").value = 0;
|
||||||
|
document.getElementById("lstt/0").value = 0;
|
||||||
|
document.getElementById("lstt/1").value = 0;
|
||||||
|
document.getElementById("lstt/2").value = 0;
|
||||||
|
document.getElementById("lstt/3").value = 0;
|
||||||
|
document.getElementById("lack/0").value = 0;
|
||||||
|
document.getElementById("lack/1").value = 0;
|
||||||
|
document.getElementById("lack/2").value = 0;
|
||||||
|
document.getElementById("lack/3").value = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
onMessage: function (e) {
|
||||||
|
var res = e.data.split(" ");
|
||||||
|
//console.log(e.data)
|
||||||
|
//console.log(res[0].substring(0,6))
|
||||||
|
//console.log(res)
|
||||||
|
//console.log(res[0].slice(1))
|
||||||
|
|
||||||
|
switch (res[0].substring(0,6)) {
|
||||||
|
|
||||||
|
case "/statu":
|
||||||
|
_WS.showstatus(e.data.slice(8));
|
||||||
|
break;
|
||||||
|
case "/simul":
|
||||||
|
pl = e.data.slice(7);
|
||||||
|
//console.log(pl)
|
||||||
|
pl2 = eval(pl.replace(/[()]/g, ''));
|
||||||
|
break;
|
||||||
|
case "/plpoi":
|
||||||
|
//console.log("plpoint");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//console.log(e);
|
||||||
|
document.getElementById(res[0].slice(1)).value = res[1];
|
||||||
|
_WS.showin(e.data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onError: function (e) {
|
||||||
|
_WS.showin('<span style="color: red;">ERROR:</span> ' + e.data);
|
||||||
|
},
|
||||||
|
|
||||||
|
showin: function (message) {
|
||||||
|
var divtext = document.getElementById('showin');
|
||||||
|
divtext.innerHTML="";
|
||||||
|
divtext.innerHTML= message.toString();
|
||||||
|
},
|
||||||
|
|
||||||
|
showout: function (message) {
|
||||||
|
var divtext = document.getElementById('showout');
|
||||||
|
divtext.innerHTML="";
|
||||||
|
divtext.innerHTML= message.toString();
|
||||||
|
},
|
||||||
|
|
||||||
|
showstatus: function (message) {
|
||||||
|
var divtext = document.getElementById('showstatus');
|
||||||
|
divtext.innerHTML="";
|
||||||
|
divtext.innerHTML= message.toString();
|
||||||
|
},
|
||||||
|
|
||||||
|
send: function (message) {
|
||||||
|
if (!message.length) {
|
||||||
|
alert('Empty message not allowed !');
|
||||||
|
} else {
|
||||||
|
_WS.showout(message);
|
||||||
|
_WS.s.send(message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
close: function () {
|
||||||
|
_WS.showout('GOODBYE !');
|
||||||
|
_WS.s.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('load', _WS.init, false);
|
||||||
|
|
BIN
www/android-chrome-192x192.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
www/android-chrome-512x512.png
Executable file
After Width: | Height: | Size: 50 KiB |
BIN
www/apple-touch-icon-80x80.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
www/apple-touch-icon.png
Executable file
After Width: | Height: | Size: 10 KiB |
1
www/config.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
websocket_uri = "ws://192.168.2.43:9001/"
|
BIN
www/css/7f37946c45abf5482c243bf326f82628.eot
Executable file
828
www/css/7f37946c45abf5482c243bf326f82628.svg
Executable file
@ -0,0 +1,828 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||||
|
<svg>
|
||||||
|
<metadata>
|
||||||
|
Created by FontForge 20120731 at Sat Jun 6 06:35:01 2020
|
||||||
|
By www
|
||||||
|
This work is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 License (click below for details).
|
||||||
|
The font was created by Michal Sulik using Fony, bdfresize, potrace, autotrace and Fontforge.
|
||||||
|
If you use this font in any public work, please be so nice and leave a link in comments on http://msulik.deviantart.com/.
|
||||||
|
</metadata>
|
||||||
|
<defs>
|
||||||
|
<font id="BusLedDisplaySmall" horiz-adv-x="458" >
|
||||||
|
<font-face
|
||||||
|
font-family="Bus Led Display Small"
|
||||||
|
font-weight="500"
|
||||||
|
font-variant="small-caps"
|
||||||
|
font-stretch="normal"
|
||||||
|
units-per-em="1024"
|
||||||
|
panose-1="2 0 6 3 0 0 0 0 0 0"
|
||||||
|
ascent="819"
|
||||||
|
descent="-205"
|
||||||
|
x-height="461"
|
||||||
|
cap-height="461"
|
||||||
|
bbox="34 -154 716 682"
|
||||||
|
underline-thickness="50"
|
||||||
|
underline-position="-101"
|
||||||
|
unicode-range="U+0001-02DD"
|
||||||
|
/>
|
||||||
|
<missing-glyph horiz-adv-x="374"
|
||||||
|
d="M34 0v682h272v-682h-272zM68 34h204v614h-204v-614z" />
|
||||||
|
<glyph glyph-name=".notdef" horiz-adv-x="374"
|
||||||
|
d="M34 0v682h272v-682h-272zM68 34h204v614h-204v-614z" />
|
||||||
|
<glyph glyph-name=".null" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="nonmarkingreturn" horiz-adv-x="341"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$000" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$000" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$001" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$002" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$003" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$004" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$005" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$006" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$007" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$008" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$009" unicode="	" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$010" unicode="
" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$011" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$012" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$013" unicode="
" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$014" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$015" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$016" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$017" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$018" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$019" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$020" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$021" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$022" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$023" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$024" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$025" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$026" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$027" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$028" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$029" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$030" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$031" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$032" unicode=" " horiz-adv-x="199"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="$033" unicode="!" horiz-adv-x="150"
|
||||||
|
d="M50 0v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$034" unicode=""" horiz-adv-x="355"
|
||||||
|
d="M204 307v51h51v-51h-51zM50 307v51h51v-51h-51zM255 410v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$035" unicode="#" horiz-adv-x="662"
|
||||||
|
d="M357 0v51h52v-51h-52zM153 0v51h51v-51h-51zM460 102v52h51v-52h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM153 102v52h51v-52h-51zM50 102v52h51v-52h-51zM409 205v51h51v-51h-51zM204 205v51h51v-51h-51zM562 307v51h51v-51h-51zM460 307v51h51v-51h-51z
|
||||||
|
M357 307v51h52v-51h-52zM255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM460 410v51h51v-51h-51zM255 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$036" unicode="$"
|
||||||
|
d="M204 -102v51h51v-51h-51zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM204 102v52h51v-52h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51zM204 307v51h51v-51h-51z
|
||||||
|
M357 358v52h52v-52h-52zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM204 512v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$037" unicode="%" horiz-adv-x="560"
|
||||||
|
d="M409 0v51h51v-51h-51zM153 0v51h51v-51h-51zM306 51v51h51v-51h-51zM460 102v52h51v-52h-51zM204 102v52h51v-52h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 256v51h51v-51h-51zM306 307v51h51v-51h-51zM50 307v51h51v-51h-51zM204 358v52h51v-52h-51z
|
||||||
|
M357 410v51h52v-51h-52zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$038" unicode="&" horiz-adv-x="611"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM460 51v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM409 154v51h51v-51h-51zM50 154v51h51v-51h-51zM153 205v51h51v-51h-51zM511 256v51h51v-51h-51zM409 256v51h51v-51h-51zM306 256v51h51v-51h-51zM50 256
|
||||||
|
v51h51v-51h-51zM409 358v52h51v-52h-51zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$039" unicode="'" horiz-adv-x="150"
|
||||||
|
d="M50 358v52h51v-52h-51zM50 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$040" unicode="(" horiz-adv-x="202"
|
||||||
|
d="M101 0v51h52v-51h-52zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$041" unicode=")" horiz-adv-x="202"
|
||||||
|
d="M50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$042" unicode="*" horiz-adv-x="560"
|
||||||
|
d="M255 51v51h51v-51h-51zM460 154v51h51v-51h-51zM255 154v51h51v-51h-51zM50 154v51h51v-51h-51zM357 205v51h52v-51h-52zM153 205v51h51v-51h-51zM255 256v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM460 358v52h51v-52h-51zM255 358v52h51v-52h-51z
|
||||||
|
M50 358v52h51v-52h-51zM255 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$043" unicode="+" horiz-adv-x="355"
|
||||||
|
d="M153 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM153 307v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$044" unicode="," horiz-adv-x="202"
|
||||||
|
d="M50 -51v51h51v-51h-51zM101 51v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$045" unicode="-" horiz-adv-x="355"
|
||||||
|
d="M255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$046" unicode="." horiz-adv-x="150"
|
||||||
|
d="M50 0v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$047" unicode="/" horiz-adv-x="406"
|
||||||
|
d="M50 -51v51h51v-51h-51zM101 51v51h52v-51h-52zM153 154v51h51v-51h-51zM204 256v51h51v-51h-51zM255 358v52h51v-52h-51zM306 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$048" unicode="0"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM357 154v51h52v-51h-52zM153 154v51h51v-51h-51zM50 154v51h51v-51h-51zM357 256v51h52v-51h-52zM255 256v51h51v-51h-51zM50 256v51h51v-51h-51zM357 358v52h52v-52h-52zM50 358
|
||||||
|
v52h51v-52h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$049" unicode="1" horiz-adv-x="304"
|
||||||
|
d="M204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM153 102v52h51v-52h-51zM153 205v51h51v-51h-51zM153 307v51h51v-51h-51zM50 358v52h51v-52h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$050" unicode="2"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM306 154v51h51v-51h-51zM204 154v51h51v-51h-51zM357 256v51h52v-51h-52zM357 358v52h52v-52h-52zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51zM153 410
|
||||||
|
v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$051" unicode="3" horiz-adv-x="406"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM306 307v51h51v-51h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$052" unicode="4"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM255 102v52h51v-52h-51zM357 154v51h52v-51h-52zM153 154v51h51v-51h-51zM50 154v51h51v-51h-51zM255 205v51h51v-51h-51zM101 256v51h52v-51h-52zM255 307v51h51v-51h-51zM101 358v52h52v-52h-52zM255 410v51h51v-51h-51z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="$053" unicode="5"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM255 256v51h51v-51h-51zM153 256v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$054" unicode="6"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM255 256v51h51v-51h-51zM153 256v51h51v-51h-51zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51z
|
||||||
|
M204 410v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$055" unicode="7"
|
||||||
|
d="M153 0v51h51v-51h-51zM204 102v52h51v-52h-51zM255 205v51h51v-51h-51zM306 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$056" unicode="8"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM306 205v51h51v-51h-51zM204 205v51h51v-51h-51zM101 205v51h52v-51h-52zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51z
|
||||||
|
M204 410v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$057" unicode="9"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 256v51h51v-51h-51zM357 358v52h52v-52h-52zM50 358v52h51v-52h-51z
|
||||||
|
M255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$058" unicode=":" horiz-adv-x="150"
|
||||||
|
d="M50 102v52h51v-52h-51zM50 307v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$059" unicode=";" horiz-adv-x="202"
|
||||||
|
d="M50 -51v51h51v-51h-51zM101 51v51h52v-51h-52zM101 256v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$060" unicode="<" horiz-adv-x="304"
|
||||||
|
d="M204 -102v51h51v-51h-51zM153 0v51h51v-51h-51zM101 102v52h52v-52h-52zM50 205v51h51v-51h-51zM101 307v51h52v-51h-52zM153 410v51h51v-51h-51zM204 512v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$061" unicode="=" horiz-adv-x="355"
|
||||||
|
d="M255 102v52h51v-52h-51zM153 102v52h51v-52h-51zM50 102v52h51v-52h-51zM255 256v51h51v-51h-51zM153 256v51h51v-51h-51zM50 256v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$062" unicode=">" horiz-adv-x="304"
|
||||||
|
d="M50 -102v51h51v-51h-51zM101 0v51h52v-51h-52zM153 102v52h51v-52h-51zM204 205v51h51v-51h-51zM153 307v51h51v-51h-51zM101 410v51h52v-51h-52zM50 512v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$063" unicode="?" horiz-adv-x="406"
|
||||||
|
d="M153 -51v51h51v-51h-51zM153 102v52h51v-52h-51zM255 205v51h51v-51h-51zM306 307v51h51v-51h-51zM50 358v52h51v-52h-51zM306 410v51h51v-51h-51zM204 461v51h51v-51h-51zM101 461v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$064" unicode="@" horiz-adv-x="560"
|
||||||
|
d="M409 0v51h51v-51h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM409 102v52h51v-52h-51zM306 102v52h51v-52h-51zM204 102v52h51v-52h-51zM50 102v52h51v-52h-51zM460 205v51h51v-51h-51zM357 205v51h52v-51h-52zM153 205v51h51v-51h-51zM50 205
|
||||||
|
v51h51v-51h-51zM460 307v51h51v-51h-51zM357 307v51h52v-51h-52zM255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51zM409 410v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$065" unicode="A"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$066" unicode="B"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 102v52h51v-52h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 307v51h51v-51h-51zM357 358
|
||||||
|
v52h52v-52h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$067" unicode="C"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$068" unicode="D"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410
|
||||||
|
v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$069" unicode="E"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410
|
||||||
|
v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$070" unicode="F"
|
||||||
|
d="M50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$071" unicode="G"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM255 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$072" unicode="H"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52z
|
||||||
|
M50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$073" unicode="I" horiz-adv-x="253"
|
||||||
|
d="M153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$074" unicode="J"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM357 307v51h52v-51h-52zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$075" unicode="K"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM255 307v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$076" unicode="L"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$077" unicode="M"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$078" unicode="N"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$079" unicode="O"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$080" unicode="P"
|
||||||
|
d="M50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM50 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 307v51h51v-51h-51zM357 358v52h52v-52h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$081" unicode="Q" horiz-adv-x="509"
|
||||||
|
d="M409 0v51h51v-51h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410
|
||||||
|
v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$082" unicode="R"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 307v51h51v-51h-51zM357 358v52h52v-52h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$083" unicode="S"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51zM357 358v52h52v-52h-52zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$084" unicode="T"
|
||||||
|
d="M204 0v51h51v-51h-51zM204 102v52h51v-52h-51zM204 205v51h51v-51h-51zM204 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$085" unicode="U"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$086" unicode="V"
|
||||||
|
d="M204 0v51h51v-51h-51zM255 102v52h51v-52h-51zM153 102v52h51v-52h-51zM306 205v51h51v-51h-51zM101 205v51h52v-51h-52zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$087" unicode="W" horiz-adv-x="662"
|
||||||
|
d="M409 0v51h51v-51h-51zM204 0v51h51v-51h-51zM460 102v52h51v-52h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM153 102v52h51v-52h-51zM511 205v51h51v-51h-51zM306 205v51h51v-51h-51zM101 205v51h52v-51h-52zM562 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M562 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$088" unicode="X"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM101 102v52h52v-52h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$089" unicode="Y"
|
||||||
|
d="M204 0v51h51v-51h-51zM204 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$090" unicode="Z"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM204 205v51h51v-51h-51zM306 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$091" unicode="[" horiz-adv-x="253"
|
||||||
|
d="M153 -51v51h51v-51h-51zM50 -51v51h51v-51h-51zM50 51v51h51v-51h-51zM50 154v51h51v-51h-51zM50 256v51h51v-51h-51zM50 358v52h51v-52h-51zM153 461v51h51v-51h-51zM50 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$092" unicode="\" horiz-adv-x="406"
|
||||||
|
d="M306 -51v51h51v-51h-51zM255 51v51h51v-51h-51zM204 154v51h51v-51h-51zM153 256v51h51v-51h-51zM101 358v52h52v-52h-52zM50 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$093" unicode="]" horiz-adv-x="253"
|
||||||
|
d="M153 -51v51h51v-51h-51zM50 -51v51h51v-51h-51zM153 51v51h51v-51h-51zM153 154v51h51v-51h-51zM153 256v51h51v-51h-51zM153 358v52h51v-52h-51zM153 461v51h51v-51h-51zM50 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$094" unicode="^" horiz-adv-x="355"
|
||||||
|
d="M255 358v52h51v-52h-51zM50 358v52h51v-52h-51zM153 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$095" unicode="_"
|
||||||
|
d="M357 -51v51h52v-51h-52zM255 -51v51h51v-51h-51zM153 -51v51h51v-51h-51zM50 -51v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$096" unicode="`" horiz-adv-x="253"
|
||||||
|
d="M153 358v52h51v-52h-51zM50 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$097" unicode="a"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$098" unicode="b"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 102v52h51v-52h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 307v51h51v-51h-51zM357 358
|
||||||
|
v52h52v-52h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$099" unicode="c"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$100" unicode="d"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410
|
||||||
|
v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$101" unicode="e"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410
|
||||||
|
v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$102" unicode="f"
|
||||||
|
d="M50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$103" unicode="g"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM255 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$104" unicode="h"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52z
|
||||||
|
M50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$105" unicode="i" horiz-adv-x="253"
|
||||||
|
d="M153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$106" unicode="j"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM357 307v51h52v-51h-52zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$107" unicode="k"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM255 307v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$108" unicode="l"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$109" unicode="m"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$110" unicode="n"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$111" unicode="o"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$112" unicode="p"
|
||||||
|
d="M50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM50 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 307v51h51v-51h-51zM357 358v52h52v-52h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$113" unicode="q" horiz-adv-x="509"
|
||||||
|
d="M409 0v51h51v-51h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410
|
||||||
|
v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$114" unicode="r"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 307v51h51v-51h-51zM357 358v52h52v-52h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$115" unicode="s"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51zM357 358v52h52v-52h-52zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$116" unicode="t"
|
||||||
|
d="M204 0v51h51v-51h-51zM204 102v52h51v-52h-51zM204 205v51h51v-51h-51zM204 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$117" unicode="u"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$118" unicode="v"
|
||||||
|
d="M204 0v51h51v-51h-51zM255 102v52h51v-52h-51zM153 102v52h51v-52h-51zM306 205v51h51v-51h-51zM101 205v51h52v-51h-52zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$119" unicode="w" horiz-adv-x="662"
|
||||||
|
d="M409 0v51h51v-51h-51zM204 0v51h51v-51h-51zM460 102v52h51v-52h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM153 102v52h51v-52h-51zM511 205v51h51v-51h-51zM306 205v51h51v-51h-51zM101 205v51h52v-51h-52zM562 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M562 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$120" unicode="x"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM101 102v52h52v-52h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$121" unicode="y"
|
||||||
|
d="M204 0v51h51v-51h-51zM204 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$122" unicode="z"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM204 205v51h51v-51h-51zM306 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$123" unicode="{" horiz-adv-x="304"
|
||||||
|
d="M204 -51v51h51v-51h-51zM153 51v51h51v-51h-51zM153 154v51h51v-51h-51zM50 205v51h51v-51h-51zM153 256v51h51v-51h-51zM153 358v52h51v-52h-51zM204 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$124" unicode="|" horiz-adv-x="150"
|
||||||
|
d="M50 -51v51h51v-51h-51zM50 51v51h51v-51h-51zM50 154v51h51v-51h-51zM50 256v51h51v-51h-51zM50 358v52h51v-52h-51zM50 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$125" unicode="}" horiz-adv-x="304"
|
||||||
|
d="M50 -51v51h51v-51h-51zM101 51v51h52v-51h-52zM101 154v51h52v-51h-52zM204 205v51h51v-51h-51zM101 256v51h52v-51h-52zM101 358v52h52v-52h-52zM50 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="$126" unicode="~"
|
||||||
|
d="M306 154v51h51v-51h-51zM50 154v51h51v-51h-51zM204 205v51h51v-51h-51zM357 256v51h52v-51h-52zM101 256v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="$127" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0080" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0081" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0082" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0083" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0084" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0085" unicode="…" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0086" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0087" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0088" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0089" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni008A" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni008B" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni008C" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni008D" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni008E" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni008F" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0090" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0091" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0092" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0093" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0094" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0095" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0096" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0097" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0098" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni0099" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni009A" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni009B" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni009C" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni009D" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni009E" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni009F" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="uni00A0" unicode=" " horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="currency" unicode="¤" horiz-adv-x="560"
|
||||||
|
d="M460 0v51h51v-51h-51zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM153 102v52h51v-52h-51zM357 205v51h52v-51h-52zM153 205v51h51v-51h-51zM357 307v51h52v-51h-52zM255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM460 410v51h51v-51h-51z
|
||||||
|
M50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="section" unicode="§"
|
||||||
|
d="M255 -102v51h51v-51h-51zM153 -102v51h51v-51h-51zM357 -51v51h52v-51h-52zM50 -51v51h51v-51h-51zM306 51v51h51v-51h-51zM204 102v52h51v-52h-51zM306 154v51h51v-51h-51zM101 154v51h52v-51h-52zM306 256v51h51v-51h-51zM101 256v51h52v-51h-52zM204 307v51h51v-51
|
||||||
|
h-51zM101 358v52h52v-52h-52zM357 461v51h52v-51h-52zM50 461v51h51v-51h-51zM255 512v51h51v-51h-51zM153 512v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="304"
|
||||||
|
d="M204 461v51h51v-51h-51zM50 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="copyright" unicode="©" horiz-adv-x="662"
|
||||||
|
d="M460 -51v51h51v-51h-51zM357 -51v51h52v-51h-52zM255 -51v51h51v-51h-51zM153 -51v51h51v-51h-51zM562 51v51h51v-51h-51zM306 51v51h51v-51h-51zM204 51v51h51v-51h-51zM50 51v51h51v-51h-51zM409 102v52h51v-52h-51zM562 154v51h51v-51h-51zM153 154v51h51v-51h-51z
|
||||||
|
M50 154v51h51v-51h-51zM562 256v51h51v-51h-51zM153 256v51h51v-51h-51zM50 256v51h51v-51h-51zM409 307v51h51v-51h-51zM562 358v52h51v-52h-51zM306 358v52h51v-52h-51zM204 358v52h51v-52h-51zM50 358v52h51v-52h-51zM460 461v51h51v-51h-51zM357 461v51h52v-51h-52z
|
||||||
|
M255 461v51h51v-51h-51zM153 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="guillemotleft" unicode="«" horiz-adv-x="355"
|
||||||
|
d="M255 154v51h51v-51h-51zM101 154v51h52v-51h-52zM204 256v51h51v-51h-51zM50 256v51h51v-51h-51zM255 358v52h51v-52h-51zM101 358v52h52v-52h-52zM255 154v51h51v-51h-51zM101 154v51h52v-51h-52zM204 256v51h51v-51h-51zM50 256v51h51v-51h-51zM255 358v52h51v-52h-51z
|
||||||
|
M101 358v52h52v-52h-52z" />
|
||||||
|
<glyph glyph-name="logicalnot" unicode="¬"
|
||||||
|
d="M357 51v51h52v-51h-52zM357 154v51h52v-51h-52zM357 256v51h52v-51h-52zM255 256v51h51v-51h-51zM153 256v51h51v-51h-51zM50 256v51h51v-51h-51zM357 51v51h52v-51h-52zM357 154v51h52v-51h-52zM357 256v51h52v-51h-52zM255 256v51h51v-51h-51zM153 256v51h51v-51h-51z
|
||||||
|
M50 256v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="uni00AD" unicode="­" horiz-adv-x="253"
|
||||||
|
d="M153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="registered" unicode="®" horiz-adv-x="765"
|
||||||
|
d="M562 -102v51h51v-51h-51zM460 -102v51h51v-51h-51zM357 -102v51h52v-51h-52zM255 -102v51h51v-51h-51zM153 -102v51h51v-51h-51zM613 0v51h52v-51h-52zM101 0v51h52v-51h-52zM460 51v51h51v-51h-51zM255 51v51h51v-51h-51zM665 102v52h51v-52h-51zM50 102v52h51v-52h-51z
|
||||||
|
M357 154v51h52v-51h-52zM255 154v51h51v-51h-51zM665 205v51h51v-51h-51zM460 205v51h51v-51h-51zM50 205v51h51v-51h-51zM255 256v51h51v-51h-51zM665 307v51h51v-51h-51zM460 307v51h51v-51h-51zM50 307v51h51v-51h-51zM357 358v52h52v-52h-52zM255 358v52h51v-52h-51z
|
||||||
|
M613 410v51h52v-51h-52zM101 410v51h52v-51h-52zM562 512v51h51v-51h-51zM460 512v51h51v-51h-51zM357 512v51h52v-51h-52zM255 512v51h51v-51h-51zM153 512v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="degree" unicode="°" horiz-adv-x="304"
|
||||||
|
d="M101 154v51h52v-51h-52zM204 205v51h51v-51h-51zM50 256v51h51v-51h-51zM153 307v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="plusminus" unicode="±" horiz-adv-x="355"
|
||||||
|
d="M255 102v52h51v-52h-51zM153 102v52h51v-52h-51zM50 102v52h51v-52h-51zM153 205v51h51v-51h-51zM255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51zM153 410v51h51v-51h-51zM255 102v52h51v-52h-51zM153 102v52h51v-52h-51zM50 102v52h51v-52h-51z
|
||||||
|
M153 205v51h51v-51h-51zM255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="uni00B2" unicode="²" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="acute" unicode="´" horiz-adv-x="202"
|
||||||
|
d="M50 358v52h51v-52h-51zM101 461v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="uni00B5" unicode="µ"
|
||||||
|
d="M50 -102v51h51v-51h-51zM357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM50 102v52h51v-52h-51zM306 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 -102v51h51v-51h-51zM357 0v51h52v-51h-52zM255 0v51
|
||||||
|
h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM50 102v52h51v-52h-51zM306 205v51h51v-51h-51zM50 205v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="paragraph" unicode="¶" horiz-adv-x="560"
|
||||||
|
d="M460 -102v51h51v-51h-51zM255 -102v51h51v-51h-51zM460 0v51h51v-51h-51zM255 0v51h51v-51h-51zM460 102v52h51v-52h-51zM255 102v52h51v-52h-51zM460 205v51h51v-51h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51zM460 307v51h51v-51h-51z
|
||||||
|
M255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM50 358v52h51v-52h-51zM460 410v51h51v-51h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 461v51h51v-51h-51zM460 512v51h51v-51h-51zM357 512v51h52v-51h-52zM255 512v51h51v-51h-51zM153 512v51h51v-51h-51z
|
||||||
|
M460 -102v51h51v-51h-51zM255 -102v51h51v-51h-51zM460 0v51h51v-51h-51zM255 0v51h51v-51h-51zM460 102v52h51v-52h-51zM255 102v52h51v-52h-51zM460 205v51h51v-51h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51zM460 307v51h51v-51h-51z
|
||||||
|
M255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM50 358v52h51v-52h-51zM460 410v51h51v-51h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 461v51h51v-51h-51zM460 512v51h51v-51h-51zM357 512v51h52v-51h-52zM255 512v51h51v-51h-51zM153 512v51h51v-51h-51z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="periodcentered" unicode="·" horiz-adv-x="150"
|
||||||
|
d="M50 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="cedilla" unicode="¸" horiz-adv-x="355"
|
||||||
|
d="M153 -154v52h51v-52h-51zM50 -154v52h51v-52h-51zM255 -102v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="guillemotright" unicode="»" horiz-adv-x="355"
|
||||||
|
d="M204 154v51h51v-51h-51zM50 154v51h51v-51h-51zM255 256v51h51v-51h-51zM101 256v51h52v-51h-52zM204 358v52h51v-52h-51zM50 358v52h51v-52h-51zM204 154v51h51v-51h-51zM50 154v51h51v-51h-51zM255 256v51h51v-51h-51zM101 256v51h52v-51h-52zM204 358v52h51v-52h-51z
|
||||||
|
M50 358v52h51v-52h-51z" />
|
||||||
|
<glyph glyph-name="Agrave" unicode="À" horiz-adv-x="449"
|
||||||
|
d="M350 0v50h50v-50h-50zM50 0v50h50v-50h-50zM350 100v50h50v-50h-50zM50 100v50h50v-50h-50zM250 150v50h50v-50h-50zM150 150v50h50v-50h-50zM350 200v50h50v-50h-50zM50 200v50h50v-50h-50zM300 300v50h50v-50h-50zM100 300v50h50v-50h-50zM250 400v50h50v-50h-50z
|
||||||
|
M150 400v50h50v-50h-50zM250 500v50h50v-50h-50zM150 550v50h50v-50h-50z" />
|
||||||
|
<glyph glyph-name="Aacute" unicode="Á"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM153 512v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Acircumflex" unicode="Â"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM306 512v51h51v-51h-51zM101 512v51h52v-51h-52zM204 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Adieresis" unicode="Ä"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="AE" unicode="Æ" horiz-adv-x="765"
|
||||||
|
d="M665 0v51h51v-51h-51zM562 0v51h51v-51h-51zM460 0v51h51v-51h-51zM357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM562 205v51h51v-51h-51zM460 205v51h51v-51h-51zM357 205
|
||||||
|
v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM101 307v51h52v-51h-52zM665 410v51h51v-51h-51zM562 410v51h51v-51h-51zM460 410v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM665 0v51h51v-51h-51zM562 0v51h51
|
||||||
|
v-51h-51zM460 0v51h51v-51h-51zM357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM562 205v51h51v-51h-51zM460 205v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51z
|
||||||
|
M357 307v51h52v-51h-52zM101 307v51h52v-51h-52zM665 410v51h51v-51h-51zM562 410v51h51v-51h-51zM460 410v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Ccedilla" unicode="Ç"
|
||||||
|
d="M255 -154v52h51v-52h-51zM357 -102v51h52v-51h-52zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51z
|
||||||
|
M204 410v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Egrave" unicode="È" horiz-adv-x="449"
|
||||||
|
d="M350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400
|
||||||
|
v50h50v-50h-50zM50 400v50h50v-50h-50zM250 500v50h50v-50h-50zM150 550v50h50v-50h-50zM350 0h50v50h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200h50v50h-50v-50zM50 200v50h50v-50
|
||||||
|
h-50zM50 300v50h50v-50h-50zM350 400h50v50h-50v-50zM250 400h50v50h-50v-50zM150 400h50v50h-50v-50zM50 400v50h50v-50h-50zM250 500v50h50v-50h-50zM150 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0h50v50h-50v-50zM50 100
|
||||||
|
h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50v-50zM250 500h50v50h-50v-50zM150 550h50v50h-50v-50zM350 0h50v50
|
||||||
|
h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200h50v50h-50v-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400h50v50h-50v-50zM250 400h50v50h-50v-50zM150 400h50v50h-50v-50z
|
||||||
|
M50 400v50h50v-50h-50zM250 500v50h50v-50h-50zM150 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0h50v50h-50v-50zM50 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50
|
||||||
|
h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50v-50zM250 500h50v50h-50v-50zM150 550h50v50h-50v-50zM350 0h50v50h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50z
|
||||||
|
M250 200h50v50h-50v-50zM150 200h50v50h-50v-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400h50v50h-50v-50zM250 400h50v50h-50v-50zM150 400h50v50h-50v-50zM50 400v50h50v-50h-50zM250 500v50h50v-50h-50zM150 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0
|
||||||
|
v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0h50v50h-50v-50zM50 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50
|
||||||
|
v-50zM250 500h50v50h-50v-50zM150 550h50v50h-50v-50z" />
|
||||||
|
<glyph glyph-name="Eacute" unicode="É"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410
|
||||||
|
v51h51v-51h-51zM50 410v51h51v-51h-51zM153 512v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Ecircumflex" unicode="Ê" horiz-adv-x="449"
|
||||||
|
d="M350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400
|
||||||
|
v50h50v-50h-50zM50 400v50h50v-50h-50zM300 500v50h50v-50h-50zM100 500v50h50v-50h-50zM200 550v50h50v-50h-50zM350 0h50v50h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200h50v50h-50
|
||||||
|
v-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400h50v50h-50v-50zM250 400h50v50h-50v-50zM150 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 500h50v50h-50v-50zM100 500v50h50v-50h-50zM200 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0v50h50v-50h-50z
|
||||||
|
M150 0v50h50v-50h-50zM50 0h50v50h-50v-50zM50 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 500
|
||||||
|
v50h50v-50h-50zM100 500h50v50h-50v-50zM200 550h50v50h-50v-50zM350 0h50v50h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200h50v50h-50v-50zM50 200v50h50v-50h-50zM50 300v50h50v-50
|
||||||
|
h-50zM350 400h50v50h-50v-50zM250 400h50v50h-50v-50zM150 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 500h50v50h-50v-50zM100 500v50h50v-50h-50zM200 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0h50v50h-50v-50z
|
||||||
|
M50 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 500v50h50v-50h-50zM100 500h50v50h-50v-50z
|
||||||
|
M200 550h50v50h-50v-50zM350 0h50v50h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200h50v50h-50v-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400h50v50h-50v-50zM250 400h50
|
||||||
|
v50h-50v-50zM150 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 500h50v50h-50v-50zM100 500v50h50v-50h-50zM200 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0h50v50h-50v-50zM50 100h50v50h-50v-50zM250 200v50h50v-50h-50z
|
||||||
|
M150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 500v50h50v-50h-50zM100 500h50v50h-50v-50zM200 550h50v50h-50v-50z" />
|
||||||
|
<glyph glyph-name="Edieresis" unicode="Ë"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410
|
||||||
|
v51h51v-51h-51zM50 410v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Iacute" unicode="Í" horiz-adv-x="253"
|
||||||
|
d="M153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM50 512v51h51v-51h-51zM153 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Icircumflex" unicode="Î" horiz-adv-x="355"
|
||||||
|
d="M204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM153 102v52h51v-52h-51zM153 205v51h51v-51h-51zM153 307v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52zM255 512v51h51v-51h-51zM50 512v51h51v-51h-51zM153 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Idieresis" unicode="Ï" horiz-adv-x="253"
|
||||||
|
d="M153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM153 563v51h51v-51h-51zM50 563v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102
|
||||||
|
v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM153 563v51h51v-51h-51zM50 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Eth" unicode="Ð" horiz-adv-x="560"
|
||||||
|
d="M357 0v51h51v-51h-51zM255 0v51h51v-51h-51zM152 0v51h52v-51h-52zM460 102v52h51v-52h-51zM152 102v52h52v-52h-52zM460 205v51h51v-51h-51zM152 205v51h52v-51h-52zM460 307v51h51v-51h-51zM255 307v51h51v-51h-51zM152 307v51h52v-51h-52zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h51v-51h-51zM255 410v51h51v-51h-51zM152 410v51h52v-51h-52zM357 0v51h51v-51h-51zM255 0v51h51v-51h-51zM152 0v51h52v-51h-52zM460 102v52h51v-52h-51zM152 102v52h52v-52h-52zM460 205v51h51v-51h-51zM152 205v51h52v-51h-52zM460 307v51h51v-51h-51z
|
||||||
|
M255 307v51h51v-51h-51zM152 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h51v-51h-51zM255 410v51h51v-51h-51zM152 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Ntilde" unicode="Ñ"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM255 512v51h51v-51h-51zM50 512v51h51v-51h-51zM357 563v51h52v-51h-52zM153 563v51h51v-51h-51zM357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205
|
||||||
|
v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM255 512v51h51v-51h-51zM50 512v51h51v-51h-51zM357 563v51h52v-51h-52zM153 563v51
|
||||||
|
h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Ograve" unicode="Ò"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52zM204 512v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Oacute" unicode="Ó"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Ocircumflex" unicode="Ô"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52zM306 512v51h51v-51h-51zM101 512v51h52v-51h-52zM204 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Odieresis" unicode="Ö"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="multiply" unicode="×" horiz-adv-x="355"
|
||||||
|
d="M255 51v51h51v-51h-51zM50 51v51h51v-51h-51zM153 154v51h51v-51h-51zM255 256v51h51v-51h-51zM50 256v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Oslash" unicode="Ø"
|
||||||
|
d="M50 -102v51h52v-51h-52zM306 0v51h52v-51h-52zM204 0v51h51v-51h-51zM102 0v51h51v-51h-51zM358 102v52h51v-52h-51zM153 102v52h51v-52h-51zM50 102v52h52v-52h-52zM358 205v51h51v-51h-51zM204 205v51h51v-51h-51zM50 205v51h52v-51h-52zM358 307v51h51v-51h-51z
|
||||||
|
M255 307v51h51v-51h-51zM50 307v51h52v-51h-52zM306 410v51h52v-51h-52zM204 410v51h51v-51h-51zM102 410v51h51v-51h-51zM358 512v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Ugrave" unicode="Ù"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM204 461
|
||||||
|
v51h51v-51h-51zM153 563v51h51v-51h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51
|
||||||
|
h-52zM50 410v51h51v-51h-51zM204 461v51h51v-51h-51zM153 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Uacute" unicode="Ú"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM204 461
|
||||||
|
v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Ucircumflex" unicode="Û"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 512v51h51v-51h-51zM101 512v51h52v-51h-52z
|
||||||
|
M204 563v51h51v-51h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 512v51h51v-51h-51zM101 512
|
||||||
|
v51h52v-51h-52zM204 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Udieresis" unicode="Ü"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM306 563
|
||||||
|
v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Yacute" unicode="Ý"
|
||||||
|
d="M204 0v51h51v-51h-51zM204 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM204 461v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="germandbls" unicode="ß"
|
||||||
|
d="M50 -51v51h51v-51h-51zM50 51v51h51v-51h-51zM255 102v52h51v-52h-51zM153 102v52h51v-52h-51zM357 154v51h52v-51h-52zM50 154v51h51v-51h-51zM357 256v51h52v-51h-52zM50 256v51h51v-51h-51zM255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM357 358v52h52v-52h-52z
|
||||||
|
M50 358v52h51v-52h-51zM357 461v51h52v-51h-52zM50 461v51h51v-51h-51zM255 512v51h51v-51h-51zM153 512v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="agrave" unicode="à" horiz-adv-x="449"
|
||||||
|
d="M350 0v50h50v-50h-50zM50 0v50h50v-50h-50zM350 100v50h50v-50h-50zM50 100v50h50v-50h-50zM250 150v50h50v-50h-50zM150 150v50h50v-50h-50zM350 200v50h50v-50h-50zM50 200v50h50v-50h-50zM300 300v50h50v-50h-50zM100 300v50h50v-50h-50zM250 400v50h50v-50h-50z
|
||||||
|
M150 400v50h50v-50h-50zM250 500v50h50v-50h-50zM150 550v50h50v-50h-50z" />
|
||||||
|
<glyph glyph-name="aacute" unicode="á"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM153 512v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="acircumflex" unicode="â"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM306 512v51h51v-51h-51zM101 512v51h52v-51h-52zM204 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="adieresis" unicode="ä"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="ae" unicode="æ" horiz-adv-x="765"
|
||||||
|
d="M665 0v51h51v-51h-51zM562 0v51h51v-51h-51zM460 0v51h51v-51h-51zM357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM562 205v51h51v-51h-51zM460 205v51h51v-51h-51zM357 205
|
||||||
|
v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM101 307v51h52v-51h-52zM665 410v51h51v-51h-51zM562 410v51h51v-51h-51zM460 410v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM665 0v51h51v-51h-51zM562 0v51h51
|
||||||
|
v-51h-51zM460 0v51h51v-51h-51zM357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM562 205v51h51v-51h-51zM460 205v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51z
|
||||||
|
M357 307v51h52v-51h-52zM101 307v51h52v-51h-52zM665 410v51h51v-51h-51zM562 410v51h51v-51h-51zM460 410v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="ccedilla" unicode="ç"
|
||||||
|
d="M255 -154v52h51v-52h-51zM357 -102v51h52v-51h-52zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51z
|
||||||
|
M204 410v51h51v-51h-51zM101 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="egrave" unicode="è" horiz-adv-x="449"
|
||||||
|
d="M350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400
|
||||||
|
v50h50v-50h-50zM50 400v50h50v-50h-50zM250 500v50h50v-50h-50zM150 550v50h50v-50h-50zM350 0h50v50h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200h50v50h-50v-50zM50 200v50h50v-50
|
||||||
|
h-50zM50 300v50h50v-50h-50zM350 400h50v50h-50v-50zM250 400h50v50h-50v-50zM150 400h50v50h-50v-50zM50 400v50h50v-50h-50zM250 500v50h50v-50h-50zM150 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0h50v50h-50v-50zM50 100
|
||||||
|
h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50v-50zM250 500h50v50h-50v-50zM150 550h50v50h-50v-50zM350 0h50v50
|
||||||
|
h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200h50v50h-50v-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400h50v50h-50v-50zM250 400h50v50h-50v-50zM150 400h50v50h-50v-50z
|
||||||
|
M50 400v50h50v-50h-50zM250 500v50h50v-50h-50zM150 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0h50v50h-50v-50zM50 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50
|
||||||
|
h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50v-50zM250 500h50v50h-50v-50zM150 550h50v50h-50v-50zM350 0h50v50h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50z
|
||||||
|
M250 200h50v50h-50v-50zM150 200h50v50h-50v-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400h50v50h-50v-50zM250 400h50v50h-50v-50zM150 400h50v50h-50v-50zM50 400v50h50v-50h-50zM250 500v50h50v-50h-50zM150 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0
|
||||||
|
v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0h50v50h-50v-50zM50 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50
|
||||||
|
v-50zM250 500h50v50h-50v-50zM150 550h50v50h-50v-50z" />
|
||||||
|
<glyph glyph-name="eacute" unicode="é"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410
|
||||||
|
v51h51v-51h-51zM50 410v51h51v-51h-51zM153 512v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="ecircumflex" unicode="ê" horiz-adv-x="449"
|
||||||
|
d="M350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400
|
||||||
|
v50h50v-50h-50zM50 400v50h50v-50h-50zM300 500v50h50v-50h-50zM100 500v50h50v-50h-50zM200 550v50h50v-50h-50zM350 0h50v50h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200h50v50h-50
|
||||||
|
v-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400h50v50h-50v-50zM250 400h50v50h-50v-50zM150 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 500h50v50h-50v-50zM100 500v50h50v-50h-50zM200 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0v50h50v-50h-50z
|
||||||
|
M150 0v50h50v-50h-50zM50 0h50v50h-50v-50zM50 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 500
|
||||||
|
v50h50v-50h-50zM100 500h50v50h-50v-50zM200 550h50v50h-50v-50zM350 0h50v50h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200h50v50h-50v-50zM50 200v50h50v-50h-50zM50 300v50h50v-50
|
||||||
|
h-50zM350 400h50v50h-50v-50zM250 400h50v50h-50v-50zM150 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 500h50v50h-50v-50zM100 500v50h50v-50h-50zM200 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0h50v50h-50v-50z
|
||||||
|
M50 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 500v50h50v-50h-50zM100 500h50v50h-50v-50z
|
||||||
|
M200 550h50v50h-50v-50zM350 0h50v50h-50v-50zM250 0h50v50h-50v-50zM150 0h50v50h-50v-50zM50 0v50h50v-50h-50zM50 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200h50v50h-50v-50zM50 200v50h50v-50h-50zM50 300v50h50v-50h-50zM350 400h50v50h-50v-50zM250 400h50
|
||||||
|
v50h-50v-50zM150 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 500h50v50h-50v-50zM100 500v50h50v-50h-50zM200 550v50h50v-50h-50zM350 0v50h50v-50h-50zM250 0v50h50v-50h-50zM150 0v50h50v-50h-50zM50 0h50v50h-50v-50zM50 100h50v50h-50v-50zM250 200v50h50v-50h-50z
|
||||||
|
M150 200v50h50v-50h-50zM50 200h50v50h-50v-50zM50 300h50v50h-50v-50zM350 400v50h50v-50h-50zM250 400v50h50v-50h-50zM150 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 500v50h50v-50h-50zM100 500h50v50h-50v-50zM200 550h50v50h-50v-50z" />
|
||||||
|
<glyph glyph-name="edieresis" unicode="ë"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410
|
||||||
|
v51h51v-51h-51zM50 410v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="iacute" unicode="í" horiz-adv-x="253"
|
||||||
|
d="M153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM50 512v51h51v-51h-51zM153 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="icircumflex" unicode="î" horiz-adv-x="355"
|
||||||
|
d="M204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM153 102v52h51v-52h-51zM153 205v51h51v-51h-51zM153 307v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52zM255 512v51h51v-51h-51zM50 512v51h51v-51h-51zM153 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="idieresis" unicode="ï" horiz-adv-x="253"
|
||||||
|
d="M153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM153 563v51h51v-51h-51zM50 563v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102
|
||||||
|
v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM153 563v51h51v-51h-51zM50 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="eth" unicode="ð" horiz-adv-x="560"
|
||||||
|
d="M357 0v51h51v-51h-51zM255 0v51h51v-51h-51zM152 0v51h52v-51h-52zM460 102v52h51v-52h-51zM152 102v52h52v-52h-52zM460 205v51h51v-51h-51zM152 205v51h52v-51h-52zM460 307v51h51v-51h-51zM255 307v51h51v-51h-51zM152 307v51h52v-51h-52zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h51v-51h-51zM255 410v51h51v-51h-51zM152 410v51h52v-51h-52zM357 0v51h51v-51h-51zM255 0v51h51v-51h-51zM152 0v51h52v-51h-52zM460 102v52h51v-52h-51zM152 102v52h52v-52h-52zM460 205v51h51v-51h-51zM152 205v51h52v-51h-52zM460 307v51h51v-51h-51z
|
||||||
|
M255 307v51h51v-51h-51zM152 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h51v-51h-51zM255 410v51h51v-51h-51zM152 410v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="ntilde" unicode="ñ"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM255 512v51h51v-51h-51zM50 512v51h51v-51h-51zM357 563v51h52v-51h-52zM153 563v51h51v-51h-51zM357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205
|
||||||
|
v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM255 512v51h51v-51h-51zM50 512v51h51v-51h-51zM357 563v51h52v-51h-52zM153 563v51
|
||||||
|
h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="ograve" unicode="ò"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52zM204 512v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="oacute" unicode="ó"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="ocircumflex" unicode="ô"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52zM306 512v51h51v-51h-51zM101 512v51h52v-51h-52zM204 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="odieresis" unicode="ö"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="divide" unicode="÷"
|
||||||
|
d="M204 0v51h51v-51h-51zM357 154v51h52v-51h-52zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM50 154v51h51v-51h-51zM204 307v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="oslash" unicode="ø"
|
||||||
|
d="M50 -102v51h52v-51h-52zM306 0v51h52v-51h-52zM204 0v51h51v-51h-51zM102 0v51h51v-51h-51zM358 102v52h51v-52h-51zM153 102v52h51v-52h-51zM50 102v52h52v-52h-52zM358 205v51h51v-51h-51zM204 205v51h51v-51h-51zM50 205v51h52v-51h-52zM358 307v51h51v-51h-51z
|
||||||
|
M255 307v51h51v-51h-51zM50 307v51h52v-51h-52zM306 410v51h52v-51h-52zM204 410v51h51v-51h-51zM102 410v51h51v-51h-51zM358 512v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="ugrave" unicode="ù"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM204 461
|
||||||
|
v51h51v-51h-51zM153 563v51h51v-51h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51
|
||||||
|
h-52zM50 410v51h51v-51h-51zM204 461v51h51v-51h-51zM153 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="uacute" unicode="ú"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM204 461
|
||||||
|
v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="ucircumflex" unicode="û"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 512v51h51v-51h-51zM101 512v51h52v-51h-52z
|
||||||
|
M204 563v51h51v-51h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 512v51h51v-51h-51zM101 512
|
||||||
|
v51h52v-51h-52zM204 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="udieresis" unicode="ü"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM306 563
|
||||||
|
v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="yacute" unicode="ý"
|
||||||
|
d="M204 0v51h51v-51h-51zM204 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM204 461v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="ydieresis" unicode="ÿ" horiz-adv-x="449"
|
||||||
|
d="M200 0v50h50v-50h-50zM200 100v50h50v-50h-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM300 300v50h50v-50h-50zM100 300v50h50v-50h-50zM350 400v50h50v-50h-50zM50 400v50h50v-50h-50zM300 550v50h50v-50h-50zM100 550v50h50v-50h-50zM200 0v50h50v-50h-50z
|
||||||
|
M200 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200v50h50v-50h-50zM300 300h50v50h-50v-50zM100 300v50h50v-50h-50zM350 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 550h50v50h-50v-50zM100 550v50h50v-50h-50zM200 0h50v50h-50v-50zM200 100h50v50h-50v-50z
|
||||||
|
M250 200v50h50v-50h-50zM150 200h50v50h-50v-50zM300 300v50h50v-50h-50zM100 300h50v50h-50v-50zM350 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 550v50h50v-50h-50zM100 550h50v50h-50v-50zM200 0v50h50v-50h-50zM200 100v50h50v-50h-50zM250 200h50v50h-50v-50z
|
||||||
|
M150 200v50h50v-50h-50zM300 300h50v50h-50v-50zM100 300v50h50v-50h-50zM350 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 550h50v50h-50v-50zM100 550v50h50v-50h-50zM200 0h50v50h-50v-50zM200 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200h50v50h-50v-50z
|
||||||
|
M300 300v50h50v-50h-50zM100 300h50v50h-50v-50zM350 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 550v50h50v-50h-50zM100 550h50v50h-50v-50zM200 0v50h50v-50h-50zM200 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200v50h50v-50h-50zM300 300h50v50h-50v-50z
|
||||||
|
M100 300v50h50v-50h-50zM350 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 550h50v50h-50v-50zM100 550v50h50v-50h-50zM200 0h50v50h-50v-50zM200 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200h50v50h-50v-50zM300 300v50h50v-50h-50zM100 300h50v50h-50v-50z
|
||||||
|
M350 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 550v50h50v-50h-50zM100 550h50v50h-50v-50z" />
|
||||||
|
<glyph glyph-name="Abreve" unicode="Ă"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM255 512v51h51v-51h-51zM153 512v51h51v-51h-51zM357 563v51h52v-51h-52zM50 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="abreve" unicode="ă"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM255 512v51h51v-51h-51zM153 512v51h51v-51h-51zM357 563v51h52v-51h-52zM50 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Aogonek" unicode="Ą"
|
||||||
|
d="M306 -102v51h51v-51h-51zM357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52z
|
||||||
|
M255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="aogonek" unicode="ą"
|
||||||
|
d="M306 -102v51h51v-51h-51zM357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM255 154v51h51v-51h-51zM153 154v51h51v-51h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM306 307v51h51v-51h-51zM101 307v51h52v-51h-52z
|
||||||
|
M255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Cacute" unicode="Ć"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52z
|
||||||
|
M204 512v51h51v-51h-51zM306 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="cacute" unicode="ć"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52z
|
||||||
|
M204 512v51h51v-51h-51zM306 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Ccaron" unicode="Č"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52z
|
||||||
|
M204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="ccaron" unicode="č"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51zM101 410v51h52v-51h-52z
|
||||||
|
M204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Dcaron" unicode="Ď"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410
|
||||||
|
v51h51v-51h-51zM153 512v51h51v-51h-51zM255 563v51h51v-51h-51zM50 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="dcaron" unicode="ď"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410
|
||||||
|
v51h51v-51h-51zM153 512v51h51v-51h-51zM255 563v51h51v-51h-51zM50 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Dcroat" unicode="Đ" horiz-adv-x="560"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM460 102v52h51v-52h-51zM153 102v52h51v-52h-51zM460 205v51h51v-51h-51zM153 205v51h51v-51h-51zM460 307v51h51v-51h-51zM255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="dcroat" unicode="đ" horiz-adv-x="560"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM460 102v52h51v-52h-51zM153 102v52h51v-52h-51zM460 205v51h51v-51h-51zM153 205v51h51v-51h-51zM460 307v51h51v-51h-51zM255 307v51h51v-51h-51zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Eogonek" unicode="Ę"
|
||||||
|
d="M153 410v51h51v-51h-51zM306 -102v51h51v-51h-51zM357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410
|
||||||
|
v51h52v-51h-52zM255 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="eogonek" unicode="ę"
|
||||||
|
d="M153 410v51h51v-51h-51zM306 -102v51h51v-51h-51zM357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410
|
||||||
|
v51h52v-51h-52zM255 410v51h51v-51h-51zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Ecaron" unicode="Ě"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410
|
||||||
|
v51h51v-51h-51zM50 410v51h51v-51h-51zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="ecaron" unicode="ě"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410
|
||||||
|
v51h51v-51h-51zM50 410v51h51v-51h-51zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Lacute" unicode="Ĺ" horiz-adv-x="509"
|
||||||
|
d="M409 0v51h51v-51h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM101 102v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM101 410v51h52v-51h-52zM50 512v51h51v-51h-51zM153 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="lacute" unicode="ĺ" horiz-adv-x="509"
|
||||||
|
d="M409 0v51h51v-51h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM101 102v52h52v-52h-52zM101 205v51h52v-51h-52zM101 307v51h52v-51h-52zM101 410v51h52v-51h-52zM50 512v51h51v-51h-51zM153 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Lcaron" unicode="Ľ"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM153 358v52h51v-52h-51zM50 410v51h51v-51h-51zM204 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="lcaron" unicode="ľ"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM50 102v52h51v-52h-51zM50 205v51h51v-51h-51zM50 307v51h51v-51h-51zM50 410v51h51v-51h-51zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Lslash" unicode="Ł" horiz-adv-x="560"
|
||||||
|
d="M460 0v51h51v-51h-51zM357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM153 102v52h51v-52h-51zM50 154v51h51v-51h-51zM153 205v51h51v-51h-51zM255 256v51h51v-51h-51zM153 307v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="lslash" unicode="ł" horiz-adv-x="560"
|
||||||
|
d="M460 0v51h51v-51h-51zM357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM153 102v52h51v-52h-51zM50 154v51h51v-51h-51zM153 205v51h51v-51h-51zM255 256v51h51v-51h-51zM153 307v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Nacute" unicode="Ń"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM204 461v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="nacute" unicode="ń"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM204 461v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Ncaron" unicode="Ň"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="ncaron" unicode="ň"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM357 102v52h52v-52h-52zM255 102v52h51v-52h-51zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM204 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM153 307v51h51v-51h-51zM50 307v51h51v-51h-51z
|
||||||
|
M357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Ohungarumlaut" unicode="Ő" horiz-adv-x="509"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52zM306 512v51h51v-51h-51zM50 512v51h51v-51h-51zM409 563v51h51v-51h-51zM153 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="ohungarumlaut" unicode="ő" horiz-adv-x="509"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM306 410v51h51v-51h-51zM204 410v51h51v-51h-51z
|
||||||
|
M101 410v51h52v-51h-52zM306 512v51h51v-51h-51zM50 512v51h51v-51h-51zM409 563v51h51v-51h-51zM153 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="OE" unicode="Œ" horiz-adv-x="699"
|
||||||
|
d="M600 0v50h50v-50h-50zM500 0v50h50v-50h-50zM400 0v50h50v-50h-50zM300 0v50h50v-50h-50zM200 0v50h50v-50h-50zM100 0v50h50v-50h-50zM350 100v50h50v-50h-50zM50 100v50h50v-50h-50zM550 200v50h50v-50h-50zM450 200v50h50v-50h-50zM350 200v50h50v-50h-50zM50 200v50
|
||||||
|
h50v-50h-50zM350 300v50h50v-50h-50zM50 300v50h50v-50h-50zM600 400v50h50v-50h-50zM500 400v50h50v-50h-50zM400 400v50h50v-50h-50zM300 400v50h50v-50h-50zM200 400v50h50v-50h-50zM100 400v50h50v-50h-50z" />
|
||||||
|
<glyph glyph-name="oe" unicode="œ" horiz-adv-x="699"
|
||||||
|
d="M600 0v50h50v-50h-50zM500 0v50h50v-50h-50zM400 0v50h50v-50h-50zM300 0v50h50v-50h-50zM200 0v50h50v-50h-50zM100 0v50h50v-50h-50zM350 100v50h50v-50h-50zM50 100v50h50v-50h-50zM550 200v50h50v-50h-50zM450 200v50h50v-50h-50zM350 200v50h50v-50h-50zM50 200v50
|
||||||
|
h50v-50h-50zM350 300v50h50v-50h-50zM50 300v50h50v-50h-50zM600 400v50h50v-50h-50zM500 400v50h50v-50h-50zM400 400v50h50v-50h-50zM300 400v50h50v-50h-50zM200 400v50h50v-50h-50zM100 400v50h50v-50h-50z" />
|
||||||
|
<glyph glyph-name="Racute" unicode="Ŕ"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 307v51h51v-51h-51zM357 358v52h52v-52h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM153 512v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="racute" unicode="ŕ"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 307v51h51v-51h-51zM357 358v52h52v-52h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM153 512v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Rcaron" unicode="Ř"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 307v51h51v-51h-51zM357 358v52h52v-52h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="rcaron" unicode="ř"
|
||||||
|
d="M357 0v51h52v-51h-52zM50 0v51h51v-51h-51zM306 102v52h51v-52h-51zM50 102v52h51v-52h-51zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 205v51h51v-51h-51zM357 256v51h52v-51h-52zM50 307v51h51v-51h-51zM357 358v52h52v-52h-52zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Sacute" unicode="Ś"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51zM357 358v52h52v-52h-52zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM153 512v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="sacute" unicode="ś"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51zM357 358v52h52v-52h-52zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM153 512v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Scedilla" unicode="Ş"
|
||||||
|
d="M204 -154v52h51v-52h-51zM101 -154v52h52v-52h-52zM306 -102v51h51v-51h-51zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51z
|
||||||
|
M357 358v52h52v-52h-52zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="scedilla" unicode="ş"
|
||||||
|
d="M204 -154v52h51v-52h-51zM101 -154v52h52v-52h-52zM306 -102v51h51v-51h-51zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51z
|
||||||
|
M357 358v52h52v-52h-52zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Scaron" unicode="Š"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51zM357 358v52h52v-52h-52zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="scaron" unicode="š"
|
||||||
|
d="M255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM357 51v51h52v-51h-52zM50 51v51h51v-51h-51zM357 154v51h52v-51h-52zM255 205v51h51v-51h-51zM153 205v51h51v-51h-51zM50 256v51h51v-51h-51zM357 358v52h52v-52h-52zM50 358v52h51v-52h-51zM255 410v51h51v-51h-51z
|
||||||
|
M153 410v51h51v-51h-51zM204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="Tcommaaccent" unicode="Ţ"
|
||||||
|
d="M255 -154v52h51v-52h-51zM153 -154v52h51v-52h-51zM306 -51v51h51v-51h-51zM204 0v51h51v-51h-51zM204 102v52h51v-52h-51zM204 205v51h51v-51h-51zM204 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51
|
||||||
|
z" />
|
||||||
|
<glyph glyph-name="tcommaaccent" unicode="ţ"
|
||||||
|
d="M255 -154v52h51v-52h-51zM153 -154v52h51v-52h-51zM306 -51v51h51v-51h-51zM204 0v51h51v-51h-51zM204 102v52h51v-52h-51zM204 205v51h51v-51h-51zM204 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51
|
||||||
|
z" />
|
||||||
|
<glyph glyph-name="Tcaron" unicode="Ť"
|
||||||
|
d="M204 512v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52zM204 0v51h51v-51h-51zM204 102v52h51v-52h-51zM204 205v51h51v-51h-51zM204 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="tcaron" unicode="ť" horiz-adv-x="611"
|
||||||
|
d="M204 0v51h51v-51h-51zM204 102v52h51v-52h-51zM204 205v51h51v-51h-51zM204 307v51h51v-51h-51zM460 358v52h51v-52h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM511 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Uring" unicode="Ů"
|
||||||
|
d="M255 459v53h51v-53h-51zM153 510v51h51v-51h-51zM306 561v51h51v-51h-51zM204 612v52h51v-52h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51z
|
||||||
|
M357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="uring" unicode="ů"
|
||||||
|
d="M255 459v53h51v-53h-51zM153 510v51h51v-51h-51zM306 561v51h51v-51h-51zM204 612v52h51v-52h-51zM306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51z
|
||||||
|
M357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Uhungarumlaut" unicode="Ű"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM255 461
|
||||||
|
v51h51v-51h-51zM153 461v51h51v-51h-51zM306 563v51h51v-51h-51zM204 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="uhungarumlaut" unicode="ű"
|
||||||
|
d="M306 0v51h51v-51h-51zM204 0v51h51v-51h-51zM101 0v51h52v-51h-52zM357 102v52h52v-52h-52zM50 102v52h51v-52h-51zM357 205v51h52v-51h-52zM50 205v51h51v-51h-51zM357 307v51h52v-51h-52zM50 307v51h51v-51h-51zM357 410v51h52v-51h-52zM50 410v51h51v-51h-51zM255 461
|
||||||
|
v51h51v-51h-51zM153 461v51h51v-51h-51zM306 563v51h51v-51h-51zM204 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Ydieresis" unicode="Ÿ" horiz-adv-x="449"
|
||||||
|
d="M200 0v50h50v-50h-50zM200 100v50h50v-50h-50zM250 200v50h50v-50h-50zM150 200v50h50v-50h-50zM300 300v50h50v-50h-50zM100 300v50h50v-50h-50zM350 400v50h50v-50h-50zM50 400v50h50v-50h-50zM300 550v50h50v-50h-50zM100 550v50h50v-50h-50zM200 0v50h50v-50h-50z
|
||||||
|
M200 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200v50h50v-50h-50zM300 300h50v50h-50v-50zM100 300v50h50v-50h-50zM350 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 550h50v50h-50v-50zM100 550v50h50v-50h-50zM200 0h50v50h-50v-50zM200 100h50v50h-50v-50z
|
||||||
|
M250 200v50h50v-50h-50zM150 200h50v50h-50v-50zM300 300v50h50v-50h-50zM100 300h50v50h-50v-50zM350 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 550v50h50v-50h-50zM100 550h50v50h-50v-50zM200 0v50h50v-50h-50zM200 100v50h50v-50h-50zM250 200h50v50h-50v-50z
|
||||||
|
M150 200v50h50v-50h-50zM300 300h50v50h-50v-50zM100 300v50h50v-50h-50zM350 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 550h50v50h-50v-50zM100 550v50h50v-50h-50zM200 0h50v50h-50v-50zM200 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200h50v50h-50v-50z
|
||||||
|
M300 300v50h50v-50h-50zM100 300h50v50h-50v-50zM350 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 550v50h50v-50h-50zM100 550h50v50h-50v-50zM200 0v50h50v-50h-50zM200 100v50h50v-50h-50zM250 200h50v50h-50v-50zM150 200v50h50v-50h-50zM300 300h50v50h-50v-50z
|
||||||
|
M100 300v50h50v-50h-50zM350 400h50v50h-50v-50zM50 400v50h50v-50h-50zM300 550h50v50h-50v-50zM100 550v50h50v-50h-50zM200 0h50v50h-50v-50zM200 100h50v50h-50v-50zM250 200v50h50v-50h-50zM150 200h50v50h-50v-50zM300 300v50h50v-50h-50zM100 300h50v50h-50v-50z
|
||||||
|
M350 400v50h50v-50h-50zM50 400h50v50h-50v-50zM300 550v50h50v-50h-50zM100 550h50v50h-50v-50z" />
|
||||||
|
<glyph glyph-name="Zacute" unicode="Ź"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM204 205v51h51v-51h-51zM306 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM153 512
|
||||||
|
v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="zacute" unicode="ź"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM204 205v51h51v-51h-51zM306 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM153 512
|
||||||
|
v51h51v-51h-51zM255 563v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Zdotaccent" unicode="Ż"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM204 205v51h51v-51h-51zM306 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM204 563
|
||||||
|
v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="zdotaccent" unicode="ż"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM204 205v51h51v-51h-51zM306 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM204 563
|
||||||
|
v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="Zcaron" unicode="Ž"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM204 205v51h51v-51h-51zM306 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM204 512
|
||||||
|
v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="zcaron" unicode="ž"
|
||||||
|
d="M357 0v51h52v-51h-52zM255 0v51h51v-51h-51zM153 0v51h51v-51h-51zM50 0v51h51v-51h-51zM101 102v52h52v-52h-52zM204 205v51h51v-51h-51zM306 307v51h51v-51h-51zM357 410v51h52v-51h-52zM255 410v51h51v-51h-51zM153 410v51h51v-51h-51zM50 410v51h51v-51h-51zM204 512
|
||||||
|
v51h51v-51h-51zM306 563v51h51v-51h-51zM101 563v51h52v-51h-52z" />
|
||||||
|
<glyph glyph-name="caron" unicode="ˇ" horiz-adv-x="355"
|
||||||
|
d="M153 358v52h51v-52h-51zM255 461v51h51v-51h-51zM50 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="breve" unicode="˘" horiz-adv-x="355"
|
||||||
|
d="M204 358v52h51v-52h-51zM101 358v52h52v-52h-52zM255 461v51h51v-51h-51zM50 461v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="dotaccent" unicode="˙" horiz-adv-x="49"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="ogonek" unicode="˛" horiz-adv-x="304"
|
||||||
|
d="M204 -102v51h51v-51h-51zM101 -102v51h52v-51h-52zM50 0v51h51v-51h-51z" />
|
||||||
|
<glyph glyph-name="hungarumlaut" unicode="˝" horiz-adv-x="355"
|
||||||
|
d="M204 358v52h51v-52h-51zM50 358v52h51v-52h-51zM255 461v51h51v-51h-51zM101 461v51h52v-51h-52z" />
|
||||||
|
</font>
|
||||||
|
</defs></svg>
|
After Width: | Height: | Size: 91 KiB |
BIN
www/css/7f37946c45abf5482c243bf326f82628.ttf
Executable file
BIN
www/css/7f37946c45abf5482c243bf326f82628.woff
Executable file
BIN
www/css/7f37946c45abf5482c243bf326f82628.woff2
Executable file
BIN
www/css/LED.eot
Normal file
519
www/css/LED.svg
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||||
|
<svg>
|
||||||
|
<metadata>
|
||||||
|
Created by FontForge 20110222 at Mon Mar 7 11:46:57 2011
|
||||||
|
By www-data
|
||||||
|
</metadata>
|
||||||
|
<defs>
|
||||||
|
<font id="LED" horiz-adv-x="463" >
|
||||||
|
<font-face
|
||||||
|
font-family="LED"
|
||||||
|
font-weight="500"
|
||||||
|
font-stretch="normal"
|
||||||
|
units-per-em="1000"
|
||||||
|
panose-1="0 0 0 0 0 0 0 0 0 0"
|
||||||
|
ascent="800"
|
||||||
|
descent="-200"
|
||||||
|
x-height="700"
|
||||||
|
cap-height="700"
|
||||||
|
bbox="-91 -200 898 863"
|
||||||
|
underline-thickness="20"
|
||||||
|
underline-position="-190"
|
||||||
|
unicode-range="U+0020-2122"
|
||||||
|
/>
|
||||||
|
<missing-glyph />
|
||||||
|
<glyph glyph-name="space" unicode=" " horiz-adv-x="282"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="exclam" unicode="!" horiz-adv-x="168"
|
||||||
|
d="M140 217l-112 70v301l112 112v-483zM140 0h-112v175h112v-175z" />
|
||||||
|
<glyph glyph-name="quotedbl" unicode=""" horiz-adv-x="325"
|
||||||
|
d="M303 413h-111v287h111v-287zM133 413h-112v287h112v-287z" />
|
||||||
|
<glyph glyph-name="numbersign" unicode="#" horiz-adv-x="569"
|
||||||
|
d="M523 482l-10 -48h-111l-36 -168h111l-9 -48h-112l-44 -204h-48l43 204h-101l-44 -204h-47l42 204h-111l10 48h112l35 168h-112l10 48h113l43 204h48l-43 -204h102l42 204h48l-43 -204h112zM353 434h-101l-36 -168h102z" />
|
||||||
|
<glyph glyph-name="dollar" unicode="$" horiz-adv-x="462"
|
||||||
|
d="M289 732l-56 -62l-58 59v54l59 58l55 -56v-53zM434 700l-124 -112h-156l-63 63l51 49h32l59 -55l55 55h146zM142 428l-113 -70v229l49 53l64 -65v-147zM405 350l-98 -49h-155l-96 50l97 62h155zM434 114l-48 -53l-63 65v163l111 54v-229zM371 48l-48 -48h-39l-52 52
|
||||||
|
l-60 -52h-144l126 112h156zM285 -89l-55 -54l-60 63v47l60 57l55 -60v-53z" />
|
||||||
|
<glyph glyph-name="percent" unicode="%" horiz-adv-x="810"
|
||||||
|
d="M286 649l-63 -61h-81l-62 61l48 51h111zM350 474l-52 -48l-61 61v86l61 64l52 -50v-113zM128 488l-64 -63l-50 48v114l52 50l62 -64v-85zM685 700l-225 -367l-61 112l154 255h132zM285 410l-48 -46h-111l-48 46l64 63h81zM732 288l-62 -61h-81l-63 61l49 50h110zM796 113
|
||||||
|
l-51 -49l-61 62v86l62 63l50 -49v-113zM576 126l-66 -63l-49 49v114l51 49l64 -64v-85zM448 313l-187 -313h-131l190 313h128zM731 49l-47 -49h-110l-49 49l64 63h81z" />
|
||||||
|
<glyph glyph-name="ampersand" unicode="&" horiz-adv-x="561"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM140 427l-112 -70v231l49 49l63 -63v-147zM433 430l-56 -61l-55 62v73l63 64l48 -64v-74zM575 351l-92 -50h-36l-55 56l55 56h37zM363 357l-54 -56h-86l-98 51l99 61h85zM432 113l-47 -48l-63 61v162l55 55l55 -56v-174zM140 126
|
||||||
|
l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="155"
|
||||||
|
d="M133 413h-112v287h112v-287z" />
|
||||||
|
<glyph glyph-name="parenleft" unicode="(" horiz-adv-x="280"
|
||||||
|
d="M266 700l-70 -112h-41l-64 63l49 49h126zM140 427l-112 -70v231l49 49l63 -63v-147zM140 126l-63 -63l-49 49v231l112 -56v-161zM266 0h-126l-49 49l64 63h41z" />
|
||||||
|
<glyph glyph-name="parenright" unicode=")" horiz-adv-x="280"
|
||||||
|
d="M189 651l-64 -63h-41l-70 112h126zM252 357l-112 56v161l62 63l50 -49v-231zM252 112l-50 -49l-62 63v147l112 70v-231zM189 49l-49 -49h-126l70 112h41z" />
|
||||||
|
<glyph glyph-name="asterisk" unicode="*" horiz-adv-x="425"
|
||||||
|
d="M268 576l-58 -40l-55 43v135l57 40l56 -43v-135zM198 456l-119 -73l-65 28l6 69l129 75l49 -35v-64zM411 416l-54 -35l-135 74v67l50 31l130 -70z" />
|
||||||
|
<glyph glyph-name="plus" unicode="+" horiz-adv-x="465"
|
||||||
|
d="M286 422l-54 -58l-59 59v95l113 50v-146zM451 406l-47 -112h-104l-50 56l57 56h144zM217 351l-58 -57h-145l48 112h99zM286 182l-111 -49v147l57 56l54 -56v-98z" />
|
||||||
|
<glyph glyph-name="comma" unicode="," horiz-adv-x="155"
|
||||||
|
d="M133 -112h-112v287h112v-287z" />
|
||||||
|
<glyph glyph-name="hyphen" unicode="-" horiz-adv-x="335"
|
||||||
|
d="M322 408l-85 -110h-223l83 110h225z" />
|
||||||
|
<glyph glyph-name="period" unicode="." horiz-adv-x="200"
|
||||||
|
d="M163 0h-112v175h112v-175z" />
|
||||||
|
<glyph glyph-name="slash" unicode="/" horiz-adv-x="583"
|
||||||
|
d="M570 700l-226 -367l-62 112l155 255h133zM332 313l-187 -313h-131l189 313h129z" />
|
||||||
|
<glyph glyph-name="zero" unicode="0"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="one" unicode="1" horiz-adv-x="461"
|
||||||
|
d="M336 357l-111 70v147l111 112v-329zM336 14l-111 112v161l111 56v-329z" />
|
||||||
|
<glyph glyph-name="two" unicode="2"
|
||||||
|
d="M371 651l-63 -63h-273l105 112h182zM435 357l-113 70v147l63 63l50 -49v-231zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-63 -63l-49 49v231l112 -56v-161zM435 0h-295l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="three" unicode="3" horiz-adv-x="462"
|
||||||
|
d="M357 651l-63 -63h-154l-126 112h293zM420 357l-113 70v147l63 63l50 -49v-231zM392 350l-98 -49h-154l-98 49l98 63h154zM420 112l-50 -49l-63 63v161l113 56v-231zM357 49l-50 -49h-293l126 112h154z" />
|
||||||
|
<glyph glyph-name="four" unicode="4"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343z" />
|
||||||
|
<glyph glyph-name="five" unicode="5" horiz-adv-x="470"
|
||||||
|
d="M441 700l-126 -112h-154l-63 63l49 49h294zM147 427l-112 -70v231l50 49l62 -63v-147zM413 350l-98 -49h-154l-98 49l98 63h154zM441 112l-49 -49l-62 63v161l111 56v-231zM378 49l-48 -49h-302l133 112h154z" />
|
||||||
|
<glyph glyph-name="six" unicode="6"
|
||||||
|
d="M435 700l-127 -112h-153l-64 63l49 49h295zM140 427l-112 -70v231l49 49l63 -63v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="seven" unicode="7" horiz-adv-x="462"
|
||||||
|
d="M378 700l-112 -112h-154l-112 112h378zM392 357l-112 70v147l112 112v-329zM392 0l-112 112v175l112 56v-343z" />
|
||||||
|
<glyph glyph-name="eight" unicode="8"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49
|
||||||
|
l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="nine" unicode="9"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 56v161l63 63l50 -49v-231zM140 413l-112 -56v231l49 49l63 -63v-161zM406 350l-98 -63h-153l-99 63l99 49h153zM435 112l-50 -49l-63 63v147l113 70v-231zM371 49l-49 -49h-294l127 112h153z" />
|
||||||
|
<glyph glyph-name="colon" unicode=":" horiz-adv-x="168"
|
||||||
|
d="M140 315h-112v175h112v-175zM140 0h-112v175h112v-175z" />
|
||||||
|
<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="168"
|
||||||
|
d="M140 315h-112v175h112v-175zM140 -112h-112v287h112v-287z" />
|
||||||
|
<glyph glyph-name="less" unicode="<" horiz-adv-x="307"
|
||||||
|
d="M283 583l-132 -222h-127l196 339h63v-117zM283 0h-68l-194 339h130l132 -229v-110z" />
|
||||||
|
<glyph glyph-name="equal" unicode="="
|
||||||
|
d="M406 425l-98 -49h-153l-99 49l99 63h153zM406 260l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="greater" unicode=">" horiz-adv-x="316"
|
||||||
|
d="M286 361h-127l-132 222v117h63zM289 339l-194 -339h-68v110l132 229h130z" />
|
||||||
|
<glyph glyph-name="question" unicode="?" horiz-adv-x="406"
|
||||||
|
d="M315 651l-63 -63h-154l-98 112h266zM378 357l-112 70v147l63 63l49 -49v-231zM350 350l-98 -49h-154v112h154zM210 0h-112v175h112v-175z" />
|
||||||
|
<glyph glyph-name="at" unicode="@" horiz-adv-x="756"
|
||||||
|
d="M700 351q-15 -90 -62 -148q-43 -53 -97 -61q-6 -1 -17 -1q-38 0 -60.5 23.5t-22.5 59.5q-6 -20 -19 -35q-35 -41 -80 -41q-22 0 -47 11q-75 34 -75 173l4 35q13 91 63 149t107 58t84 -52l5 -10l9 56l48 -1l-37 -209l-14 -85q-1 -8 -1.5 -17t-0.5 -13q0 -19 4 -31.5
|
||||||
|
t14 -20.5t25 -8q7 0 18 4t22.5 12.5t29.5 30.5t31.5 54.5t18.5 67t5 63.5q0 111 -68.5 181.5t-175.5 70.5q-22 0 -46 -3q-107 -15 -179 -104t-72 -211v-23q2 -11 2 -15l9 -54q27 -105 102 -166t172 -61q84 0 160 47q24 14 48 35q31 26 52 55l20 -35l-25 -28
|
||||||
|
q-112 -118 -258 -118q-150 0 -245 110t-95 278q0 52 20 105q17 47 49 91q46 61 107.5 98t132.5 45q11 2 23 2h19q130 0 214.5 -84.5t84.5 -215.5q0 -31 -6 -64zM462 471q-4 27 -22.5 43t-42.5 16q-15 0 -25 -5q-26 -11 -42 -33q-19 -26 -35 -75l-13 -48q-4 -24 -5 -44
|
||||||
|
t-1 -42q0 -18 3.5 -33t9.5 -27q16 -36 56 -36q25 0 44 19q14 14 23.5 31t22.5 53l17 73l2 9l7 41q1 10 1.5 20.5t0.5 15.5q0 15 -1 22z" />
|
||||||
|
<glyph glyph-name="A" unicode="A"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="B" unicode="B"
|
||||||
|
d="M371 651l-63 -63h-153l-113 112h280zM140 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l63 63l50 -49v-231zM406 350l-98 -49h-153l-99 49l99 63h153zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-112 -112v329l112 -56v-161zM371 49l-49 -49h-280
|
||||||
|
l113 112h153z" />
|
||||||
|
<glyph glyph-name="C" unicode="C" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-64 63l49 49h280zM140 413l-112 -56v231l49 49l63 -63v-161zM140 126l-63 -63l-49 49v231l112 -70v-147zM420 0h-280l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="D" unicode="D"
|
||||||
|
d="M371 651l-63 -63h-153l-113 112h280zM140 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l63 63l50 -49v-231zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-112 -112v329l112 -56v-161zM371 49l-49 -49h-280l113 112h153z" />
|
||||||
|
<glyph glyph-name="E" unicode="E" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153z" />
|
||||||
|
<glyph glyph-name="F" unicode="F" horiz-adv-x="413"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="G" unicode="G"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM140 427l-112 -70v231l49 49l63 -63v-147zM406 350l-98 -49h-70l-98 49l98 63h70zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="H" unicode="H"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="I" unicode="I" horiz-adv-x="168"
|
||||||
|
d="M140 357l-112 70v161l112 112v-343zM140 0l-112 112v175l112 56v-343z" />
|
||||||
|
<glyph glyph-name="J" unicode="J"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM435 14l-113 112v161l113 56v-329zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153z" />
|
||||||
|
<glyph glyph-name="K" unicode="K"
|
||||||
|
d="M435 624l-114 -189l-129 -1l162 266h81v-76zM140 427l-112 -70v343l112 -112v-161zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="L" unicode="L"
|
||||||
|
d="M140 427l-112 -70v343l112 -112v-161zM435 14l-113 112v161l113 56v-329zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153z" />
|
||||||
|
<glyph glyph-name="M" unicode="M" horiz-adv-x="756"
|
||||||
|
d="M715 700l-113 -112h-156l-68 70l-69 -70h-156l-111 112h673zM140 427l-112 -70v329l112 -112v-147zM728 357l-112 70v147l112 111v-328zM434 399l-56 -42l-56 42v175l55 57l57 -57v-175zM728 0l-112 112v175l112 56v-343zM435 112l-57 -112l-56 112v175l56 56l57 -56
|
||||||
|
v-175zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="N" unicode="N"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 0l-113 126v161l113 56v-343zM140 98l-112 -98v343l112 -56v-189z" />
|
||||||
|
<glyph glyph-name="O" unicode="O"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="P" unicode="P"
|
||||||
|
d="M371 651l-63 -63h-153l-113 112h280zM140 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l63 63l50 -49v-231zM406 350l-98 -49h-153l-99 49l99 63h153zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="Q" unicode="Q" horiz-adv-x="464"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 144l-50 -50l-63 63v130l113 56v-199zM140 123l-63 -60l-49 49v231l112 -56v-164zM265 0h-125l-51 51l67 60zM436 -143l-255 255h159
|
||||||
|
l96 -95v-160z" />
|
||||||
|
<glyph glyph-name="R" unicode="R"
|
||||||
|
d="M371 651l-63 -63h-153l-113 112h280zM140 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l63 63l50 -49v-231zM406 350l-98 -49h-153l-99 49l99 63h153zM140 112l-112 -112v343l112 -56v-175zM491 0l-164 111l-72 170h57l49 23z" />
|
||||||
|
<glyph glyph-name="S" unicode="S"
|
||||||
|
d="M435 700l-127 -112h-153l-64 63l49 49h295zM140 427l-112 -70v231l49 49l63 -63v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 112l-50 -49l-63 63v161l113 56v-231zM371 49l-49 -49h-294l127 112h153z" />
|
||||||
|
<glyph glyph-name="T" unicode="T" horiz-adv-x="379"
|
||||||
|
d="M393 700l-78 -112h-55l-68 70l-72 -70h-57l-77 112h407zM246 419l-55 -62l-59 62v152l59 64l55 -63v-153zM246 62l-56 -62l-60 62v219l60 63l56 -63v-219z" />
|
||||||
|
<glyph glyph-name="U" unicode="U"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="V" unicode="V"
|
||||||
|
d="M435 357l-113 70v189l113 84v-343zM140 427l-112 -70v343l112 -84v-189zM435 344l-127 -344l-67 137l56 157zM227 135l-70 -135l-129 344l140 -51zM286 0h-110l57 111z" />
|
||||||
|
<glyph glyph-name="W" unicode="W" horiz-adv-x="757"
|
||||||
|
d="M728 357l-112 56v175l112 112v-343zM435 413l-57 -56l-56 56v175l56 112l57 -112v-175zM140 413l-112 -56v343l112 -112v-175zM435 126l-56 -57l-56 57v175l55 42l57 -42v-175zM729 113l-50 -48l-65 64v145l115 70v-231zM140 128l-64 -63l-48 48v232l112 -72v-145z
|
||||||
|
M666 52l-51 -52h-477l-49 51l63 61h158l68 -68l68 68h156z" />
|
||||||
|
<glyph glyph-name="X" unicode="X" horiz-adv-x="437"
|
||||||
|
d="M424 583l-132 -222h-63v111l132 228h63v-117zM209 361h-62l-133 228v111h68l127 -228v-111zM424 0h-68l-128 224v115h64l132 -229v-110zM209 224l-130 -224h-65v115l130 224h65v-115z" />
|
||||||
|
<glyph glyph-name="Y" unicode="Y"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM406 350l-98 -49h-153l-99 49l99 63h153zM289 63l-58 -63l-57 63v217h115v-217z" />
|
||||||
|
<glyph glyph-name="Z" unicode="Z" horiz-adv-x="436"
|
||||||
|
d="M337 700l-66 -112h-145l-111 112h322zM422 585l-150 -256l-70 105l158 266h62v-115zM265 313l-162 -313h-89v106l126 216zM421 0h-299l59 112h127z" />
|
||||||
|
<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="287"
|
||||||
|
d="M280 700l-112 -112h-13l-113 112h238zM140 427l-112 -70v329l112 -112v-147zM140 126l-112 -112v329l112 -56v-161zM280 0h-238l113 112h13z" />
|
||||||
|
<glyph glyph-name="backslash" unicode="\" horiz-adv-x="583"
|
||||||
|
d="M298 445l-62 -112l-226 367h133zM566 0h-131l-187 313h129z" />
|
||||||
|
<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="287"
|
||||||
|
d="M245 700l-112 -112h-14l-112 112h238zM259 357l-112 56v161l112 112v-329zM259 14l-112 112v147l112 70v-329zM245 0h-238l112 112h14z" />
|
||||||
|
<glyph glyph-name="asciicircum" unicode="^" horiz-adv-x="464"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147z" />
|
||||||
|
<glyph glyph-name="underscore" unicode="_" horiz-adv-x="354"
|
||||||
|
d="M354 -200h-354l-2 41h355z" />
|
||||||
|
<glyph glyph-name="grave" unicode="`"
|
||||||
|
d="M406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="a" unicode="a"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="b" unicode="b"
|
||||||
|
d="M371 651l-63 -63h-153l-113 112h280zM140 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l63 63l50 -49v-231zM406 350l-98 -49h-153l-99 49l99 63h153zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-112 -112v329l112 -56v-161zM371 49l-49 -49h-280
|
||||||
|
l113 112h153z" />
|
||||||
|
<glyph glyph-name="c" unicode="c" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-64 63l49 49h280zM140 413l-112 -56v231l49 49l63 -63v-161zM140 126l-63 -63l-49 49v231l112 -70v-147zM420 0h-280l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="d" unicode="d"
|
||||||
|
d="M371 651l-63 -63h-153l-113 112h280zM140 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l63 63l50 -49v-231zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-112 -112v329l112 -56v-161zM371 49l-49 -49h-280l113 112h153z" />
|
||||||
|
<glyph glyph-name="e" unicode="e" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153z" />
|
||||||
|
<glyph glyph-name="f" unicode="f" horiz-adv-x="413"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="g" unicode="g"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM140 427l-112 -70v231l49 49l63 -63v-147zM406 350l-98 -49h-70l-98 49l98 63h70zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="h" unicode="h"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="i" unicode="i" horiz-adv-x="168"
|
||||||
|
d="M140 357l-112 70v161l112 112v-343zM140 0l-112 112v175l112 56v-343z" />
|
||||||
|
<glyph glyph-name="j" unicode="j"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM435 14l-113 112v161l113 56v-329zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153z" />
|
||||||
|
<glyph glyph-name="k" unicode="k"
|
||||||
|
d="M435 624l-114 -189l-129 -1l162 266h81v-76zM140 427l-112 -70v343l112 -112v-161zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="l" unicode="l"
|
||||||
|
d="M140 427l-112 -70v343l112 -112v-161zM435 14l-113 112v161l113 56v-329zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153z" />
|
||||||
|
<glyph glyph-name="m" unicode="m" horiz-adv-x="756"
|
||||||
|
d="M715 700l-113 -112h-156l-68 70l-69 -70h-156l-111 112h673zM140 427l-112 -70v329l112 -112v-147zM728 357l-112 70v147l112 111v-328zM434 399l-56 -42l-56 42v175l55 57l57 -57v-175zM728 0l-112 112v175l112 56v-343zM435 112l-57 -112l-56 112v175l56 56l57 -56
|
||||||
|
v-175zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="n" unicode="n"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 0l-113 126v161l113 56v-343zM140 98l-112 -98v343l112 -56v-189z" />
|
||||||
|
<glyph glyph-name="o" unicode="o"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="p" unicode="p"
|
||||||
|
d="M371 651l-63 -63h-153l-113 112h280zM140 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l63 63l50 -49v-231zM406 350l-98 -49h-153l-99 49l99 63h153zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="q" unicode="q" horiz-adv-x="464"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 144l-50 -50l-63 63v130l113 56v-199zM140 123l-63 -60l-49 49v231l112 -56v-164zM265 0h-125l-51 51l67 60zM436 -143l-255 255h159
|
||||||
|
l96 -95v-160z" />
|
||||||
|
<glyph glyph-name="r" unicode="r"
|
||||||
|
d="M371 651l-63 -63h-153l-113 112h280zM140 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l63 63l50 -49v-231zM406 350l-98 -49h-153l-99 49l99 63h153zM140 112l-112 -112v343l112 -56v-175zM491 0l-164 111l-72 170h57l49 23z" />
|
||||||
|
<glyph glyph-name="s" unicode="s"
|
||||||
|
d="M435 700l-127 -112h-153l-64 63l49 49h295zM140 427l-112 -70v231l49 49l63 -63v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 112l-50 -49l-63 63v161l113 56v-231zM371 49l-49 -49h-294l127 112h153z" />
|
||||||
|
<glyph glyph-name="t" unicode="t" horiz-adv-x="379"
|
||||||
|
d="M393 700l-78 -112h-55l-68 70l-72 -70h-57l-77 112h407zM246 419l-55 -62l-59 62v152l59 64l55 -63v-153zM246 62l-56 -62l-60 62v219l60 63l56 -63v-219z" />
|
||||||
|
<glyph glyph-name="u" unicode="u"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="v" unicode="v"
|
||||||
|
d="M435 357l-113 70v189l113 84v-343zM140 427l-112 -70v343l112 -84v-189zM435 344l-127 -344l-67 137l56 157zM227 135l-70 -135l-129 344l140 -51zM286 0h-110l57 111z" />
|
||||||
|
<glyph glyph-name="w" unicode="w" horiz-adv-x="757"
|
||||||
|
d="M728 357l-112 56v175l112 112v-343zM435 413l-57 -56l-56 56v175l56 112l57 -112v-175zM140 413l-112 -56v343l112 -112v-175zM435 126l-56 -57l-56 57v175l55 42l57 -42v-175zM729 113l-50 -48l-65 64v145l115 70v-231zM140 128l-64 -63l-48 48v232l112 -72v-145z
|
||||||
|
M666 52l-51 -52h-477l-49 51l63 61h158l68 -68l68 68h156z" />
|
||||||
|
<glyph glyph-name="x" unicode="x" horiz-adv-x="437"
|
||||||
|
d="M424 583l-132 -222h-63v111l132 228h63v-117zM209 361h-62l-133 228v111h68l127 -228v-111zM424 0h-68l-128 224v115h64l132 -229v-110zM209 224l-130 -224h-65v115l130 224h65v-115z" />
|
||||||
|
<glyph glyph-name="y" unicode="y"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM406 350l-98 -49h-153l-99 49l99 63h153zM289 63l-58 -63l-57 63v217h115v-217z" />
|
||||||
|
<glyph glyph-name="z" unicode="z" horiz-adv-x="436"
|
||||||
|
d="M337 700l-66 -112h-145l-111 112h322zM422 585l-150 -256l-70 105l158 266h62v-115zM265 313l-162 -313h-89v106l126 216zM421 0h-299l59 112h127z" />
|
||||||
|
<glyph glyph-name="braceleft" unicode="{" horiz-adv-x="280"
|
||||||
|
d="M266 700l-70 -112h-41l-64 63l49 49h126zM140 427l-112 -70v231l49 49l63 -63v-147zM140 126l-63 -63l-49 49v231l112 -56v-161zM266 0h-126l-49 49l64 63h41z" />
|
||||||
|
<glyph glyph-name="bar" unicode="|" horiz-adv-x="168"
|
||||||
|
d="M140 427l-112 -70v343l112 -112v-161zM140 112l-112 -112v343l112 -56v-175z" />
|
||||||
|
<glyph glyph-name="braceright" unicode="}" horiz-adv-x="280"
|
||||||
|
d="M189 651l-64 -63h-41l-70 112h126zM252 357l-112 56v161l62 63l50 -49v-231zM252 112l-50 -49l-62 63v147l112 70v-231zM189 49l-49 -49h-126l70 112h41z" />
|
||||||
|
<glyph glyph-name="asciitilde" unicode="~" horiz-adv-x="578"
|
||||||
|
d="M555 470h-288l113 112h63zM300 580l-112 -112h-58l-113 112h283z" />
|
||||||
|
<glyph glyph-name="Adieresis" unicode="Ä"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM401 800l-82 -49l-77 49l77 63z
|
||||||
|
M215 800l-82 -49l-77 49l77 63z" />
|
||||||
|
<glyph glyph-name="Aring" unicode="Å"
|
||||||
|
d="M352 800l-98 -49h-70l-98 49l98 63h70zM420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="Ccedilla" unicode="Ç" horiz-adv-x="420"
|
||||||
|
d="M287 -145l-70 67l70 69v-136zM420 700l-112 -112h-153l-64 63l49 49h280zM140 413l-112 -56v231l49 49l63 -63v-161zM140 126l-63 -63l-49 49v231l112 -70v-147zM420 0h-280l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="Eacute" unicode="É" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153zM391 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Ntilde" unicode="Ñ"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 0l-113 126v161l113 56v-343zM140 98l-112 -98v343l112 -56v-189zM406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Odieresis" unicode="Ö"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM401 800
|
||||||
|
l-82 -49l-77 49l77 63zM215 800l-82 -49l-77 49l77 63z" />
|
||||||
|
<glyph glyph-name="Udieresis" unicode="Ü"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM401 800l-82 -49l-77 49l77 63zM215 800l-82 -49l-77 49l77 63z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="aacute" unicode="á"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM403 800l-98 -49h-153l-99 49l99 63
|
||||||
|
h153z" />
|
||||||
|
<glyph glyph-name="agrave" unicode="à"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM406 800l-98 -49h-153l-99 49l99 63
|
||||||
|
h153z" />
|
||||||
|
<glyph glyph-name="acircumflex" unicode="â"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM406 800l-98 -49h-153l-99 49l99 63
|
||||||
|
h153z" />
|
||||||
|
<glyph glyph-name="adieresis" unicode="ä"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM401 800l-82 -49l-77 49l77 63z
|
||||||
|
M215 800l-82 -49l-77 49l77 63z" />
|
||||||
|
<glyph glyph-name="atilde" unicode="ã"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM406 800l-98 -49h-153l-99 49l99 63
|
||||||
|
h153z" />
|
||||||
|
<glyph glyph-name="aring" unicode="å"
|
||||||
|
d="M352 800l-98 -49h-70l-98 49l98 63h70zM420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="ccedilla" unicode="ç" horiz-adv-x="420"
|
||||||
|
d="M287 -145l-70 67l70 69v-136zM420 700l-112 -112h-153l-64 63l49 49h280zM140 413l-112 -56v231l49 49l63 -63v-161zM140 126l-63 -63l-49 49v231l112 -70v-147zM420 0h-280l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="eacute" unicode="é" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153zM391 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="egrave" unicode="è" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153zM388 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="ecircumflex" unicode="ê" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153zM396 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="edieresis" unicode="ë" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153zM386 800l-82 -49l-77 49l77 63zM200 800l-82 -49l-77 49l77 63z" />
|
||||||
|
<glyph glyph-name="iacute" unicode="í" horiz-adv-x="168"
|
||||||
|
d="M140 357l-112 70v161l112 112v-343zM140 0l-112 112v175l112 56v-343zM265 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="igrave" unicode="ì" horiz-adv-x="168"
|
||||||
|
d="M140 357l-112 70v161l112 112v-343zM140 0l-112 112v175l112 56v-343zM268 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="icircumflex" unicode="î" horiz-adv-x="168"
|
||||||
|
d="M140 357l-112 70v161l112 112v-343zM140 0l-112 112v175l112 56v-343zM271 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="idieresis" unicode="ï" horiz-adv-x="168"
|
||||||
|
d="M140 357l-112 70v161l112 112v-343zM140 0l-112 112v175l112 56v-343zM254 800l-82 -49l-77 49l77 63zM68 800l-82 -49l-77 49l77 63z" />
|
||||||
|
<glyph glyph-name="ntilde" unicode="ñ"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 0l-113 126v161l113 56v-343zM140 98l-112 -98v343l112 -56v-189zM406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="oacute" unicode="ó"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800
|
||||||
|
l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="ograve" unicode="ò"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800
|
||||||
|
l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="ocircumflex" unicode="ô"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800
|
||||||
|
l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="odieresis" unicode="ö"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM401 800
|
||||||
|
l-82 -49l-77 49l77 63zM215 800l-82 -49l-77 49l77 63z" />
|
||||||
|
<glyph glyph-name="otilde" unicode="õ"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800
|
||||||
|
l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="uacute" unicode="ú"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="ugrave" unicode="ù"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="ucircumflex" unicode="û"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM403 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="udieresis" unicode="ü"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM401 800l-82 -49l-77 49l77 63zM215 800l-82 -49l-77 49l77 63z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="dagger" unicode="†" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="degree" unicode="°" horiz-adv-x="416"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="cent" unicode="¢" horiz-adv-x="436"
|
||||||
|
d="M283 733l-60 -58l-54 56v55l56 54l58 -53v-54zM422 700l-115 -112h-152l-61 61l46 51h30l54 -55l56 55h142zM140 412l-111 -54v229l50 50l61 -64v-161zM140 123l-63 -62l-49 49v234l112 -71v-150zM421 0h-139l-56 54l-56 -54h-31l-46 46l63 66h153zM282 -87l-56 -58
|
||||||
|
l-57 60v54l57 55l56 -55v-56z" />
|
||||||
|
<glyph glyph-name="sterling" unicode="£" horiz-adv-x="532"
|
||||||
|
d="M490 700l-93 -112h-157l-62 61l50 51h262zM227 430l-55 -61l-57 59v160l48 48l64 -63v-143zM367 351l-95 -50h-32l-54 56l54 56h33zM156 358l-53 -57h-35l-82 57l67 55h49zM227 124l-113 -124v286l56 58l57 -58v-162zM518 0h-378l102 112h181z" />
|
||||||
|
<glyph glyph-name="section" unicode="§"
|
||||||
|
d="M435 700l-127 -112h-153l-64 63l49 49h295zM140 471l-112 -70v187l49 49l63 -63v-103zM409 395l-102 -49h-153l-97 49l97 63h162zM140 171l-113 -56v274l113 -57v-161zM434 115l-112 56v161l112 55v-272zM406 108l-99 -63h-153l-98 63l98 49h153zM434 -70l-49 -49l-63 63
|
||||||
|
v87l112 70v-171zM371 -133l-49 -49h-295l127 112h153z" />
|
||||||
|
<glyph glyph-name="bullet" unicode="•" horiz-adv-x="354"
|
||||||
|
d="M308 350q0 -55 -38 -93t-93 -38t-93 38t-38 93t38 93t93 38t93 -38t38 -93z" />
|
||||||
|
<glyph glyph-name="paragraph" unicode="¶" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="germandbls" unicode="ß" horiz-adv-x="926"
|
||||||
|
d="M898 700l-127 -112h-153l-64 63l49 49h295zM435 700l-127 -112h-153l-64 63l49 49h295zM603 427l-112 -70v231l49 49l63 -63v-147zM140 427l-112 -70v231l49 49l63 -63v-147zM869 350l-98 -49h-153l-99 49l99 63h153zM406 350l-98 -49h-153l-99 49l99 63h153zM898 112
|
||||||
|
l-50 -49l-63 63v161l113 56v-231zM435 112l-50 -49l-63 63v161l113 56v-231zM834 49l-49 -49h-294l127 112h153zM371 49l-49 -49h-294l127 112h153z" />
|
||||||
|
<glyph glyph-name="registered" unicode="®" horiz-adv-x="768"
|
||||||
|
d="M719 316q0 -139 -98 -237t-237 -98q-140 0 -237.5 97.5t-97.5 237.5t97.5 237.5t237.5 97.5q139 0 237 -98t98 -237zM681 316q0 123 -87.5 209.5t-210.5 86.5q-122 0 -209 -87t-87 -210q0 -122 87 -209t210 -87q122 0 209.5 86.5t87.5 210.5zM580 147h-92l-129 172h-26
|
||||||
|
v-127q0 -15 14 -21.5t32 -6.5v-17h-155v17q21 0 34 6t13 20v280q0 21 -6 25t-37 4v17h163q27 0 42 -1.5t31 -7.5t28 -14q17 -12 23 -22.5t9 -23t3 -22.5q0 -22 -8.5 -40t-22 -30t-24.5 -17q-20 -10 -43 -10l116 -150q5 -7 12.5 -10.5t22.5 -3.5v-17zM461 430q-3 34 -24 50
|
||||||
|
q-15 12 -33 12l-51 4q-8 0 -14.5 -5.5t-6.5 -14.5l1 -135h16q17 0 28 1t26 7q59 20 59 69q0 8 -1 12z" />
|
||||||
|
<glyph glyph-name="copyright" unicode="©" horiz-adv-x="768"
|
||||||
|
d="M720 321q0 -140 -97 -238t-238 -98q-139 0 -237 98t-98 238t97.5 237.5t237.5 97.5t237.5 -97.5t97.5 -237.5zM682 321q0 122 -87 209t-210 87q-122 0 -209.5 -86.5t-87.5 -209.5t87 -210t210 -87q122 0 209.5 86.5t87.5 210.5zM535 196q-32 -32 -51 -44q-42 -27 -93 -27
|
||||||
|
q-20 0 -30 1t-32 7q-60 16 -93 66.5t-33 113.5q0 49 18.5 89.5t57.5 68.5q26 18 54 26.5t52 8.5q30 0 63 -9q13 -4 27 -8q4 -1 12 -1q20 0 23 16h19l4 -125h-20q-4 24 -18 47q-19 31 -48 44q-10 4 -25 7t-25 3q-56 0 -92 -45q-19 -24 -29 -57t-10 -66q0 -62 30 -106t84 -44
|
||||||
|
q48 0 74 7.5t58 34.5l12 10z" />
|
||||||
|
<glyph glyph-name="trademark" unicode="™" horiz-adv-x="865"
|
||||||
|
d="M831 285h-155v17q25 0 37 5.5t12 22.5v269l-130 -314h-18l-140 298v-253q0 -16 12.5 -22t37.5 -6v-17h-125v17q25 0 37 5.5t12 22.5v273q0 21 -9 27.5t-28 6.5h-14v17h111l128 -280l122 280h109v-17q-24 0 -35.5 -3.5t-11.5 -21.5v-282q0 -16 12 -22t36 -6v-17zM332 560
|
||||||
|
l-18 -1q0 35 -17 54t-58 19l-36 1v-303q0 -16 12.5 -22t36.5 -6v-17h-156v17q25 0 37.5 5.5t12.5 22.5v303l-36 -1q-40 0 -57.5 -19t-17.5 -54l-18 1l3 94h309z" />
|
||||||
|
<glyph glyph-name="acute" unicode="´"
|
||||||
|
d="M406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="0"
|
||||||
|
d="M401 800l-82 -49l-77 49l77 63zM215 800l-82 -49l-77 49l77 63z" />
|
||||||
|
<glyph glyph-name="AE" unicode="Æ" horiz-adv-x="883"
|
||||||
|
d="M883 700l-112 -112h-153l-113 112h378zM420 700l-112 -112h-153l-113 112h378zM603 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM869 350l-98 -49h-153l-99 49l99 63h153zM406 350l-98 -49h-153l-99 49
|
||||||
|
l99 63h153zM603 126l-112 -112v329l112 -56v-161zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM883 0h-378l113 112h153z" />
|
||||||
|
<glyph glyph-name="Oslash" unicode="Ø"
|
||||||
|
d="M309 498l-81 -135v211h81v-76zM234 126h-81v76l81 135v-211zM371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56
|
||||||
|
v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="plusminus" unicode="±" horiz-adv-x="571"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="yen" unicode="¥"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM406 350l-98 -49h-153l-99 49l99 63h153zM289 234l-60 -45l-55 44v47h115v-46zM438 174l-78 -57h-51l-73 55l75 57h49zM223 172l-80 -55h-42l-75 55l75 57h47zM287 58l-57 -58l-57 58v56l57 42
|
||||||
|
l57 -43v-55z" />
|
||||||
|
<glyph glyph-name="mu" unicode="µ" horiz-adv-x="599"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="ordfeminine" unicode="ª" horiz-adv-x="324"
|
||||||
|
d="M294 700l-78 -78h-108l-79 78h265zM304 460l-79 49v103l79 78v-230zM98 509l-78 -49v230l78 -78v-103zM284 455l-68 -34h-108l-69 34l69 44h108zM304 210l-79 78v123l79 39v-240zM98 288l-78 -78v240l78 -39v-123z" />
|
||||||
|
<glyph glyph-name="ordmasculine" unicode="º" horiz-adv-x="324"
|
||||||
|
d="M260 666l-44 -44h-108l-44 44l34 34h127zM304 460l-79 49v103l44 44l35 -34v-162zM98 509l-78 -49v162l34 34l44 -44v-103zM304 288l-35 -34l-44 44v113l79 39v-162zM98 298l-44 -44l-34 34v162l78 -39v-113zM260 244l-35 -34h-127l-34 34l44 44h108z" />
|
||||||
|
<glyph glyph-name="ae" unicode="æ" horiz-adv-x="883"
|
||||||
|
d="M883 700l-112 -112h-153l-113 112h378zM420 700l-112 -112h-153l-113 112h378zM603 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM869 350l-98 -49h-153l-99 49l99 63h153zM406 350l-98 -49h-153l-99 49
|
||||||
|
l99 63h153zM603 126l-112 -112v329l112 -56v-161zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM883 0h-378l113 112h153z" />
|
||||||
|
<glyph glyph-name="oslash" unicode="ø"
|
||||||
|
d="M309 498l-81 -135v211h81v-76zM234 126h-81v76l81 135v-211zM371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56
|
||||||
|
v-161zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="questiondown" unicode="¿" horiz-adv-x="406"
|
||||||
|
d="M308 525h-112v175h112v-175zM308 287h-154l-98 63l98 49h154v-112zM140 126l-63 -63l-49 49v231l112 -70v-147zM406 0h-266l-49 49l63 63h154z" />
|
||||||
|
<glyph glyph-name="exclamdown" unicode="¡" horiz-adv-x="168"
|
||||||
|
d="M140 525h-112v175h112v-175zM140 112l-112 -112v483l112 -70v-301z" />
|
||||||
|
<glyph glyph-name="logicalnot" unicode="¬" horiz-adv-x="742"
|
||||||
|
d="M707 0h-58v242h-633v58h691v-300z" />
|
||||||
|
<glyph glyph-name="florin" unicode="ƒ" horiz-adv-x="520"
|
||||||
|
d="M515 644q0 -19 -15 -33t-37 -14q-16 0 -26 16q-12 15 -12 22l1 5l11 25l1 6q0 15 -21 15q-26 0 -48 -29t-28 -73l-20 -137l-2 -13h133l-10 -36h-127l-32 -258l-11 -48l-26 -116q-15 -66 -60 -126q-39 -50 -99 -50q-38 0 -62 20t-24 51q0 22 14 37t36 15q18 0 29.5 -10.5
|
||||||
|
t11.5 -26.5q0 -6 -8 -30l-4 -11l-1 -7v-5l6 -5h10q31 0 49 27.5t31 92.5l12 61l4 36l36 353h-122l14 36h116q16 130 68.5 204.5t130.5 74.5q33 0 57 -20t24 -49z" />
|
||||||
|
<glyph glyph-name="guillemotleft" unicode="«" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="guillemotright" unicode="»" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="ellipsis" unicode="…" horiz-adv-x="600"
|
||||||
|
d="M563 0h-112v175h112v-175zM363 0h-112v175h112v-175zM163 0h-112v175h112v-175z" />
|
||||||
|
<glyph glyph-name="nonbreakingspace" unicode=" " horiz-adv-x="282"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="Agrave" unicode="À"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM406 800l-98 -49h-153l-99 49l99 63
|
||||||
|
h153z" />
|
||||||
|
<glyph glyph-name="Atilde" unicode="Ã"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM406 800l-98 -49h-153l-99 49l99 63
|
||||||
|
h153z" />
|
||||||
|
<glyph glyph-name="Otilde" unicode="Õ"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800
|
||||||
|
l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="OE" unicode="Œ" horiz-adv-x="883"
|
||||||
|
d="M883 700l-112 -112h-153l-113 112h378zM371 651l-63 -63h-153l-64 63l49 49h182zM603 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM869 350l-98 -49h-153l-99 49l99 63h153zM435 112l-50 -49
|
||||||
|
l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM603 126l-112 -112v329l112 -56v-161zM883 0h-378l113 112h153zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="oe" unicode="œ" horiz-adv-x="883"
|
||||||
|
d="M883 700l-112 -112h-153l-113 112h378zM371 651l-63 -63h-153l-64 63l49 49h182zM603 427l-112 -70v329l112 -112v-147zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM869 350l-98 -49h-153l-99 49l99 63h153zM435 112l-50 -49
|
||||||
|
l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM603 126l-112 -112v329l112 -56v-161zM883 0h-378l113 112h153zM371 49l-49 -49h-182l-49 49l64 63h153z" />
|
||||||
|
<glyph glyph-name="endash" unicode="–" horiz-adv-x="400"
|
||||||
|
d="M400 408l-46 -111h-354l47 111h353z" />
|
||||||
|
<glyph glyph-name="emdash" unicode="—" horiz-adv-x="800"
|
||||||
|
d="M800 408l-46 -111h-754l47 111h753z" />
|
||||||
|
<glyph glyph-name="quotedblleft" unicode="“" horiz-adv-x="325"
|
||||||
|
d="M303 413h-111v287h111v-287zM133 413h-112v287h112v-287z" />
|
||||||
|
<glyph glyph-name="quotedblright" unicode="”" horiz-adv-x="325"
|
||||||
|
d="M303 413h-111v287h111v-287zM133 413h-112v287h112v-287z" />
|
||||||
|
<glyph glyph-name="quoteleft" unicode="‘" horiz-adv-x="155"
|
||||||
|
d="M133 413h-112v287h112v-287z" />
|
||||||
|
<glyph glyph-name="quoteright" unicode="’" horiz-adv-x="155"
|
||||||
|
d="M133 413h-112v287h112v-287z" />
|
||||||
|
<glyph glyph-name="divide" unicode="÷" horiz-adv-x="571"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="ydieresis" unicode="ÿ"
|
||||||
|
d="M401 800l-82 -49l-77 49l77 63zM215 800l-82 -49l-77 49l77 63zM435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM406 350l-98 -49h-153l-99 49l99 63h153zM289 63l-58 -63l-57 63v217h115v-217z" />
|
||||||
|
<glyph glyph-name="Ydieresis" unicode="Ÿ"
|
||||||
|
d="M401 800l-82 -49l-77 49l77 63zM215 800l-82 -49l-77 49l77 63zM435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM406 350l-98 -49h-153l-99 49l99 63h153zM289 63l-58 -63l-57 63v217h115v-217z" />
|
||||||
|
<glyph glyph-name="currency" unicode="¤" horiz-adv-x="555"
|
||||||
|
d="M542 184l-70 -72l-87 84q-51 -30 -109 -30q-30 0 -57 7.5t-53 23.5l-81 -85l-71 72l81 85q-30 51 -30 109q0 30 7.5 57t23.5 53l-82 84l71 72l85 -85q49 30 106 30q60 0 110 -31l86 86l70 -72l-84 -85q30 -51 30 -109q0 -30 -7.5 -56.5t-22.5 -52.5zM389 378q0 47 -33 80
|
||||||
|
t-80 33t-80 -33t-33 -80t33 -80t80 -33t80 33t33 80z" />
|
||||||
|
<glyph glyph-name="guilsinglleft" unicode="‹" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="guilsinglright" unicode="›" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="daggerdbl" unicode="‡" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="periodcentered" unicode="·" horiz-adv-x="200"
|
||||||
|
d="M163 266h-112v175h112v-175z" />
|
||||||
|
<glyph glyph-name="periodcentered" unicode="∙" horiz-adv-x="200"
|
||||||
|
d="M163 266h-112v175h112v-175z" />
|
||||||
|
<glyph glyph-name="quotesinglbase" unicode="‚" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="quotedblbase" unicode="„" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="perthousand" unicode="‰" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="Acircumflex" unicode="Â"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM406 800l-98 -49h-153l-99 49l99 63
|
||||||
|
h153z" />
|
||||||
|
<glyph glyph-name="Ecircumflex" unicode="Ê" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153zM396 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Aacute" unicode="Á"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM435 357l-113 70v147l113 112v-329zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 0l-113 112v175l113 56v-343zM140 112l-112 -112v343l112 -56v-175zM403 800l-98 -49h-153l-99 49l99 63
|
||||||
|
h153z" />
|
||||||
|
<glyph glyph-name="Edieresis" unicode="Ë" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153zM386 800l-82 -49l-77 49l77 63zM200 800l-82 -49l-77 49l77 63z" />
|
||||||
|
<glyph glyph-name="Egrave" unicode="È" horiz-adv-x="420"
|
||||||
|
d="M420 700l-112 -112h-153l-113 112h378zM140 427l-112 -70v329l112 -112v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM140 126l-112 -112v329l112 -56v-161zM420 0h-378l113 112h153zM388 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Iacute" unicode="Í" horiz-adv-x="168"
|
||||||
|
d="M140 357l-112 70v161l112 112v-343zM140 0l-112 112v175l112 56v-343zM265 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Icircumflex" unicode="Î" horiz-adv-x="168"
|
||||||
|
d="M140 357l-112 70v161l112 112v-343zM140 0l-112 112v175l112 56v-343zM271 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Idieresis" unicode="Ï" horiz-adv-x="168"
|
||||||
|
d="M140 357l-112 70v161l112 112v-343zM140 0l-112 112v175l112 56v-343zM254 800l-82 -49l-77 49l77 63zM68 800l-82 -49l-77 49l77 63z" />
|
||||||
|
<glyph glyph-name="Igrave" unicode="Ì" horiz-adv-x="168"
|
||||||
|
d="M140 357l-112 70v161l112 112v-343zM140 0l-112 112v175l112 56v-343zM268 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Oacute" unicode="Ó"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800
|
||||||
|
l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Ocircumflex" unicode="Ô"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800
|
||||||
|
l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Ograve" unicode="Ò"
|
||||||
|
d="M371 651l-63 -63h-153l-64 63l49 49h182zM435 357l-113 70v147l63 63l50 -49v-231zM140 427l-112 -70v231l49 49l63 -63v-147zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800
|
||||||
|
l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Uacute" unicode="Ú"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Ucircumflex" unicode="Û"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM403 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Ugrave" unicode="Ù"
|
||||||
|
d="M435 357l-113 70v161l113 112v-343zM140 427l-112 -70v343l112 -112v-161zM435 112l-50 -49l-63 63v161l113 56v-231zM140 126l-63 -63l-49 49v231l112 -56v-161zM371 49l-49 -49h-182l-49 49l64 63h153zM406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="circumflex" unicode="ˆ"
|
||||||
|
d="M406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="tilde" unicode="˜"
|
||||||
|
d="M406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="macron" unicode="¯"
|
||||||
|
d="M406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="cedilla" unicode="¸" horiz-adv-x="420"
|
||||||
|
d="M287 -145l-70 67l70 69v-136z" />
|
||||||
|
<glyph glyph-name="Scaron" unicode="Š"
|
||||||
|
d="M435 700l-127 -112h-153l-64 63l49 49h295zM140 427l-112 -70v231l49 49l63 -63v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 112l-50 -49l-63 63v161l113 56v-231zM371 49l-49 -49h-294l127 112h153zM406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="scaron" unicode="š"
|
||||||
|
d="M435 700l-127 -112h-153l-64 63l49 49h295zM140 427l-112 -70v231l49 49l63 -63v-147zM406 350l-98 -49h-153l-99 49l99 63h153zM435 112l-50 -49l-63 63v161l113 56v-231zM371 49l-49 -49h-294l127 112h153zM406 800l-98 -49h-153l-99 49l99 63h153z" />
|
||||||
|
<glyph glyph-name="Zcaron" unicode="Ž" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="zcaron" unicode="ž" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="brokenbar" unicode="¦" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="Eth" unicode="Ð" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="eth" unicode="ð" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="Yacute" unicode="Ý" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="yacute" unicode="ý" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="Thorn" unicode="Þ" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="thorn" unicode="þ" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="minus" unicode="­" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="multiply" unicode="×" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="onesuperior" unicode="¹" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="twosuperior" unicode="²" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="threesuperior" unicode="³" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="onehalf" unicode="½" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="onequarter" unicode="¼" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="threequarters" unicode="¾" horiz-adv-x="0"
|
||||||
|
/>
|
||||||
|
</font>
|
||||||
|
</defs></svg>
|
After Width: | Height: | Size: 49 KiB |
BIN
www/css/LED.ttf
Normal file
BIN
www/css/LED.woff
Normal file
377
www/css/common.css
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
.grid-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
grid-template-rows: 0.8fr 47px 0.7fr 2.8fr;
|
||||||
|
grid-template-areas: ". . ." ". . ." ". . ." ". . .";
|
||||||
|
}
|
||||||
|
.buttons-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
grid-template-areas: ". . ." ". . ." ". . ." ". . .";
|
||||||
|
}
|
||||||
|
.buttons-6container {
|
||||||
|
display: grid;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . . . . .";
|
||||||
|
}
|
||||||
|
.buttons-7container {
|
||||||
|
display: grid;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . . . . . .";
|
||||||
|
}
|
||||||
|
#title{
|
||||||
|
font-family: "Lucida Grande", Verdana, Arial, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
color: #ddd;
|
||||||
|
font-size: 4ex;
|
||||||
|
}
|
||||||
|
#text{
|
||||||
|
font-family: "Lucida Grande", Verdana, Arial, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 2ex;
|
||||||
|
}
|
||||||
|
.encoders{
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.mainGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . . . . . . .";
|
||||||
|
}
|
||||||
|
.buttonsGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 70px 70px 70px 70px 70px 70px 70px 70px 70px 70px 70px 70px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . . . ." ". . . . ." ". . . . .";
|
||||||
|
}
|
||||||
|
.FxGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 70px 70px 70px 70px 70px 70px 70px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
align-items: stretch;
|
||||||
|
background-color: #020202;
|
||||||
|
grid-template-areas: ". . . . . . ,";
|
||||||
|
}
|
||||||
|
.RGYGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 70px 70px 70px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
background-color: #020202;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . .";
|
||||||
|
}
|
||||||
|
.RGBGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 70px 70px 70px 70px 70px 70px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
background-color: #020202;
|
||||||
|
grid-template-areas: ". . . . . .";
|
||||||
|
}
|
||||||
|
.TopRackGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 120px 600px 30px 30px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . . .";
|
||||||
|
}
|
||||||
|
.TextGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 250px 370px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". .";
|
||||||
|
}
|
||||||
|
.Rackgrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 170px 70px 70px 70px 70px 70px 70px 70px 70px 70px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . . . . . . . . .";
|
||||||
|
}
|
||||||
|
.Settingrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 110px 80px 80px 100px 80px 80px 140px 40px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . . . . . . . .";
|
||||||
|
}
|
||||||
|
.ColorRackGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 170px 70px 70px 70px 70px 70px 70px 70px 70px 70px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . . . . . . . . .";
|
||||||
|
}
|
||||||
|
.grid3 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . .";
|
||||||
|
}
|
||||||
|
.encodersGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: "." "." "." "." ".";
|
||||||
|
}
|
||||||
|
.webaudiobut{
|
||||||
|
border-radius: 4px;
|
||||||
|
border : #002020 1px solid;
|
||||||
|
-webkit-box-shadow: 2px 4px 8px -1px rgba(0,0,0,0.72);
|
||||||
|
-moz-box-shadow: 2px 4px 8px -1px rgba(0,0,0,0.72);
|
||||||
|
box-shadow: 2px 4px 8px -1px rgba(0,0,0,0.72);
|
||||||
|
background-image: linear-gradient(174deg, #111,#030303);
|
||||||
|
}
|
||||||
|
.content{
|
||||||
|
width : 800px;
|
||||||
|
padding : 10px 20px;
|
||||||
|
margin : 5px auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
border : #212121 2px solid;
|
||||||
|
background-color: #000000;
|
||||||
|
background-image: linear-gradient(174deg, #222,#111);
|
||||||
|
-webkit-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
-moz-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
}
|
||||||
|
.Rackcontent{
|
||||||
|
width : 845px;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin : 1px auto;
|
||||||
|
border : #111 2px solid;
|
||||||
|
background-color: #111;
|
||||||
|
-webkit-box-shadow: 4px 6px 44px -1px rgba(0,0,0,0.72);
|
||||||
|
-moz-box-shadow: 4px 6px 44px -1px rgba(0,0,0,0.72);
|
||||||
|
box-shadow: 4px 6px 44px -1px rgba(0,0,0,0.72);
|
||||||
|
}
|
||||||
|
.content-title {
|
||||||
|
color : #ddd;
|
||||||
|
border : none;
|
||||||
|
margin-top : 15px;
|
||||||
|
padding-bottom : 0;
|
||||||
|
margin-bottom : 0;
|
||||||
|
background-color : inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-names {
|
||||||
|
padding : 10px;
|
||||||
|
padding-top : 0;
|
||||||
|
border : none;
|
||||||
|
box-shadow : none;
|
||||||
|
background-color : inherit;
|
||||||
|
}
|
||||||
|
.etherled {
|
||||||
|
color: #666;
|
||||||
|
font-family: 'Lucida Grande', Verdana, Arial, sans-serif;
|
||||||
|
font-size: 1.5ex;
|
||||||
|
text-align: middle;
|
||||||
|
margin-left: 20px
|
||||||
|
margin-top: 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
a { text-decoration: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
a:hover, a:focus {
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
position: relative;
|
||||||
|
line-height: 3ex;
|
||||||
|
color: #666;
|
||||||
|
text-align: middle;
|
||||||
|
font-family: 'Lucida Grande', Verdana, Arial, sans-serif;
|
||||||
|
font-size: 1.7ex;
|
||||||
|
margin-top : 1px;
|
||||||
|
text-shadow: 2px 3px #000;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
|
||||||
|
font-family: "Bus Led Display Small";
|
||||||
|
src: url("7f37946c45abf5482c243bf326f82628.eot"); /* IE9*/
|
||||||
|
src: url("7f37946c45abf5482c243bf326f82628.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
|
||||||
|
url("7f37946c45abf5482c243bf326f82628.woff2") format("woff2"), /* chrome、firefox */
|
||||||
|
url("7f37946c45abf5482c243bf326f82628.woff") format("woff"), /* chrome、firefox */
|
||||||
|
url("7f37946c45abf5482c243bf326f82628.ttf") format("truetype"), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
|
||||||
|
url("7f37946c45abf5482c243bf326f82628.svg#Bus Led Display Small") format("svg"); /* iOS 4.1- */
|
||||||
|
}
|
||||||
|
|
||||||
|
.busled{
|
||||||
|
color: #ccc;
|
||||||
|
background: #000;
|
||||||
|
font-family:"Bus Led Display Small" !important;
|
||||||
|
font-size:2em;
|
||||||
|
font-style:normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-webkit-text-stroke-width: 0.7px;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
.navled{
|
||||||
|
color: #ccc;
|
||||||
|
background: #000;
|
||||||
|
font-family:"Bus Led Display Small" !important;
|
||||||
|
font-size:1.5em;
|
||||||
|
margin-left: 2px;
|
||||||
|
font-style:normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-webkit-text-stroke-width: 0.7px;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
.submit {
|
||||||
|
background: #000;
|
||||||
|
color: #f0f0f0;
|
||||||
|
width: 90px;
|
||||||
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 15px;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-family:"Bus Led Display Small" !important;
|
||||||
|
font-size:1.1em;
|
||||||
|
font-style:normal;
|
||||||
|
border: 1px solid #445;
|
||||||
|
-webkit-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
-moz-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
}
|
||||||
|
.submite {
|
||||||
|
background: #000;
|
||||||
|
color: #f0f0f0;
|
||||||
|
width: 120px;
|
||||||
|
height: 25px;
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 15px;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-family:"Bus Led Display Small" !important;
|
||||||
|
font-size:1.3em;
|
||||||
|
font-style:normal;
|
||||||
|
border: 1px solid #033;
|
||||||
|
-webkit-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
-moz-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
}
|
||||||
|
.submitalign {
|
||||||
|
background: #000;
|
||||||
|
color: #f0f0f0;
|
||||||
|
width: 60px;
|
||||||
|
height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 15px;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-family:"Bus Led Display Small" !important;
|
||||||
|
font-size:1.4em;
|
||||||
|
font-style:normal;
|
||||||
|
border: 1px solid #001515;
|
||||||
|
-webkit-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
-moz-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
}
|
||||||
|
.submites {
|
||||||
|
background: #000;
|
||||||
|
color: #f0f0f0;
|
||||||
|
width: 30px;
|
||||||
|
height: 35px;
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 15px;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-family:"Bus Led Display Small" !important;
|
||||||
|
font-size:1.3em;
|
||||||
|
font-style:normal;
|
||||||
|
border: 1px solid #445;
|
||||||
|
-webkit-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
-moz-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
}
|
||||||
|
.submitext{
|
||||||
|
font-family: 'Bus Led Display Small';
|
||||||
|
color: #fff;
|
||||||
|
background: #000;
|
||||||
|
font-size: 5ex;"
|
||||||
|
border-radius: 5px;
|
||||||
|
border : #222222 2px solid;
|
||||||
|
-webkit-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
-moz-box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
box-shadow: 4px 6px 10px -1px rgba(0,0,0,0.72);
|
||||||
|
|
||||||
|
}
|
||||||
|
#overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 200px;
|
||||||
|
left: 650px;
|
||||||
|
-o-transform : scaleX(-1);
|
||||||
|
-webkit-transform : scaleX(-1);
|
||||||
|
transform : scaleX(-1);
|
||||||
|
-ms-filter : fliph; /*IE*/
|
||||||
|
filter : fliph; /*IE*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#videoel {
|
||||||
|
-o-transform : scaleX(-1);
|
||||||
|
-webkit-transform : scaleX(-1);
|
||||||
|
transform : scaleX(-1);
|
||||||
|
-ms-filter : fliph; /*IE*/
|
||||||
|
filter : fliph; /*IE*/
|
||||||
|
}
|
||||||
|
.lasertext {
|
||||||
|
font-size: small;
|
||||||
|
font-family: Helvetica, Verdana, Arial, sans-serif;
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
.mgalign {
|
||||||
|
color: #aaa;
|
||||||
|
text-align: middle;
|
||||||
|
font-family: 'Lucida Grande', Verdana, Arial, sans-serif;
|
||||||
|
display: grid;
|
||||||
|
height: 400px;
|
||||||
|
grid-template-columns: 200px 200px 200px 200px;
|
||||||
|
grid-template-rows: 1Fr;
|
||||||
|
|
||||||
|
border-width: 1px solid #445;
|
||||||
|
gap: 1px 1px;
|
||||||
|
grid-template-areas: ". . . . . . . . . .";
|
||||||
|
}
|
||||||
|
.lasergrid {
|
||||||
|
display: grid;
|
||||||
|
height: 323px;
|
||||||
|
width: 200px;
|
||||||
|
grid-template-columns: 62px 62px 62px;
|
||||||
|
grid-template-rows: 30px 19px 10px 55px 19px 20px 16px 55px 19px 25px 16px 55px 19px;
|
||||||
|
line-height: 1;
|
||||||
|
justify-items: center;
|
||||||
|
align-items: center;
|
||||||
|
color:#88c;
|
||||||
|
}
|
||||||
|
.lissabox {
|
||||||
|
display: grid;
|
||||||
|
height: 353px;
|
||||||
|
width: 126px;
|
||||||
|
grid-template-columns: 124px;
|
||||||
|
grid-template-rows: 15px 338px;
|
||||||
|
background-color: #000000;
|
||||||
|
background-image: linear-gradient(147deg, #000000 0%, #434343 374%);
|
||||||
|
line-height: 1;
|
||||||
|
padding: 6px;
|
||||||
|
justify-items: center;
|
||||||
|
align-items: center;
|
||||||
|
border-color: #334;
|
||||||
|
border-style: groove;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
5
www/css/font-awesome.min.css
vendored
Normal file
4522
www/css/fontawesome.css
vendored
Normal file
1
www/css/style.css
Normal file
@ -0,0 +1 @@
|
|||||||
|
* { box-sizing: border-box; } body {margin: 0;}.row{display:table;padding:10px;width:100%;}.cell{width:8%;display:table-cell;height:75px;}body, html{background-color:#1d1c25;margin:0;padding:0;}.range{-webkit-appearance:none;-moz-appearance:none;position:absolute;left:50%;top:50%;width:200px;margin-top:10px;transform:translate(-50%, -50%);}input[type=range]::-webkit-slider-runnable-track{-webkit-appearance:none;background:linear-gradient(45deg, rgba(59,173,227,1) 0%, rgba(87,111,230,1) 25%, rgba(152,68,183,1) 51%, rgba(255,53,127,1) 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#3bade3 ', endColorstr='#ff357f ', GradientType=1 );height:2px;}input[type=range]:focus{outline:none;}input[type=range]::-moz-range-track{-moz-appearance:none;background:linear-gradient(45deg, rgba(59,173,227,1) 0%, rgba(87,111,230,1) 25%, rgba(152,68,183,1) 51%, rgba(255,53,127,1) 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#3bade3 ', endColorstr='#ff357f ', GradientType=1 );height:2px;}input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;border:2px solid;border-radius:50%;height:25px;width:25px;max-width:80px;position:relative;bottom:11px;background-color:#1d1c25;cursor:-webkit-grab;-webkit-transition:border 1000ms ease;transition:border 1000ms ease;}input[type=range]::-moz-range-thumb{-moz-appearance:none;border:2px solid;border-radius:50%;height:25px;width:25px;max-width:80px;position:relative;bottom:11px;background-color:#1d1c25;cursor:-moz-grab;-moz-transition:border 1000ms ease;transition:border 1000ms ease;}.range.blue::-webkit-slider-thumb{border-color:rgb(59,173,227);}.range.ltpurple::-webkit-slider-thumb{border-color:rgb(87,111,230);}.range.purple::-webkit-slider-thumb{border-color:rgb(152,68,183);}.range.pink::-webkit-slider-thumb{border-color:rgb(255,53,127);}.range.blue::-moz-range-thumb{border-color:rgb(59,173,227);}.range.ltpurple::-moz-range-thumb{border-color:rgb(87,111,230);}.range.purple::-moz-range-thumb{border-color:rgb(152,68,183);}.range.pink::-moz-range-thumb{border-color:rgb(255,53,127);}input[type=range]::-webkit-slider-thumb:active{cursor:-webkit-grabbing;}input[type=range]::-moz-range-thumb:active{cursor:-moz-grabbing;}.range.blue{position:relative;background-color:rgba(31,27,27,0.09);width:75%;top:37.5px;}*{box-sizing:border-box;}body{margin:0;}#iy3nk{height:68px;}#il4ah{text-align:center;color:#ef4079;}#i7ox{font-family:Verdana, Geneva, sans-serif;color:#40acef;text-align:left;}#io5q{color:#40acef;}#iy2eh{text-align:center;}#i8a73{text-align:center;color:#4540ef;}#i3fzo{text-align:center;color:#7740ef;}#ikbjg{text-align:center;color:#b140ef;}@media (max-width: 768px){.cell{width:100%;display:block;}}
|
1
www/css/style2.css
Normal file
@ -0,0 +1 @@
|
|||||||
|
input[type=range]::-webkit-slider-runnable-track{-webkit-appearance:none;background:linear-gradient(45deg, rgba(59,173,227,1) 0%, rgba(87,111,230,1) 25%, rgba(152,68,183,1) 51%, rgba(255,53,127,1) 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#3bade3 ', endColorstr='#ff357f ', GradientType=1 );height:2px;}input[type=range]:focus{outline:none;}input[type=range]::-moz-range-track{-moz-appearance:none;background:linear-gradient(45deg, rgba(59,173,227,1) 0%, rgba(87,111,230,1) 25%, rgba(152,68,183,1) 51%, rgba(255,53,127,1) 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#3bade3 ', endColorstr='#ff357f ', GradientType=1 );height:2px;}input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;border:2px solid;border-radius:50%;height:25px;width:25px;max-width:80px;position:relative;bottom:11px;background-color:#1d1c25;cursor:-webkit-grab;-webkit-transition:border 1000ms ease;transition:border 1000ms ease;}input[type=range]::-moz-range-thumb{-moz-appearance:none;border:2px solid;border-radius:50%;height:25px;width:25px;max-width:80px;position:relative;bottom:11px;background-color:#1d1c25;cursor:-moz-grab;-moz-transition:border 1000ms ease;transition:border 1000ms ease;}.range.blue::-webkit-slider-thumb{border-color:rgb(59,173,227);}.range.ltpurple::-webkit-slider-thumb{border-color:rgb(87,111,230);}.range.purple::-webkit-slider-thumb{border-color:rgb(152,68,183);}.range.pink::-webkit-slider-thumb{border-color:rgb(255,53,127);}.range.blue::-moz-range-thumb{border-color:rgb(59,173,227);}.range.ltpurple::-moz-range-thumb{border-color:rgb(87,111,230);}.range.purple::-moz-range-thumb{border-color:rgb(152,68,183);}.range.pink::-moz-range-thumb{border-color:rgb(255,53,127);}input[type=range]::-webkit-slider-thumb:active{cursor:-webkit-grabbing;}input[type=range]::-moz-range-thumb:active{cursor:-moz-grabbing;}.range.blue{position:relative;background-color:rgba(31,27,27,0.09);width:75%;top:37.5px;}body{margin:0;}#iy3nk{font-family: "Lucida Grande", Verdana, Arial, sans-serif; font-size: 10ex; height:68px;}#il4ah{text-align:center;color:#ef4079;}#i7ox{font-family:Verdana, Geneva, sans-serif;color:#40acef;text-align:left;}#io5q{color:#40acef;}#iy2eh{text-align:center;}#i8a73{text-align:center;color:#4540ef;}#i3fzo{text-align:center;color:#7740ef;}#ikbjg{text-align:center;color:#b140ef;}@media (max-width: 768px){}
|
BIN
www/favicon-16x16.png
Executable file
After Width: | Height: | Size: 1.8 KiB |
BIN
www/favicon-32x32.png
Executable file
After Width: | Height: | Size: 2.5 KiB |
BIN
www/favicon.ico
Executable file
After Width: | Height: | Size: 15 KiB |
BIN
www/knobs/.DS_Store
vendored
Normal file
BIN
www/knobs/big0.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
www/knobs/big1.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
www/knobs/big2.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
www/knobs/big3.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
www/knobs/blue.png
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
www/knobs/blue.psd
Normal file
BIN
www/knobs/blue2.png
Normal file
After Width: | Height: | Size: 228 KiB |
37
www/knobs/close.svg
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 31.112 31.112" style="enable-background:new 0 0 31.112 31.112;" xml:space="preserve">
|
||||||
|
<polygon points="31.112,1.414 29.698,0 15.556,14.142 1.414,0 0,1.414 14.142,15.556 0,29.698 1.414,31.112 15.556,16.97
|
||||||
|
29.698,31.112 31.112,29.698 16.97,15.556 "/>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 672 B |
BIN
www/knobs/cyan.png
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
www/knobs/green.png
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
www/knobs/green.sync-conflict-20200612-000836.png
Normal file
After Width: | Height: | Size: 228 KiB |
BIN
www/knobs/indexs.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
www/knobs/lasergrid0.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
www/knobs/lasergrid1.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
www/knobs/lasergrid2.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
www/knobs/lasergrid3.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
www/knobs/leds.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
www/knobs/pink.png
Normal file
After Width: | Height: | Size: 77 KiB |
BIN
www/knobs/power.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
www/knobs/red.png
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
www/knobs/simplegray.png
Normal file
After Width: | Height: | Size: 222 KiB |
BIN
www/knobs/white.png
Normal file
After Width: | Height: | Size: 77 KiB |
BIN
www/knobs/yellow.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
www/launch.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
www/repository/calig.png
Normal file
After Width: | Height: | Size: 120 KiB |
BIN
www/repository/display.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
www/repository/layer.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
www/repository/lj2.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
www/repository/scenes.png
Normal file
After Width: | Height: | Size: 50 KiB |