First commit
459
README.md
Normal file
@ -0,0 +1,459 @@
|
||||
LJ v0.7.0
|
||||
|
||||
By Sam Neurohack, Loloster, Cocoa
|
||||
|
||||
LICENCE : CC BY
|
||||
|
||||
|
||||
|
||||
![LJ](http://www.teamlaser.fr/thsf/images/fulls/THSF9-33.jpg)
|
||||
|
||||
A software server with gui for up to 4 lasers live actions. Think creative like Laser "battles", planetarium,...
|
||||
|
||||
No .ild file here, you run your client that generate/send point lists to LJ. Any redis capable programming langage is fine.
|
||||
|
||||
Needs at least : an etherdream DAC connected to an ILDA laser, RJ 45 IP network (gigabits only !! no wifi, 100 mpbs doesn't work well with several lasers)
|
||||
|
||||
GUIs : WebUI, TouchOSC, Pure Data patch. You can build your own GUI and send/get commands to/from LJ through OSC. Attention : the Pure Data patch works with PD-extended 0.43. Any contribution for whatever "better" Pure Data version are welcome.
|
||||
|
||||
Devices supported : Launchpad mini, LP8, enttec DMX PRO, bhoreal, nozoids, gamepad, smartphone & tablet (with OSC like gyroscopes) and any MIDI controller that is recognised by your OS.
|
||||
|
||||
Nozosc : Semi modular synthetizers from Nozoids can send a lot of their inner sound curves and be displayed in many ways, i.e VCO 1 on X axis and LFO 2 on Y axis.
|
||||
|
||||
You can also send OSC commands to a video, music,... external software to trigger what you want.
|
||||
|
||||
|
||||
The server approach is based on redis. One process per etherdream is spawn to : retrieve the given point list from redis, warp, resample and manage the given etherdream DAC dialog.
|
||||
|
||||
|
||||
#
|
||||
# Features among many others.
|
||||
#
|
||||
|
||||
(Doc in progress)
|
||||
|
||||
- Automatically hook to Midi devices IN & OUT seen by OS. Very cool : LJ can script or be scripted by a midi device : Triggering different musics at given moments,... or in opposite, you can make a midi file with an external midi sequencer to script/trigger laser effects.
|
||||
- Automatic USB enttec PRO DMX interface detection. See mydmx.py
|
||||
- OSC server. Very cool : LJ can also script or be scripted with an OSC sequencer like Vezer or score.
|
||||
- OSC to midi bridge (see /note and /cc/number)
|
||||
- OSC to DMX bridge (see /cc/number)
|
||||
- Bhoreal and Launchpad device start animation
|
||||
- Control all leds of Bhoreal and Launchpad Mini through midi. Notes on and off, velocity is color.
|
||||
- Interactive (mouse style) warp correction for each laser.
|
||||
- Interactive (mouse style) any shape correction. Imagine you project on a building and want to use the windows like in a pinball. You need to define rectangle corner points and align them to the window, that's a shape you can use. The shape point list must be defined in the given laser "screen". See configuration file mainy.conf example.
|
||||
- Using python for client, you can use all bhorosc functions like control Resolume Arena video software through OSC :
|
||||
import bhorosc
|
||||
bhorosc.sendresol("/layer1/clip1/connect",1)
|
||||
|
||||
- Web ui : In your browser open webui/index.html. Javascript is needed.
|
||||
- Status every 0.5 seconds : every etherdream DAC state, number of buffer points sent,...
|
||||
- "Optimisation" points automatically added, can be changed live for glitch art. See
|
||||
|
||||
|
||||
#
|
||||
# External devices
|
||||
#
|
||||
|
||||
(Doc in Progress)
|
||||
|
||||
- LPD8 : A config file is included.
|
||||
- enttec USB pro
|
||||
- LaunchPad mini
|
||||
- Bhoreal
|
||||
- Joypads : Joypads are detected and read by pygame. You need to adapt the button mapping to your specific gamepad in the code. Search "joypad" in setexample.py
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Introduction
|
||||
#
|
||||
|
||||
|
||||
You need to update mainy.conf to your network/etherdreams IPs and Be sure to check command arguments : python mainyservers.py --help
|
||||
|
||||
LJ is meant for Live, so a lot of parameters can be changed via OSC/midi, webUI,...
|
||||
|
||||
|
||||
Program your own "Client" :
|
||||
-------------------------
|
||||
|
||||
- Read the Introduction part in this readme.
|
||||
- Carefully read all comments in clients examples.
|
||||
- Generate at least one point list array (say a square).
|
||||
- Feed your point list string to redis server
|
||||
|
||||
|
||||
If you need to receive data externally :
|
||||
|
||||
use /nozoid/osc/number value : Get the new value in gstt.osc[number] (number : 0-255)
|
||||
or program your own OSC commands in bhorosc.py
|
||||
|
||||
|
||||
|
||||
Joypads :
|
||||
---------
|
||||
|
||||
You need to decide what to do with joypads axis, hat, buttons. See joypads() in setexample.py. To adapt pygame button numbers to your gamepad use :
|
||||
|
||||
python joys.py
|
||||
|
||||
|
||||
|
||||
|
||||
"Shapes" :
|
||||
----------
|
||||
|
||||
"Shapes" are mouse editable areas i.e you make a flipper on a building and want something happen with the building windows. "Shapes" are the list of points you see at the beginning of conf file. "Shapes" are grouped in "Screens" that will be displayed by a given laser. See curve 0 in setexample.py
|
||||
Again "Shapes" are only mousely editable list of points : you can display them or not.
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Install
|
||||
#
|
||||
|
||||
In terminal type :
|
||||
|
||||
./install.sh
|
||||
|
||||
Check the bind line in /etc/redis/redis.conf :
|
||||
|
||||
- If client and laser servers computers are the same, use 127.0.0.1
|
||||
- Client and laser server are different, use the laser server computer IP.
|
||||
|
||||
In webui/index.html change the ws ip adress to the server IP or 127.0.0.1 if client computer = laser server computer.
|
||||
|
||||
Using the same idea check all ip address in mainy.conf.
|
||||
|
||||
For network Gurus : bind to all network interface scheme is not working yet.
|
||||
|
||||
|
||||
|
||||
#
|
||||
# To run
|
||||
#
|
||||
|
||||
Always start the laser server first.
|
||||
|
||||
Case 1 : the laser server computer is the same that the computer running a client :
|
||||
|
||||
python mainyservers.py
|
||||
|
||||
Open/reload in browser webui/index.html. (javascript must be enabled)
|
||||
|
||||
Check in your client if the server IP is the good one
|
||||
|
||||
Run your client
|
||||
|
||||
to monitor redis server :
|
||||
|
||||
redis-cli monitor
|
||||
|
||||
|
||||
Case 2 : Server and Client computers are different :
|
||||
|
||||
|
||||
Say the laser server computer (running LJ) IP is 192.138.1.13, the client computer is 192.168.1.52
|
||||
|
||||
On the server computer :
|
||||
edit /etc/redis/redis.conf
|
||||
python mainyservers.py -r 192.168.1.13
|
||||
|
||||
on the client computer for all features :
|
||||
|
||||
to just generate and send list points
|
||||
node testredis.js
|
||||
|
||||
to monitor redis server :
|
||||
|
||||
|
||||
redis-cli -h monitor
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Todo
|
||||
#
|
||||
|
||||
(Doc in Progress)
|
||||
|
||||
- Find 3D rotations matrices and 2 projections, test speed / normal algo with algotest.py
|
||||
- Smaller cpu footprint (compute only when something has changed,...)
|
||||
- kpps live modification for glitch art.
|
||||
- Improve Bhoreal & LaunchPad inputs
|
||||
- Tags for automatic laser load/ balancing
|
||||
- Texts : multilasers support, more fonts.
|
||||
- Improve WebUI with simulator.
|
||||
- tomidi should not disable other targets.
|
||||
- Warp corrections should not used warpdestinations default values in conf file.
|
||||
|
||||
|
||||
|
||||
#
|
||||
# LJ OSC commands :
|
||||
#
|
||||
|
||||
# General
|
||||
|
||||
/noteon number velocity
|
||||
: Note on sent to laser (see Midi below for notes effects). Noteon can also be send to midi targets if gstt.tomidi is True, but this disable all other targets for the moment. Todo.
|
||||
|
||||
/noteoff number : Note off is sent only to midi targets.
|
||||
|
||||
|
||||
/accxyz x y z : TouchOSC gyroscope x assigned to cc 1 and y assigned to cc 2. See Midi below for cc effects.
|
||||
|
||||
/gyrosc/gyro x y z : Change 3D rotation angles with gyroscope float values. i.e for GyrOSC iOS app. At this time Z is ignored and Z rotation set to 0
|
||||
|
||||
/point x y z : Set point coordinates for "slave" curve. Need to be changed change to collections deque as in llstr.py
|
||||
|
||||
/stop/rotation : Set all 3D rotations speed and 3D rotation angles to 0
|
||||
|
||||
/cc/number value : Change the cc with given value. Effect will depend on flags set to True : gstt.todmx (value is forwarded to dmx channel) , gstt.tomidi, gstt.tolaser (center align or curve mode). See cc effects below
|
||||
|
||||
/number value : switch current displayed curve to value.
|
||||
|
||||
/quit : Do nothing yet
|
||||
|
||||
|
||||
# Laser Control
|
||||
|
||||
|
||||
/display number : Select what point list (PL) is displayed by simulator
|
||||
|
||||
|
||||
/swap/X/lasernumber value (0 or 1)
|
||||
: switch on and off general X inversion on given laser
|
||||
|
||||
/swap/Y/lasernumber value (0 or 1)
|
||||
: switch on and off general Y inversion on given laser
|
||||
|
||||
|
||||
/loffset/X/lasernumber value
|
||||
: Move X center on given laser of value pixels
|
||||
|
||||
/loffset/Y/lasernumber value
|
||||
: Move Y center on given laser of value pixels
|
||||
|
||||
|
||||
/scale/X/lasernumber value
|
||||
: Stretch laser display of given laser of value
|
||||
|
||||
/scale/Y/lasernumber value
|
||||
: Stretch laser display of given laser of value
|
||||
|
||||
|
||||
/ip/lasernumber IP
|
||||
: Assign a new etherdream (by its IP adress) for given laser number
|
||||
|
||||
/angle/lasernumber value
|
||||
: Change geometric angle correction for given laser number by computing a new homgraphy
|
||||
|
||||
/intens/lasernumber value
|
||||
: Assign a new beam intensity for given laser (todo : if etherdream can actually change it)
|
||||
|
||||
/grid/lasernumber value (0 or 1)
|
||||
: Toggle a grid display for given laser
|
||||
|
||||
/mouse/lasernumber value (0 or 1)
|
||||
: Toggle the mapping function for given laser
|
||||
|
||||
|
||||
# Colors
|
||||
|
||||
For currently selected laser and in RGB Color mode (see below MIDI notes effects to switch Color mode and "current" laser selection)
|
||||
|
||||
/red 0 : Switch off blue laser.
|
||||
|
||||
/red 255 (or >0) Switch on blue laser
|
||||
|
||||
|
||||
/green 0 : Switch off blue laser
|
||||
|
||||
/green 255 (or >0) Switch on blue laser
|
||||
|
||||
|
||||
/blue 0 : Switch off blue laser
|
||||
|
||||
/blue 255 (or >0) Switch on blue laser
|
||||
|
||||
|
||||
|
||||
# Bhoreal and Launchpad devices
|
||||
|
||||
![Bhoreal](http://levfestival.com/13/wp-content/uploads/Bhoreal_2.jpg)
|
||||
|
||||
/led led number color : Switch on given led with given color.
|
||||
|
||||
/led/xy x y color Switch on led with x y position to given color.
|
||||
|
||||
/xy x y
|
||||
|
||||
/allcolorbhor : Switch all Bhoreal Leds with given colour (0-127)
|
||||
|
||||
/clsbhor : Switch off all bhoreal leds
|
||||
|
||||
/padmode : Code not available yet in LJay. Different modes available for Bhoreal and Launchpad. "Prompt" = 10 ; "Myxo" = 2 ; "Midifile" = 3
|
||||
|
||||
|
||||
|
||||
|
||||
# Nozoids synthetizers
|
||||
|
||||
![Nozoid synthetizer](http://nozoid.com/wp-content/uploads/2017/05/OCS_previus-600x330.png)
|
||||
|
||||
|
||||
|
||||
Functions originated by nozosc.py and executed in llstr.py (See Nozosc readme for complete OSC implementation and how to control Nozosc). A new firmware by loloster is mandatory for OCS 2 (https://github.com/loloster/ocs-2) and MMO3 (https://github.com/loloster/mmo-3). "curve" means on of the 4 curves managed by nozosc. setllstr.py as differents Set/Curve generator called by LJay that displays these 4 "curves";
|
||||
|
||||
|
||||
/nozoid/osc/number value : Store a new value for given oscillator/LFO/VCO
|
||||
|
||||
/nozoid/X value curve : Use given oscillator/LFO/VCO number as X axis for given curve . See llstr.py
|
||||
|
||||
/nozoid/Y value curve : use given oscillator/LFO/VCO number for Y axis for given curve. See llstr.py
|
||||
|
||||
/nozoid/color r g b curve : set current laser color for given curve
|
||||
|
||||
/nozoid/knob/number value : Not used yet
|
||||
|
||||
/nozoid/mix/number value : Not used yet
|
||||
|
||||
/nozoid/vco/number value : Not used yet
|
||||
|
||||
/nozoid/lfo/number value : Not used yet
|
||||
|
||||
|
||||
|
||||
# GUI
|
||||
|
||||
![Advanced Gui](http://www.teamlaser.fr/mcontroller.png)
|
||||
|
||||
/on : Accept a GUI with status widget. Automatically get its IP, send status,...
|
||||
|
||||
/off : Disconnect the GUI
|
||||
|
||||
/status text Display some text on status widget GUI
|
||||
|
||||
TouchOSC GUI button matrix
|
||||
|
||||
/clear : Clear status widget text.
|
||||
|
||||
/enter : should validate previous chosen number
|
||||
|
||||
/control/matrix/Y/X 0 or 1
|
||||
First screen ("Control") buttons toggle state : on or off
|
||||
|
||||
/pad/rights/note 0 or 1
|
||||
"Pad" screen (launchpad mini simulator screen), right column : Send note on and note off
|
||||
|
||||
/pad/tops/cc 0 or 1
|
||||
"Pad" screen top raw : Send CC 0/127
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Midi commands
|
||||
#
|
||||
|
||||
Midi Note : built in midi notes assignation. More : if you hook a midi led matrix like bhoreal, led are updated. See Noteon_Update() in bhorosc.py
|
||||
|
||||
0-7 Curve choice. Note on 0 to set Curve O, Note on 1 for Curve 1,...
|
||||
|
||||
8-15 Set choice. All happening Live, so as the new Set may not have the same Curve number, changing Set autoselect the builtin "black" curve (-1) as a fallback, so you can safely choose a new Curve in the new Set.
|
||||
Example : to switch to Set 0, use note on 8. For Set 1 use note on 9,....
|
||||
|
||||
16-23 Laser choice. "Current laser" choice
|
||||
Example : to switch to Laser 0, use note on 16. For Laser 1 use note on 17,....
|
||||
|
||||
|
||||
24-31 SimuPL choice. Example : to display PL 0 on simulator it's note on 24. To display PL 1 on simulator it's note on 25....
|
||||
|
||||
57 Color mode : Rainbow
|
||||
|
||||
58 Color mode : RGB
|
||||
|
||||
|
||||
Midi CC channel effects (0-127) built in assignation, *only* if you use built in 3D rotation and 2D projection in your code. You can assign any CC to any function you code. You can get current value in gstt.cc[ccnumber]. See setexample.py
|
||||
|
||||
1 X position
|
||||
|
||||
2 Y position
|
||||
|
||||
5 X select for Lissa curves (set curve )
|
||||
|
||||
6 Y select for Lissa curves (set curve )
|
||||
|
||||
|
||||
21 3D projection : FOV
|
||||
|
||||
22 3D projection : Distance
|
||||
|
||||
|
||||
29 3D Rotation speed X
|
||||
|
||||
30 3D Rotation speed Y
|
||||
|
||||
31 3D Rotation speed Z
|
||||
|
||||
|
||||
#
|
||||
# Resolume Arena commands
|
||||
#
|
||||
|
||||
A dedicated OSC client is built in. To send OSC commands to resolume use something like
|
||||
|
||||
bhorosc.sendresol("/layer1/clip1/connect",1)
|
||||
|
||||
Remember to specify Resolume IP and port in the beginning of bhorosc.py
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Ether dream configuration
|
||||
#
|
||||
|
||||
![Etherdream Laser DAC](https://www.ether-dream.com/ed2-external.jpg)
|
||||
|
||||
This program suppose that the ether dream is configured in a certain way especially for its IP address. For ether dream 1 : write an autoplay.txt file inside an SD Card within the ether dream DAC, with the following lines you can adjust i.e for pps or fps. Yes, there is a builtin DHCP client in the ether dream DAC but if you run multiple lasers, having a fixed dedicated network makes you focus on laser stuff.
|
||||
|
||||
/net/ipaddr 192.168.1.3
|
||||
|
||||
/net/netmask 255.255.255.0
|
||||
|
||||
/net/gateway 192.168.1.1
|
||||
|
||||
/ilda/pps 25000
|
||||
|
||||
/ilda/fps 25
|
||||
|
||||
About hardware setup, especially if you have several lasers : ILDA cables are insanely expensive. You may consider the Power Over Ethernet 'POE' option. Buy a very small ILDA cable, a POE splitter and connect everything to the ether dream fixed near your laser. You can have then a simple and very long network cable and use a Power Over Ethernet injector or switch closed to the driving computer. Beware some vendors use 24V POE Injector : POE injectors and splitters must match.
|
||||
|
||||
|
||||
#
|
||||
# Coordinates if you use the proj() function
|
||||
#
|
||||
|
||||
3D points (x,y,z) has *0,0,0 in the middle*
|
||||
A square centered around origin and size 200 (z =0 is added automatically) :
|
||||
([-200, -200, 0], [200, -200, 0], [200, 200, 0], [-200, 200, 0], [-200, -200, 0])
|
||||
|
||||
Pygame screen points are 2D. *0,0 is top left*
|
||||
with no 3D rotations + 3D -> 2D Projection + translation to top left:
|
||||
[(300.0, 400.0), (500.0, 400.0), (500.0, 200.0), (300.0, 200.0), (300.0, 400.0)]
|
||||
|
||||
|
||||
Pygame points with color is fed to laser renderer
|
||||
[(300.0, 400.0, 0), (500.0, 400.0, 16776960), (500.0, 200.0, 16776960), (300.0, 200.0, 16776960), (300.0, 400.0, 16776960)]
|
||||
|
||||
|
||||
Laser points traced
|
||||
|
||||
Because of blanking many points are automatically added and converted in etherdream coordinates system -32765 to +32765 in x and y axis.
|
||||
|
||||
16 (-1500.0, 1500.0, 65280, 65280, 0), (-1500.0, 1500.0, 65280, 65280, 0), (-1500.0, 1500.0, 65280, 65280, 0), (-1500.0, 1500.0, 65280, 65280, 0), (-1500.0, 1500.0, 65280, 65280, 0), (-1500.0, 1500.0, 65280, 65280, 0), (-1500.0, 1500.0, 65280, 65280, 0), (-1500.0, 1500.0, 65280, 65280, 0), (-1500.0, 1500.0, 0, 0, 0), (-1500.0, 1500.0, 0, 0, 0), (-1500.0, 1500.0, 0, 0, 0), (-1500.0, 1500.0, 0, 0, 0), (-1500.0, 1500.0, 0, 0, 0), (-1500.0, 1500.0, 0, 0, 0), (-1500.0, 1500.0, 0, 0, 0), (-1500.0, 1500.0, 0, 0, 0)
|
||||
8 (1500.0, 1500.0, 65280, 65280, 0), (1500.0, 1500.0, 65280, 65280, 0), (1500.0, 1500.0, 65280, 65280, 0), (1500.0, 1500.0, 65280, 65280, 0), (1500.0, 1500.0, 65280, 65280, 0), (1500.0, 1500.0, 65280, 65280, 0), (1500.0, 1500.0, 65280, 65280, 0), (1500.0, 1500.0, 65280, 65280, 0)
|
||||
8 (1500.0, -1500.0, 65280, 65280, 0), (1500.0, -1500.0, 65280, 65280, 0), (1500.0, -1500.0, 65280, 65280, 0), (1500.0, -1500.0, 65280, 65280, 0), (1500.0, -1500.0, 65280, 65280, 0), (1500.0, -1500.0, 65280, 65280, 0), (1500.0, -1500.0, 65280, 65280, 0), (1500.0, -1500.0, 65280, 65280, 0)
|
||||
8 (-1500.0, -1500.0, 65280, 65280, 0), (-1500.0, -1500.0, 65280, 65280, 0), (-1500.0, -1500.0, 65280, 65280, 0), (-1500.0, -1500.0, 65280, 65280, 0), (-1500.0, -1500.0, 65280, 65280, 0), (-1500.0, -1500.0, 65280, 65280, 0), (-1500.0, -1500.0, 65280, 65280, 0), (-1500.0, -1500.0, 65280, 65280, 0)
|
163
cli.py
Normal file
@ -0,0 +1,163 @@
|
||||
# coding=UTF-8
|
||||
"""
|
||||
LJay/LJ
|
||||
|
||||
v0.8
|
||||
|
||||
Command line arguments parser
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
"""
|
||||
|
||||
|
||||
import gstt
|
||||
import argparse
|
||||
|
||||
|
||||
def handle():
|
||||
|
||||
if gstt.debug > 2:
|
||||
print ""
|
||||
print "Arguments parsing if needed..."
|
||||
#have to be done before importing bhorosc.py to get correct port assignment
|
||||
argsparser = argparse.ArgumentParser(description="LJay")
|
||||
argsparser.add_argument("-r","--redisIP",help="Redis computer IP address (gstt.LjayServerIP by default)",type=str)
|
||||
argsparser.add_argument("-i","--iport",help="OSC port number to listen to (8001 by default)",type=int)
|
||||
argsparser.add_argument("-o","--oport",help="OSC port number to send to (8002 by default)",type=int)
|
||||
argsparser.add_argument("-x","--invx",help="Invert laser 0 X axis again",action="store_true")
|
||||
argsparser.add_argument("-y","--invy",help="Invert laser 0 Y axis again",action="store_true")
|
||||
argsparser.add_argument("-s","--set",help="Only for VJ version. Specify wich generator set to use (default is in gstt.py)",type=int)
|
||||
argsparser.add_argument("-c","--curve",help="Only for VJ version. Specify with generator curve to use (default is in gstt.py)",type=int)
|
||||
argsparser.add_argument("-a","--align",help="Reset laser 0 alignement values",action="store_true")
|
||||
argsparser.add_argument("-d","--display",help="Point List number displayed in pygame simulator",type=int)
|
||||
argsparser.add_argument("-v","--verbose",help="Debug mode 0,1 or 2.",type=int)
|
||||
argsparser.add_argument("-L","--Lasers",help="Number of lasers connected.",type=int)
|
||||
argsparser.add_argument("-b","--bhoroscIP",help="Computer IP running bhorosc ('127.0.0.1' by default)",type=str)
|
||||
argsparser.add_argument("-n","--nozoscIP",help="Computer IP running Nozosc ('127.0.0.1' by default)",type=str)
|
||||
|
||||
|
||||
|
||||
# Keep it ! if new features of cli.py is used in a monolaser program
|
||||
# argsparser.add_argument("-l","--laser",help="Last digit of etherdream ip address 192.168.1.0/24 (4 by default). Localhost if digit provided is 0.",type=int)
|
||||
|
||||
|
||||
args = argsparser.parse_args()
|
||||
|
||||
|
||||
# Ports arguments
|
||||
if args.iport:
|
||||
iport = args.iport
|
||||
gstt.iport = iport
|
||||
else:
|
||||
iport = gstt.iport
|
||||
|
||||
if args.oport:
|
||||
oport = args.oport
|
||||
gstt.oport = oport
|
||||
else:
|
||||
oport = gstt.oport
|
||||
|
||||
if gstt.debug > 0:
|
||||
print "gstt.oport:",gstt.oport
|
||||
print "gstt.iport:",gstt.iport
|
||||
|
||||
|
||||
# X Y inversion arguments
|
||||
if args.invx == True:
|
||||
|
||||
gstt.swapX[0] = -1 * gstt.swapX[0]
|
||||
gstt.centerx[0] = 0
|
||||
gstt.centery[0] = 0
|
||||
#WriteSettings()
|
||||
print("laser 0 X new invertion Asked")
|
||||
if gstt.swapX[0] == 1:
|
||||
print ("X not Inverted")
|
||||
else:
|
||||
print ("X Inverted")
|
||||
|
||||
if args.invy == True:
|
||||
|
||||
gstt.swapY[0] = -1 * gstt.swapY[0]
|
||||
gstt.centerx[0] = 0
|
||||
gstt.centery[0] = 0
|
||||
#WriteSettings()
|
||||
print("laser 0 Y new invertion Asked")
|
||||
if gstt.swapY[0] == 1:
|
||||
print ("Y not Inverted")
|
||||
else:
|
||||
print("Y inverted")
|
||||
|
||||
# Redis Computer IP
|
||||
if args.redisIP != None:
|
||||
gstt.LjayServerIP = args.redisIP
|
||||
|
||||
|
||||
# Set / Curves arguments
|
||||
if args.set != None:
|
||||
gstt.Set = args.set
|
||||
print "Set : " + str(gstt.Set)
|
||||
|
||||
if args.curve != None:
|
||||
gstt.Curve = args.curve
|
||||
print "Curve : " + str(gstt.Curve)
|
||||
|
||||
|
||||
# Point list number used by simulator
|
||||
if args.display != None:
|
||||
gstt.simuPL = args.display
|
||||
print "Display : " + str(gstt.simuPL)
|
||||
|
||||
|
||||
|
||||
# Verbose = debug
|
||||
if args.verbose != None:
|
||||
gstt.debug = args.verbose
|
||||
|
||||
|
||||
# Lasers = number of laser connected
|
||||
if args.Lasers != None:
|
||||
gstt.LaserNumber = args.Lasers
|
||||
|
||||
|
||||
if args.bhoroscIP != None:
|
||||
gstt.oscIPin = args.bhoroscIP
|
||||
else:
|
||||
gstt.oscIPin = '127.0.0.1'
|
||||
|
||||
if args.nozoscIP != None:
|
||||
gstt.nozoscIP = args.nozoscIP
|
||||
else:
|
||||
gstt.nozoscIP = '127.0.0.1'
|
||||
|
||||
# Etherdream target for mono laser program
|
||||
'''
|
||||
if args.laser != None:
|
||||
lstdgtlaser = args.laser
|
||||
|
||||
if lstdgtlaser == 0:
|
||||
etherIP = "127.0.0.1"
|
||||
else:
|
||||
etherIP = "192.168.1."+str(lstdgtlaser)
|
||||
|
||||
else:
|
||||
etherIP = "192.168.1.4"
|
||||
|
||||
#print ("Laser 1 etherIP:",etherIP)
|
||||
'''
|
||||
|
||||
# Reset alignment values
|
||||
if args.align == True:
|
||||
|
||||
gstt.centerx[0] = 0
|
||||
gstt.centery[0] = 0
|
||||
gstt.zoomx[0] = 15
|
||||
gstt.zoomy[0] = 15
|
||||
gstt.sizex[0] = 32000
|
||||
gstt.sizey[0] = 32000
|
||||
gstt.finangle[0] = 0.0
|
||||
gstt.swapx[0] = 1
|
||||
gstt.swapy[0] = 1
|
||||
#Settings.Write()
|
||||
|
114
clients/framy.py
Normal file
@ -0,0 +1,114 @@
|
||||
# coding=UTF-8
|
||||
|
||||
'''
|
||||
LJay v0.8.0
|
||||
|
||||
|
||||
LICENCE : CC
|
||||
pclf, Sam Neurohack
|
||||
|
||||
'''
|
||||
|
||||
import math
|
||||
import redis
|
||||
|
||||
redisIP = '192.168.1.13'
|
||||
r = redis.StrictRedis(host=redisIP, port=6379, db=0)
|
||||
|
||||
point_list = []
|
||||
pl = [[],[],[],[]]
|
||||
|
||||
def LineTo(xy, c, PL):
|
||||
|
||||
pl[PL].append((xy + (c,)))
|
||||
|
||||
def Line(xy1, xy2, c, PL):
|
||||
LineTo(xy1, 0, PL)
|
||||
LineTo(xy2, c , PL)
|
||||
|
||||
|
||||
def PolyLineOneColor(xy_list, c, PL , closed ):
|
||||
#print "--"
|
||||
#print "c",c
|
||||
#print "xy_list",xy_list
|
||||
#print "--"
|
||||
xy0 = None
|
||||
for xy in xy_list:
|
||||
if xy0 is None:
|
||||
xy0 = xy
|
||||
#print "xy0:",xy0
|
||||
LineTo(xy0,0, PL)
|
||||
else:
|
||||
#print "xy:",xy
|
||||
LineTo(xy,c, PL)
|
||||
if closed:
|
||||
LineTo(xy0,c, PL)
|
||||
|
||||
|
||||
# Computing points coordinates for rPolyline function from 3D and around 0,0 to pygame coordinates
|
||||
def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
|
||||
|
||||
x = xy[0] * resize
|
||||
y = xy[1] * resize
|
||||
z = 0
|
||||
|
||||
rad = rotx * math.pi / 180
|
||||
cosaX = math.cos(rad)
|
||||
sinaX = math.sin(rad)
|
||||
|
||||
y2 = y
|
||||
y = y2 * cosaX - z * sinaX
|
||||
z = y2 * sinaX + z * cosaX
|
||||
|
||||
rad = roty * math.pi / 180
|
||||
cosaY = math.cos(rad)
|
||||
sinaY = math.sin(rad)
|
||||
|
||||
z2 = z
|
||||
z = z2 * cosaY - x * sinaY
|
||||
x = z2 * sinaY + x * cosaY
|
||||
|
||||
rad = rotz * math.pi / 180
|
||||
cosZ = math.cos(rad)
|
||||
sinZ = math.sin(rad)
|
||||
|
||||
x2 = x
|
||||
x = x2 * cosZ - y * sinZ
|
||||
y = x2 * sinZ + y * cosZ
|
||||
|
||||
#print xy, (x + xpos,y+ ypos)
|
||||
return (x + xpos,y+ ypos)
|
||||
'''
|
||||
to understand why it get negative Y
|
||||
|
||||
# 3D to 2D projection
|
||||
factor = 4 * gstt.cc[22] / ((gstt.cc[21] * 8) + z)
|
||||
print xy, (x * factor + xpos, - y * factor + ypos )
|
||||
return (x * factor + xpos, - y * factor + ypos )
|
||||
'''
|
||||
|
||||
# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos
|
||||
#def rPolyLineOneColor(self, xy_list, c, PL , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
|
||||
def rPolyLineOneColor(xy_list, c, PL , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
|
||||
xy0 = None
|
||||
for xy in xy_list:
|
||||
if xy0 is None:
|
||||
xy0 = xy
|
||||
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),0, PL)
|
||||
else:
|
||||
LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz),c, PL)
|
||||
if closed:
|
||||
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL)
|
||||
|
||||
|
||||
# set all points for given laser. special behavior depends on GridDisplay flag
|
||||
# 0: point list / 1: Grid
|
||||
def LinesPL(PL):
|
||||
|
||||
if r.set('/pl/'+str(PL), str(pl[PL])) == True:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def ResetPL(self, PL):
|
||||
pl[PL] = []
|
91
clients/nodeclient.js
Normal file
@ -0,0 +1,91 @@
|
||||
// Send points lists to redis server
|
||||
// In compatible LJay string format (pythonic lists)
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient(6379,'192.168.1.13');
|
||||
|
||||
|
||||
|
||||
function rgb2int(r,g,b) {
|
||||
// Generate color from r g b components
|
||||
var color = hex(r) + hex(g) + hex(b);
|
||||
return parseInt(color, 16)
|
||||
}
|
||||
|
||||
function hex(v) {
|
||||
// Get hexadecimal numbers.
|
||||
var hex = v.toString(16);
|
||||
if (v < 16) {
|
||||
hex = "0" + hex;
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
// add one dot to Laser 0 point list
|
||||
function adddot0(dotdata){
|
||||
var dotstring = "(" + dotdata + "),";
|
||||
pl0 += dotstring;
|
||||
}
|
||||
|
||||
// add one dot to Laser 1 point list
|
||||
function adddot1(dotdata){
|
||||
var dotstring = "(" + dotdata + "),";
|
||||
pl1 += dotstring;
|
||||
}
|
||||
|
||||
// Generate same square to laser 0 and laser 1
|
||||
function GenPoints()
|
||||
{
|
||||
var pt = {};
|
||||
|
||||
// direct colors, i.e red
|
||||
pt.r = 255;
|
||||
pt.g = 0;
|
||||
pt.b = 0;
|
||||
|
||||
// named colors
|
||||
var white = rgb2int(255, 255, 255);
|
||||
|
||||
pt.x = 100;
|
||||
pt.y = 200;
|
||||
adddot0([pt.x, pt.y, rgb2int(pt.r, pt.g, pt.b)]);
|
||||
adddot1([pt.x, pt.y, rgb2int(pt.r, pt.g, pt.b)]);
|
||||
|
||||
pt.x = 100;
|
||||
pt.y = 300;
|
||||
adddot0([pt.x, pt.y, white]);
|
||||
adddot1([pt.x, pt.y, white]);
|
||||
|
||||
pt.x = 200;
|
||||
pt.y = 300;
|
||||
adddot0([pt.x, pt.y, white]);
|
||||
adddot1([pt.x, pt.y, white]);
|
||||
|
||||
pt.x = 200;
|
||||
pt.y = 200;
|
||||
adddot0([pt.x, pt.y, white]);
|
||||
adddot1([pt.x, pt.y, white]);
|
||||
|
||||
pt.x = 100;
|
||||
pt.y = 200;
|
||||
adddot0([pt.x, pt.y, white]);
|
||||
adddot1([pt.x, pt.y, white]);
|
||||
}
|
||||
|
||||
// Point lists strings
|
||||
var pl0 = "[";
|
||||
var pl1 = "[";
|
||||
GenPoints();
|
||||
pl0 = pl0.slice(0,-1) + "]"
|
||||
pl1 = pl1.slice(0,-1) + "]"
|
||||
|
||||
console.log(pl0);
|
||||
console.log(pl1);
|
||||
|
||||
// Send points lists to redis server
|
||||
client.set("/pl/0",pl0);
|
||||
client.set("/pl/1",pl1);
|
||||
|
||||
// Quit
|
||||
client.quit()
|
||||
|
56
clients/pyclient.py
Normal file
@ -0,0 +1,56 @@
|
||||
# coding=UTF-8
|
||||
|
||||
'''
|
||||
Multi Laser client example
|
||||
|
||||
LICENCE : CC
|
||||
'''
|
||||
|
||||
import redis
|
||||
|
||||
# IP defined in /etd/redis/redis.conf
|
||||
redisIP = '127.0.0.1'
|
||||
|
||||
r = redis.StrictRedis(host=redisIP, port=6379, db=0)
|
||||
|
||||
# (x,y,color in integer) 65280 is color #00FF00
|
||||
# Green rectangular shape :
|
||||
pl0 = [(100,300,65280),(200,300,65280),(200,200,65280),(100,200,65280)]
|
||||
|
||||
|
||||
# If you want to use rgb for color :
|
||||
def rgb2int(r,g,b):
|
||||
return int('0x%02x%02x%02x' % (r,g,b),0)
|
||||
|
||||
# White rectangular shape
|
||||
pl1 = [(100,300,rgb2int(255,255,255)),(200,300,rgb2int(255,255,255)),(200,200,rgb2int(255,255,255)),(100,200,rgb2int(255,255,255))]
|
||||
|
||||
# Send to laser 0 (see mainy.conf)
|
||||
r.set('/pl/0', str(pl0))
|
||||
|
||||
# Send to laser 1 (see mainy.conf)
|
||||
r.set('/pl/1', str(pl1))
|
||||
|
||||
r.set('/pl/2', str(pl1))
|
||||
|
||||
'''
|
||||
You can also use PolyLineOneColor or rPolylineOneColor to stack n point lists to build a "frame"
|
||||
|
||||
import framy
|
||||
|
||||
# for laser0 :
|
||||
|
||||
pl0 = [(100,300),(200,300),(200,200),(100,200)]
|
||||
framy.PolyLineOneColor(pl0, rgb2int(255,255,255), 0 , closed = False)
|
||||
# You can add as much polylineOneColor as you want = construct a "frame"
|
||||
# Then send it to the laser server :
|
||||
print "All one color lines sent to laser 0 :",framy.LinesPL(0) # Will be True is sent correctly
|
||||
|
||||
# instead of PolyLineOneColor you can use rPolylineOneColor to send 2D point list around 0,0 with 3D rotation,resizing and repositioning at xpos ypos
|
||||
# rPolylineOneColor is very useful to add different polylines to different position. Imagine different game elements.
|
||||
# rPolyLineOneColor(xy_list, c, PL , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
|
||||
# Send the pl0 to laser 1
|
||||
|
||||
framy.rPolyLineOneColor((pl0, c = rgb2int(255,255,255), PL = 1, closed = False, xpos = 200, ypos = 250, resize = 1, rotx =0, roty =0 , rotz=0)
|
||||
print "All one color lines sent to laser 1 :",framy.LinesPL(1) # Will be True is sent correctly
|
||||
'''
|
39
clients/rebclient.r
Normal file
@ -0,0 +1,39 @@
|
||||
REBOL []
|
||||
|
||||
outport: open/lines tcp://localhost:13857
|
||||
on: 1
|
||||
off: 0
|
||||
|
||||
pl0: "[(100,200, 0), (100,300, 65280), (200,300, 65280), (200,200, 65280), (100,200, 65280)]"
|
||||
|
||||
|
||||
oscommand: to-string reduce ["pl/0 " pl0]
|
||||
insert outport oscommand
|
||||
|
||||
for counter 1 2 1 [
|
||||
;; print counter
|
||||
oscommand: to-string reduce ["/40h/clear " on]
|
||||
insert outport oscommand
|
||||
wait 0.3
|
||||
|
||||
]
|
||||
|
||||
for counter 1 2 1 [
|
||||
for raw 0 7 1 [
|
||||
oscommand: to-string reduce ["/40h/led_row " raw " " on]
|
||||
insert outport oscommand
|
||||
wait 0.001
|
||||
]
|
||||
|
||||
]
|
||||
|
||||
for counter 1 2 1 [
|
||||
;; print counter
|
||||
oscommand: to-string reduce ["/40h/frame 0 126 126 126 126 126 126 0"]
|
||||
insert outport oscommand
|
||||
|
||||
wait 0.3
|
||||
|
||||
]
|
||||
|
||||
close outport
|
47
clients/rebserver.py
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
#!/usr/bin/env python
|
||||
# coding=UTF-8
|
||||
"""
|
||||
|
||||
TCP server for rebol links like from Amiga
|
||||
Forward /pl/lasernumber pointslist to redis server
|
||||
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
"""
|
||||
|
||||
import socket, time,random, redis
|
||||
|
||||
|
||||
r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
|
||||
|
||||
|
||||
|
||||
# TCP listener
|
||||
|
||||
TCP_IP = '127.0.0.1'
|
||||
TCP_PORT = 13857
|
||||
BUFFER_SIZE = 1024 # Normally 1024, but we want fast response
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind((TCP_IP, TCP_PORT))
|
||||
s.listen(1)
|
||||
conn, addr = s.accept()
|
||||
print 'Connection address:', addr
|
||||
|
||||
|
||||
while 1:
|
||||
data = conn.recv(BUFFER_SIZE)
|
||||
if not data: break
|
||||
#print "received data:", data
|
||||
commands = data.split()
|
||||
nb_oscargs = len(commands)
|
||||
print commands
|
||||
|
||||
#r.set('/pl/'+str(PL), str(something to code with commands, nb_oscargs))
|
||||
#conn.send(data) # echo
|
||||
|
||||
|
||||
conn.close()
|
8
clients/redclient.red
Normal file
@ -0,0 +1,8 @@
|
||||
Red []
|
||||
|
||||
|
||||
#https://github.com/red/red/wiki/[DOC]-Guru-Meditations#how-to-make-http-requests
|
||||
|
||||
pl0: "[(100,200, 0), (100,300, 65280), (200,300, 65280), (200,200, 65280), (100,200, 65280)]"
|
||||
|
||||
read http://127.0.0.1:13857/path?name="jones"
|
57
clients/redserver.py
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
#!/usr/bin/env python
|
||||
# coding=UTF-8
|
||||
"""
|
||||
|
||||
Http server for red 0.6.4
|
||||
Forward /pl/lasernumber pointslist to redis server
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
"""
|
||||
|
||||
|
||||
import redis
|
||||
|
||||
r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
|
||||
|
||||
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
|
||||
|
||||
PORT_NUMBER = 8080
|
||||
|
||||
#This class will handles any incoming request from
|
||||
#the browser
|
||||
class myHandler(BaseHTTPRequestHandler):
|
||||
|
||||
#Handler for the GET requests
|
||||
def do_GET(self):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type','text/html')
|
||||
self.end_headers()
|
||||
|
||||
# Send the html message
|
||||
self.wfile.write("Hello World !")
|
||||
|
||||
# r.set('/pl/'+str(PL), str(self.grid_points))
|
||||
|
||||
return
|
||||
|
||||
try:
|
||||
#Create a web server and define the handler to manage the
|
||||
#incoming request
|
||||
server = HTTPServer(('', PORT_NUMBER), myHandler)
|
||||
print 'Started httpserver on port ' , PORT_NUMBER
|
||||
|
||||
#Wait forever for incoming htto requests
|
||||
server.serve_forever()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print '^C received, shutting down the web server'
|
||||
server.socket.close()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
230
gstt.py
Normal file
@ -0,0 +1,230 @@
|
||||
# coding=UTF-8
|
||||
'''
|
||||
Etat global (anciennement singleton de la classe GameState + autres VARIABLES nécessaires partout)"
|
||||
'''
|
||||
|
||||
#from globalVars import *
|
||||
|
||||
#ConfigName = "setexample.conf"
|
||||
ConfigName = "mainy.conf"
|
||||
|
||||
debug = 0
|
||||
|
||||
anims= [[],[],[],[]]
|
||||
|
||||
# How many lasers are connected. Different that "currentlaser" used by bhorosc
|
||||
LaserNumber = 2
|
||||
screen_size = [800,600]
|
||||
xy_center = [screen_size[0]/2,screen_size[1]/2]
|
||||
|
||||
# Will be overriden by mainy.conf file data
|
||||
LjayServerIP = '192.168.1.13'
|
||||
oscIPin = '192.168.1.15'
|
||||
nozoscip = '192.168.1.15'
|
||||
|
||||
# gstt.Laser select to what laser modifcation will occur.
|
||||
# Can be changed with /noteon 16-23
|
||||
Laser = 2
|
||||
|
||||
# gstt.simuPL select what point list number to display in pygame simulator
|
||||
# Can be changed with /noteon 24-31
|
||||
simuPL = 1
|
||||
|
||||
# gstt.laserIPS. Will be overridden by the ConfigName (see below) file values
|
||||
lasersIPS = ['192.168.1.5','192.168.1.6','192.168.1.3','192.168.1.4']
|
||||
|
||||
|
||||
# gstt.laserPLS : What point list is sent to what laser.
|
||||
# ** Will be overridden by the ConfigName (see below) file values **
|
||||
lasersPLS = [0,1,2,0]
|
||||
|
||||
|
||||
# gstt.kpps stores kpps for each laser.
|
||||
# ** Will be overridden by the ConfigName (see below) file values **
|
||||
kpps = [25000,25000,25000,25000]
|
||||
|
||||
# gstt.GridDisplay : if = 1 Curve points actually sent to PL are replaced by a grid
|
||||
GridDisplay = [0,0,0,0]
|
||||
|
||||
# with 4 laser available, 4 PL only are necessary
|
||||
PL = [[],[],[],[]]
|
||||
|
||||
|
||||
# Transformation Matrix for each laser
|
||||
EDH = [[], [], [], []]
|
||||
|
||||
# Laser states
|
||||
# ipconn is initial newdac to its etherdream
|
||||
lstt_ipconn = [[-1], [-1], [-1], [-1]]
|
||||
# dacstt is dac light engine state
|
||||
lstt_dacstt = [[-1], [-1], [-1], [-1]]
|
||||
# store last dac answers ACK, not ACK
|
||||
lstt_dacanswers = [[-1], [-1], [-1], [-1]]
|
||||
# store last number of points sent to etherdreams buffer
|
||||
lstt_points = [[0], [0], [0], [0]]
|
||||
|
||||
swapX = [1,1,1,-1]
|
||||
swapY = [1,1,1,-1]
|
||||
|
||||
maxCurvesByLaser = 4
|
||||
|
||||
|
||||
# For glitch art : change position and decrease number of points added by newdac.py
|
||||
# shortline for lines shorter than 4000 (in etherdream coordinates)
|
||||
# i.e (0.25,3) means add 3 points at 25% on the line.
|
||||
stepshortline = [ (1.0, 8)]
|
||||
stepslongline = [ (0.25, 3), (0.75, 3), (1.0, 10)]
|
||||
|
||||
|
||||
#curveColor = [255,0,0] * maxCurvesByLaser
|
||||
#curveColor = [[0 for _ in range(3)] for _ in range(maxCurvesByLaser)]
|
||||
curveColor = [[255 for _ in range(3)] for _ in range(maxCurvesByLaser)]
|
||||
colorX = [[255 for _ in range(3)] for _ in range(maxCurvesByLaser)]
|
||||
colorY = [[255 for _ in range(3)] for _ in range(maxCurvesByLaser)]
|
||||
offsetX = [0] * maxCurvesByLaser
|
||||
offsetY = [0] * maxCurvesByLaser
|
||||
curveNumber = 0
|
||||
Curve = curveNumber
|
||||
XTimeAxe=30000
|
||||
YTimeAxe=30000
|
||||
|
||||
#curveX = [255,255,255] * maxCurvesByLaser
|
||||
#curveY = [255,255,255] * maxCurvesByLaser
|
||||
|
||||
Mode = 5
|
||||
|
||||
point = [0,0,0]
|
||||
|
||||
# gstt.colormode select what to display. Can be changed with /noteon 57-64
|
||||
colormode = 0
|
||||
color = [255,255,255]
|
||||
newcolor = 0
|
||||
|
||||
surpriseoff = 10
|
||||
surpriseon = 50
|
||||
surprisey = -10
|
||||
surprisex = -10
|
||||
|
||||
|
||||
cc = [0] * 256
|
||||
lfo = [0] * 10
|
||||
osc = [0] * 255
|
||||
oscInUse = [0] * 255
|
||||
knob = [0] * 33
|
||||
|
||||
stars0=[]
|
||||
stars1=[]
|
||||
stars2=[]
|
||||
#stars3=[]
|
||||
# Viewer distance (cc 21)
|
||||
cc[21]=60
|
||||
viewer_distance = cc[21] * 8
|
||||
|
||||
# fov (cc 22)
|
||||
cc[22]= 60
|
||||
fov = 4 * cc[22]
|
||||
|
||||
|
||||
|
||||
'''
|
||||
Also vailable with args : -v Value
|
||||
|
||||
if debug = 1 you get :
|
||||
|
||||
|
||||
if debug = 2 you get :
|
||||
- dac errors
|
||||
|
||||
'''
|
||||
|
||||
|
||||
JumpFlag =0
|
||||
|
||||
|
||||
# nice X (cc 5) Y (cc 6) curve at first
|
||||
cc[5] = cc[6] = 60
|
||||
|
||||
# Dot mode start at middle screen
|
||||
cc[1] = cc[2] = 63
|
||||
|
||||
note = 0
|
||||
velocity = 0
|
||||
|
||||
WingHere = -1
|
||||
BhorealHere = -1
|
||||
LaunchHere = -1
|
||||
BhorLeds = [0] * 64
|
||||
|
||||
oscx = 0
|
||||
oscy = 0
|
||||
oscz = 0
|
||||
|
||||
|
||||
# Ai Parameters
|
||||
|
||||
aivelocity = 0.5
|
||||
aiexpressivity = 0.5
|
||||
aisensibility = 0.5
|
||||
aibeauty = 0.5
|
||||
|
||||
|
||||
# OSC ports
|
||||
#temporaray fix hack : iport=nozoport
|
||||
iport = 8001 #LJay (bhorosc) input port
|
||||
oport = 8002 #LJay (bhorosc) output port
|
||||
noziport=8003 #nozosc.py receiving commands port
|
||||
nozoport=8001 #nozosc.py sending port to LJay (main.py)
|
||||
nozuport=0 #linux serial usb port connecting nozoid devices ACM0 by default
|
||||
|
||||
|
||||
X = [0] * maxCurvesByLaser
|
||||
Y = [0] * maxCurvesByLaser
|
||||
|
||||
# No rotation X (cc 29) Y (cc 30) Z (cc 31) at first
|
||||
cc[29] = cc[30] = cc[31] = prev_cc29 = 0
|
||||
prev_cc29 = prev_cc30 = prev_cc31 = -1
|
||||
|
||||
angleX = 0
|
||||
angleY = 0
|
||||
angleZ = 0
|
||||
|
||||
tomidi = False # currently tomidi bypass all other directions
|
||||
todmx = False
|
||||
toled = False
|
||||
tolaser = True
|
||||
tosynth = False
|
||||
|
||||
sernozoid = ""
|
||||
nozoid = ""
|
||||
serdmx = ""
|
||||
newnumber = ""
|
||||
oldnumber = ""
|
||||
|
||||
'''
|
||||
# will be overrided but settings.conf values.
|
||||
# legacy one laser only values
|
||||
centerx = LASER_CENTER_X
|
||||
centery = LASER_CENTER_Y
|
||||
zoomx = LASER_ZOOM_X
|
||||
zoomy = LASER_ZOOM_Y
|
||||
sizex = LASER_SIZE_X
|
||||
sizey = LASER_SIZE_Y
|
||||
finangle = LASER_ANGLE
|
||||
'''
|
||||
|
||||
# multilasers arrays
|
||||
# will be overrided but settings.conf values.
|
||||
centerX = [0,0,0,0]
|
||||
centerY = [0,0,0,0]
|
||||
zoomX = [0,0,0,0]
|
||||
zoomY = [0,0,0,0]
|
||||
sizeX = [0,0,0,0]
|
||||
sizeY = [0,0,0,0]
|
||||
finANGLE = [0,0,0,0]
|
||||
|
||||
warpdest = [[[ 1. , 0. , 0.],[ 0. , 1. , 0.],[ 0. , 0. , 1.]],
|
||||
[[ 1. , 0. , 0.],[ 0. , 1. , 0.],[ 0. , 0. , 1.]],
|
||||
[[ 1. , 0. , 0.],[ 0. , 1. , 0.],[ 0. , 0. , 1.]],
|
||||
[[ 1. , 0. , 0.],[ 0. , 1. , 0.],[ 0. , 0. , 1.]]
|
||||
]
|
||||
|
246
homographyp.py
Executable file
@ -0,0 +1,246 @@
|
||||
|
||||
#!/usr/bin/python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: Python -*-
|
||||
|
||||
'''
|
||||
|
||||
LJay/LJ
|
||||
v0.7.0
|
||||
|
||||
LICENCE : CC
|
||||
Sam Neurohack
|
||||
|
||||
Homographies for align + swap corrections and warp corrections
|
||||
|
||||
Align + swap homography if found with 4 original points and corrected coordinates
|
||||
Warp correction is disabled for the moment. Should be computed at warp edition : set 1 curve 1
|
||||
|
||||
Use the :
|
||||
|
||||
########################################################################
|
||||
# Module to compute homographies #
|
||||
# #
|
||||
# Author : Alexis Mignon #
|
||||
# email : alexis.mignon@info.unicaen.fr #
|
||||
# date : 10/03/2010 #
|
||||
########################################################################
|
||||
|
||||
Module to compute homographies between two sets of 2D points
|
||||
|
||||
implemented functions :
|
||||
- find_homography(points1,points2) : finds the homography between
|
||||
two sets of 2D points
|
||||
- find_affine_homography(points1,points2) : finds the affine
|
||||
homography between two sets of 2D points
|
||||
- apply_homography(H,points) : applies homography H to the set of
|
||||
2D points 'points'
|
||||
|
||||
example :
|
||||
>>> from homography import *
|
||||
>>>
|
||||
>>> points1 = np.array([[ 0., 0. ],
|
||||
>>> [ 1., 0. ],
|
||||
>>> [ 0., 1. ],
|
||||
>>> [ 1., 1. ]])
|
||||
>>>
|
||||
>>> points2 = np.array([[ 0. , 0. ],
|
||||
>>> [ 1. , 0. ],
|
||||
>>> [ 0.25, 1. ],
|
||||
>>> [ 0.75, 1. ]])
|
||||
>>>
|
||||
>>> points3 = np.array([[-1., 0.],
|
||||
>>> [ 0.,-1.],
|
||||
>>> [ 0., 1.],
|
||||
>>> [ 1., 0.]])
|
||||
>>>
|
||||
>>> H1 = find_homography(points1,points2)
|
||||
>>> print H1
|
||||
>>> print apply_homography(H1,points1)
|
||||
>>> H2 = find_affine_homography(points1,points3)
|
||||
>>> print H2
|
||||
>>> print apply_homography(H2,points1)
|
||||
'''
|
||||
|
||||
|
||||
import numpy as np
|
||||
import math
|
||||
from scipy.linalg import svd,lstsq
|
||||
import ast
|
||||
import gstt
|
||||
#from globalVars import xy_center
|
||||
import redis
|
||||
|
||||
|
||||
r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
|
||||
|
||||
def find(points1,points2):
|
||||
if points1.shape[0] != points2.shape[0] : raise ValueError("The number of input and output points mismatches")
|
||||
if points1.shape[1] == 2 :
|
||||
p1 = np.ones((len(points1),3),'float64')
|
||||
p1[:,:2] = points1
|
||||
elif points1.shape[1] == 3 : p1 = points1
|
||||
else : raise ValueError("Bad shape for input points")
|
||||
|
||||
if points2.shape[1] == 2 :
|
||||
p2 = np.ones((len(points2),3),'float64')
|
||||
p2[:,:2] = points2
|
||||
elif points2.shape[1] == 3 : p2 = points2
|
||||
else : raise ValueError("Bad shape for output points")
|
||||
|
||||
npoints = len(points1)
|
||||
|
||||
A = np.zeros((3*npoints,9),'float64')
|
||||
|
||||
for i in xrange(npoints):
|
||||
p1i = p1[i]
|
||||
x2i,y2i,w2i = p2[i]
|
||||
xpi = x2i*p1i
|
||||
ypi = y2i*p1i
|
||||
wpi = w2i*p1i
|
||||
|
||||
A[i*3 ,3:6] = -wpi
|
||||
A[i*3 ,6:9] = ypi
|
||||
A[i*3+1,0:3] = wpi
|
||||
A[i*3+1,6:9] = -xpi
|
||||
A[i*3+2,0:3] = -ypi
|
||||
A[i*3+2,3:6] = xpi
|
||||
|
||||
U,s,Vt = svd(A,full_matrices = False, overwrite_a = True)
|
||||
del U,s
|
||||
h = Vt[-1]
|
||||
H = h.reshape(3,3)
|
||||
return H
|
||||
|
||||
def find_affine(points1,points2):
|
||||
if points1.shape[0] != points2.shape[0] : raise ValueError("The number of input and output points mismatches")
|
||||
if points1.shape[1] == 2 :
|
||||
p1 = np.ones((len(points1),3),'float64')
|
||||
p1[:,:2] = points1
|
||||
elif points1.shape[1] == 3 : p1 = points1
|
||||
else : raise ValueError("Bad shape for input points")
|
||||
|
||||
if points2.shape[1] == 2 :
|
||||
p2 = np.ones((len(points2),3),'float64')
|
||||
p2[:,:2] = points2
|
||||
elif points2.shape[1] == 3 : p2 = points2
|
||||
else : raise ValueError("Bad shape for output points")
|
||||
|
||||
npoints = len(points1)
|
||||
|
||||
A = np.zeros((3*npoints,6),'float64')
|
||||
b = np.zeros((3*npoints,1),'float64')
|
||||
for i in xrange(npoints):
|
||||
p1i = p1[i]
|
||||
x2i,y2i,w2i = p2[i]
|
||||
xpi = x2i*p1i
|
||||
ypi = y2i*p1i
|
||||
wpi = w2i*p1i
|
||||
|
||||
A[i*3 ,3:6] = -wpi
|
||||
A[i*3+1,0:3] = wpi
|
||||
A[i*3+2,0:3] = -ypi
|
||||
A[i*3+2,3:6] = xpi
|
||||
|
||||
b[i*3 ] = -y2i*p1i[2]
|
||||
b[i*3+1] = x2i*p1i[2]
|
||||
|
||||
h = lstsq(A,b,overwrite_a = True, overwrite_b = True)[0]
|
||||
H = np.zeros( (3,3) , 'float64' )
|
||||
H[:2,:] = h.reshape(2,3)
|
||||
H[2,2] = 1
|
||||
return H
|
||||
|
||||
def apply(H,points):
|
||||
|
||||
p = np.ones((len(points),3),'float64')
|
||||
p[:,:2] = points
|
||||
pp = np.dot(p,H.T)
|
||||
pp[:,:2]/=pp[:,2].reshape(len(p),1)
|
||||
return pp[:,:2]
|
||||
|
||||
# Align and axis swap corrections
|
||||
# Reference points
|
||||
pointsref = np.array([(300.0, 400.0), (500.0, 400.0), (500.0, 200.0), (300.0, 200.0)])
|
||||
|
||||
def EDpoint(mylaser,(pygamex,pygamey)):
|
||||
|
||||
#print "current point : ", pygamex, pygamey
|
||||
XX = pygamex - gstt.xy_center[0]
|
||||
YY = pygamey - gstt.xy_center[1]
|
||||
CosANGLE = math.cos(gstt.finANGLE[mylaser])
|
||||
SinANGLE = math.sin(gstt.finANGLE[mylaser])
|
||||
# Multilaser style
|
||||
x = (gstt.xy_center[0] + ((XX * CosANGLE) - (YY * SinANGLE)) - gstt.xy_center[0]) * gstt.zoomX[mylaser] + gstt.centerX[mylaser]
|
||||
y = (gstt.xy_center[1] + ((XX * SinANGLE) + (YY * CosANGLE)) - gstt.xy_center[1]) * gstt.zoomY[mylaser] + gstt.centerY[mylaser]
|
||||
|
||||
if gstt.debug >0:
|
||||
|
||||
#print "global center :", xy_center
|
||||
|
||||
print "Laser :", mylaser, "center at : ", gstt.centerX[mylaser], gstt.centerY[mylaser]
|
||||
'''
|
||||
print "swaps : ", (gstt.swapX[mylaser]), str(gstt.swapY[mylaser])
|
||||
print "zooms : ", gstt.zoomX[mylaser], gstt.zoomY[mylaser]
|
||||
print "angles : ", gstt.finANGLE[mylaser]
|
||||
'''
|
||||
print "result : ", x * gstt.swapX[mylaser] , y * gstt.swapY[mylaser]
|
||||
return [x * gstt.swapX[mylaser] , y * gstt.swapY[mylaser]]
|
||||
|
||||
'''
|
||||
def EDpoint((pygamex,pygamey)):
|
||||
|
||||
XX = pygamex - xy_center[0]
|
||||
YY = pygamey - xy_center[1]
|
||||
CosANGLE = math.cos(finangle)
|
||||
SinANGLE = math.sin(finangle)
|
||||
# Multilaser style
|
||||
x = (xy_center[0] + ((XX * CosANGLE) - (YY * SinANGLE)) - xy_center[0]) * zoomx + centerx
|
||||
y = (xy_center[1] + ((XX * SinANGLE) + (YY * CosANGLE)) - xy_center[1]) * zoomy + centery
|
||||
|
||||
return [x*1, y*1]
|
||||
'''
|
||||
|
||||
|
||||
# New total homography from always the same reference points : ED (= align + swap) transform + warp transform.
|
||||
# WARP IS DISABLED. Some bug tracking is needed !
|
||||
def newEDH(mylaser):
|
||||
|
||||
EDpoints = []
|
||||
for point in xrange(4):
|
||||
EDpoints.append(EDpoint(mylaser,pointsref[point]))
|
||||
|
||||
# H matrix tansform pygame points in Etherdream system with align and swap correction,
|
||||
H = find(pointsref, np.array(EDpoints))
|
||||
|
||||
# Computer Hwarp matrix with previously reference warped points in configuration file.
|
||||
Hwarp = find(pointsref, gstt.warpdest[mylaser])
|
||||
#Hwarp = np.identity(3, dtype = float)
|
||||
# EDH matrix
|
||||
gstt.EDH[mylaser] = H
|
||||
|
||||
# EDH matrix is H x Hwarp
|
||||
#gstt.EDH[mylaser] = np.dot(H,Hwarp)
|
||||
print "Laser",mylaser,"NEW EDH computed, sending to redis..."
|
||||
r.set('/EDH/'+str(mylaser), np.array2string(gstt.EDH[mylaser], separator=','))
|
||||
|
||||
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
|
||||
order = r.get('/order')
|
||||
print order
|
||||
neworder = order & ~(1<< mylaser*2)
|
||||
neworder = neworder | (1<< 1+mylaser*2)
|
||||
r.set('/order', str(neworder))
|
||||
|
||||
if gstt.debug >1:
|
||||
print ""
|
||||
print "laser ", mylaser
|
||||
print "reference points", pointsref
|
||||
print "laser EDpoints :", EDpoints
|
||||
print "-> Computed H :",H
|
||||
#print "warped points coordinates ", gstt.warpdest[mylaser]
|
||||
#print "-> Computed Hwarp", Hwarp
|
||||
#print "laser ", mylaser, "warpd ",ast.literal_eval(gstt.warpdest[gstt.Laser])
|
||||
#print "laser ", mylaser, "Hwarp ", Hwarp
|
||||
#print ""
|
||||
print "-> new EDH :", gstt.EDH[mylaser]
|
||||
|
230
las.py
Normal file
@ -0,0 +1,230 @@
|
||||
# coding=UTF-8
|
||||
"""
|
||||
|
||||
LJ OSC handler
|
||||
v0.7.0
|
||||
|
||||
|
||||
LICENCE : CC
|
||||
by Sam Neurohack, Loloster,
|
||||
from /team/laser
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import types, time
|
||||
import gstt
|
||||
|
||||
#import colorify
|
||||
import homographyp
|
||||
import settings
|
||||
#import alignp
|
||||
import redis
|
||||
|
||||
|
||||
r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0)
|
||||
|
||||
def GridOn(laser):
|
||||
|
||||
print "Grid for laser ", laser
|
||||
# Grid PL is Laser bit 0 = 1 and bit 1 = 1
|
||||
order = r.get('/order')
|
||||
neworder = order | (1<<laser*2)
|
||||
neworder = neworder | (1<< 1+laser*2)
|
||||
r.set('/order', str(neworder))
|
||||
|
||||
|
||||
def UserOn(laser):
|
||||
|
||||
# Laser bit 0 = 0 and bit 1 = 0 : USER PL
|
||||
order = r.get('/order')
|
||||
neworder = order & ~(1<< laser*2)
|
||||
neworder = neworder & ~(1<< 1+ laser*2)
|
||||
r.set('/order', str(neworder))
|
||||
|
||||
|
||||
def BlackOn(laser):
|
||||
|
||||
print "Black for laser ", laser
|
||||
# Black PL is Laser bit 0 = 1 and bit 1 = 0 :
|
||||
order = r.get('/order')
|
||||
neworder = order | (1<<laser*2)
|
||||
neworder = neworder & ~(1<< 1+laser*2)
|
||||
r.set('/order', str(neworder))
|
||||
|
||||
|
||||
def NewEDH(laser):
|
||||
|
||||
settings.Write()
|
||||
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
|
||||
order = r.get('/order')
|
||||
neworder = order & ~(1<< laser*2)
|
||||
neworder = neworder | (1<< 1+laser*2)
|
||||
r.set('/order', str(neworder))
|
||||
|
||||
|
||||
|
||||
|
||||
def handler(path, tags, args, source):
|
||||
|
||||
|
||||
oscpath = path.split("/")
|
||||
pathlength = len(oscpath)
|
||||
sendWSall(path + " " + str(args[0]))
|
||||
if pathlength == 2:
|
||||
laser = int(oscpath[2])
|
||||
else:
|
||||
laser = int(oscpath[2])
|
||||
|
||||
|
||||
if debug >0:
|
||||
print ""
|
||||
print "default handler"
|
||||
print "Bhorosc said for laser",laser,": ", path, oscpath, args
|
||||
|
||||
|
||||
# /grid/lasernumber value (0 or 1)
|
||||
if oscpath[1] == "grid":
|
||||
|
||||
if args[0] == "1":
|
||||
print "Grid requested for laser ", laser
|
||||
GridOn(laser)
|
||||
else:
|
||||
print "No grid for laser ", laser
|
||||
UserOn(laser)
|
||||
|
||||
|
||||
# /black/lasernumber value (0 or 1)
|
||||
if oscpath[1] == "black":
|
||||
|
||||
if args[0] == "1":
|
||||
print "Grid requested for laser ", laser
|
||||
BlackOn(laser)
|
||||
else:
|
||||
print "No grid for laser ", laser
|
||||
UserOn(laser)
|
||||
|
||||
|
||||
|
||||
# /ip/lasernumber value
|
||||
if oscpath[1] == "ip":
|
||||
print "New IP for laser ", laser
|
||||
gstt.lasersIPS[laser]= args[0]
|
||||
NewEDH(laser)
|
||||
|
||||
# /kpps/lasernumber value
|
||||
# Live change of kpps is not implemented in newdac.py. Change will effect next startup.
|
||||
if oscpath[1] == "kpps":
|
||||
print "New kpps for laser ", laser, " next startup", args[0]
|
||||
gstt.kpps[laser]= int(args[0])
|
||||
NewEDH(laser)
|
||||
|
||||
# /angle/lasernumber value
|
||||
if oscpath[1] == "angle":
|
||||
print "New Angle modification for laser ", oscpath[2], ":", args[0]
|
||||
gstt.finANGLE[laser] += int(args[0])
|
||||
homographyp.newEDH(laser)
|
||||
NewEDH(laser)
|
||||
|
||||
|
||||
|
||||
# /intens/lasernumber value
|
||||
if oscpath[1] == "intens":
|
||||
print "New intensity requested for laser ", oscpath[2], ":", args[0]
|
||||
print "Change not implemented yet"
|
||||
|
||||
|
||||
|
||||
# /mouse/lasernumber value (0 or 1)
|
||||
if oscpath[1] == "mouse":
|
||||
|
||||
if args[0] == "1":
|
||||
print "Mouse requested for laser ", oscpath[2]
|
||||
gstt.Laser = oscpath[2]
|
||||
else:
|
||||
print "No mouse for laser ", oscpath[2]
|
||||
|
||||
|
||||
# /swap/X/lasernumber value (0 or 1)
|
||||
if oscpath[1] == "swap" and oscpath[2] == "X":
|
||||
|
||||
if args[0] == "0":
|
||||
print "swap X : -1 for laser ", laser
|
||||
gstt.swapX[laser]= -1
|
||||
homographyp.newEDH(laser)
|
||||
NewEDH(laser)
|
||||
|
||||
else:
|
||||
print "swap X : 1 for laser ", laser
|
||||
gstt.swapX[laser]= 1
|
||||
homographyp.newEDH(laser)
|
||||
NewEDH(laser)
|
||||
|
||||
# /swap/Y/lasernumber value (0 or 1)
|
||||
if oscpath[1] == "swap" and oscpath[2] == "Y":
|
||||
if args[0] == "0":
|
||||
print "swap Y : -1 for laser ", laser
|
||||
gstt.swapY[laser]= -1
|
||||
homographyp.newEDH(laser)
|
||||
NewEDH(laser)
|
||||
else:
|
||||
print "swap Y : 1 for laser ", laser
|
||||
gstt.swapY[laser]= 1
|
||||
homographyp.newEDH(laser)
|
||||
NewEDH(laser)
|
||||
|
||||
# /loffset/X/lasernumber value
|
||||
if oscpath[1] == "loffset" and oscpath[2] == "X":
|
||||
print "offset/X laser ", laser, "modified : ", args[0]
|
||||
gstt.centerX[laser] -= int(args[0])
|
||||
homographyp.newEDH(laser)
|
||||
NewEDH(laser)
|
||||
|
||||
# /loffset/Y/lasernumber value
|
||||
if oscpath[1] == "loffset" and oscpath[2] == "Y":
|
||||
print "offset/Y laser ", laser, "modified : ", args[0]
|
||||
gstt.centerY[laser] -= int(args[0])
|
||||
homographyp.newEDH(laser)
|
||||
NewEDH(laser)
|
||||
|
||||
|
||||
# /scale/X/lasernumber value
|
||||
if oscpath[1] == "scale" and oscpath[2] == "X":
|
||||
print "scale/X laser ", laser , "modified : ", args[0]
|
||||
gstt.zoomX[laser] += int(args[0])
|
||||
homographyp.newEDH(laser)
|
||||
NewEDH(laser)
|
||||
|
||||
# /scale/Y/lasernumber value
|
||||
if oscpath[1] == "scale" and oscpath[2] == "Y":
|
||||
print "scale/Y laser ", laser, "modified : ", args[0]
|
||||
gstt.zoomY[laser] += int(args[0])
|
||||
homographyp.newEDH(laser)
|
||||
NewEDH(laser)
|
||||
|
||||
'''
|
||||
For reference values of EDH modifier if assign to keyboard keys (was alignp)
|
||||
|
||||
gstt.centerY[gstt.Laser] -= 20
|
||||
|
||||
gstt.centerY[gstt.Laser] += 20
|
||||
|
||||
gstt.zoomX[gstt.Laser]-= 0.1
|
||||
|
||||
gstt.zoomX[gstt.Laser] += 0.1
|
||||
gstt.zoomY[gstt.Laser] -= 0.1
|
||||
|
||||
gstt.zoomY[gstt.Laser] += 0.1
|
||||
|
||||
gstt.sizeX[gstt.Laser] -= 50
|
||||
|
||||
gstt.sizeX[gstt.Laser] += 50
|
||||
|
||||
gstt.sizeY[gstt.Laser] -= 50
|
||||
|
||||
gstt.sizeY[gstt.Laser] += 50
|
||||
|
||||
gstt.finANGLE[gstt.Laser] -= 0.001
|
||||
|
||||
gstt.finANGLE[gstt.Laser] += 0.001
|
||||
'''
|
84
mainy.conf
Normal file
@ -0,0 +1,84 @@
|
||||
[General]
|
||||
set = 5
|
||||
curve = 0
|
||||
lasernumber = 3
|
||||
ljayserverip = 127.0.0.1
|
||||
nozoscip = 127.0.0.1
|
||||
bhoroscip = 127.0.0.1
|
||||
|
||||
[laser0]
|
||||
pl = 0
|
||||
color = -1
|
||||
ip = 192.168.1.4
|
||||
kpps = 25000
|
||||
centerx = 0
|
||||
centery = 0
|
||||
zoomx = 49.2
|
||||
zoomy = 49.0
|
||||
sizex = 31450
|
||||
sizey = 32000
|
||||
finangle = 0.0
|
||||
swapx = 1
|
||||
swapy = -1
|
||||
warpdest = [[-1500., 1500.],
|
||||
[ 1500., 1500.],
|
||||
[ 1500.,-1500.],
|
||||
[-1500.,-1500.]]
|
||||
|
||||
[laser1]
|
||||
pl = 1
|
||||
color = -1
|
||||
ip = 192.168.1.5
|
||||
kpps = 25000
|
||||
centerx = 0
|
||||
centery = 0
|
||||
zoomx = 48.5
|
||||
zoomy = 50.1
|
||||
sizex = 32000
|
||||
sizey = 32000
|
||||
finangle = 0.0
|
||||
swapx = 1
|
||||
swapy = 1
|
||||
warpdest = [[-1500., 1500.],
|
||||
[ 1500., 1500.],
|
||||
[ 1500.,-1500.],
|
||||
[-1500.,-1500.]]
|
||||
|
||||
[laser2]
|
||||
pl = 2
|
||||
color = -1
|
||||
ip = 192.168.1.6
|
||||
kpps = 25000
|
||||
centerx = 0
|
||||
centery = 0
|
||||
zoomx = 47.8
|
||||
zoomy = 39.3
|
||||
sizex = 30600
|
||||
sizey = 32000
|
||||
finangle = -0.008
|
||||
swapx = 1
|
||||
swapy = 1
|
||||
warpdest = [[-1500., 1500.],
|
||||
[ 1500., 1500.],
|
||||
[ 1500.,-1500.],
|
||||
[-1500.,-1500.]]
|
||||
|
||||
[laser3]
|
||||
pl = 3
|
||||
color = -1
|
||||
ip = 192.168.1.3
|
||||
kpps = 25000
|
||||
centerx = 0
|
||||
centery = 0
|
||||
zoomx = 38.0
|
||||
zoomy = 26.0
|
||||
sizex = 32000
|
||||
sizey = 32000
|
||||
finangle = 0.0
|
||||
swapx = -1
|
||||
swapy = -1
|
||||
warpdest = [[-1500., 1500.],
|
||||
[ 1500., 1500.],
|
||||
[ 1500.,-1500.],
|
||||
[-1500.,-1500.]]
|
||||
|
534
mainyservers.py
Normal file
@ -0,0 +1,534 @@
|
||||
'''
|
||||
LJ Servers v0.8
|
||||
|
||||
Laser server + webUI servers (ws + OSC)
|
||||
|
||||
- get point list to draw : /pl/lasernumber
|
||||
- for report /lstt/lasernumber /lack/lasernumber /cap/lasernumber
|
||||
|
||||
todo :
|
||||
|
||||
r.set('/resampler/0', '[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]')
|
||||
r.set('/resampler/1', '[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]')
|
||||
r.set('/resampler/2', '[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]')
|
||||
r.set('/resampler/3', '[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]')
|
||||
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
import time
|
||||
import gstt
|
||||
import redis
|
||||
|
||||
|
||||
print ""
|
||||
print ""
|
||||
print "LJ Laser Servers"
|
||||
print "v0.8.0"
|
||||
print ""
|
||||
|
||||
import settings
|
||||
settings.Read()
|
||||
|
||||
from multiprocessing import Process, Queue, TimeoutError
|
||||
import random, ast
|
||||
|
||||
import newdacp
|
||||
import homographyp
|
||||
import las
|
||||
|
||||
|
||||
from OSC import OSCServer, OSCClient, OSCMessage
|
||||
from websocket_server import WebsocketServer
|
||||
#import socket
|
||||
import types, thread, time
|
||||
|
||||
r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0)
|
||||
|
||||
def dac_process(number, pl):
|
||||
while True:
|
||||
try:
|
||||
d = newdacp.DAC(number,pl)
|
||||
d.play_stream()
|
||||
except Exception as e:
|
||||
|
||||
import sys, traceback
|
||||
if gstt.debug == 2:
|
||||
print '\n---------------------'
|
||||
print 'Exception: %s' % e
|
||||
print '- - - - - - - - - - -'
|
||||
traceback.print_tb(sys.exc_info()[2])
|
||||
print "\n"
|
||||
pass
|
||||
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
|
||||
'''
|
||||
def Laserver():
|
||||
|
||||
|
||||
|
||||
|
||||
#for laserid in range(0,4):
|
||||
# r.set('/lack/'+str(laserid),0)
|
||||
# r.set('/lstt/'+str(laserid),0)
|
||||
|
||||
|
||||
|
||||
# Some random lists for all lasers at launch.
|
||||
print ""
|
||||
print "Creating startup point lists..."
|
||||
|
||||
random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)]
|
||||
if r.set('/pl/0', str(random_points)) == True:
|
||||
print "/pl/0 ", ast.literal_eval(r.get('/pl/0'))
|
||||
|
||||
random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)]
|
||||
if r.set('/pl/1', str(random_points)) == True:
|
||||
print "/pl/1 ", ast.literal_eval(r.get('/pl/1'))
|
||||
|
||||
random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)]
|
||||
if r.set('/pl/2', str(random_points)) == True:
|
||||
print "/pl/2 ", ast.literal_eval(r.get('/pl/2'))
|
||||
|
||||
random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)]
|
||||
if r.set('/pl/3', str(random_points)) == True:
|
||||
print "/pl/3 ", ast.literal_eval(r.get('/pl/3'))
|
||||
|
||||
|
||||
# Order all lasers to show these random shapes at startup -> tell all 4 laser process to USER PLs
|
||||
r.set('/order', "0")
|
||||
|
||||
|
||||
# Launch one process (a newdacp instance) by etherdream
|
||||
|
||||
print ""
|
||||
dac_worker0= Process(target=dac_process,args=(0,0))
|
||||
print "Launching Laser 0 Process..."
|
||||
dac_worker0.start()
|
||||
|
||||
if lasernumber >0:
|
||||
dac_worker1= Process(target=dac_process,args=(1,0))
|
||||
print "Launching Laser 1 Process..."
|
||||
dac_worker1.start()
|
||||
|
||||
if lasernumber >1:
|
||||
dac_worker2= Process(target=dac_process,args=(2,0))
|
||||
print "Launching Laser 2 Process..."
|
||||
dac_worker2.start()
|
||||
|
||||
if lasernumber >2:
|
||||
dac_worker3= Process(target=dac_process,args=(3,0))
|
||||
print "Launching Laser 3 Process..."
|
||||
dac_worker3.start()
|
||||
|
||||
# Main loop do nothing. Maybe do the webui server ?
|
||||
try:
|
||||
#while True:
|
||||
|
||||
# Websocket startup
|
||||
|
||||
server = WebsocketServer(wsPORT,host=serverIP)
|
||||
# Launch OSC thread listening to Bhorosc
|
||||
print ""
|
||||
print "Launching webUI OSC Handler..."
|
||||
thread.start_new_thread(osc_thread, ())
|
||||
# Default OSC handler for all incoming message from Bhorosc
|
||||
oscserver.addMsgHandler("default", handler)
|
||||
|
||||
#print server
|
||||
print ""
|
||||
print "Launching webUI Websocket server..."
|
||||
print "at :", serverIP, "port :",wsPORT
|
||||
server.set_fn_new_client(new_client)
|
||||
server.set_fn_client_left(client_left)
|
||||
server.set_fn_message_received(message_received)
|
||||
server.run_forever()
|
||||
print ""
|
||||
print "Running..."
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
# Gently stop on CTRL C
|
||||
|
||||
finally:
|
||||
|
||||
dac_worker0.join()
|
||||
if lasernumber >0:
|
||||
dac_worker1.join()
|
||||
if lasernumber >1:
|
||||
dac_worker2.join()
|
||||
if lasernumber >2:
|
||||
dac_worker3.join()
|
||||
|
||||
|
||||
for laserid in range(0,lasernumber+1):
|
||||
print "reset redis values for laser",laserid
|
||||
r.set('/lack/'+str(laserid),64)
|
||||
r.set('/lstt/'+str(laserid),64)
|
||||
r.set('/cap/'+str(laserid),0)
|
||||
|
||||
print "Fin des haricots"
|
||||
'''
|
||||
|
||||
|
||||
#
|
||||
# webUI server
|
||||
#
|
||||
|
||||
|
||||
serverIP = gstt.LjayServerIP
|
||||
print "Redis IP :", serverIP
|
||||
|
||||
bhoroscIP = gstt.oscIPin
|
||||
print "Bhorosc IP :", bhoroscIP
|
||||
|
||||
nozoscIP = gstt.nozoscip
|
||||
print "Nozosc IP :", nozoscIP
|
||||
|
||||
debug = gstt.debug
|
||||
print "Debug :", debug
|
||||
|
||||
lasernumber = gstt.LaserNumber -1
|
||||
print "Lasers requested :", gstt.LaserNumber
|
||||
|
||||
|
||||
# Websocket listening port
|
||||
wsPORT = 9001
|
||||
|
||||
# With Bhorosc
|
||||
# OSC Server : relay OSC message from Bhorosc outport 8002 to UI
|
||||
#oscIPin = "192.168.1.10"
|
||||
bhoroscIPin = serverIP
|
||||
bhoroscPORTin = 8002
|
||||
|
||||
# OSC Client : relay message from UI to Bhorosc inport 8001
|
||||
bhoroscIPout = bhoroscIP
|
||||
bhoroscPORTout = 8001
|
||||
|
||||
|
||||
# With Nozosc
|
||||
# OSC Client : relay message from UI to Nozosc inport 8003
|
||||
NozoscIPout = nozoscIP
|
||||
NozoscPORTout = 8003
|
||||
|
||||
|
||||
#
|
||||
# OSC part
|
||||
#
|
||||
|
||||
print ""
|
||||
print "Launching Bhorosc commands receiver..."
|
||||
print "at", bhoroscIPin, "port",str(bhoroscPORTin)
|
||||
oscserver = OSCServer( (bhoroscIPin, bhoroscPORTin) )
|
||||
oscserver.timeout = 0
|
||||
OSCRunning = True
|
||||
|
||||
|
||||
def handle_timeout(self):
|
||||
self.timed_out = True
|
||||
|
||||
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
|
||||
|
||||
osclientbhorosc = OSCClient()
|
||||
oscmsg = OSCMessage()
|
||||
osclientbhorosc.connect((bhoroscIPout, bhoroscPORTout))
|
||||
|
||||
# send UI string as OSC message to Bhorosc 8001
|
||||
# sendbhorosc(oscaddress, [arg1, arg2,...])
|
||||
|
||||
def sendbhorosc(oscaddress,oscargs=''):
|
||||
|
||||
oscmsg = OSCMessage()
|
||||
oscmsg.setAddress(oscaddress)
|
||||
oscmsg.append(oscargs)
|
||||
|
||||
#print ("sending to bhorosc : ",oscmsg)
|
||||
try:
|
||||
osclientbhorosc.sendto(oscmsg, (bhoroscIPout, bhoroscPORTout))
|
||||
oscmsg.clearData()
|
||||
except:
|
||||
print ('Connection to bhorosc refused : died ?')
|
||||
sendWSall("/on 0")
|
||||
sendWSall("/status NoLJay")
|
||||
pass
|
||||
#time.sleep(0.001)
|
||||
|
||||
|
||||
# send UI string as OSC message to Nozosc 8003
|
||||
# sendnozosc(oscaddress, [arg1, arg2,...])
|
||||
|
||||
def sendnozosc(oscaddress,oscargs=''):
|
||||
|
||||
oscmsg = OSCMessage()
|
||||
oscmsg.setAddress(oscaddress)
|
||||
oscmsg.append(oscargs)
|
||||
|
||||
#print ("sending to nozosc : ",oscmsg)
|
||||
try:
|
||||
osclientnozosc.sendto(oscmsg, (NozoscIPout, NozoscPORTout))
|
||||
oscmsg.clearData()
|
||||
except:
|
||||
print ('Connection to nozosc refused : died ?')
|
||||
sendWSall("/on 0")
|
||||
sendWSall("/status No Nozosc ")
|
||||
pass
|
||||
#time.sleep(0.001)
|
||||
|
||||
# NOT USED see las.py
|
||||
# OSC default path handler : send OSC message from Bhorosc 8002 to UI via websocket 9001
|
||||
def handler(path, tags, args, source):
|
||||
|
||||
oscpath = path.split("/")
|
||||
pathlength = len(oscpath)
|
||||
if debug >0:
|
||||
print ""
|
||||
print "default handler"
|
||||
print "Bhorosc said : ", path, oscpath, args
|
||||
sendWSall(path + " " + str(args[0]))
|
||||
|
||||
'''
|
||||
# /lstt/number value
|
||||
if oscpath[1] == "lstt":
|
||||
sendWSall(path + " " + str(args[0]))
|
||||
# /status string
|
||||
if oscpath[1] == "status":
|
||||
sendWSall(path + " " + str(args[0]))
|
||||
'''
|
||||
|
||||
|
||||
# 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()
|
||||
|
||||
|
||||
|
||||
# OSC Thread. Bhorosc handler and Automated status sender to UI.
|
||||
def osc_thread():
|
||||
|
||||
print "Launching Automatic Dac status and bhorosc forwarder."
|
||||
print "Will use Redis server IP ", serverIP
|
||||
|
||||
'''
|
||||
r = redis.StrictRedis(host=serverIP, port=6379, db=0)
|
||||
print "Connection to redis server.."
|
||||
print "Running..."
|
||||
'''
|
||||
|
||||
while True:
|
||||
try:
|
||||
while True:
|
||||
|
||||
time.sleep(1)
|
||||
osc_frame()
|
||||
|
||||
|
||||
for laserid in range(0,lasernumber): # Laser not used -> led is not lit
|
||||
|
||||
lstt = r.get('/lstt/'+ str(laserid))
|
||||
#print "laserid", laserid,"lstt",lstt
|
||||
if lstt == "0": # Dac IDLE state(0) -> led is blue (3)
|
||||
sendWSall("/lstt/" + str(laserid) + " 3")
|
||||
if lstt == "1": # Dac PREPARE state (1) -> led is cyan (2)
|
||||
sendWSall("/lstt/" + str(laserid) + " 2")
|
||||
if lstt == "2": # Dac PLAYING (2) -> led is green (1)
|
||||
sendWSall("/lstt/" + str(laserid) + " 1")
|
||||
|
||||
# This is used not working : lack never change. Todo : retest.
|
||||
lack= r.get('/lack/'+str(laserid))
|
||||
#print "laserid", laserid,"lack",lack
|
||||
if lack == 'a': # Dac sent ACK ("a") -> led is green (1)
|
||||
sendWSall("/lack/" + str(laserid) +" 1")
|
||||
if lack == 'F': # Dac sent FULL ("F") -> led is orange (5)
|
||||
sendWSall("/lack/" + str(laserid) +" 5")
|
||||
if lack == 'I': # Dac sent INVALID ("I") -> led is yellow (4)
|
||||
sendWSall("/lack/" + str(laserid)+" 4")
|
||||
#print lack
|
||||
|
||||
if lack == "64" or lack =="35": # no connection to dac -> leds are red (6)
|
||||
sendWSall("/lack/" + str(laserid) + " 0")
|
||||
sendWSall("/lstt/" + str(laserid) + " 0")
|
||||
#sendWSall("/lstt/" + str(laserid) + " 0")
|
||||
sendWSall("/points/" + str(laserid) + " 0")
|
||||
|
||||
else:
|
||||
# last number of points sent to etherdream buffer
|
||||
sendWSall("/points/" + str(laserid) + " " + str(r.get('/cap/'+str(laserid))))
|
||||
|
||||
#sendWSall("/plframe/" + str(laserid) ) # + " " + str(r.get('/pl/'+str(laserid))))
|
||||
|
||||
# WIP Too much packets -> flood webUI : Draw all PL point lists in JS canvas in WebUI
|
||||
|
||||
'''
|
||||
for pl in range(0,1):
|
||||
bhorosc.sendosc("/plframe/" + str(pl),"")
|
||||
for plpoint in range(0,len(gstt.PL[pl])):
|
||||
bhorosc.sendosc("/plpoint/" + str(pl),"")
|
||||
'''
|
||||
|
||||
|
||||
|
||||
except Exception as e:
|
||||
import sys, traceback
|
||||
print '\n---------------------'
|
||||
print 'Exception: %s' % e
|
||||
print '- - - - - - - - - - -'
|
||||
traceback.print_tb(sys.exc_info()[2])
|
||||
print "\n"
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Websocket part
|
||||
#
|
||||
|
||||
# Called for every WS client connecting (after handshake)
|
||||
def new_client(client, server):
|
||||
print("New WS client connected and was given id %d" % client['id'])
|
||||
sendWSall("/status Hello %d" % client['id'])
|
||||
|
||||
# Called for every WS client disconnecting
|
||||
def client_left(client, server):
|
||||
print("WS Client(%d) disconnected" % client['id'])
|
||||
|
||||
|
||||
# Called when a WS client sends a message
|
||||
def message_received(client, server, message):
|
||||
if len(message) > 200:
|
||||
message = message[:200]+'..'
|
||||
if debug >0:
|
||||
print("WS Client(%d) said: %s" % (client['id'], message))
|
||||
oscpath = message.split(" ")
|
||||
|
||||
# current UI has no dedicated off button so /on 0 trigs /off to bhorosc
|
||||
if oscpath[0] == "/on":
|
||||
if oscpath[1] == "1":
|
||||
sendbhorosc("/on")
|
||||
else:
|
||||
sendbhorosc("/off")
|
||||
else:
|
||||
print "sending to bhorosc",oscpath[0],oscpath[1]
|
||||
sendbhorosc(oscpath[0],oscpath[1])
|
||||
|
||||
# if needed a loop back : WS Client -> server -> WS Client
|
||||
#sendWSall("ws"+message)
|
||||
|
||||
|
||||
def handle_timeout(self):
|
||||
self.timed_out = True
|
||||
|
||||
|
||||
def sendWSall(message):
|
||||
if debug >0:
|
||||
print("WS sending %s" % (message))
|
||||
server.send_message_to_all(message)
|
||||
|
||||
|
||||
|
||||
# Some random lists for all lasers at launch.
|
||||
print ""
|
||||
print "Creating startup point lists..."
|
||||
|
||||
random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)]
|
||||
if r.set('/pl/0', str(random_points)) == True:
|
||||
print "/pl/0 ", ast.literal_eval(r.get('/pl/0'))
|
||||
|
||||
random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)]
|
||||
if r.set('/pl/1', str(random_points)) == True:
|
||||
print "/pl/1 ", ast.literal_eval(r.get('/pl/1'))
|
||||
|
||||
random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)]
|
||||
if r.set('/pl/2', str(random_points)) == True:
|
||||
print "/pl/2 ", ast.literal_eval(r.get('/pl/2'))
|
||||
|
||||
random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)]
|
||||
if r.set('/pl/3', str(random_points)) == True:
|
||||
print "/pl/3 ", ast.literal_eval(r.get('/pl/3'))
|
||||
|
||||
|
||||
# Order all lasers to show these random shapes at startup -> tell all 4 laser process to USER PLs
|
||||
r.set('/order', "0")
|
||||
|
||||
|
||||
# Launch one process (a newdacp instance) by etherdream
|
||||
|
||||
print ""
|
||||
dac_worker0= Process(target=dac_process,args=(0,0))
|
||||
print "Launching Laser 0 Process..."
|
||||
dac_worker0.start()
|
||||
|
||||
if lasernumber >0:
|
||||
dac_worker1= Process(target=dac_process,args=(1,0))
|
||||
print "Launching Laser 1 Process..."
|
||||
dac_worker1.start()
|
||||
|
||||
if lasernumber >1:
|
||||
dac_worker2= Process(target=dac_process,args=(2,0))
|
||||
print "Launching Laser 2 Process..."
|
||||
dac_worker2.start()
|
||||
|
||||
if lasernumber >2:
|
||||
dac_worker3= Process(target=dac_process,args=(3,0))
|
||||
print "Launching Laser 3 Process..."
|
||||
dac_worker3.start()
|
||||
|
||||
# Main loop do nothing. Maybe do the webui server ?
|
||||
try:
|
||||
#while True:
|
||||
|
||||
# Websocket startup
|
||||
|
||||
server = WebsocketServer(wsPORT,host=serverIP)
|
||||
# Launch OSC thread listening to Bhorosc
|
||||
print ""
|
||||
print "Launching webUI OSC Handler..."
|
||||
thread.start_new_thread(osc_thread, ())
|
||||
# Default OSC handler for all incoming message from Bhorosc
|
||||
oscserver.addMsgHandler("default", las.handler)
|
||||
|
||||
#print server
|
||||
print ""
|
||||
print "Launching webUI Websocket server..."
|
||||
print "at :", serverIP, "port :",wsPORT
|
||||
server.set_fn_new_client(new_client)
|
||||
server.set_fn_client_left(client_left)
|
||||
server.set_fn_message_received(message_received)
|
||||
server.run_forever()
|
||||
print ""
|
||||
print "Running..."
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
# Gently stop on CTRL C
|
||||
|
||||
finally:
|
||||
|
||||
dac_worker0.join()
|
||||
if lasernumber >0:
|
||||
dac_worker1.join()
|
||||
if lasernumber >1:
|
||||
dac_worker2.join()
|
||||
if lasernumber >2:
|
||||
dac_worker3.join()
|
||||
|
||||
|
||||
for laserid in range(0,lasernumber+1):
|
||||
print "Redis Etherdream",laserid,"feedback reset."
|
||||
r.set('/lack/'+str(laserid),64)
|
||||
r.set('/lstt/'+str(laserid),64)
|
||||
r.set('/cap/'+str(laserid),0)
|
||||
|
||||
print "Fin des haricots"
|
||||
|
||||
|
||||
|
||||
|
||||
|
444
newdacp.py
Normal file
@ -0,0 +1,444 @@
|
||||
#!/usr/bin/python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: Python -*-
|
||||
|
||||
'''
|
||||
LJay v0.8.0
|
||||
|
||||
newdacp.py
|
||||
Unhanced version (redis and process style) of the etherdream python library from j4cDAC.
|
||||
|
||||
LICENCE : CC
|
||||
Sam Neurohack, pclf
|
||||
|
||||
Conversion in etherdream coordinates, geometric corrections,...
|
||||
Init call with a laser number and which point list to draw. Etherdream IP is found in conf file for given laser number
|
||||
|
||||
Uses redis keys value for live inputs/outputs
|
||||
These redis keys are read and set at each main loop.
|
||||
|
||||
Live inputs :
|
||||
/pl/lasernumber [(x,y,color),(x1,y1,color),...] A string of list of pygame points list.
|
||||
/resampler/lasernumber [(1.0,8), (0.25,3),(0.75,3),(1.0,10)] : a string for resampling rules.
|
||||
the first tuple (1.0,8) is for short line < 4000 in etherdream space
|
||||
(0.25,3),(0.75,3),(1.0,10) for long line > 4000
|
||||
i.e (0.25,3) means go at 25% position on the line, send 3 times this position to etherdream
|
||||
|
||||
Live ouputs :
|
||||
/lstt/lasernumber value etherdream last_status.playback_state (0: idle 1: prepare 2: playing)
|
||||
/cap/lasernumber number of empty points sent to fill etherdream buffer (up to 1799)
|
||||
/lack/lasernumber value "a": ACK "F": Full "I": invalid. 64 or 35 for no connection.
|
||||
Geometric corrections :
|
||||
|
||||
|
||||
|
||||
|
||||
'''
|
||||
|
||||
import socket
|
||||
import time
|
||||
import struct
|
||||
from gstt import debug, PL
|
||||
import gstt
|
||||
import math
|
||||
from itertools import cycle
|
||||
#from globalVars import *
|
||||
import pdb
|
||||
import ast
|
||||
import redis
|
||||
|
||||
import homographyp
|
||||
import numpy as np
|
||||
|
||||
black_points = [(278.0,225.0,0),(562.0,279.0,0),(401.0,375.0,0),(296.0,454.0,0),(298.0,165.0,0)]
|
||||
grid_points = [(300.0,200.0,0),(500.0,00.0,65280),(500.0,400.0,65280),(300.0,400.0,65280),(300.0,200.0,65280),(200.0,100.0,0),(600.0,100.0,65280),(600.0,500.0,65280),(200.0,500.0,65280),(200.0,100.0,65280)]
|
||||
|
||||
r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
|
||||
|
||||
|
||||
def pack_point(x, y, r, g, b, i = -1, u1 = 0, u2 = 0, flags = 0):
|
||||
"""Pack some color values into a struct dac_point.
|
||||
|
||||
Values must be specified for x, y, r, g, and b. If a value is not
|
||||
passed in for the other fields, i will default to max(r, g, b); the
|
||||
rest default to zero.
|
||||
"""
|
||||
|
||||
if i < 0:
|
||||
i = max(r, g, b)
|
||||
|
||||
return struct.pack("<HhhHHHHHH", flags, x, y, r, g, b, i, u1, u2)
|
||||
|
||||
|
||||
class ProtocolError(Exception):
|
||||
"""Exception used when a protocol error is detected."""
|
||||
pass
|
||||
|
||||
|
||||
class Status(object):
|
||||
"""Represents a status response from the DAC."""
|
||||
|
||||
def __init__(self, data):
|
||||
"""Initialize from a chunk of data."""
|
||||
self.protocol_version, self.le_state, self.playback_state, \
|
||||
self.source, self.le_flags, self.playback_flags, \
|
||||
self.source_flags, self.fullness, self.point_rate, \
|
||||
self.point_count = \
|
||||
struct.unpack("<BBBBHHHHII", data)
|
||||
|
||||
def dump(self, prefix = " - "):
|
||||
"""Dump to a string."""
|
||||
lines = [
|
||||
""
|
||||
"Host ",
|
||||
"Light engine: state %d, flags 0x%x" %
|
||||
(self.le_state, self.le_flags),
|
||||
"Playback: state %d, flags 0x%x" %
|
||||
(self.playback_state, self.playback_flags),
|
||||
"Buffer: %d points" %
|
||||
(self.fullness, ),
|
||||
"Playback: %d kpps, %d points played" %
|
||||
(self.point_rate, self.point_count),
|
||||
"Source: %d, flags 0x%x" %
|
||||
(self.source, self.source_flags)
|
||||
]
|
||||
'''
|
||||
if debug == 2:
|
||||
for l in lines:
|
||||
print prefix + l
|
||||
'''
|
||||
|
||||
class BroadcastPacket(object):
|
||||
"""Represents a broadcast packet from the DAC."""
|
||||
|
||||
def __init__(self, st):
|
||||
"""Initialize from a chunk of data."""
|
||||
self.mac = st[:6]
|
||||
self.hw_rev, self.sw_rev, self.buffer_capacity, \
|
||||
self.max_point_rate = struct.unpack("<HHHI", st[6:16])
|
||||
self.status = Status(st[16:36])
|
||||
|
||||
def dump(self, prefix = " - "):
|
||||
"""Dump to a string."""
|
||||
lines = [
|
||||
"MAC: " + ":".join(
|
||||
"%02x" % (ord(o), ) for o in self.mac),
|
||||
"HW %d, SW %d" %
|
||||
(self.hw_rev, self.sw_rev),
|
||||
"Capabilities: max %d points, %d kpps" %
|
||||
(self.buffer_capacity, self.max_point_rate)
|
||||
]
|
||||
for l in lines:
|
||||
print prefix + l
|
||||
if debug == 1:
|
||||
self.status.dump(prefix)
|
||||
|
||||
|
||||
class DAC(object):
|
||||
"""A connection to a DAC."""
|
||||
|
||||
|
||||
# "Laser point List" Point generator
|
||||
# each points is yielded : Getpoints() call n times OnePoint()
|
||||
|
||||
def OnePoint(self):
|
||||
|
||||
while True:
|
||||
|
||||
#pdb.set_trace()
|
||||
for indexpoint,currentpoint in enumerate(self.pl):
|
||||
#print indexpoint, currentpoint
|
||||
xyc = [currentpoint[0],currentpoint[1],currentpoint[2]]
|
||||
self.xyrgb = self.EtherPoint(xyc)
|
||||
|
||||
delta_x, delta_y = self.xyrgb[0] - self.xyrgb_prev[0], self.xyrgb[1] - self.xyrgb_prev[1]
|
||||
|
||||
#test adaptation selon longueur ligne
|
||||
if math.hypot(delta_x, delta_y) < 4000:
|
||||
|
||||
# For glitch art : decrease lsteps
|
||||
l_steps = [ (1.0, 8)]
|
||||
#l_steps = gstt.stepshortline
|
||||
|
||||
else:
|
||||
# For glitch art : decrease lsteps
|
||||
l_steps = [ (0.25, 3), (0.75, 3), (1.0, 10)]
|
||||
#_steps = gstt.stepslongline
|
||||
|
||||
for e in l_steps:
|
||||
step = e[0]
|
||||
|
||||
for i in xrange(0,e[1]):
|
||||
|
||||
self.xyrgb_step = (self.xyrgb_prev[0] + step*delta_x, self.xyrgb_prev[1] + step*delta_y) + self.xyrgb[2:]
|
||||
yield self.xyrgb_step
|
||||
|
||||
self.xyrgb_prev = self.xyrgb
|
||||
|
||||
|
||||
def GetPoints(self, n):
|
||||
|
||||
d = [self.newstream.next() for i in xrange(n)]
|
||||
#print d
|
||||
return d
|
||||
|
||||
|
||||
# Etherpoint all transform in one matrix, with warp !!
|
||||
# xyc : x y color
|
||||
def EtherPoint(self,xyc):
|
||||
|
||||
c = xyc[2]
|
||||
|
||||
#print ""
|
||||
#print "pygame point",[(xyc[0],xyc[1],xyc[2])]
|
||||
#gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
|
||||
position = homographyp.apply(gstt.EDH[self.mylaser],np.array([(xyc[0],xyc[1])]))
|
||||
|
||||
#print "etherdream point",position[0][0], position[0][1], ((c >> 16) & 0xFF) << 8, ((c >> 8) & 0xFF) << 8, (c & 0xFF) << 8
|
||||
#print ''
|
||||
return (position[0][0], position[0][1], ((c >> 16) & 0xFF) << 8, ((c >> 8) & 0xFF) << 8, (c & 0xFF) << 8)
|
||||
|
||||
|
||||
def read(self, l):
|
||||
"""Read exactly length bytes from the connection."""
|
||||
while l > len(self.buf):
|
||||
self.buf += self.conn.recv(4096)
|
||||
|
||||
obuf = self.buf
|
||||
self.buf = obuf[l:]
|
||||
return obuf[:l]
|
||||
|
||||
def readresp(self, cmd):
|
||||
"""Read a response from the DAC."""
|
||||
data = self.read(22)
|
||||
response = data[0]
|
||||
#print "laser response", self.mylaser, response
|
||||
gstt.lstt_dacanswers[self.mylaser] = response
|
||||
cmdR = data[1]
|
||||
status = Status(data[2:])
|
||||
r.set('/lack/'+str(self.mylaser), response)
|
||||
|
||||
if cmdR != cmd:
|
||||
raise ProtocolError("expected resp for %r, got %r"
|
||||
% (cmd, cmdR))
|
||||
|
||||
if response != "a":
|
||||
raise ProtocolError("expected ACK, got %r"
|
||||
% (response, ))
|
||||
|
||||
self.last_status = status
|
||||
return status
|
||||
|
||||
def __init__(self, mylaser, PL, port = 7765):
|
||||
"""Connect to the DAC over TCP."""
|
||||
socket.setdefaulttimeout(2)
|
||||
|
||||
#print "init"
|
||||
self.mylaser = mylaser
|
||||
#print "DAC", self.mylaser, "Handler process, connecting to", gstt.lasersIPS[mylaser]
|
||||
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.connstatus = self.conn.connect_ex((gstt.lasersIPS[mylaser], port))
|
||||
#print "Connection status for", self.mylaser,":", self.connstatus
|
||||
#print 'debug', debug, gstt.debug
|
||||
# ipconn state is -1 at startup (see gstt) and modified here
|
||||
r.set('/lack/'+str(self.mylaser), self.connstatus)
|
||||
gstt.lstt_ipconn[self.mylaser] = self.connstatus
|
||||
|
||||
self.buf = ""
|
||||
# Upper case PL is the Point List number
|
||||
self.PL = PL
|
||||
|
||||
# Lower case pl is the actual point list coordinates
|
||||
self.pl = ast.literal_eval(r.get('/pl/'+str(self.mylaser)))
|
||||
#if self.mylaser ==0:
|
||||
print "DAC Init Laser", self.mylaser
|
||||
#print "pl :", self.pl
|
||||
#print "EDH/"+str(self.mylaser),r.get('/EDH/'+str(self.mylaser))
|
||||
if r.get('/EDH/'+str(self.mylaser)) == None:
|
||||
print "Laser",self.mylaser,"NO EDH !! Computing one..."
|
||||
homographyp.newEDH(self.mylaser)
|
||||
else:
|
||||
gstt.EDH[self.mylaser] = np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
|
||||
print "Laser",self.mylaser,"found its EDH in redis"
|
||||
#print gstt.EDH[self.mylaser]
|
||||
|
||||
'''
|
||||
d =homographyp.apply(gstt.EDH[self.mylaser],np.array([(300,400)]))
|
||||
print ''
|
||||
print "d",d
|
||||
print "d0",d[0]
|
||||
#print "d1",len(d[1])
|
||||
print " "
|
||||
'''
|
||||
|
||||
self.xyrgb = self.xyrgb_prev = (0,0,0,0,0)
|
||||
self.newstream = self.OnePoint()
|
||||
|
||||
print "Connection status for", self.mylaser,":", self.connstatus
|
||||
#print 'debug', debug
|
||||
if self.connstatus != 0:
|
||||
print ""
|
||||
print "Connection ERROR",self.connstatus,"with laser", str(mylaser),":",str(gstt.lasersIPS[mylaser])
|
||||
#print "first 10 points in PL",self.PL, self.GetPoints(10)
|
||||
|
||||
# Reference points
|
||||
# Read the "hello" message
|
||||
first_status = self.readresp("?")
|
||||
first_status.dump()
|
||||
position = []
|
||||
|
||||
|
||||
def begin(self, lwm, rate):
|
||||
cmd = struct.pack("<cHI", "b", lwm, rate)
|
||||
#print "Begin newdac : Laser ", str(self.mylaser), " PL : ", str(self.PL)
|
||||
|
||||
self.conn.sendall(cmd)
|
||||
return self.readresp("b")
|
||||
|
||||
def update(self, lwm, rate):
|
||||
cmd = struct.pack("<cHI", "u", lwm, rate)
|
||||
self.conn.sendall(cmd)
|
||||
return self.readresp("u")
|
||||
|
||||
def encode_point(self, point):
|
||||
return pack_point(*point)
|
||||
|
||||
def write(self, points):
|
||||
epoints = map(self.encode_point, points)
|
||||
cmd = struct.pack("<cH", "d", len(epoints))
|
||||
self.conn.sendall(cmd + "".join(epoints))
|
||||
return self.readresp("d")
|
||||
|
||||
def prepare(self):
|
||||
self.conn.sendall("p")
|
||||
return self.readresp("p")
|
||||
|
||||
|
||||
def stop(self):
|
||||
self.conn.sendall("s")
|
||||
return self.readresp("s")
|
||||
|
||||
def estop(self):
|
||||
self.conn.sendall("\xFF")
|
||||
return self.readresp("\xFF")
|
||||
|
||||
def clear_estop(self):
|
||||
self.conn.sendall("c")
|
||||
return self.readresp("c")
|
||||
|
||||
def ping(self):
|
||||
self.conn.sendall("?")
|
||||
return self.readresp("?")
|
||||
|
||||
def play_stream(self):
|
||||
|
||||
# print last playback state
|
||||
#print "laser", self.mylaser, "Pb : ",self.last_status.playback_state
|
||||
|
||||
# error if etherdream is already playing state (from other source)
|
||||
if self.last_status.playback_state == 2:
|
||||
raise Exception("already playing?!")
|
||||
|
||||
# if idle go to prepare state
|
||||
elif self.last_status.playback_state == 0:
|
||||
self.prepare()
|
||||
|
||||
started = 0
|
||||
|
||||
while True:
|
||||
|
||||
#print "laser", self.mylaser, "Pb : ",self.last_status.playback_state
|
||||
# update drawing parameters from redis keys
|
||||
|
||||
order = int(r.get('/order'))
|
||||
|
||||
#Laser order bit 0 = 0
|
||||
if not order & (1 << (self.mylaser*2)):
|
||||
#print "laser",mylaser,"bit 0 : 0"
|
||||
|
||||
# Laser bit 0 = 0 and bit 1 = 0 : USER PL
|
||||
if not order & (1 << (1+self.mylaser*2)):
|
||||
#print "laser",mylaser,"bit 1 : 0"
|
||||
self.pl = ast.literal_eval(r.get('/pl/'+str(self.mylaser)))
|
||||
|
||||
else:
|
||||
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
|
||||
#print "laser",mylaser,"bit 1 : 1"
|
||||
print "Laser",self.mylaser,"new EDH ORDER in redis"
|
||||
gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
|
||||
# Back to USER PL
|
||||
order = r.get('/order')
|
||||
neworder = order & ~(1<< self.mylaser*2)
|
||||
neworder = neworder & ~(1<< 1+ self.mylaser*2)
|
||||
r.set('/order', str(neworder))
|
||||
else:
|
||||
|
||||
# Laser bit 0 = 1
|
||||
print "laser",mylaser,"bit 0 : 1"
|
||||
|
||||
# Laser bit 0 = 1 and bit 1 = 0 : Black PL
|
||||
if not order & (1 << (1+self.mylaser*2)):
|
||||
#print "laser",mylaser,"bit 1 : 0"
|
||||
self.pl = black_points
|
||||
|
||||
else:
|
||||
# Laser bit 0 = 1 and bit 1 = 1 : GRID PL
|
||||
#print "laser",mylaser,"bit 1 : 1"
|
||||
self.pl = grid_points
|
||||
|
||||
|
||||
|
||||
#self.pl = ast.literal_eval(r.get('/pl/'+str(self.mylaser)))
|
||||
|
||||
#if self.mylaser == 0:
|
||||
# print "franken pl for ", self.mylaser, ":", self.pl
|
||||
#print "franken 0 point :", self.pl[0]
|
||||
|
||||
'''
|
||||
self.resampler = ast.literal_eval(r.get('/resampler/'+str(self.mylaser)))
|
||||
print "resampler for", self.mylaser, ":",self.resampler
|
||||
gstt.stepshortline = self.resampler[0]
|
||||
gstt.stepslongline[0] = self.resampler[1]
|
||||
gstt.stepslongline[1] = self.resampler[2]
|
||||
gstt.stepslongline[2] = self.resampler[3]
|
||||
'''
|
||||
|
||||
r.set('/lstt/'+str(self.mylaser), self.last_status.playback_state)
|
||||
# pdb.set_trace()
|
||||
# How much room?
|
||||
|
||||
cap = 1799 - self.last_status.fullness
|
||||
points = self.GetPoints(cap)
|
||||
|
||||
r.set('/cap/'+str(self.mylaser), cap)
|
||||
|
||||
#if self.mylaser == 0:
|
||||
#print self.mylaser, cap
|
||||
if cap < 100:
|
||||
time.sleep(0.001)
|
||||
cap += 150
|
||||
|
||||
# print "Writing %d points" % (cap, )
|
||||
#t0 = time.time()
|
||||
#print points
|
||||
self.write(points)
|
||||
#t1 = time.time()
|
||||
# print "Took %f" % (t1 - t0, )
|
||||
|
||||
if not started:
|
||||
self.begin(0, gstt.kpps[self.mylaser])
|
||||
started = 1
|
||||
|
||||
# not used in LJay.
|
||||
def find_dac():
|
||||
"""Listen for broadcast packets."""
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.bind(("0.0.0.0", 7654))
|
||||
|
||||
while True:
|
||||
data, addr = s.recvfrom(1024)
|
||||
bp = BroadcastPacket(data)
|
||||
|
||||
print "Packet from %s: " % (addr, )
|
||||
bp.dump()
|
107
settings.py
Normal file
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: Python -*-
|
||||
'''
|
||||
LJay/LJ
|
||||
v0.7.0
|
||||
|
||||
Settings Handler
|
||||
|
||||
LICENCE : CC
|
||||
'''
|
||||
|
||||
import ConfigParser
|
||||
import gstt
|
||||
import ast
|
||||
import numpy as np
|
||||
|
||||
|
||||
def Write():
|
||||
|
||||
config.set('General', 'set', str(gstt.Set))
|
||||
config.set('General', 'curve', str(gstt.Curve))
|
||||
config.set('General', 'lasernumber', str(gstt.LaserNumber))
|
||||
config.set('General', 'ljayserverip', str(gstt.LjayServerIP))
|
||||
config.set('General', 'bhoroscip', str(gstt.oscIPin))
|
||||
config.set('General', 'nozoscip', str(gstt.nozoscIP))
|
||||
|
||||
for i in range(gstt.LaserNumber):
|
||||
laser = 'laser' + str(i)
|
||||
config.set(laser, 'ip', str(gstt.lasersIPS[i]))
|
||||
config.set(laser, 'kpps', str(gstt.kpps[i]))
|
||||
config.set(laser, 'centerx', str(gstt.centerX[i]))
|
||||
config.set(laser, 'centery', str(gstt.centerY[i]))
|
||||
config.set(laser, 'zoomx', str(gstt.zoomX[i]))
|
||||
config.set(laser, 'zoomy', str(gstt.zoomY[i]))
|
||||
config.set(laser, 'sizex', str(gstt.sizeX[i]))
|
||||
config.set(laser, 'sizey', str(gstt.sizeY[i]))
|
||||
config.set(laser, 'finangle', str(gstt.finANGLE[i]))
|
||||
config.set(laser, 'swapx', str(gstt.swapX[i]))
|
||||
config.set(laser, 'swapy', str(gstt.swapY[i]))
|
||||
config.set(laser, 'warpdest', np.array2string(gstt.warpdest[i], precision=2, separator=',',suppress_small=True))
|
||||
|
||||
config.write(open(gstt.ConfigName,'w'))
|
||||
|
||||
|
||||
|
||||
def Read():
|
||||
|
||||
gstt.Set = config.getint('General', 'set')
|
||||
gstt.Curve = config.getint('General', 'curve')
|
||||
gstt.LaserNumber = config.getint('General', 'lasernumber')
|
||||
gstt.LjayServerIP= config.get('General', 'ljayserverip')
|
||||
gstt.oscIPin = config.get('General', 'bhoroscip')
|
||||
gstt.nozoscip = config.get('General', 'nozoscip')
|
||||
|
||||
for i in range(4):
|
||||
laser = 'laser' + str(i)
|
||||
gstt.lasersIPS[i]= config.get(laser, 'ip')
|
||||
gstt.lasersPLS[i] = config.getint(laser, 'PL')
|
||||
gstt.kpps[i] = config.getint(laser, 'kpps')
|
||||
#gstt.lasersPLcolor[i] = config.getint(laser, 'color')
|
||||
gstt.centerX[i]= config.getint(laser, 'centerx')
|
||||
gstt.centerY[i] = config.getint(laser, 'centery')
|
||||
gstt.zoomX[i] = config.getfloat(laser, 'zoomx')
|
||||
gstt.zoomY[i] = config.getfloat(laser, 'zoomy')
|
||||
gstt.sizeX[i] = config.getint(laser, 'sizex')
|
||||
gstt.sizeY[i] = config.getint(laser, 'sizey')
|
||||
gstt.finANGLE[i] = config.getfloat(laser, 'finangle')
|
||||
gstt.swapX[i] = config.getint(laser, 'swapx')
|
||||
gstt.swapY[i] = config.getint(laser, 'swapy')
|
||||
gstt.warpdest[i]= np.array(ast.literal_eval(config.get(laser, 'warpdest')))
|
||||
|
||||
|
||||
print "* Reading", gstt.ConfigName, "setup file.*"
|
||||
config = ConfigParser.ConfigParser()
|
||||
config.read(gstt.ConfigName)
|
||||
|
||||
|
||||
|
||||
# Save all points for a given "shape" (=['Windows','0']) shapecoord is a list
|
||||
# in any section of the mapping conf file
|
||||
def MappingWrite(sections, shape, shapecoord):
|
||||
|
||||
shapestr = " ".join(str(x) for x in shapecoord)
|
||||
config.set(sections[gstt.CurrentSection], shape, shapestr.replace("] [","],["))
|
||||
config.write(open(gstt.ConfigName,'w'))
|
||||
|
||||
def MappingWriteSection(sections, shape, shapecoord):
|
||||
|
||||
shapestr = " ".join(str(x) for x in shapecoord)
|
||||
shapestr = "[" + shapestr.replace("] [","],[") + "]"
|
||||
config.set(sections, shape, shapestr)
|
||||
config.write(open(gstt.ConfigName,'w'))
|
||||
|
||||
# Get a list of all points (="Corners") for a given "shape" = [section,option] like ['Windows','0']
|
||||
def MappingRead(shape):
|
||||
archi = ast.literal_eval(config.get(shape[0], shape[1]))
|
||||
return archi
|
||||
|
||||
|
||||
# Get shape numbers (i.e of windows in Windows section)
|
||||
def Mapping(shape):
|
||||
return len(config.options(shape))
|
||||
|
||||
# Get a list of all sections
|
||||
def MappingSections():
|
||||
return config.sections()
|
371
websocket_server.py
Executable file
@ -0,0 +1,371 @@
|
||||
# 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)
|
||||
|
||||
|
||||
# ------------------------- 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)
|
800
webui/index.html
Normal file
@ -0,0 +1,800 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>LJay</title>
|
||||
|
||||
<!-- Web audio defaults -->
|
||||
<script src="webcomponents-lite.js"></script>
|
||||
<script>
|
||||
WebAudioControlsOptions={
|
||||
useMidi:1,
|
||||
knobSrc:"knobs/simplegray.png",
|
||||
knobSprites:100,
|
||||
switchSrc:"knobs/switch_toggle.png",
|
||||
sliderSrc:"knobs/vsliderbody.png",
|
||||
sliderKnobsrc:"knobs/vsliderknob.png",
|
||||
}
|
||||
</script>
|
||||
<script src="webaudio-controls.js"></script>
|
||||
<link rel="stylesheet" href="ljaygrid.css" />
|
||||
|
||||
<!-- Webscoket handler -->
|
||||
<script type="text/javascript">
|
||||
|
||||
var _WS = {
|
||||
uri: 'ws://127.0.0.1:9001/',
|
||||
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');
|
||||
},
|
||||
onClose: function () {
|
||||
_WS.showout('DISCONNECTED');
|
||||
},
|
||||
onMessage: function (e) {
|
||||
var res = e.data.split(" ");
|
||||
//console.log(e.data)
|
||||
//console.log(res[0].substring(0,6))
|
||||
switch (res[0].substring(0,6)) {
|
||||
case "/statu":
|
||||
_WS.showstatus(e.data.slice(8));
|
||||
break;
|
||||
case "/plfra":
|
||||
console.log(e.data.slice(11));
|
||||
break;
|
||||
case "/plpoi":
|
||||
//console.log("plpoint");
|
||||
break;
|
||||
default:
|
||||
console.log(res[0] + " " + res[1])
|
||||
//console.log(res[1])
|
||||
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);
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body style="background-color:#222;">
|
||||
|
||||
<!-- mg : MainGrid Webpage one column, different raws displayed or hidden by menu button -->
|
||||
<div class="maingrid">
|
||||
|
||||
<!-- mg : Title and laser state ()-->
|
||||
<div class="mgtitle">
|
||||
|
||||
<!-- LJ Logo -->
|
||||
<div><img src="knobs/ljaylogo.png">
|
||||
</div>
|
||||
|
||||
<!-- ON OFF button -->
|
||||
<div class="onoffgrid">
|
||||
<div class="lasertextxs">/on</div>
|
||||
<div><webaudio-switch id="on" height="52" width="41" value="0" src="knobs/bigbluetoggle.png" type="toggle"></webaudio-switch></div>
|
||||
</div>
|
||||
|
||||
<!-- Lasers state grid -->
|
||||
<div class="lsttgrid">
|
||||
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div class="lasertextxs">S</div>
|
||||
<div class="lasertextxs">C</div>
|
||||
|
||||
<div class="lasertextxs">0</div>
|
||||
<div></div>
|
||||
<div><webaudio-knob id="lstt/0" src="knobs/leds.png" height="17" width="17" diameter="17" min="0" max="6" value="0" sprites="6"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="lack/0" src="knobs/leds.png" height="17" width="17" diameter="17" min="0" max="6" value="0" sprites="6"></webaudio-knob></div>
|
||||
|
||||
<div class="lasertextxs">1</div>
|
||||
<div></div>
|
||||
<div><webaudio-knob id="lstt/1" src="knobs/leds.png" height="17" width="17" diameter="17" min="0" max="6" value="0" sprites="6"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="lack/1" src="knobs/leds.png" height="17" width="17" diameter="17" min="0" max="6" value="0" sprites="6"></webaudio-knob></div>
|
||||
|
||||
<div class="lasertextxs">2</div>
|
||||
<div></div>
|
||||
<div><webaudio-knob id="lstt/2" src="knobs/leds.png" height="17" width="17" diameter="17" min="0" max="6" value="0" sprites="6"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="lack/2" src="knobs/leds.png" height="17" width="17" diameter="17" min="0" max="6" value="0" sprites="6"></webaudio-knob></div>
|
||||
|
||||
|
||||
<div class="lasertextxs">3</div>
|
||||
<div></div>
|
||||
<div><webaudio-knob id="lstt/3" src="knobs/leds.png" height="17" width="17" diameter="17" min="0" max="6" value="0" sprites="6"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="lack/3" src="knobs/leds.png" height="17" width="17" diameter="17" min="0" max="6" value="0" sprites="6"></webaudio-knob></div>
|
||||
</div>
|
||||
|
||||
<div class="topgrid">
|
||||
<div class="lasertext">Laser</div>
|
||||
<div><webaudio-knob id="noteon" src="knobs/Prophetic5.png" diameter="70" min="16" max="20" value="0" sprites="5"></webaudio-knob></div>
|
||||
<div><webaudio-param style="font-size:medium;" link="noteon"></webaudio-param></div>
|
||||
<div class="lasertext">Set</div>
|
||||
<div><webaudio-knob id="noteon" src="knobs/Prophetic5.png" diameter="70" min="8" max="12" value="4" sprites="5"></webaudio-knob></div>
|
||||
<div class="lasertext">Curve</div>
|
||||
<div><webaudio-knob id="noteon" src="knobs/Prophetic10.png" diameter="70" min="0" max="7" value="4" sprites="10"></webaudio-knob></div>
|
||||
<div class="lasertext">Simu</div>
|
||||
<div><webaudio-knob id="noteon" src="knobs/Prophetic5.png" diameter="70" min="24" max="28" value="0" sprites="5"></webaudio-knob></div>
|
||||
</div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
<!-- mg : Menu buttons and Status display -->
|
||||
<div id="mgstatus" class="mgstatus">
|
||||
<div>
|
||||
<!-- <webaudio-switch id="align" height="10" width="99" value="0" src="knobs/align.png" type="toggle"></webaudio-switch>
|
||||
<webaudio-switch id="simu" height="10" width="99" value="0" src="knobs/simu.png" type="toggle"></webaudio-switch>
|
||||
<webaudio-switch id="run" height="10" width="99" value="0" src="knobs/run.png" type="toggle"></webaudio-switch>
|
||||
<webaudio-switch id="live" height="10" width="99" value="0" src="knobs/live.png" type="toggle"></webaudio-switch> -->
|
||||
<button class="button:checked" id="showalign" onclick="showAlign()" checked="checked">Align</button>
|
||||
<button class="button" id="showcanvas" onclick="showCanvas()">Simu</button>
|
||||
<button class="button" id="showrun" onclick="showRun()">Run</button>
|
||||
<button class="button" id="showlive" onclick="showLive()">Live</button>
|
||||
</div>
|
||||
<div><button class="button" id="showstatus">DISCONNECTED</button></div>
|
||||
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
<!-- mg : Align -->
|
||||
<div id="mgalign" class="mgalign">
|
||||
|
||||
<!-- Laserbox 0 -->
|
||||
<div class="laserbox">
|
||||
<!-- IP 0 -->
|
||||
<div>
|
||||
<form onsubmit="onSubmit(); return false;">
|
||||
<input class = "submit" onchange = "onSubmit(this.id)" type="text" id="ip/0">
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Align Icons -->
|
||||
<webaudio-switch id="grid/0" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/grid.png"></webaudio-switch>
|
||||
<webaudio-switch id="mouse/0" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/mouse.png"></webaudio-switch>
|
||||
<!-- Blackout icon -->
|
||||
<webaudio-switch id="black/0" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/blackout.png"></webaudio-switch>
|
||||
<!-- Swap Icons -->
|
||||
<webaudio-switch id="swap/X/0" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapx.png"></webaudio-switch>
|
||||
<webaudio-switch id="swap/Y/0" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapy.png"></webaudio-switch>
|
||||
</div>
|
||||
<!-- Lasergrid 0 -->
|
||||
<div class="lasergrid" style="background-image: url(knobs/lasergrid0.png);">
|
||||
|
||||
<div><webaudio-param id="kpps/0" link="kpps/0" ></webaudio-param></div>
|
||||
<div><webaudio-param id="points/0" link="points/0"></webaudio-param></div>
|
||||
<div class="lasertext">kPPS</div>
|
||||
<div class="lasertext">Points</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="loffset/X/0" diameter="60" min="-320" max="320" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="loffset/Y/0" diameter="60" min="-320" max="320" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-param link="loffset/X/0" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="loffset/Y/0" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">Offset X</div>
|
||||
<div class="lasertext">Offset Y</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="scale/X/0" diameter="60" min="-10" max="10" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="scale/Y/0" diameter="60" min="-10" max="10" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-param link="scale/X/0" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="scale/Y/0" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">Scale X</div>
|
||||
<div class="lasertext">Scale Y</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="angle/0" diameter="60" min="-1" max="1" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="intens/0" diameter="60" min="0" max="127" value="127"></webaudio-knob></div>
|
||||
<div class="lasertext">Angle</div>
|
||||
<div class="lasertext">Intens.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Laserbox 1 -->
|
||||
<div class="laserbox">
|
||||
<!-- IP 1 -->
|
||||
<div>
|
||||
<form onsubmit="onSubmit(); return false;">
|
||||
<input class = "submit" onchange = "onSubmit(this.id)" type="text" id="ip/1">
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Align Icons -->
|
||||
<webaudio-switch id="grid/1" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/grid.png"></webaudio-switch>
|
||||
<webaudio-switch id="mouse/1" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/mouse.png"></webaudio-switch>
|
||||
<!-- Blackout icon -->
|
||||
<webaudio-switch id="black/1" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/blackout.png"></webaudio-switch>
|
||||
<!-- Swap Icons -->
|
||||
<webaudio-switch id="swap/X/1" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapx.png"></webaudio-switch>
|
||||
<webaudio-switch id="swap/Y/1" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapy.png"></webaudio-switch>
|
||||
</div>
|
||||
<!-- Lasergrid 1 -->
|
||||
<div class="lasergrid" style="background-image: url(knobs/lasergrid1.png);">
|
||||
<div><webaudio-param id="kpps/1" link="kpps/1"></webaudio-param></div>
|
||||
<div><webaudio-param id="points/1" link="points/1"></webaudio-param></div>
|
||||
<div class="lasertext">kPPS</div>
|
||||
<div class="lasertext">Points</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="loffset/X/1" diameter="60" min="-20" max="20" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="loffset/Y/1" diameter="60" min="-20" max="20" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-param link="loffset/X/1" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="loffset/Y/1" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">Offset X</div>
|
||||
<div class="lasertext">Offset Y</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="scale/X/1" diameter="60" min="-10" max="10" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="scale/Y/1" diameter="60" min="-10" max="10" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-param link="scale/X/1" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="scale/Y/1" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">Scale X</div>
|
||||
<div class="lasertext">Scale Y</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="angle/1" diameter="60" min="-1" max="1" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="intens/1" diameter="60" min="0" max="127"value="127"></webaudio-knob></div>
|
||||
<div class="lasertext">Angle</div>
|
||||
<div class="lasertext">Intens.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Laserbox 2 -->
|
||||
<div class="laserbox">
|
||||
<!-- IP 2 -->
|
||||
<div>
|
||||
<form onsubmit="onSubmit(); return false;">
|
||||
<input class = "submit" onchange = "onSubmit(this.id)" type="text" id="ip/2">
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Align Icons -->
|
||||
<webaudio-switch id="grid/2" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/grid.png"></webaudio-switch>
|
||||
<webaudio-switch id="mouse/2" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/mouse.png"></webaudio-switch>
|
||||
<!-- Blackout icon -->
|
||||
<webaudio-switch id="black/2" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/blackout.png"></webaudio-switch>
|
||||
<!-- Swap Icons -->
|
||||
<webaudio-switch id="swap/X/2" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapx.png"></webaudio-switch>
|
||||
<webaudio-switch id="swap/Y/2" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapy.png"></webaudio-switch>
|
||||
</div>
|
||||
<!-- Laser 2 grid -->
|
||||
<div class="lasergrid" style="background-image: url(knobs/lasergrid2.png)">
|
||||
<div><webaudio-param id="kpps/2" link="kpps/2"></webaudio-param></div>
|
||||
<div><webaudio-param id="points/2" link="points/2"></webaudio-param></div>
|
||||
<div class="lasertext">kPPS</div>
|
||||
<div class="lasertext">Points</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="loffset/X/2" diameter="60" min="-20" max="20" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="loffset/Y/2" diameter="60" min="-20" max="20" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-param link="loffset/X/2" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="loffset/Y/2" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">Offset X</div>
|
||||
<div class="lasertext">Offset Y</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="scale/X/2" diameter="60" min="-10" max="10" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="scale/Y/2" diameter="60" min="-10" max="10" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-param link="scale/X/2" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="scale/Y/2" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">Scale X</div>
|
||||
<div class="lasertext">Scale Y</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="angle/2" diameter="60" min="-1" max="1" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="intens/2" diameter="60" min="0" max="127"value="127"></webaudio-knob></div>
|
||||
<div class="lasertext">Angle</div>
|
||||
<div class="lasertext">Intens.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Laserbox 3 -->
|
||||
<div class="laserbox">
|
||||
<!-- IP 3 -->
|
||||
<div>
|
||||
<form onsubmit="onSubmit(); return false;">
|
||||
<input class = "submit" onchange = "onSubmit(this.id)" type="text" id="ip/3">
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Align Icons -->
|
||||
<webaudio-switch id="grid/3" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/grid.png"></webaudio-switch>
|
||||
<webaudio-switch id="mouse/3" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/mouse.png"></webaudio-switch>
|
||||
<!-- Blackout icon -->
|
||||
<webaudio-switch id="black/3" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/blackout.png"></webaudio-switch>
|
||||
<!-- Swap Icons -->
|
||||
<webaudio-switch id="swap/X/3" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapx.png"></webaudio-switch>
|
||||
<webaudio-switch id="swap/Y/3" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapy.png"></webaudio-switch>
|
||||
</div>
|
||||
<!-- Laser 3 grid -->
|
||||
<div class="lasergrid" style="background-image: url(knobs/lasergrid3.png)">
|
||||
<div><webaudio-param id="kpps/3" link="kpps/3" ></webaudio-param></div>
|
||||
<div><webaudio-param id="points/3" link="points/3"></webaudio-param></div>
|
||||
<div class="lasertext">kPPS</div>
|
||||
<div class="lasertext">Points</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="loffset/X/3" diameter="60" min="-20" max="20" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="loffset/Y/3" diameter="60" min="-20" max="20" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-param link="loffset/X/3" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="loffset/Y/3" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">Offset X</div>
|
||||
<div class="lasertext">Offset Y</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="scale/X/3" diameter="60" min="-10" max="10" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="scale/Y/3" diameter="60" min="-10" max="10" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-param link="scale/X/3" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="scale/Y/3" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">Scale X</div>
|
||||
<div class="lasertext">Scale Y</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="angle/2" diameter="60" min="-1" max="1" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="intens/3" diameter="60" min="0" max="127" value="127"></webaudio-knob></div>
|
||||
<div class="lasertext">Angle</div>
|
||||
<div class="lasertext">Intens.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- mg : Live -->
|
||||
<div id="mglive" class="mglive">
|
||||
|
||||
|
||||
<!-- with AI box -->
|
||||
<div class="withaibox">
|
||||
<div class="lasertext" style="border-color:#334;border-style: groove;border-width:1px;">With AI
|
||||
</div>
|
||||
<div class="withaigrid">
|
||||
<div><webaudio-knob id="ai/velocity" diameter="60" min="0" max="127" value="64"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="ai/expressivity" diameter="60" min="0" max="127" value="64"></webaudio-knob></div>
|
||||
<div><webaudio-param link="ai/velocity" value="64"></webaudio-param></div>
|
||||
<div><webaudio-param link="ai/expressivity" value="64"></webaudio-param></div>
|
||||
<div class="lasertext">Velocity</div>
|
||||
<div class="lasertext">Express.</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="ai/sensibility" diameter="60" min="0" max="127" value="64"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="ai/beauty" diameter="60" min="0" max="127" value="64"></webaudio-knob></div>
|
||||
<div><webaudio-param link="ai/sensibility" value="64"></webaudio-param></div>
|
||||
<div><webaudio-param link="ai/beauty" value="64"></webaudio-param></div>
|
||||
<div class="lasertext">Sens.</div>
|
||||
<div class="lasertext">Beauty</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="cc/1" diameter="60" min="1" max="127" value="64"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="cc/2" diameter="60" min="1" max="127" value="64"></webaudio-knob></div>
|
||||
<div><webaudio-param link="cc/1" value="1"></webaudio-param></div>
|
||||
<div><webaudio-param link="cc/2" value="1"></webaudio-param></div>
|
||||
<div class="lasertext">CC 1</div>
|
||||
<div class="lasertext">CC 2</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Lissabox -->
|
||||
<div class="lissabox">
|
||||
<div class="lasertext" style="border-color:#334;border-style: groove;border-width:1px;">LISSA
|
||||
</div>
|
||||
<div class="lissagrid">
|
||||
|
||||
<div><webaudio-knob id="cc/5" diameter="60" min="0" max="127" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="cc/6" diameter="60" min="0" max="127" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-param link="cc/5" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="cc/6" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">Select X</div>
|
||||
<div class="lasertext">Select Y</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="cc/21" diameter="60" min="1" max="127" value="1"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="cc/22" diameter="60" min="1" max="127" value="1"></webaudio-knob></div>
|
||||
<div><webaudio-param link="cc/21" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="cc/22" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">FOV</div>
|
||||
<div class="lasertext">Dist</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="cc/1" diameter="60" min="1" max="127" value="1"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="cc/2" diameter="60" min="1" max="127" value="1"></webaudio-knob></div>
|
||||
<div><webaudio-param link="cc/1" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="cc/2" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">Offset X</div>
|
||||
<div class="lasertext">Offset Y</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3D proj grid -->
|
||||
<div class="projgrid">
|
||||
<div></div>
|
||||
<div class="lasertext" style="border-color:#334;border-style: groove;border-width:1px;">3D ROT</div>
|
||||
<div></div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer"></div>
|
||||
<div><webaudio-knob id="cc/29" diameter="60" min="0" max="127" value="0" ></webaudio-knob></div>
|
||||
<div><webaudio-knob id="cc/10" diameter="60" min="0" max="127" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="cc/31" diameter="60" min="0" max="127" value="0"></webaudio-knob></div>
|
||||
<div><webaudio-param link="cc/29" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="cc/10" value="0"></webaudio-param></div>
|
||||
<div><webaudio-param link="cc/31" value="0"></webaudio-param></div>
|
||||
<div class="lasertext">X</div>
|
||||
<div class="lasertext">Y</div>
|
||||
<div class="lasertext">Z</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- mg : canvas to display point list as laser simulator -->
|
||||
<div id = "mgcanvas" class="mgcanvas">
|
||||
<div>
|
||||
<canvas id="canvas" width="500" height="500"></canvas>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
<!-- mg run icons grid -->
|
||||
<div id="mgrun"class="mgrun">
|
||||
<!-- Curve selection grid -->
|
||||
<div><img src="img/iconljay2.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconljay2.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconastro.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconljay2.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconllstr.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconastro.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconljay2.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconpose.png" alt=" " class="icongrid" /></div>
|
||||
<div><button id ="noteon 0" onclick ="buttonClicked(this.id)" class="button">Map.</button></div>
|
||||
<div><button id ="noteon 1" onclick ="buttonClicked(this.id)" class="button">xPLS</button></div>
|
||||
<div><button id ="noteon 2" onclick ="buttonClicked(this.id)" class="button">Orbits</button></div>
|
||||
<div><button id ="noteon 3" onclick ="buttonClicked(this.id)" class="button">Dot</button></div>
|
||||
<div><button id ="noteon 4" onclick ="buttonClicked(this.id)" class="button">Sine</button></div>
|
||||
<div><button id ="noteon 5" onclick ="buttonClicked(this.id)" class="button">Astro</button></div>
|
||||
<div><button id ="noteon 6" onclick ="buttonClicked(this.id)" class="button:checked">Text</button></div>
|
||||
<div><button id ="noteon 7" onclick ="buttonClicked(this.id)" class="button">Pose</button></div>
|
||||
<!-- Set selection grid -->
|
||||
<div><img src="img/iconljay1.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconljay1.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconllstr.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconpose.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconljay1.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconljay1.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconljay1.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconljay1.png" alt=" " class="icongrid" /></div>
|
||||
<div><button id ="noteon 8" onclick ="buttonClicked(this.id)" class="button:checked">Set 0</button></div>
|
||||
<div><button id ="noteon 9" onclick ="buttonClicked(this.id)" class="button">Set 1</button></div>
|
||||
<div><button id ="noteon 10" onclick ="buttonClicked(this.id)" class="button">LLSTR</button></div>
|
||||
<div><button id ="noteon 11" onclick ="buttonClicked(this.id)" class="button">Franken</button></div>
|
||||
<div><button id ="noteon 12" onclick ="buttonClicked(this.id)" class="button">Ex.</button></div>
|
||||
<div><button id ="noteon 13" onclick ="buttonClicked(this.id)" class="button">5.</button></div>
|
||||
<div><button id ="noteon 14" onclick ="buttonClicked(this.id)" class="button">6</button></div>
|
||||
<div><button id ="noteon 15" onclick ="buttonClicked(this.id)" class="button">7</button></div>
|
||||
<!-- Laser selection grid -->
|
||||
<div><img src="img/iconlaser.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconlaser.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconlaser.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconlaser.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconblack.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconblack.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconblack.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconblack.png" alt=" " class="icongrid" /></div>
|
||||
<div><button id ="noteon 16" onclick ="buttonClicked(this.id)" class="button:checked">0</button></div>
|
||||
<div><button id ="noteon 17" onclick ="buttonClicked(this.id)" class="button">1</button></div>
|
||||
<div><button id ="noteon 18" onclick ="buttonClicked(this.id)" class="button">2</button></div>
|
||||
<div><button id ="noteon 19" onclick ="buttonClicked(this.id)" class="button">3</button></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<!-- Simulator PL selection grid -->
|
||||
<div><img src="img/iconsimu.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconsimu.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconsimu.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconsimu.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconblack.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconblack.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconblack.png" alt=" " class="icongrid" /></div>
|
||||
<div><img src="img/iconblack.png" alt=" " class="icongrid" /></div>
|
||||
<div><button id ="noteon 24" onclick ="buttonClicked(this.id)" class="button:checked">PL 0</button></div>
|
||||
<div><button id ="noteon 25" onclick ="buttonClicked(this.id)" class="button">PL 1</button></div>
|
||||
<div><button id ="noteon 26" onclick ="buttonClicked(this.id)" class="button">PL 2</button></div>
|
||||
<div><button id ="noteon 27" onclick ="buttonClicked(this.id)" class="button">PL 3</button></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
<!-- mg : footer display events for debug -->
|
||||
<div class="mgfooter">
|
||||
<div id="showin"></div>
|
||||
<div id="showout"></div>
|
||||
<div id="events"</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- web audio animations -->
|
||||
<script type="text/javascript">
|
||||
var message="";
|
||||
var log=[];
|
||||
var knobs = document.getElementsByTagName('webaudio-knob');
|
||||
for(var i = 0; i < knobs.length; i++){
|
||||
knobs[i].addEventListener("input",Dump,false);
|
||||
knobs[i].addEventListener("change",Dump,false);
|
||||
}
|
||||
var sliders = document.getElementsByTagName('webaudio-slider');
|
||||
for(var i = 0; i < sliders.length; i++){
|
||||
sliders[i].addEventListener("input",Dump,false);
|
||||
sliders[i].addEventListener("change",Dump,false);
|
||||
}
|
||||
var switches = document.getElementsByTagName('webaudio-switch');
|
||||
for(var i = 0; i < switches.length; i++) {
|
||||
switches[i].addEventListener("change",Dump,false);
|
||||
}
|
||||
function Dump(e) {
|
||||
var str="";
|
||||
str=e.type + " : " + e.target.id + " : " + e.target.value + " ";
|
||||
//console.log(str);
|
||||
log.unshift(str);
|
||||
log.length=1;
|
||||
str="";
|
||||
for(var i=19;i>=0;--i) {
|
||||
if(log[i])
|
||||
str+=log[i]+"<br/>";
|
||||
}
|
||||
var evview=document.getElementById("events");
|
||||
evview.innerHTML=str;
|
||||
//console.log( e.type + "/" + e.target.id + "/" + e.target.value);
|
||||
|
||||
if (e.target.id === "noteon" && e.type ==="input")
|
||||
console.log("only noteon change are sent not input");
|
||||
|
||||
else
|
||||
_WS.send("/" + e.target.id + " " + e.target.value);
|
||||
|
||||
// for /scale : after a change (knob is released) reset knob value to 0
|
||||
if (e.target.id.substring(0,5) === "scale" && e.type === "change") {
|
||||
e.target.value = 0;
|
||||
//console.log(e.target.id + "set to 0")
|
||||
}
|
||||
// for /loffset : after a change (knob is released) reset knob value to 0
|
||||
if (e.target.id.substring(0,7) === "loffset" && e.type === "change") {
|
||||
e.target.value = 0;
|
||||
console.log(e.target.id + "set to 0")
|
||||
}
|
||||
// for /angle : after a change (knob is released) reset knob value to 0
|
||||
if (e.target.id.substring(0,5) === "angle" && e.type === "change") {
|
||||
e.target.value = 0;
|
||||
//console.log(e.target.id + "set to 0")
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Menu buttons handler -->
|
||||
<!-- This could be better, simpler with CSS tabs -->
|
||||
<script type="text/javascript">
|
||||
|
||||
function noMenu() {
|
||||
// Set all menu button with normal button style
|
||||
var x = document.getElementById("showalign");
|
||||
x.className = "button";
|
||||
var x = document.getElementById("showrun");
|
||||
x.className = "button";
|
||||
var x = document.getElementById("showcanvas");
|
||||
x.className = "button";
|
||||
var x = document.getElementById("showlive");
|
||||
x.className = "button";
|
||||
|
||||
// Hide all possible main central grids.
|
||||
var x = document.getElementById("mgalign");
|
||||
x.style.display = "none";
|
||||
var x = document.getElementById("mgcanvas");
|
||||
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("showalign");
|
||||
x.className = "button:checked";
|
||||
}
|
||||
|
||||
function showRun() {
|
||||
noMenu();
|
||||
var x = document.getElementById("mgrun");
|
||||
x.style.display = "grid";
|
||||
var x = document.getElementById("showrun");
|
||||
x.className = "button:checked";
|
||||
}
|
||||
|
||||
function showCanvas() {
|
||||
noMenu();
|
||||
var x = document.getElementById("mgcanvas");
|
||||
x.style.display = "block";
|
||||
var x = document.getElementById("showcanvas");
|
||||
x.className = "button:checked";
|
||||
}
|
||||
|
||||
function showLive() {
|
||||
noMenu();
|
||||
var x = document.getElementById("mglive");
|
||||
x.style.display = "grid";
|
||||
var x = document.getElementById("showlive");
|
||||
x.className = "button:checked";
|
||||
}
|
||||
|
||||
function buttonClicked(clicked_id) {
|
||||
_WS.send("/" + clicked_id);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Point list draw -->
|
||||
<script>
|
||||
|
||||
// Store Reference To The Canvas & Set Context
|
||||
var canvas = document.getElementById("canvas");
|
||||
var ctx = canvas.getContext("2d");
|
||||
|
||||
//var re = document.getElementById('speed');
|
||||
//re.addEventListener('change', function(){
|
||||
// speed = re.value;
|
||||
// });
|
||||
|
||||
|
||||
function draw() {
|
||||
|
||||
// Clear Canvas At The Start Of Every Frame
|
||||
ctx.clearRect(0,0,400,400);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(Math.random() * 220, Math.random() * 220);
|
||||
|
||||
// var xA = new Array();
|
||||
// var yA = new Array();
|
||||
//for (var i=0; i<=100, i++){
|
||||
//xA[i] = ;
|
||||
//yA[i] = ;
|
||||
//}
|
||||
|
||||
// Draw Additional Randomly Placed Lines
|
||||
for (var i = 0; i < 25; i++) {
|
||||
ctx.lineTo(Math.random() * 400, Math.random() * 400);
|
||||
}
|
||||
ctx.strokeStyle = "#888";
|
||||
ctx.stroke();
|
||||
|
||||
// Call Draw Function Again To Continue
|
||||
// Drawing To Canvas To Create Animation
|
||||
window.requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
<!--
|
||||
|
||||
//var speed = 100;
|
||||
var lastpoint = { x: 0, y: 0 };
|
||||
var pt = { x: 0, y: 0 };
|
||||
|
||||
// fade background a bit...
|
||||
ctx.globalAlpha = 0.1;
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.fillRect(0, 0, 400, 400);
|
||||
ctx.globalAlpha = 1.0;
|
||||
for (var i=0; i<=100; i++){
|
||||
//var pt = seg.points[point];
|
||||
pt.x = Math.random() * 400;
|
||||
pt.y = Math.random() * 400;
|
||||
// console.log('draw', pt);
|
||||
var newpoint = {
|
||||
x: pt.x,
|
||||
y: pt.y
|
||||
//x: 200 + 190 * pt.x / 32768,
|
||||
//y: 200 - 190 * pt.y / 32768
|
||||
};
|
||||
ctx.strokeStyle = "#888";
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(lastpoint.x, lastpoint.y);
|
||||
ctx.lineTo(newpoint.x, newpoint.y);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
|
||||
lastpoint.x = newpoint.x;
|
||||
lastpoint.y = newpoint.y;
|
||||
}
|
||||
|
||||
-->
|
||||
|
||||
|
||||
|
||||
// Initialize The Draw Function
|
||||
draw();
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
<!-- non displayed items, for code reference
|
||||
<div>
|
||||
<span class="lasertext">Swap X</span>
|
||||
<span class="lasertext">Swap Y</span>
|
||||
</div>
|
||||
<div>
|
||||
<webaudio-switch id="swap/X" value="0" height="76" width="76" tooltip="Switch-B" src="knobs/switch_toggle.png"></webaudio-switch>
|
||||
<webaudio-switch id="swap/Y" value="0" height="76" width="76" tooltip="Switch-B" src="knobs/switch_toggle.png"></webaudio-switch>
|
||||
</div>
|
||||
|
||||
<div><webaudio-knob id="choice" src="knobs/Prophet5.png" diameter="80" min="0" max="10" value="0" sprites="9"></webaudio-knob></div>
|
||||
<div><webaudio-knob id="choice2" src="knobs/Old11.png" diameter="80" min="0" max="10" value="0" sprites="10">></webaudio-knob></div>
|
||||
<div><webaudio-knob id="laser" src="knobs/Prophetic5.png" diameter="70" min="0" max="5" value="0" sprites="5"></webaudio-knob></div>
|
||||
|
||||
<div>
|
||||
<webaudio-slider id="slider1" width="24" height="120"></webaudio-slider>
|
||||
<webaudio-slider id="slider2" width="24" height="120"></webaudio-slider>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<webaudio-switch id="laser/0" height="64" width="25" value="0" src="knobs/key0.png" type="toggle"></webaudio-switch>
|
||||
<webaudio-switch id="laser/1" height="64" width="25" value="0" src="knobs/key0.png" type="toggle"></webaudio-switch>
|
||||
<webaudio-switch id="laser/2" height="64" width="25" value="0" src="knobs/key0.png" type="toggle"></webaudio-switch>
|
||||
<webaudio-switch id="laser/3" height="64" width="25" value="0" src="knobs/key0.png" type="toggle"></webaudio-switch>
|
||||
</div>
|
||||
-->
|
||||
|
||||
</html>
|
BIN
webui/knobs/Prophetic10.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
webui/knobs/Prophetic5.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
webui/knobs/bigbluetoggle.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
webui/knobs/blackout.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
webui/knobs/grid.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
webui/knobs/lasergrid0.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
webui/knobs/lasergrid1.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
webui/knobs/lasergrid2.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
webui/knobs/lasergrid3.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
webui/knobs/leds.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
webui/knobs/ljaylogo.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
webui/knobs/mouse.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
webui/knobs/simplegray.png
Executable file
After Width: | Height: | Size: 222 KiB |
BIN
webui/knobs/swapx.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
webui/knobs/swapy.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
webui/knobs/switch_toggle.png
Executable file
After Width: | Height: | Size: 4.4 KiB |
1875
webui/webaudio-controls.js
Executable file
197
webui/webcomponents-lite.js
Executable file
@ -0,0 +1,197 @@
|
||||
(function(){/*
|
||||
|
||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
'use strict';var p,q="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this,ba="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)};function ca(){ca=function(){};q.Symbol||(q.Symbol=da)}var da=function(){var a=0;return function(b){return"jscomp_symbol_"+(b||"")+a++}}();
|
||||
function ea(){ca();var a=q.Symbol.iterator;a||(a=q.Symbol.iterator=q.Symbol("iterator"));"function"!=typeof Array.prototype[a]&&ba(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return fa(this)}});ea=function(){}}function fa(a){var b=0;return ha(function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}})}function ha(a){ea();a={next:a};a[q.Symbol.iterator]=function(){return this};return a}function ia(a){ea();var b=a[Symbol.iterator];return b?b.call(a):fa(a)}
|
||||
function ja(a){for(var b,c=[];!(b=a.next()).done;)c.push(b.value);return c}
|
||||
(function(){if(!function(){var a=document.createEvent("Event");a.initEvent("foo",!0,!0);a.preventDefault();return a.defaultPrevented}()){var a=Event.prototype.preventDefault;Event.prototype.preventDefault=function(){this.cancelable&&(a.call(this),Object.defineProperty(this,"defaultPrevented",{get:function(){return!0},configurable:!0}))}}var b=/Trident/.test(navigator.userAgent);if(!window.CustomEvent||b&&"function"!==typeof window.CustomEvent)window.CustomEvent=function(a,b){b=b||{};var c=document.createEvent("CustomEvent");
|
||||
c.initCustomEvent(a,!!b.bubbles,!!b.cancelable,b.detail);return c},window.CustomEvent.prototype=window.Event.prototype;if(!window.Event||b&&"function"!==typeof window.Event){var c=window.Event;window.Event=function(a,b){b=b||{};var c=document.createEvent("Event");c.initEvent(a,!!b.bubbles,!!b.cancelable);return c};if(c)for(var d in c)window.Event[d]=c[d];window.Event.prototype=c.prototype}if(!window.MouseEvent||b&&"function"!==typeof window.MouseEvent){b=window.MouseEvent;window.MouseEvent=function(a,
|
||||
b){b=b||{};var c=document.createEvent("MouseEvent");c.initMouseEvent(a,!!b.bubbles,!!b.cancelable,b.view||window,b.detail,b.screenX,b.screenY,b.clientX,b.clientY,b.ctrlKey,b.altKey,b.shiftKey,b.metaKey,b.button,b.relatedTarget);return c};if(b)for(d in b)window.MouseEvent[d]=b[d];window.MouseEvent.prototype=b.prototype}Array.from||(Array.from=function(a){return[].slice.call(a)});Object.assign||(Object.assign=function(a,b){for(var c=[].slice.call(arguments,1),d=0,e;d<c.length;d++)if(e=c[d])for(var f=
|
||||
a,m=e,n=Object.getOwnPropertyNames(m),t=0;t<n.length;t++)e=n[t],f[e]=m[e];return a})})(window.WebComponents);(function(){function a(){}function b(a,b){if(!a.childNodes.length)return[];switch(a.nodeType){case Node.DOCUMENT_NODE:return t.call(a,b);case Node.DOCUMENT_FRAGMENT_NODE:return C.call(a,b);default:return n.call(a,b)}}var c="undefined"===typeof HTMLTemplateElement,d=!(document.createDocumentFragment().cloneNode()instanceof DocumentFragment),e=!1;/Trident/.test(navigator.userAgent)&&function(){function a(a,b){if(a instanceof DocumentFragment)for(var d;d=a.firstChild;)c.call(this,d,b);else c.call(this,
|
||||
a,b);return a}e=!0;var b=Node.prototype.cloneNode;Node.prototype.cloneNode=function(a){a=b.call(this,a);this instanceof DocumentFragment&&(a.__proto__=DocumentFragment.prototype);return a};DocumentFragment.prototype.querySelectorAll=HTMLElement.prototype.querySelectorAll;DocumentFragment.prototype.querySelector=HTMLElement.prototype.querySelector;Object.defineProperties(DocumentFragment.prototype,{nodeType:{get:function(){return Node.DOCUMENT_FRAGMENT_NODE},configurable:!0},localName:{get:function(){},
|
||||
configurable:!0},nodeName:{get:function(){return"#document-fragment"},configurable:!0}});var c=Node.prototype.insertBefore;Node.prototype.insertBefore=a;var d=Node.prototype.appendChild;Node.prototype.appendChild=function(b){b instanceof DocumentFragment?a.call(this,b,null):d.call(this,b);return b};var f=Node.prototype.removeChild,h=Node.prototype.replaceChild;Node.prototype.replaceChild=function(b,c){b instanceof DocumentFragment?(a.call(this,b,c),f.call(this,c)):h.call(this,b,c);return c};Document.prototype.createDocumentFragment=
|
||||
function(){var a=this.createElement("df");a.__proto__=DocumentFragment.prototype;return a};var g=Document.prototype.importNode;Document.prototype.importNode=function(a,b){b=g.call(this,a,b||!1);a instanceof DocumentFragment&&(b.__proto__=DocumentFragment.prototype);return b}}();var f=Node.prototype.cloneNode,h=Document.prototype.createElement,g=Document.prototype.importNode,k=Node.prototype.removeChild,l=Node.prototype.appendChild,m=Node.prototype.replaceChild,n=Element.prototype.querySelectorAll,
|
||||
t=Document.prototype.querySelectorAll,C=DocumentFragment.prototype.querySelectorAll,eb=function(){if(!c){var a=document.createElement("template"),b=document.createElement("template");b.content.appendChild(document.createElement("div"));a.content.appendChild(b);a=a.cloneNode(!0);return 0===a.content.childNodes.length||0===a.content.firstChild.content.childNodes.length||d}}();if(c){var J=document.implementation.createHTMLDocument("template"),Ca=!0,Da=document.createElement("style");Da.textContent="template{display:none;}";
|
||||
var Ea=document.head;Ea.insertBefore(Da,Ea.firstElementChild);a.prototype=Object.create(HTMLElement.prototype);var x=!document.createElement("div").hasOwnProperty("innerHTML");a.D=function(b){if(!b.content){b.content=J.createDocumentFragment();for(var c;c=b.firstChild;)l.call(b.content,c);if(x)b.__proto__=a.prototype;else if(b.cloneNode=function(b){return a.ca(this,b)},Ca)try{na(b),aa(b)}catch(Mg){Ca=!1}a.J(b.content)}};var na=function(b){Object.defineProperty(b,"innerHTML",{get:function(){for(var a=
|
||||
"",b=this.content.firstChild;b;b=b.nextSibling)a+=b.outerHTML||b.data.replace(oa,U);return a},set:function(b){J.body.innerHTML=b;for(a.J(J);this.content.firstChild;)k.call(this.content,this.content.firstChild);for(;J.body.firstChild;)l.call(this.content,J.body.firstChild)},configurable:!0})},aa=function(a){Object.defineProperty(a,"outerHTML",{get:function(){return"<template>"+this.innerHTML+"</template>"},set:function(a){if(this.parentNode){J.body.innerHTML=a;for(a=this.ownerDocument.createDocumentFragment();J.body.firstChild;)l.call(a,
|
||||
J.body.firstChild);m.call(this.parentNode,a,this)}else throw Error("Failed to set the 'outerHTML' property on 'Element': This element has no parent node.");},configurable:!0})};na(a.prototype);aa(a.prototype);a.J=function(c){c=b(c,"template");for(var d=0,e=c.length,f;d<e&&(f=c[d]);d++)a.D(f)};document.addEventListener("DOMContentLoaded",function(){a.J(document)});Document.prototype.createElement=function(){var b=h.apply(this,arguments);"template"===b.localName&&a.D(b);return b};var oa=/[&\u00A0<>]/g,
|
||||
U=function(a){switch(a){case "&":return"&";case "<":return"<";case ">":return">";case "\u00a0":return" "}}}if(c||eb){a.ca=function(a,b){var c=f.call(a,!1);this.D&&this.D(c);b&&(l.call(c.content,f.call(a.content,!0)),fb(c.content,a.content));return c};var fb=function(c,d){if(d.querySelectorAll&&(d=b(d,"template"),0!==d.length)){c=b(c,"template");for(var e=0,f=c.length,h,g;e<f;e++)g=d[e],h=c[e],a&&a.D&&a.D(g),m.call(h.parentNode,pa.call(g,!0),h)}},pa=Node.prototype.cloneNode=function(b){if(!e&&
|
||||
d&&this instanceof DocumentFragment)if(b)var c=qa.call(this.ownerDocument,this,!0);else return this.ownerDocument.createDocumentFragment();else c=this.nodeType===Node.ELEMENT_NODE&&"template"===this.localName?a.ca(this,b):f.call(this,b);b&&fb(c,this);return c},qa=Document.prototype.importNode=function(c,d){d=d||!1;if("template"===c.localName)return a.ca(c,d);var e=g.call(this,c,d);if(d){fb(e,c);c=b(e,'script:not([type]),script[type="application/javascript"],script[type="text/javascript"]');for(var f,
|
||||
k=0;k<c.length;k++){f=c[k];d=h.call(document,"script");d.textContent=f.textContent;for(var l=f.attributes,qa=0,pa;qa<l.length;qa++)pa=l[qa],d.setAttribute(pa.name,pa.value);m.call(f.parentNode,d,f)}}return e}}c&&(window.HTMLTemplateElement=a)})();var ka=Array.isArray?Array.isArray:function(a){return"[object Array]"===Object.prototype.toString.call(a)};var la=0,ma,ra="undefined"!==typeof window?window:void 0,sa=ra||{},ta=sa.MutationObserver||sa.WebKitMutationObserver,ua="undefined"!==typeof Uint8ClampedArray&&"undefined"!==typeof importScripts&&"undefined"!==typeof MessageChannel;function va(){return"undefined"!==typeof ma?function(){ma(wa)}:xa()}function ya(){var a=0,b=new ta(wa),c=document.createTextNode("");b.observe(c,{characterData:!0});return function(){c.data=a=++a%2}}
|
||||
function za(){var a=new MessageChannel;a.port1.onmessage=wa;return function(){return a.port2.postMessage(0)}}function xa(){var a=setTimeout;return function(){return a(wa,1)}}var Aa=Array(1E3);function wa(){for(var a=0;a<la;a+=2)(0,Aa[a])(Aa[a+1]),Aa[a]=void 0,Aa[a+1]=void 0;la=0}var Ba,Fa;
|
||||
if("undefined"===typeof self&&"undefined"!==typeof process&&"[object process]"==={}.toString.call(process))Fa=function(){return process.ib(wa)};else{var Ga;if(ta)Ga=ya();else{var Ha;if(ua)Ha=za();else{var Ia;if(void 0===ra&&"function"===typeof require)try{var Ja=require("vertx");ma=Ja.kb||Ja.jb;Ia=va()}catch(a){Ia=xa()}else Ia=xa();Ha=Ia}Ga=Ha}Fa=Ga}Ba=Fa;function Ka(a,b){Aa[la]=a;Aa[la+1]=b;la+=2;2===la&&Ba()};function La(a,b){var c=this,d=new this.constructor(Ma);void 0===d[Na]&&Oa(d);var e=c.g;if(e){var f=arguments[e-1];Ka(function(){return Pa(e,d,f,c.f)})}else Qa(c,d,a,b);return d};function Ra(a){if(a&&"object"===typeof a&&a.constructor===this)return a;var b=new this(Ma);Sa(b,a);return b};var Na=Math.random().toString(36).substring(16);function Ma(){}var Ua=new Ta;function Va(a){try{return a.then}catch(b){return Ua.error=b,Ua}}function Wa(a,b,c,d){try{a.call(b,c,d)}catch(e){return e}}function Xa(a,b,c){Ka(function(a){var d=!1,f=Wa(c,b,function(c){d||(d=!0,b!==c?Sa(a,c):r(a,c))},function(b){d||(d=!0,u(a,b))});!d&&f&&(d=!0,u(a,f))},a)}function Ya(a,b){1===b.g?r(a,b.f):2===b.g?u(a,b.f):Qa(b,void 0,function(b){return Sa(a,b)},function(b){return u(a,b)})}
|
||||
function Za(a,b,c){b.constructor===a.constructor&&c===La&&b.constructor.resolve===Ra?Ya(a,b):c===Ua?(u(a,Ua.error),Ua.error=null):void 0===c?r(a,b):"function"===typeof c?Xa(a,b,c):r(a,b)}function Sa(a,b){if(a===b)u(a,new TypeError("You cannot resolve a promise with itself"));else{var c=typeof b;null===b||"object"!==c&&"function"!==c?r(a,b):Za(a,b,Va(b))}}function $a(a){a.na&&a.na(a.f);ab(a)}function r(a,b){void 0===a.g&&(a.f=b,a.g=1,0!==a.I.length&&Ka(ab,a))}
|
||||
function u(a,b){void 0===a.g&&(a.g=2,a.f=b,Ka($a,a))}function Qa(a,b,c,d){var e=a.I,f=e.length;a.na=null;e[f]=b;e[f+1]=c;e[f+2]=d;0===f&&a.g&&Ka(ab,a)}function ab(a){var b=a.I,c=a.g;if(0!==b.length){for(var d,e,f=a.f,h=0;h<b.length;h+=3)d=b[h],e=b[h+c],d?Pa(c,d,e,f):e(f);a.I.length=0}}function Ta(){this.error=null}var bb=new Ta;
|
||||
function Pa(a,b,c,d){var e="function"===typeof c;if(e){try{var f=c(d)}catch(l){bb.error=l,f=bb}if(f===bb){var h=!0;var g=f.error;f.error=null}else var k=!0;if(b===f){u(b,new TypeError("A promises callback cannot return that same promise."));return}}else f=d,k=!0;void 0===b.g&&(e&&k?Sa(b,f):h?u(b,g):1===a?r(b,f):2===a&&u(b,f))}function cb(a,b){try{b(function(b){Sa(a,b)},function(b){u(a,b)})}catch(c){u(a,c)}}var db=0;function Oa(a){a[Na]=db++;a.g=void 0;a.f=void 0;a.I=[]};function gb(a,b){this.Ea=a;this.A=new a(Ma);this.A[Na]||Oa(this.A);if(ka(b))if(this.S=this.length=b.length,this.f=Array(this.length),0===this.length)r(this.A,this.f);else{this.length=this.length||0;for(a=0;void 0===this.g&&a<b.length;a++)hb(this,b[a],a);0===this.S&&r(this.A,this.f)}else u(this.A,Error("Array Methods must be provided an Array"))}
|
||||
function hb(a,b,c){var d=a.Ea,e=d.resolve;e===Ra?(e=Va(b),e===La&&void 0!==b.g?ib(a,b.g,c,b.f):"function"!==typeof e?(a.S--,a.f[c]=b):d===v?(d=new d(Ma),Za(d,b,e),jb(a,d,c)):jb(a,new d(function(a){return a(b)}),c)):jb(a,e(b),c)}function ib(a,b,c,d){var e=a.A;void 0===e.g&&(a.S--,2===b?u(e,d):a.f[c]=d);0===a.S&&r(e,a.f)}function jb(a,b,c){Qa(b,void 0,function(b){return ib(a,1,c,b)},function(b){return ib(a,2,c,b)})};function kb(a){return(new gb(this,a)).A};function lb(a){var b=this;return ka(a)?new b(function(c,d){for(var e=a.length,f=0;f<e;f++)b.resolve(a[f]).then(c,d)}):new b(function(a,b){return b(new TypeError("You must pass an array to race."))})};function mb(a){var b=new this(Ma);u(b,a);return b};function v(a){this[Na]=db++;this.f=this.g=void 0;this.I=[];if(Ma!==a){if("function"!==typeof a)throw new TypeError("You must pass a resolver function as the first argument to the promise constructor");if(this instanceof v)cb(this,a);else throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");}}v.prototype={constructor:v,then:La,a:function(a){return this.then(null,a)}};/*
|
||||
|
||||
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
window.Promise||(window.Promise=v,v.prototype["catch"]=v.prototype.a,v.prototype.then=v.prototype.then,v.all=kb,v.race=lb,v.resolve=Ra,v.reject=mb);(function(a){function b(a,b){if("function"===typeof window.CustomEvent)return new CustomEvent(a,b);var c=document.createEvent("CustomEvent");c.initCustomEvent(a,!!b.bubbles,!!b.cancelable,b.detail);return c}function c(a){if(C)return a.ownerDocument!==document?a.ownerDocument:null;var b=a.__importDoc;if(!b&&a.parentNode){b=a.parentNode;if("function"===typeof b.closest)b=b.closest("link[rel=import]");else for(;!g(b)&&(b=b.parentNode););a.__importDoc=b}return b}function d(a){var b=m(document,"link[rel=import]:not([import-dependency])"),
|
||||
c=b.length;c?n(b,function(b){return h(b,function(){0===--c&&a()})}):a()}function e(a){function b(){"loading"!==document.readyState&&document.body&&(document.removeEventListener("readystatechange",b),a())}document.addEventListener("readystatechange",b);b()}function f(a){e(function(){return d(function(){return a&&a()})})}function h(a,b){if(a.__loaded)b&&b();else if("script"===a.localName&&!a.src||"style"===a.localName&&!a.firstChild)a.__loaded=!0,b&&b();else{var c=function(d){a.removeEventListener(d.type,
|
||||
c);a.__loaded=!0;b&&b()};a.addEventListener("load",c);aa&&"style"===a.localName||a.addEventListener("error",c)}}function g(a){return a.nodeType===Node.ELEMENT_NODE&&"link"===a.localName&&"import"===a.rel}function k(){var a=this;this.a={};this.b=0;this.c=new MutationObserver(function(b){return a.Ra(b)});this.c.observe(document.head,{childList:!0,subtree:!0});this.loadImports(document)}function l(a){n(m(a,"template"),function(a){n(m(a.content,'script:not([type]),script[type="application/javascript"],script[type="text/javascript"]'),
|
||||
function(a){var b=document.createElement("script");n(a.attributes,function(a){return b.setAttribute(a.name,a.value)});b.textContent=a.textContent;a.parentNode.replaceChild(b,a)});l(a.content)})}function m(a,b){return a.childNodes.length?a.querySelectorAll(b):eb}function n(a,b,c){var d=a?a.length:0,e=c?-1:1;for(c=c?d-1:0;c<d&&0<=c;c+=e)b(a[c],c)}var t=document.createElement("link"),C="import"in t,eb=t.querySelectorAll("*"),J=null;!1==="currentScript"in document&&Object.defineProperty(document,"currentScript",
|
||||
{get:function(){return J||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null)},configurable:!0});var Ca=/(url\()([^)]*)(\))/g,Da=/(@import[\s]+(?!url\())([^;]*)(;)/g,Ea=/(<link[^>]*)(rel=['|"]?stylesheet['|"]?[^>]*>)/g,x={La:function(a,b){a.href&&a.setAttribute("href",x.Y(a.getAttribute("href"),b));a.src&&a.setAttribute("src",x.Y(a.getAttribute("src"),b));if("style"===a.localName){var c=x.ta(a.textContent,b,Ca);a.textContent=x.ta(c,b,Da)}},ta:function(a,b,c){return a.replace(c,
|
||||
function(a,c,d,e){a=d.replace(/["']/g,"");b&&(a=x.Y(a,b));return c+"'"+a+"'"+e})},Y:function(a,b){if(void 0===x.ba){x.ba=!1;try{var c=new URL("b","http://a");c.pathname="c%20d";x.ba="http://a/c%20d"===c.href}catch(Lg){}}if(x.ba)return(new URL(a,b)).href;c=x.Ba;c||(c=document.implementation.createHTMLDocument("temp"),x.Ba=c,c.ma=c.createElement("base"),c.head.appendChild(c.ma),c.la=c.createElement("a"));c.ma.href=b;c.la.href=a;return c.la.href||a}},na={async:!0,load:function(a,b,c){if(a)if(a.match(/^data:/)){a=
|
||||
a.split(",");var d=a[1];d=-1<a[0].indexOf(";base64")?atob(d):decodeURIComponent(d);b(d)}else{var e=new XMLHttpRequest;e.open("GET",a,na.async);e.onload=function(){var a=e.responseURL||e.getResponseHeader("Location");a&&0===a.indexOf("/")&&(a=(location.origin||location.protocol+"//"+location.host)+a);var d=e.response||e.responseText;304===e.status||0===e.status||200<=e.status&&300>e.status?b(d,a):c(d)};e.send()}else c("error: href must be specified")}},aa=/Trident/.test(navigator.userAgent)||/Edge\/\d./i.test(navigator.userAgent);
|
||||
k.prototype.loadImports=function(a){var b=this;a=m(a,"link[rel=import]");n(a,function(a){return b.s(a)})};k.prototype.s=function(a){var b=this,c=a.href;if(void 0!==this.a[c]){var d=this.a[c];d&&d.__loaded&&(a.__import=d,this.h(a))}else this.b++,this.a[c]="pending",na.load(c,function(a,d){a=b.Sa(a,d||c);b.a[c]=a;b.b--;b.loadImports(a);b.L()},function(){b.a[c]=null;b.b--;b.L()})};k.prototype.Sa=function(a,b){if(!a)return document.createDocumentFragment();aa&&(a=a.replace(Ea,function(a,b,c){return-1===
|
||||
a.indexOf("type=")?b+" type=import-disable "+c:a}));var c=document.createElement("template");c.innerHTML=a;if(c.content)a=c.content,l(a);else for(a=document.createDocumentFragment();c.firstChild;)a.appendChild(c.firstChild);if(c=a.querySelector("base"))b=x.Y(c.getAttribute("href"),b),c.removeAttribute("href");c=m(a,'link[rel=import],link[rel=stylesheet][href][type=import-disable],style:not([type]),link[rel=stylesheet][href]:not([type]),script:not([type]),script[type="application/javascript"],script[type="text/javascript"]');
|
||||
var d=0;n(c,function(a){h(a);x.La(a,b);a.setAttribute("import-dependency","");"script"===a.localName&&!a.src&&a.textContent&&(a.setAttribute("src","data:text/javascript;charset=utf-8,"+encodeURIComponent(a.textContent+("\n//# sourceURL="+b+(d?"-"+d:"")+".js\n"))),a.textContent="",d++)});return a};k.prototype.L=function(){var a=this;if(!this.b){this.c.disconnect();this.flatten(document);var b=!1,c=!1,d=function(){c&&b&&(a.loadImports(document),a.b||(a.c.observe(document.head,{childList:!0,subtree:!0}),
|
||||
a.Pa()))};this.Ua(function(){c=!0;d()});this.Ta(function(){b=!0;d()})}};k.prototype.flatten=function(a){var b=this;a=m(a,"link[rel=import]");n(a,function(a){var c=b.a[a.href];(a.__import=c)&&c.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&(b.a[a.href]=a,a.readyState="loading",a.__import=a,b.flatten(c),a.appendChild(c))})};k.prototype.Ta=function(a){function b(e){if(e<d){var f=c[e],g=document.createElement("script");f.removeAttribute("import-dependency");n(f.attributes,function(a){return g.setAttribute(a.name,
|
||||
a.value)});J=g;f.parentNode.replaceChild(g,f);h(g,function(){J=null;b(e+1)})}else a()}var c=m(document,"script[import-dependency]"),d=c.length;b(0)};k.prototype.Ua=function(a){var b=m(document,"style[import-dependency],link[rel=stylesheet][import-dependency]"),d=b.length;if(d){var e=aa&&!!document.querySelector("link[rel=stylesheet][href][type=import-disable]");n(b,function(b){h(b,function(){b.removeAttribute("import-dependency");0===--d&&a()});if(e&&b.parentNode!==document.head){var f=document.createElement(b.localName);
|
||||
f.__appliedElement=b;f.setAttribute("type","import-placeholder");b.parentNode.insertBefore(f,b.nextSibling);for(f=c(b);f&&c(f);)f=c(f);f.parentNode!==document.head&&(f=null);document.head.insertBefore(b,f);b.removeAttribute("type")}})}else a()};k.prototype.Pa=function(){var a=this,b=m(document,"link[rel=import]");n(b,function(b){return a.h(b)},!0)};k.prototype.h=function(a){a.__loaded||(a.__loaded=!0,a.import&&(a.import.readyState="complete"),a.dispatchEvent(b(a.import?"load":"error",{bubbles:!1,
|
||||
cancelable:!1,detail:void 0})))};k.prototype.Ra=function(a){var b=this;n(a,function(a){return n(a.addedNodes,function(a){a&&a.nodeType===Node.ELEMENT_NODE&&(g(a)?b.s(a):b.loadImports(a))})})};var oa=null;if(C)t=m(document,"link[rel=import]"),n(t,function(a){a.import&&"loading"===a.import.readyState||(a.__loaded=!0)}),t=function(a){a=a.target;g(a)&&(a.__loaded=!0)},document.addEventListener("load",t,!0),document.addEventListener("error",t,!0);else{var U=Object.getOwnPropertyDescriptor(Node.prototype,
|
||||
"baseURI");Object.defineProperty((!U||U.configurable?Node:Element).prototype,"baseURI",{get:function(){var a=g(this)?this:c(this);return a?a.href:U&&U.get?U.get.call(this):(document.querySelector("base")||window.location).href},configurable:!0,enumerable:!0});Object.defineProperty(HTMLLinkElement.prototype,"import",{get:function(){return this.__import||null},configurable:!0,enumerable:!0});e(function(){oa=new k})}f(function(){return document.dispatchEvent(b("HTMLImportsLoaded",{cancelable:!0,bubbles:!0,
|
||||
detail:void 0}))});a.useNative=C;a.whenReady=f;a.importForElement=c;a.loadImports=function(a){oa&&oa.loadImports(a)}})(window.HTMLImports=window.HTMLImports||{});/*
|
||||
|
||||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
window.WebComponents=window.WebComponents||{flags:{}};var nb=document.querySelector('script[src*="webcomponents-lite.js"]'),ob=/wc-(.+)/,w={};if(!w.noOpts){location.search.slice(1).split("&").forEach(function(a){a=a.split("=");var b;a[0]&&(b=a[0].match(ob))&&(w[b[1]]=a[1]||!0)});if(nb)for(var pb=0,qb;qb=nb.attributes[pb];pb++)"src"!==qb.name&&(w[qb.name]=qb.value||!0);if(w.log&&w.log.split){var rb=w.log.split(",");w.log={};rb.forEach(function(a){w.log[a]=!0})}else w.log={}}
|
||||
window.WebComponents.flags=w;var sb=w.shadydom;sb&&(window.ShadyDOM=window.ShadyDOM||{},window.ShadyDOM.force=sb);var tb=w.register||w.ce;tb&&window.customElements&&(window.customElements.forcePolyfill=tb);/*
|
||||
|
||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
var y=window.ShadyDOM||{};y.Na=!(!Element.prototype.attachShadow||!Node.prototype.getRootNode);var ub=Object.getOwnPropertyDescriptor(Node.prototype,"firstChild");y.M=!!(ub&&ub.configurable&&ub.get);y.sa=y.force||!y.Na;function vb(a){return a.__shady&&void 0!==a.__shady.firstChild}function z(a){return"ShadyRoot"===a.ya}function wb(a){a=a.getRootNode();if(z(a))return a}var xb=Element.prototype,yb=xb.matches||xb.matchesSelector||xb.mozMatchesSelector||xb.msMatchesSelector||xb.oMatchesSelector||xb.webkitMatchesSelector;
|
||||
function zb(a,b){if(a&&b)for(var c=Object.getOwnPropertyNames(b),d=0,e;d<c.length&&(e=c[d]);d++){var f=Object.getOwnPropertyDescriptor(b,e);f&&Object.defineProperty(a,e,f)}}function Ab(a,b){for(var c=[],d=1;d<arguments.length;++d)c[d-1]=arguments[d];for(d=0;d<c.length;d++)zb(a,c[d]);return a}function Bb(a,b){for(var c in b)a[c]=b[c]}var Cb=document.createTextNode(""),Db=0,Eb=[];(new MutationObserver(function(){for(;Eb.length;)try{Eb.shift()()}catch(a){throw Cb.textContent=Db++,a;}})).observe(Cb,{characterData:!0});
|
||||
function Fb(a){Eb.push(a);Cb.textContent=Db++}var Gb=!!document.contains;function Hb(a,b){for(;b;){if(b==a)return!0;b=b.parentNode}return!1};var Ib=[],Jb;function Kb(a){Jb||(Jb=!0,Fb(Lb));Ib.push(a)}function Lb(){Jb=!1;for(var a=!!Ib.length;Ib.length;)Ib.shift()();return a}Lb.list=Ib;function Mb(){this.a=!1;this.addedNodes=[];this.removedNodes=[];this.V=new Set}function Nb(a){a.a||(a.a=!0,Fb(function(){Ob(a)}))}function Ob(a){if(a.a){a.a=!1;var b=a.takeRecords();b.length&&a.V.forEach(function(a){a(b)})}}Mb.prototype.takeRecords=function(){if(this.addedNodes.length||this.removedNodes.length){var a=[{addedNodes:this.addedNodes,removedNodes:this.removedNodes}];this.addedNodes=[];this.removedNodes=[];return a}return[]};
|
||||
function Pb(a,b){a.__shady=a.__shady||{};a.__shady.N||(a.__shady.N=new Mb);a.__shady.N.V.add(b);var c=a.__shady.N;return{Ca:b,C:c,Ga:a,takeRecords:function(){return c.takeRecords()}}}function Qb(a){var b=a&&a.C;b&&(b.V.delete(a.Ca),b.V.size||(a.Ga.__shady.N=null))}
|
||||
function Rb(a,b){var c=b.getRootNode();return a.map(function(a){var b=c===a.target.getRootNode();if(b&&a.addedNodes){if(b=Array.from(a.addedNodes).filter(function(a){return c===a.getRootNode()}),b.length)return a=Object.create(a),Object.defineProperty(a,"addedNodes",{value:b,configurable:!0}),a}else if(b)return a}).filter(function(a){return a})};var A={},Sb=Element.prototype.insertBefore,Tb=Element.prototype.removeChild,Ub=Element.prototype.setAttribute,Vb=Element.prototype.removeAttribute,Wb=Element.prototype.cloneNode,Xb=Document.prototype.importNode,Yb=Element.prototype.addEventListener,Zb=Element.prototype.removeEventListener,$b=Window.prototype.addEventListener,ac=Window.prototype.removeEventListener,bc=Element.prototype.dispatchEvent,cc=Element.prototype.querySelector,dc=Element.prototype.querySelectorAll,ec=Node.prototype.contains||
|
||||
HTMLElement.prototype.contains;A.appendChild=Element.prototype.appendChild;A.insertBefore=Sb;A.removeChild=Tb;A.setAttribute=Ub;A.removeAttribute=Vb;A.cloneNode=Wb;A.importNode=Xb;A.addEventListener=Yb;A.removeEventListener=Zb;A.ab=$b;A.bb=ac;A.dispatchEvent=bc;A.querySelector=cc;A.querySelectorAll=dc;A.contains=ec;var fc=/[&\u00A0"]/g,gc=/[&\u00A0<>]/g;function hc(a){switch(a){case "&":return"&";case "<":return"<";case ">":return">";case '"':return""";case "\u00a0":return" "}}function ic(a){for(var b={},c=0;c<a.length;c++)b[a[c]]=!0;return b}var jc=ic("area base br col command embed hr img input keygen link meta param source track wbr".split(" ")),kc=ic("style script xmp iframe noembed noframes plaintext noscript".split(" "));
|
||||
function lc(a,b){"template"===a.localName&&(a=a.content);for(var c="",d=b?b(a):a.childNodes,e=0,f=d.length,h;e<f&&(h=d[e]);e++){a:{var g=h;var k=a;var l=b;switch(g.nodeType){case Node.ELEMENT_NODE:for(var m=g.localName,n="<"+m,t=g.attributes,C=0;k=t[C];C++)n+=" "+k.name+'="'+k.value.replace(fc,hc)+'"';n+=">";g=jc[m]?n:n+lc(g,l)+"</"+m+">";break a;case Node.TEXT_NODE:g=g.data;g=k&&kc[k.localName]?g:g.replace(gc,hc);break a;case Node.COMMENT_NODE:g="\x3c!--"+g.data+"--\x3e";break a;default:throw window.console.error(g),
|
||||
Error("not implemented");}}c+=g}return c};var B={},D=document.createTreeWalker(document,NodeFilter.SHOW_ALL,null,!1),E=document.createTreeWalker(document,NodeFilter.SHOW_ELEMENT,null,!1);function mc(a){var b=[];D.currentNode=a;for(a=D.firstChild();a;)b.push(a),a=D.nextSibling();return b}B.parentNode=function(a){D.currentNode=a;return D.parentNode()};B.firstChild=function(a){D.currentNode=a;return D.firstChild()};B.lastChild=function(a){D.currentNode=a;return D.lastChild()};B.previousSibling=function(a){D.currentNode=a;return D.previousSibling()};
|
||||
B.nextSibling=function(a){D.currentNode=a;return D.nextSibling()};B.childNodes=mc;B.parentElement=function(a){E.currentNode=a;return E.parentNode()};B.firstElementChild=function(a){E.currentNode=a;return E.firstChild()};B.lastElementChild=function(a){E.currentNode=a;return E.lastChild()};B.previousElementSibling=function(a){E.currentNode=a;return E.previousSibling()};B.nextElementSibling=function(a){E.currentNode=a;return E.nextSibling()};
|
||||
B.children=function(a){var b=[];E.currentNode=a;for(a=E.firstChild();a;)b.push(a),a=E.nextSibling();return b};B.innerHTML=function(a){return lc(a,function(a){return mc(a)})};B.textContent=function(a){switch(a.nodeType){case Node.ELEMENT_NODE:case Node.DOCUMENT_FRAGMENT_NODE:a=document.createTreeWalker(a,NodeFilter.SHOW_TEXT,null,!1);for(var b="",c;c=a.nextNode();)b+=c.nodeValue;return b;default:return a.nodeValue}};var nc=Object.getOwnPropertyDescriptor(Element.prototype,"innerHTML")||Object.getOwnPropertyDescriptor(HTMLElement.prototype,"innerHTML"),oc=document.implementation.createHTMLDocument("inert"),pc=Object.getOwnPropertyDescriptor(Document.prototype,"activeElement"),qc={parentElement:{get:function(){var a=this.__shady&&this.__shady.parentNode;a&&a.nodeType!==Node.ELEMENT_NODE&&(a=null);return void 0!==a?a:B.parentElement(this)},configurable:!0},parentNode:{get:function(){var a=this.__shady&&this.__shady.parentNode;
|
||||
return void 0!==a?a:B.parentNode(this)},configurable:!0},nextSibling:{get:function(){var a=this.__shady&&this.__shady.nextSibling;return void 0!==a?a:B.nextSibling(this)},configurable:!0},previousSibling:{get:function(){var a=this.__shady&&this.__shady.previousSibling;return void 0!==a?a:B.previousSibling(this)},configurable:!0},className:{get:function(){return this.getAttribute("class")||""},set:function(a){this.setAttribute("class",a)},configurable:!0},nextElementSibling:{get:function(){if(this.__shady&&
|
||||
void 0!==this.__shady.nextSibling){for(var a=this.nextSibling;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling;return a}return B.nextElementSibling(this)},configurable:!0},previousElementSibling:{get:function(){if(this.__shady&&void 0!==this.__shady.previousSibling){for(var a=this.previousSibling;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}return B.previousElementSibling(this)},configurable:!0}},rc={childNodes:{get:function(){if(vb(this)){if(!this.__shady.childNodes){this.__shady.childNodes=
|
||||
[];for(var a=this.firstChild;a;a=a.nextSibling)this.__shady.childNodes.push(a)}var b=this.__shady.childNodes}else b=B.childNodes(this);b.item=function(a){return b[a]};return b},configurable:!0},childElementCount:{get:function(){return this.children.length},configurable:!0},firstChild:{get:function(){var a=this.__shady&&this.__shady.firstChild;return void 0!==a?a:B.firstChild(this)},configurable:!0},lastChild:{get:function(){var a=this.__shady&&this.__shady.lastChild;return void 0!==a?a:B.lastChild(this)},
|
||||
configurable:!0},textContent:{get:function(){if(vb(this)){for(var a=[],b=0,c=this.childNodes,d;d=c[b];b++)d.nodeType!==Node.COMMENT_NODE&&a.push(d.textContent);return a.join("")}return B.textContent(this)},set:function(a){if("undefined"===typeof a||null===a)a="";switch(this.nodeType){case Node.ELEMENT_NODE:case Node.DOCUMENT_FRAGMENT_NODE:for(;this.firstChild;)this.removeChild(this.firstChild);(0<a.length||this.nodeType===Node.ELEMENT_NODE)&&this.appendChild(document.createTextNode(a));break;default:this.nodeValue=
|
||||
a}},configurable:!0},firstElementChild:{get:function(){if(this.__shady&&void 0!==this.__shady.firstChild){for(var a=this.firstChild;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling;return a}return B.firstElementChild(this)},configurable:!0},lastElementChild:{get:function(){if(this.__shady&&void 0!==this.__shady.lastChild){for(var a=this.lastChild;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}return B.lastElementChild(this)},configurable:!0},children:{get:function(){var a=vb(this)?
|
||||
Array.prototype.filter.call(this.childNodes,function(a){return a.nodeType===Node.ELEMENT_NODE}):B.children(this);a.item=function(b){return a[b]};return a},configurable:!0},innerHTML:{get:function(){var a="template"===this.localName?this.content:this;return vb(this)?lc(a):B.innerHTML(a)},set:function(a){for(var b="template"===this.localName?this.content:this;b.firstChild;)b.removeChild(b.firstChild);var c=this.localName;c&&"template"!==c||(c="div");c=oc.createElement(c);for(nc&&nc.set?nc.set.call(c,
|
||||
a):c.innerHTML=a;c.firstChild;)b.appendChild(c.firstChild)},configurable:!0}},sc={shadowRoot:{get:function(){return this.__shady&&this.__shady.Va||null},configurable:!0}},tc={activeElement:{get:function(){var a=pc&&pc.get?pc.get.call(document):y.M?void 0:document.activeElement;if(a&&a.nodeType){var b=!!z(this);if(this===document||b&&this.host!==a&&A.contains.call(this.host,a)){for(b=wb(a);b&&b!==this;)a=b.host,b=wb(a);a=this===document?b?null:a:b===this?a:null}else a=null}else a=null;return a},set:function(){},
|
||||
configurable:!0}};function F(a,b,c){for(var d in b){var e=Object.getOwnPropertyDescriptor(a,d);e&&e.configurable||!e&&c?Object.defineProperty(a,d,b[d]):c&&console.warn("Could not define",d,"on",a)}}function G(a){F(a,qc);F(a,rc);F(a,tc)}var uc=y.M?function(){}:function(a){a.__shady&&a.__shady.za||(a.__shady=a.__shady||{},a.__shady.za=!0,F(a,qc,!0))},vc=y.M?function(){}:function(a){a.__shady&&a.__shady.xa||(a.__shady=a.__shady||{},a.__shady.xa=!0,F(a,rc,!0),F(a,sc,!0))};function wc(a,b,c){uc(a);c=c||null;a.__shady=a.__shady||{};b.__shady=b.__shady||{};c&&(c.__shady=c.__shady||{});a.__shady.previousSibling=c?c.__shady.previousSibling:b.lastChild;var d=a.__shady.previousSibling;d&&d.__shady&&(d.__shady.nextSibling=a);(d=a.__shady.nextSibling=c)&&d.__shady&&(d.__shady.previousSibling=a);a.__shady.parentNode=b;c?c===b.__shady.firstChild&&(b.__shady.firstChild=a):(b.__shady.lastChild=a,b.__shady.firstChild||(b.__shady.firstChild=a));b.__shady.childNodes=null}
|
||||
function xc(a){if(!a.__shady||void 0===a.__shady.firstChild){a.__shady=a.__shady||{};a.__shady.firstChild=B.firstChild(a);a.__shady.lastChild=B.lastChild(a);vc(a);for(var b=a.__shady.childNodes=B.childNodes(a),c=0,d;c<b.length&&(d=b[c]);c++)d.__shady=d.__shady||{},d.__shady.parentNode=a,d.__shady.nextSibling=b[c+1]||null,d.__shady.previousSibling=b[c-1]||null,uc(d)}};function yc(a,b,c){if(b===a)throw Error("Failed to execute 'appendChild' on 'Node': The new child element contains the parent.");if(c){var d=c.__shady&&c.__shady.parentNode;if(void 0!==d&&d!==a||void 0===d&&B.parentNode(c)!==a)throw Error("Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.");}if(c===b)return b;b.parentNode&&zc(b.parentNode,b);d=wb(a);var e;if(e=d)a:{if(!b.__noInsertionPoint){var f;"slot"===b.localName?f=[b]:
|
||||
b.querySelectorAll&&(f=b.querySelectorAll("slot"));if(f&&f.length){e=f;break a}}e=void 0}(f=e)&&d.H.push.apply(d.H,[].concat(f instanceof Array?f:ja(ia(f))));d&&("slot"===a.localName||f)&&Ac(d);if(vb(a)){d=c;vc(a);a.__shady=a.__shady||{};void 0!==a.__shady.firstChild&&(a.__shady.childNodes=null);if(b.nodeType===Node.DOCUMENT_FRAGMENT_NODE){f=b.childNodes;for(e=0;e<f.length;e++)wc(f[e],a,d);b.__shady=b.__shady||{};d=void 0!==b.__shady.firstChild?null:void 0;b.__shady.firstChild=b.__shady.lastChild=
|
||||
d;b.__shady.childNodes=d}else wc(b,a,d);if(Bc(a)){Ac(a.__shady.root);var h=!0}else a.__shady.root&&(h=!0)}h||(h=z(a)?a.host:a,c?(c=Cc(c),A.insertBefore.call(h,b,c)):A.appendChild.call(h,b));Dc(a,b);return b}
|
||||
function zc(a,b){if(b.parentNode!==a)throw Error("The node to be removed is not a child of this node: "+b);var c=wb(b);if(vb(a)){b.__shady=b.__shady||{};a.__shady=a.__shady||{};b===a.__shady.firstChild&&(a.__shady.firstChild=b.__shady.nextSibling);b===a.__shady.lastChild&&(a.__shady.lastChild=b.__shady.previousSibling);var d=b.__shady.previousSibling,e=b.__shady.nextSibling;d&&(d.__shady=d.__shady||{},d.__shady.nextSibling=e);e&&(e.__shady=e.__shady||{},e.__shady.previousSibling=d);b.__shady.parentNode=
|
||||
b.__shady.previousSibling=b.__shady.nextSibling=void 0;void 0!==a.__shady.childNodes&&(a.__shady.childNodes=null);if(Bc(a)){Ac(a.__shady.root);var f=!0}}Ec(b);if(c){(d=a&&"slot"===a.localName)&&(f=!0);Fc(c);e=c.l;for(var h in e)for(var g=e[h],k=0;k<g.length;k++){var l=g[k];if(Hb(b,l)){g.splice(k,1);var m=c.o.indexOf(l);0<=m&&c.o.splice(m,1);k--;if(m=l.__shady.K)for(l=0;l<m.length;l++){var n=m[l],t=B.parentNode(n);t&&A.removeChild.call(t,n)}m=!0}}(m||d)&&Ac(c)}f||(f=z(a)?a.host:a,(!a.__shady.root&&
|
||||
"slot"!==b.localName||f===B.parentNode(b))&&A.removeChild.call(f,b));Dc(a,null,b);return b}function Ec(a){if(a.__shady&&void 0!==a.__shady.ka)for(var b=a.childNodes,c=0,d=b.length,e;c<d&&(e=b[c]);c++)Ec(e);a.__shady&&(a.__shady.ka=void 0)}function Cc(a){var b=a;a&&"slot"===a.localName&&(b=(b=a.__shady&&a.__shady.K)&&b.length?b[0]:Cc(a.nextSibling));return b}function Bc(a){return(a=a&&a.__shady&&a.__shady.root)&&Gc(a)}
|
||||
function Hc(a,b){if("slot"===b)a=a.parentNode,Bc(a)&&Ac(a.__shady.root);else if("slot"===a.localName&&"name"===b&&(b=wb(a))){var c=a.Aa,d=Ic(a);if(d!==c){c=b.l[c];var e=c.indexOf(a);0<=e&&c.splice(e,1);c=b.l[d]||(b.l[d]=[]);c.push(a);1<c.length&&(b.l[d]=Jc(c))}Ac(b)}}function Dc(a,b,c){if(a=a.__shady&&a.__shady.N)b&&a.addedNodes.push(b),c&&a.removedNodes.push(c),Nb(a)}
|
||||
function Kc(a){if(a&&a.nodeType){a.__shady=a.__shady||{};var b=a.__shady.ka;void 0===b&&(b=z(a)?a:(b=a.parentNode)?Kc(b):a,A.contains.call(document.documentElement,a)&&(a.__shady.ka=b));return b}}function Lc(a,b,c){var d=[];Mc(a.childNodes,b,c,d);return d}function Mc(a,b,c,d){for(var e=0,f=a.length,h;e<f&&(h=a[e]);e++){var g;if(g=h.nodeType===Node.ELEMENT_NODE){g=h;var k=b,l=c,m=d,n=k(g);n&&m.push(g);l&&l(n)?g=n:(Mc(g.childNodes,k,l,m),g=void 0)}if(g)break}}var Nc=null;
|
||||
function Oc(a,b,c){Nc||(Nc=window.ShadyCSS&&window.ShadyCSS.ScopingShim);Nc&&"class"===b?Nc.setElementClass(a,c):(A.setAttribute.call(a,b,c),Hc(a,b))}function Pc(a,b){if(a.ownerDocument!==document)return A.importNode.call(document,a,b);var c=A.importNode.call(document,a,!1);if(b){a=a.childNodes;b=0;for(var d;b<a.length;b++)d=Pc(a[b],!0),c.appendChild(d)}return c};var Qc="__eventWrappers"+Date.now(),Rc={blur:!0,focus:!0,focusin:!0,focusout:!0,click:!0,dblclick:!0,mousedown:!0,mouseenter:!0,mouseleave:!0,mousemove:!0,mouseout:!0,mouseover:!0,mouseup:!0,wheel:!0,beforeinput:!0,input:!0,keydown:!0,keyup:!0,compositionstart:!0,compositionupdate:!0,compositionend:!0,touchstart:!0,touchend:!0,touchmove:!0,touchcancel:!0,pointerover:!0,pointerenter:!0,pointerdown:!0,pointermove:!0,pointerup:!0,pointercancel:!0,pointerout:!0,pointerleave:!0,gotpointercapture:!0,lostpointercapture:!0,
|
||||
dragstart:!0,drag:!0,dragenter:!0,dragleave:!0,dragover:!0,drop:!0,dragend:!0,DOMActivate:!0,DOMFocusIn:!0,DOMFocusOut:!0,keypress:!0};function Sc(a,b){var c=[],d=a;for(a=a===window?window:a.getRootNode();d;)c.push(d),d=d.assignedSlot?d.assignedSlot:d.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&d.host&&(b||d!==a)?d.host:d.parentNode;c[c.length-1]===document&&c.push(window);return c}
|
||||
function Tc(a,b){if(!z)return a;a=Sc(a,!0);for(var c=0,d,e,f,h;c<b.length;c++)if(d=b[c],f=d===window?window:d.getRootNode(),f!==e&&(h=a.indexOf(f),e=f),!z(f)||-1<h)return d}
|
||||
var Uc={get composed(){!1!==this.isTrusted&&void 0===this.Z&&(this.Z=Rc[this.type]);return this.Z||!1},composedPath:function(){this.b||(this.b=Sc(this.__target,this.composed));return this.b},get target(){return Tc(this.currentTarget,this.composedPath())},get relatedTarget(){if(!this.$)return null;this.c||(this.c=Sc(this.$,!0));return Tc(this.currentTarget,this.c)},stopPropagation:function(){Event.prototype.stopPropagation.call(this);this.a=!0},stopImmediatePropagation:function(){Event.prototype.stopImmediatePropagation.call(this);
|
||||
this.a=this.h=!0}};function Vc(a){function b(b,d){b=new a(b,d);b.Z=d&&!!d.composed;return b}Bb(b,a);b.prototype=a.prototype;return b}var Wc={focus:!0,blur:!0};function Xc(a){return a.__target!==a.target||a.$!==a.relatedTarget}function Yc(a,b,c){if(c=b.__handlers&&b.__handlers[a.type]&&b.__handlers[a.type][c])for(var d=0,e;(e=c[d])&&(!Xc(a)||a.target!==a.relatedTarget)&&(e.call(b,a),!a.h);d++);}
|
||||
function Zc(a){var b=a.composedPath();Object.defineProperty(a,"currentTarget",{get:function(){return d},configurable:!0});for(var c=b.length-1;0<=c;c--){var d=b[c];Yc(a,d,"capture");if(a.a)return}Object.defineProperty(a,"eventPhase",{get:function(){return Event.AT_TARGET}});var e;for(c=0;c<b.length;c++){d=b[c];var f=d.__shady&&d.__shady.root;if(0===c||f&&f===e)if(Yc(a,d,"bubble"),d!==window&&(e=d.getRootNode()),a.a)break}}
|
||||
function $c(a,b,c,d,e,f){for(var h=0;h<a.length;h++){var g=a[h],k=g.type,l=g.capture,m=g.once,n=g.passive;if(b===g.node&&c===k&&d===l&&e===m&&f===n)return h}return-1}
|
||||
function ad(a,b,c){if(b){var d=typeof b;if("function"===d||"object"===d)if("object"!==d||b.handleEvent&&"function"===typeof b.handleEvent){if(c&&"object"===typeof c){var e=!!c.capture;var f=!!c.once;var h=!!c.passive}else e=!!c,h=f=!1;var g=c&&c.aa||this,k=b[Qc];if(k){if(-1<$c(k,g,a,e,f,h))return}else b[Qc]=[];k=function(e){f&&this.removeEventListener(a,b,c);e.__target||bd(e);if(g!==this){var h=Object.getOwnPropertyDescriptor(e,"currentTarget");Object.defineProperty(e,"currentTarget",{get:function(){return g},
|
||||
configurable:!0})}if(e.composed||-1<e.composedPath().indexOf(g))if(Xc(e)&&e.target===e.relatedTarget)e.eventPhase===Event.BUBBLING_PHASE&&e.stopImmediatePropagation();else if(e.eventPhase===Event.CAPTURING_PHASE||e.bubbles||e.target===g||g instanceof Window){var k="function"===d?b.call(g,e):b.handleEvent&&b.handleEvent(e);g!==this&&(h?(Object.defineProperty(e,"currentTarget",h),h=null):delete e.currentTarget);return k}};b[Qc].push({node:this,type:a,capture:e,once:f,passive:h,cb:k});Wc[a]?(this.__handlers=
|
||||
this.__handlers||{},this.__handlers[a]=this.__handlers[a]||{capture:[],bubble:[]},this.__handlers[a][e?"capture":"bubble"].push(k)):(this instanceof Window?A.ab:A.addEventListener).call(this,a,k,c)}}}
|
||||
function cd(a,b,c){if(b){if(c&&"object"===typeof c){var d=!!c.capture;var e=!!c.once;var f=!!c.passive}else d=!!c,f=e=!1;var h=c&&c.aa||this,g=void 0;var k=null;try{k=b[Qc]}catch(l){}k&&(e=$c(k,h,a,d,e,f),-1<e&&(g=k.splice(e,1)[0].cb,k.length||(b[Qc]=void 0)));(this instanceof Window?A.bb:A.removeEventListener).call(this,a,g||b,c);g&&Wc[a]&&this.__handlers&&this.__handlers[a]&&(a=this.__handlers[a][d?"capture":"bubble"],g=a.indexOf(g),-1<g&&a.splice(g,1))}}
|
||||
function dd(){for(var a in Wc)window.addEventListener(a,function(a){a.__target||(bd(a),Zc(a))},!0)}function bd(a){a.__target=a.target;a.$=a.relatedTarget;if(y.M){var b=Object.getPrototypeOf(a);if(!b.hasOwnProperty("__patchProto")){var c=Object.create(b);c.fb=b;zb(c,Uc);b.__patchProto=c}a.__proto__=b.__patchProto}else zb(a,Uc)}var ed=Vc(window.Event),fd=Vc(window.CustomEvent),gd=Vc(window.MouseEvent);function hd(a,b){return{index:a,O:[],U:b}}
|
||||
function id(a,b,c,d){var e=0,f=0,h=0,g=0,k=Math.min(b-e,d-f);if(0==e&&0==f)a:{for(h=0;h<k;h++)if(a[h]!==c[h])break a;h=k}if(b==a.length&&d==c.length){g=a.length;for(var l=c.length,m=0;m<k-h&&jd(a[--g],c[--l]);)m++;g=m}e+=h;f+=h;b-=g;d-=g;if(0==b-e&&0==d-f)return[];if(e==b){for(b=hd(e,0);f<d;)b.O.push(c[f++]);return[b]}if(f==d)return[hd(e,b-e)];k=e;h=f;d=d-h+1;g=b-k+1;b=Array(d);for(l=0;l<d;l++)b[l]=Array(g),b[l][0]=l;for(l=0;l<g;l++)b[0][l]=l;for(l=1;l<d;l++)for(m=1;m<g;m++)if(a[k+m-1]===c[h+l-1])b[l][m]=
|
||||
b[l-1][m-1];else{var n=b[l-1][m]+1,t=b[l][m-1]+1;b[l][m]=n<t?n:t}k=b.length-1;h=b[0].length-1;d=b[k][h];for(a=[];0<k||0<h;)0==k?(a.push(2),h--):0==h?(a.push(3),k--):(g=b[k-1][h-1],l=b[k-1][h],m=b[k][h-1],n=l<m?l<g?l:g:m<g?m:g,n==g?(g==d?a.push(0):(a.push(1),d=g),k--,h--):n==l?(a.push(3),k--,d=l):(a.push(2),h--,d=m));a.reverse();b=void 0;k=[];for(h=0;h<a.length;h++)switch(a[h]){case 0:b&&(k.push(b),b=void 0);e++;f++;break;case 1:b||(b=hd(e,0));b.U++;e++;b.O.push(c[f]);f++;break;case 2:b||(b=hd(e,0));
|
||||
b.U++;e++;break;case 3:b||(b=hd(e,0)),b.O.push(c[f]),f++}b&&k.push(b);return k}function jd(a,b){return a===b};var kd={};function H(a,b,c){if(a!==kd)throw new TypeError("Illegal constructor");a=document.createDocumentFragment();a.__proto__=H.prototype;a.ya="ShadyRoot";xc(b);xc(a);a.host=b;a.Fa=c&&c.mode;b.__shady=b.__shady||{};b.__shady.root=a;b.__shady.Va="closed"!==a.Fa?a:null;a.T=!1;a.o=[];a.l={};a.H=[];c=B.childNodes(b);for(var d=0,e=c.length;d<e;d++)A.removeChild.call(b,c[d]);return a}H.prototype=Object.create(DocumentFragment.prototype);function Ac(a){a.T||(a.T=!0,Kb(function(){return ld(a)}))}
|
||||
function ld(a){for(var b;a;){a.T&&(b=a);a:{var c=a;a=c.host.getRootNode();if(z(a))for(var d=c.host.childNodes,e=0;e<d.length;e++)if(c=d[e],"slot"==c.localName)break a;a=void 0}}b&&b._renderRoot()}
|
||||
H.prototype._renderRoot=function(){this.T=!1;Fc(this);for(var a=0,b;a<this.o.length;a++){b=this.o[a];var c=b.__shady.assignedNodes;b.__shady.assignedNodes=[];b.__shady.K=[];if(b.__shady.oa=c)for(var d=0;d<c.length;d++){var e=c[d];e.__shady.ga=e.__shady.assignedSlot;e.__shady.assignedSlot===b&&(e.__shady.assignedSlot=null)}}for(b=this.host.firstChild;b;b=b.nextSibling)md(this,b);for(a=0;a<this.o.length;a++){b=this.o[a];if(!b.__shady.assignedNodes.length)for(c=b.firstChild;c;c=c.nextSibling)md(this,
|
||||
c,b);c=b.parentNode;(c=c.__shady&&c.__shady.root)&&Gc(c)&&c._renderRoot();nd(this,b.__shady.K,b.__shady.assignedNodes);if(c=b.__shady.oa){for(d=0;d<c.length;d++)c[d].__shady.ga=null;b.__shady.oa=null;c.length>b.__shady.assignedNodes.length&&(b.__shady.ia=!0)}b.__shady.ia&&(b.__shady.ia=!1,od(this,b))}a=this.o;b=[];for(c=0;c<a.length;c++)d=a[c].parentNode,d.__shady&&d.__shady.root||!(0>b.indexOf(d))||b.push(d);for(a=0;a<b.length;a++){c=b[a];d=c===this?this.host:c;e=[];c=c.childNodes;for(var f=0;f<
|
||||
c.length;f++){var h=c[f];if("slot"==h.localName){h=h.__shady.K;for(var g=0;g<h.length;g++)e.push(h[g])}else e.push(h)}c=void 0;f=B.childNodes(d);h=id(e,e.length,f,f.length);for(var k=g=0;g<h.length&&(c=h[g]);g++){for(var l=0,m;l<c.O.length&&(m=c.O[l]);l++)B.parentNode(m)===d&&A.removeChild.call(d,m),f.splice(c.index+k,1);k-=c.U}for(k=0;k<h.length&&(c=h[k]);k++)for(g=f[c.index],l=c.index;l<c.index+c.U;l++)m=e[l],A.insertBefore.call(d,m,g),f.splice(l,0,m)}};
|
||||
function md(a,b,c){b.__shady=b.__shady||{};var d=b.__shady.ga;b.__shady.ga=null;c||(c=(a=a.l[b.slot||"__catchall"])&&a[0]);c?(c.__shady.assignedNodes.push(b),b.__shady.assignedSlot=c):b.__shady.assignedSlot=void 0;d!==b.__shady.assignedSlot&&b.__shady.assignedSlot&&(b.__shady.assignedSlot.__shady.ia=!0)}function nd(a,b,c){for(var d=0,e;d<c.length&&(e=c[d]);d++)if("slot"==e.localName){var f=e.__shady.assignedNodes;f&&f.length&&nd(a,b,f)}else b.push(c[d])}
|
||||
function od(a,b){A.dispatchEvent.call(b,new Event("slotchange"));b.__shady.assignedSlot&&od(a,b.__shady.assignedSlot)}function Fc(a){if(a.H.length){for(var b=a.H,c,d=0;d<b.length;d++){var e=b[d];e.__shady=e.__shady||{};xc(e);xc(e.parentNode);var f=Ic(e);a.l[f]?(c=c||{},c[f]=!0,a.l[f].push(e)):a.l[f]=[e];a.o.push(e)}if(c)for(var h in c)a.l[h]=Jc(a.l[h]);a.H=[]}}function Ic(a){var b=a.name||a.getAttribute("name")||"__catchall";return a.Aa=b}
|
||||
function Jc(a){return a.sort(function(a,c){a=pd(a);for(var b=pd(c),e=0;e<a.length;e++){c=a[e];var f=b[e];if(c!==f)return a=Array.from(c.parentNode.childNodes),a.indexOf(c)-a.indexOf(f)}})}function pd(a){var b=[];do b.unshift(a);while(a=a.parentNode);return b}function Gc(a){Fc(a);return!!a.o.length}H.prototype.addEventListener=function(a,b,c){"object"!==typeof c&&(c={capture:!!c});c.aa=this;this.host.addEventListener(a,b,c)};
|
||||
H.prototype.removeEventListener=function(a,b,c){"object"!==typeof c&&(c={capture:!!c});c.aa=this;this.host.removeEventListener(a,b,c)};H.prototype.getElementById=function(a){return Lc(this,function(b){return b.id==a},function(a){return!!a})[0]||null};var qd=H.prototype;F(qd,rc,!0);F(qd,tc,!0);function rd(a){var b=a.getRootNode();z(b)&&ld(b);return a.__shady&&a.__shady.assignedSlot||null}
|
||||
var sd={addEventListener:ad.bind(window),removeEventListener:cd.bind(window)},td={addEventListener:ad,removeEventListener:cd,appendChild:function(a){return yc(this,a)},insertBefore:function(a,b){return yc(this,a,b)},removeChild:function(a){return zc(this,a)},replaceChild:function(a,b){yc(this,a,b);zc(this,b);return a},cloneNode:function(a){if("template"==this.localName)var b=A.cloneNode.call(this,a);else if(b=A.cloneNode.call(this,!1),a){a=this.childNodes;for(var c=0,d;c<a.length;c++)d=a[c].cloneNode(!0),
|
||||
b.appendChild(d)}return b},getRootNode:function(){return Kc(this)},contains:function(a){return Hb(this,a)},get isConnected(){var a=this.ownerDocument;if(Gb&&A.contains.call(a,this)||a.documentElement&&A.contains.call(a.documentElement,this))return!0;for(a=this;a&&!(a instanceof Document);)a=a.parentNode||(a instanceof H?a.host:void 0);return!!(a&&a instanceof Document)},dispatchEvent:function(a){Lb();return A.dispatchEvent.call(this,a)}},ud={get assignedSlot(){return rd(this)}},vd={querySelector:function(a){return Lc(this,
|
||||
function(b){return yb.call(b,a)},function(a){return!!a})[0]||null},querySelectorAll:function(a){return Lc(this,function(b){return yb.call(b,a)})}},wd={assignedNodes:function(a){if("slot"===this.localName){var b=this.getRootNode();z(b)&&ld(b);return this.__shady?(a&&a.flatten?this.__shady.K:this.__shady.assignedNodes)||[]:[]}}},xd=Ab({setAttribute:function(a,b){Oc(this,a,b)},removeAttribute:function(a){A.removeAttribute.call(this,a);Hc(this,a)},attachShadow:function(a){if(!this)throw"Must provide a host.";
|
||||
if(!a)throw"Not enough arguments.";return new H(kd,this,a)},get slot(){return this.getAttribute("slot")},set slot(a){Oc(this,"slot",a)},get assignedSlot(){return rd(this)}},vd,wd);Object.defineProperties(xd,sc);var yd=Ab({importNode:function(a,b){return Pc(a,b)},getElementById:function(a){return Lc(this,function(b){return b.id==a},function(a){return!!a})[0]||null}},vd);Object.defineProperties(yd,{_activeElement:tc.activeElement});
|
||||
var zd=HTMLElement.prototype.blur,Ad=Ab({blur:function(){var a=this.__shady&&this.__shady.root;(a=a&&a.activeElement)?a.blur():zd.call(this)}});function I(a,b){for(var c=Object.getOwnPropertyNames(b),d=0;d<c.length;d++){var e=c[d],f=Object.getOwnPropertyDescriptor(b,e);f.value?a[e]=f.value:Object.defineProperty(a,e,f)}};if(y.sa){var ShadyDOM={inUse:y.sa,patch:function(a){return a},isShadyRoot:z,enqueue:Kb,flush:Lb,settings:y,filterMutations:Rb,observeChildren:Pb,unobserveChildren:Qb,nativeMethods:A,nativeTree:B};window.ShadyDOM=ShadyDOM;window.Event=ed;window.CustomEvent=fd;window.MouseEvent=gd;dd();var Bd=window.customElements&&window.customElements.nativeHTMLElement||HTMLElement;I(window.Node.prototype,td);I(window.Window.prototype,sd);I(window.Text.prototype,ud);I(window.DocumentFragment.prototype,vd);I(window.Element.prototype,
|
||||
xd);I(window.Document.prototype,yd);window.HTMLSlotElement&&I(window.HTMLSlotElement.prototype,wd);I(Bd.prototype,Ad);y.M&&(G(window.Node.prototype),G(window.Text.prototype),G(window.DocumentFragment.prototype),G(window.Element.prototype),G(Bd.prototype),G(window.Document.prototype),window.HTMLSlotElement&&G(window.HTMLSlotElement.prototype));window.ShadowRoot=H};var Cd=new Set("annotation-xml color-profile font-face font-face-src font-face-uri font-face-format font-face-name missing-glyph".split(" "));function Dd(a){var b=Cd.has(a);a=/^[a-z][.0-9_a-z]*-[\-.0-9_a-z]*$/.test(a);return!b&&a}function K(a){var b=a.isConnected;if(void 0!==b)return b;for(;a&&!(a.__CE_isImportDocument||a instanceof Document);)a=a.parentNode||(window.ShadowRoot&&a instanceof ShadowRoot?a.host:void 0);return!(!a||!(a.__CE_isImportDocument||a instanceof Document))}
|
||||
function Ed(a,b){for(;b&&b!==a&&!b.nextSibling;)b=b.parentNode;return b&&b!==a?b.nextSibling:null}
|
||||
function L(a,b,c){c=void 0===c?new Set:c;for(var d=a;d;){if(d.nodeType===Node.ELEMENT_NODE){var e=d;b(e);var f=e.localName;if("link"===f&&"import"===e.getAttribute("rel")){d=e.import;if(d instanceof Node&&!c.has(d))for(c.add(d),d=d.firstChild;d;d=d.nextSibling)L(d,b,c);d=Ed(a,e);continue}else if("template"===f){d=Ed(a,e);continue}if(e=e.__CE_shadowRoot)for(e=e.firstChild;e;e=e.nextSibling)L(e,b,c)}d=d.firstChild?d.firstChild:Ed(a,d)}}function M(a,b,c){a[b]=c};function Fd(){this.a=new Map;this.s=new Map;this.h=[];this.c=!1}function Gd(a,b,c){a.a.set(b,c);a.s.set(c.constructor,c)}function Hd(a,b){a.c=!0;a.h.push(b)}function Id(a,b){a.c&&L(b,function(b){return a.b(b)})}Fd.prototype.b=function(a){if(this.c&&!a.__CE_patched){a.__CE_patched=!0;for(var b=0;b<this.h.length;b++)this.h[b](a)}};function N(a,b){var c=[];L(b,function(a){return c.push(a)});for(b=0;b<c.length;b++){var d=c[b];1===d.__CE_state?a.connectedCallback(d):Jd(a,d)}}
|
||||
function O(a,b){var c=[];L(b,function(a){return c.push(a)});for(b=0;b<c.length;b++){var d=c[b];1===d.__CE_state&&a.disconnectedCallback(d)}}
|
||||
function P(a,b,c){c=void 0===c?{}:c;var d=c.$a||new Set,e=c.va||function(b){return Jd(a,b)},f=[];L(b,function(b){if("link"===b.localName&&"import"===b.getAttribute("rel")){var c=b.import;c instanceof Node&&(c.__CE_isImportDocument=!0,c.__CE_hasRegistry=!0);c&&"complete"===c.readyState?c.__CE_documentLoadHandled=!0:b.addEventListener("load",function(){var c=b.import;if(!c.__CE_documentLoadHandled){c.__CE_documentLoadHandled=!0;var f=new Set(d);f.delete(c);P(a,c,{$a:f,va:e})}})}else f.push(b)},d);if(a.c)for(b=
|
||||
0;b<f.length;b++)a.b(f[b]);for(b=0;b<f.length;b++)e(f[b])}
|
||||
function Jd(a,b){if(void 0===b.__CE_state){var c=b.ownerDocument;if(c.defaultView||c.__CE_isImportDocument&&c.__CE_hasRegistry)if(c=a.a.get(b.localName)){c.constructionStack.push(b);var d=c.constructor;try{try{if(new d!==b)throw Error("The custom element constructor did not produce the element being upgraded.");}finally{c.constructionStack.pop()}}catch(h){throw b.__CE_state=2,h;}b.__CE_state=1;b.__CE_definition=c;if(c.attributeChangedCallback)for(c=c.observedAttributes,d=0;d<c.length;d++){var e=c[d],
|
||||
f=b.getAttribute(e);null!==f&&a.attributeChangedCallback(b,e,null,f,null)}K(b)&&a.connectedCallback(b)}}}Fd.prototype.connectedCallback=function(a){var b=a.__CE_definition;b.connectedCallback&&b.connectedCallback.call(a)};Fd.prototype.disconnectedCallback=function(a){var b=a.__CE_definition;b.disconnectedCallback&&b.disconnectedCallback.call(a)};
|
||||
Fd.prototype.attributeChangedCallback=function(a,b,c,d,e){var f=a.__CE_definition;f.attributeChangedCallback&&-1<f.observedAttributes.indexOf(b)&&f.attributeChangedCallback.call(a,b,c,d,e)};function Kd(a){var b=document;this.j=a;this.a=b;this.C=void 0;P(this.j,this.a);"loading"===this.a.readyState&&(this.C=new MutationObserver(this.b.bind(this)),this.C.observe(this.a,{childList:!0,subtree:!0}))}Kd.prototype.disconnect=function(){this.C&&this.C.disconnect()};Kd.prototype.b=function(a){var b=this.a.readyState;"interactive"!==b&&"complete"!==b||this.disconnect();for(b=0;b<a.length;b++)for(var c=a[b].addedNodes,d=0;d<c.length;d++)P(this.j,c[d])};function Ld(){var a=this;this.b=this.a=void 0;this.c=new Promise(function(b){a.b=b;a.a&&b(a.a)})}Ld.prototype.resolve=function(a){if(this.a)throw Error("Already resolved.");this.a=a;this.b&&this.b(a)};function Q(a){this.da=!1;this.j=a;this.ha=new Map;this.ea=function(a){return a()};this.R=!1;this.fa=[];this.Da=new Kd(a)}
|
||||
Q.prototype.define=function(a,b){var c=this;if(!(b instanceof Function))throw new TypeError("Custom element constructors must be functions.");if(!Dd(a))throw new SyntaxError("The element name '"+a+"' is not valid.");if(this.j.a.get(a))throw Error("A custom element with name '"+a+"' has already been defined.");if(this.da)throw Error("A custom element is already being defined.");this.da=!0;try{var d=function(a){var b=e[a];if(void 0!==b&&!(b instanceof Function))throw Error("The '"+a+"' callback must be a function.");
|
||||
return b},e=b.prototype;if(!(e instanceof Object))throw new TypeError("The custom element constructor's prototype is not an object.");var f=d("connectedCallback");var h=d("disconnectedCallback");var g=d("adoptedCallback");var k=d("attributeChangedCallback");var l=b.observedAttributes||[]}catch(m){return}finally{this.da=!1}b={localName:a,constructor:b,connectedCallback:f,disconnectedCallback:h,adoptedCallback:g,attributeChangedCallback:k,observedAttributes:l,constructionStack:[]};Gd(this.j,a,b);this.fa.push(b);
|
||||
this.R||(this.R=!0,this.ea(function(){return Md(c)}))};function Md(a){if(!1!==a.R){a.R=!1;for(var b=a.fa,c=[],d=new Map,e=0;e<b.length;e++)d.set(b[e].localName,[]);P(a.j,document,{va:function(b){if(void 0===b.__CE_state){var e=b.localName,f=d.get(e);f?f.push(b):a.j.a.get(e)&&c.push(b)}}});for(e=0;e<c.length;e++)Jd(a.j,c[e]);for(;0<b.length;){var f=b.shift();e=f.localName;f=d.get(f.localName);for(var h=0;h<f.length;h++)Jd(a.j,f[h]);(e=a.ha.get(e))&&e.resolve(void 0)}}}
|
||||
Q.prototype.get=function(a){if(a=this.j.a.get(a))return a.constructor};Q.prototype.a=function(a){if(!Dd(a))return Promise.reject(new SyntaxError("'"+a+"' is not a valid custom element name."));var b=this.ha.get(a);if(b)return b.c;b=new Ld;this.ha.set(a,b);this.j.a.get(a)&&!this.fa.some(function(b){return b.localName===a})&&b.resolve(void 0);return b.c};Q.prototype.b=function(a){this.Da.disconnect();var b=this.ea;this.ea=function(c){return a(function(){return b(c)})}};
|
||||
window.CustomElementRegistry=Q;Q.prototype.define=Q.prototype.define;Q.prototype.get=Q.prototype.get;Q.prototype.whenDefined=Q.prototype.a;Q.prototype.polyfillWrapFlushCallback=Q.prototype.b;var Nd=window.Document.prototype.createElement,Od=window.Document.prototype.createElementNS,Pd=window.Document.prototype.importNode,Qd=window.Document.prototype.prepend,Rd=window.Document.prototype.append,Sd=window.DocumentFragment.prototype.prepend,Td=window.DocumentFragment.prototype.append,Ud=window.Node.prototype.cloneNode,Vd=window.Node.prototype.appendChild,Wd=window.Node.prototype.insertBefore,Xd=window.Node.prototype.removeChild,Yd=window.Node.prototype.replaceChild,Zd=Object.getOwnPropertyDescriptor(window.Node.prototype,
|
||||
"textContent"),$d=window.Element.prototype.attachShadow,ae=Object.getOwnPropertyDescriptor(window.Element.prototype,"innerHTML"),be=window.Element.prototype.getAttribute,ce=window.Element.prototype.setAttribute,de=window.Element.prototype.removeAttribute,ee=window.Element.prototype.getAttributeNS,fe=window.Element.prototype.setAttributeNS,ge=window.Element.prototype.removeAttributeNS,he=window.Element.prototype.insertAdjacentElement,ie=window.Element.prototype.prepend,je=window.Element.prototype.append,
|
||||
ke=window.Element.prototype.before,le=window.Element.prototype.after,me=window.Element.prototype.replaceWith,ne=window.Element.prototype.remove,oe=window.HTMLElement,pe=Object.getOwnPropertyDescriptor(window.HTMLElement.prototype,"innerHTML"),qe=window.HTMLElement.prototype.insertAdjacentElement;var re=new function(){};function se(){var a=te;window.HTMLElement=function(){function b(){var b=this.constructor,d=a.s.get(b);if(!d)throw Error("The custom element being constructed was not registered with `customElements`.");var e=d.constructionStack;if(0===e.length)return e=Nd.call(document,d.localName),Object.setPrototypeOf(e,b.prototype),e.__CE_state=1,e.__CE_definition=d,a.b(e),e;d=e.length-1;var f=e[d];if(f===re)throw Error("The HTMLElement constructor was either called reentrantly for this constructor or called multiple times.");
|
||||
e[d]=re;Object.setPrototypeOf(f,b.prototype);a.b(f);return f}b.prototype=oe.prototype;return b}()};function ue(a,b,c){function d(b){return function(c){for(var d=[],e=0;e<arguments.length;++e)d[e-0]=arguments[e];e=[];for(var f=[],l=0;l<d.length;l++){var m=d[l];m instanceof Element&&K(m)&&f.push(m);if(m instanceof DocumentFragment)for(m=m.firstChild;m;m=m.nextSibling)e.push(m);else e.push(m)}b.apply(this,d);for(d=0;d<f.length;d++)O(a,f[d]);if(K(this))for(d=0;d<e.length;d++)f=e[d],f instanceof Element&&N(a,f)}}void 0!==c.X&&(b.prepend=d(c.X));void 0!==c.append&&(b.append=d(c.append))};function ve(){var a=te;M(Document.prototype,"createElement",function(b){if(this.__CE_hasRegistry){var c=a.a.get(b);if(c)return new c.constructor}b=Nd.call(this,b);a.b(b);return b});M(Document.prototype,"importNode",function(b,c){b=Pd.call(this,b,c);this.__CE_hasRegistry?P(a,b):Id(a,b);return b});M(Document.prototype,"createElementNS",function(b,c){if(this.__CE_hasRegistry&&(null===b||"http://www.w3.org/1999/xhtml"===b)){var d=a.a.get(c);if(d)return new d.constructor}b=Od.call(this,b,c);a.b(b);return b});
|
||||
ue(a,Document.prototype,{X:Qd,append:Rd})};function we(){var a=te;function b(b,d){Object.defineProperty(b,"textContent",{enumerable:d.enumerable,configurable:!0,get:d.get,set:function(b){if(this.nodeType===Node.TEXT_NODE)d.set.call(this,b);else{var c=void 0;if(this.firstChild){var e=this.childNodes,g=e.length;if(0<g&&K(this)){c=Array(g);for(var k=0;k<g;k++)c[k]=e[k]}}d.set.call(this,b);if(c)for(b=0;b<c.length;b++)O(a,c[b])}}})}M(Node.prototype,"insertBefore",function(b,d){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);
|
||||
b=Wd.call(this,b,d);if(K(this))for(d=0;d<c.length;d++)N(a,c[d]);return b}c=K(b);d=Wd.call(this,b,d);c&&O(a,b);K(this)&&N(a,b);return d});M(Node.prototype,"appendChild",function(b){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);b=Vd.call(this,b);if(K(this))for(var e=0;e<c.length;e++)N(a,c[e]);return b}c=K(b);e=Vd.call(this,b);c&&O(a,b);K(this)&&N(a,b);return e});M(Node.prototype,"cloneNode",function(b){b=Ud.call(this,b);this.ownerDocument.__CE_hasRegistry?P(a,b):
|
||||
Id(a,b);return b});M(Node.prototype,"removeChild",function(b){var c=K(b),e=Xd.call(this,b);c&&O(a,b);return e});M(Node.prototype,"replaceChild",function(b,d){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);b=Yd.call(this,b,d);if(K(this))for(O(a,d),d=0;d<c.length;d++)N(a,c[d]);return b}c=K(b);var f=Yd.call(this,b,d),h=K(this);h&&O(a,d);c&&O(a,b);h&&N(a,b);return f});Zd&&Zd.get?b(Node.prototype,Zd):Hd(a,function(a){b(a,{enumerable:!0,configurable:!0,get:function(){for(var a=
|
||||
[],b=0;b<this.childNodes.length;b++)a.push(this.childNodes[b].textContent);return a.join("")},set:function(a){for(;this.firstChild;)Xd.call(this,this.firstChild);Vd.call(this,document.createTextNode(a))}})})};function xe(a){var b=Element.prototype;function c(b){return function(c){for(var d=[],e=0;e<arguments.length;++e)d[e-0]=arguments[e];e=[];for(var g=[],k=0;k<d.length;k++){var l=d[k];l instanceof Element&&K(l)&&g.push(l);if(l instanceof DocumentFragment)for(l=l.firstChild;l;l=l.nextSibling)e.push(l);else e.push(l)}b.apply(this,d);for(d=0;d<g.length;d++)O(a,g[d]);if(K(this))for(d=0;d<e.length;d++)g=e[d],g instanceof Element&&N(a,g)}}void 0!==ke&&(b.before=c(ke));void 0!==ke&&(b.after=c(le));void 0!==
|
||||
me&&M(b,"replaceWith",function(b){for(var c=[],d=0;d<arguments.length;++d)c[d-0]=arguments[d];d=[];for(var h=[],g=0;g<c.length;g++){var k=c[g];k instanceof Element&&K(k)&&h.push(k);if(k instanceof DocumentFragment)for(k=k.firstChild;k;k=k.nextSibling)d.push(k);else d.push(k)}g=K(this);me.apply(this,c);for(c=0;c<h.length;c++)O(a,h[c]);if(g)for(O(a,this),c=0;c<d.length;c++)h=d[c],h instanceof Element&&N(a,h)});void 0!==ne&&M(b,"remove",function(){var b=K(this);ne.call(this);b&&O(a,this)})};function ye(){var a=te;function b(b,c){Object.defineProperty(b,"innerHTML",{enumerable:c.enumerable,configurable:!0,get:c.get,set:function(b){var d=this,e=void 0;K(this)&&(e=[],L(this,function(a){a!==d&&e.push(a)}));c.set.call(this,b);if(e)for(var f=0;f<e.length;f++){var l=e[f];1===l.__CE_state&&a.disconnectedCallback(l)}this.ownerDocument.__CE_hasRegistry?P(a,this):Id(a,this);return b}})}function c(b,c){M(b,"insertAdjacentElement",function(b,d){var e=K(d);b=c.call(this,b,d);e&&O(a,d);K(b)&&N(a,d);
|
||||
return b})}$d&&M(Element.prototype,"attachShadow",function(a){return this.__CE_shadowRoot=a=$d.call(this,a)});ae&&ae.get?b(Element.prototype,ae):pe&&pe.get?b(HTMLElement.prototype,pe):Hd(a,function(a){b(a,{enumerable:!0,configurable:!0,get:function(){return Ud.call(this,!0).innerHTML},set:function(a){var b="template"===this.localName,c=b?this.content:this,d=Nd.call(document,this.localName);for(d.innerHTML=a;0<c.childNodes.length;)Xd.call(c,c.childNodes[0]);for(a=b?d.content:d;0<a.childNodes.length;)Vd.call(c,
|
||||
a.childNodes[0])}})});M(Element.prototype,"setAttribute",function(b,c){if(1!==this.__CE_state)return ce.call(this,b,c);var d=be.call(this,b);ce.call(this,b,c);c=be.call(this,b);a.attributeChangedCallback(this,b,d,c,null)});M(Element.prototype,"setAttributeNS",function(b,c,f){if(1!==this.__CE_state)return fe.call(this,b,c,f);var d=ee.call(this,b,c);fe.call(this,b,c,f);f=ee.call(this,b,c);a.attributeChangedCallback(this,c,d,f,b)});M(Element.prototype,"removeAttribute",function(b){if(1!==this.__CE_state)return de.call(this,
|
||||
b);var c=be.call(this,b);de.call(this,b);null!==c&&a.attributeChangedCallback(this,b,c,null,null)});M(Element.prototype,"removeAttributeNS",function(b,c){if(1!==this.__CE_state)return ge.call(this,b,c);var d=ee.call(this,b,c);ge.call(this,b,c);var e=ee.call(this,b,c);d!==e&&a.attributeChangedCallback(this,c,d,e,b)});qe?c(HTMLElement.prototype,qe):he?c(Element.prototype,he):console.warn("Custom Elements: `Element#insertAdjacentElement` was not patched.");ue(a,Element.prototype,{X:ie,append:je});xe(a)}
|
||||
;var ze=window.customElements;if(!ze||ze.forcePolyfill||"function"!=typeof ze.define||"function"!=typeof ze.get){var te=new Fd;se();ve();ue(te,DocumentFragment.prototype,{X:Sd,append:Td});we();ye();document.__CE_hasRegistry=!0;var customElements=new Q(te);Object.defineProperty(window,"customElements",{configurable:!0,enumerable:!0,value:customElements})};function Ae(){this.end=this.start=0;this.rules=this.parent=this.previous=null;this.cssText=this.parsedCssText="";this.atRule=!1;this.type=0;this.parsedSelector=this.selector=this.keyframesName=""}
|
||||
function Be(a){a=a.replace(Ce,"").replace(De,"");var b=Ee,c=a,d=new Ae;d.start=0;d.end=c.length;for(var e=d,f=0,h=c.length;f<h;f++)if("{"===c[f]){e.rules||(e.rules=[]);var g=e,k=g.rules[g.rules.length-1]||null;e=new Ae;e.start=f+1;e.parent=g;e.previous=k;g.rules.push(e)}else"}"===c[f]&&(e.end=f+1,e=e.parent||d);return b(d,a)}
|
||||
function Ee(a,b){var c=b.substring(a.start,a.end-1);a.parsedCssText=a.cssText=c.trim();a.parent&&(c=b.substring(a.previous?a.previous.end:a.parent.start,a.start-1),c=Fe(c),c=c.replace(Ge," "),c=c.substring(c.lastIndexOf(";")+1),c=a.parsedSelector=a.selector=c.trim(),a.atRule=0===c.indexOf("@"),a.atRule?0===c.indexOf("@media")?a.type=He:c.match(Ie)&&(a.type=Je,a.keyframesName=a.selector.split(Ge).pop()):a.type=0===c.indexOf("--")?Ke:Le);if(c=a.rules)for(var d=0,e=c.length,f;d<e&&(f=c[d]);d++)Ee(f,
|
||||
b);return a}function Fe(a){return a.replace(/\\([0-9a-f]{1,6})\s/gi,function(a,c){a=c;for(c=6-a.length;c--;)a="0"+a;return"\\"+a})}
|
||||
function Me(a,b,c){c=void 0===c?"":c;var d="";if(a.cssText||a.rules){var e=a.rules,f;if(f=e)f=e[0],f=!(f&&f.selector&&0===f.selector.indexOf("--"));if(f){f=0;for(var h=e.length,g;f<h&&(g=e[f]);f++)d=Me(g,b,d)}else b?b=a.cssText:(b=a.cssText,b=b.replace(Ne,"").replace(Oe,""),b=b.replace(Pe,"").replace(Qe,"")),(d=b.trim())&&(d=" "+d+"\n")}d&&(a.selector&&(c+=a.selector+" {\n"),c+=d,a.selector&&(c+="}\n\n"));return c}
|
||||
var Le=1,Je=7,He=4,Ke=1E3,Ce=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,De=/@import[^;]*;/gim,Ne=/(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,Oe=/(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim,Pe=/@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim,Qe=/[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,Ie=/^@[^\s]*keyframes/,Ge=/\s+/g;var R=!(window.ShadyDOM&&window.ShadyDOM.inUse),Re;function Se(a){Re=a&&a.shimcssproperties?!1:R||!(navigator.userAgent.match(/AppleWebKit\/601|Edge\/15/)||!window.CSS||!CSS.supports||!CSS.supports("box-shadow","0 0 0 var(--foo)"))}window.ShadyCSS&&void 0!==window.ShadyCSS.nativeCss?Re=window.ShadyCSS.nativeCss:window.ShadyCSS?(Se(window.ShadyCSS),window.ShadyCSS=void 0):Se(window.WebComponents&&window.WebComponents.flags);var S=Re;var Te=/(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};{])+)|\{([^}]*)\}(?:(?=[;\s}])|$))/gi,Ue=/(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi,Ve=/(--[\w-]+)\s*([:,;)]|$)/gi,We=/(animation\s*:)|(animation-name\s*:)/,Xe=/@media\s(.*)/,Ye=/\{[^}]*\}/g;var Ze=new Set;function $e(a,b){if(!a)return"";"string"===typeof a&&(a=Be(a));b&&af(a,b);return Me(a,S)}function bf(a){!a.__cssRules&&a.textContent&&(a.__cssRules=Be(a.textContent));return a.__cssRules||null}function cf(a){return!!a.parent&&a.parent.type===Je}function af(a,b,c,d){if(a){var e=!1,f=a.type;if(d&&f===He){var h=a.selector.match(Xe);h&&(window.matchMedia(h[1]).matches||(e=!0))}f===Le?b(a):c&&f===Je?c(a):f===Ke&&(e=!0);if((a=a.rules)&&!e){e=0;f=a.length;for(var g;e<f&&(g=a[e]);e++)af(g,b,c,d)}}}
|
||||
function df(a,b,c,d){var e=document.createElement("style");b&&e.setAttribute("scope",b);e.textContent=a;ef(e,c,d);return e}var T=null;function ef(a,b,c){b=b||document.head;b.insertBefore(a,c&&c.nextSibling||b.firstChild);T?a.compareDocumentPosition(T)===Node.DOCUMENT_POSITION_PRECEDING&&(T=a):T=a}
|
||||
function ff(a,b){var c=a.indexOf("var(");if(-1===c)return b(a,"","","");a:{var d=0;var e=c+3;for(var f=a.length;e<f;e++)if("("===a[e])d++;else if(")"===a[e]&&0===--d)break a;e=-1}d=a.substring(c+4,e);c=a.substring(0,c);a=ff(a.substring(e+1),b);e=d.indexOf(",");return-1===e?b(c,d.trim(),"",a):b(c,d.substring(0,e).trim(),d.substring(e+1).trim(),a)}function gf(a,b){R?a.setAttribute("class",b):window.ShadyDOM.nativeMethods.setAttribute.call(a,"class",b)}
|
||||
function V(a){var b=a.localName,c="";b?-1<b.indexOf("-")||(c=b,b=a.getAttribute&&a.getAttribute("is")||""):(b=a.is,c=a.extends);return{is:b,P:c}};function hf(){}function jf(a,b,c){var d=W;a.__styleScoped?a.__styleScoped=null:kf(d,a,b||"",c)}function kf(a,b,c,d){b.nodeType===Node.ELEMENT_NODE&&lf(b,c,d);if(b="template"===b.localName?(b.content||b.gb).childNodes:b.children||b.childNodes)for(var e=0;e<b.length;e++)kf(a,b[e],c,d)}
|
||||
function lf(a,b,c){if(b)if(a.classList)c?(a.classList.remove("style-scope"),a.classList.remove(b)):(a.classList.add("style-scope"),a.classList.add(b));else if(a.getAttribute){var d=a.getAttribute(mf);c?d&&(b=d.replace("style-scope","").replace(b,""),gf(a,b)):gf(a,(d?d+" ":"")+"style-scope "+b)}}function nf(a,b,c){var d=W,e=a.__cssBuild;R||"shady"===e?b=$e(b,c):(a=V(a),b=of(d,b,a.is,a.P,c)+"\n\n");return b.trim()}
|
||||
function of(a,b,c,d,e){var f=pf(c,d);c=c?qf+c:"";return $e(b,function(b){b.c||(b.selector=b.m=rf(a,b,a.b,c,f),b.c=!0);e&&e(b,c,f)})}function pf(a,b){return b?"[is="+a+"]":a}function rf(a,b,c,d,e){var f=b.selector.split(sf);if(!cf(b)){b=0;for(var h=f.length,g;b<h&&(g=f[b]);b++)f[b]=c.call(a,g,d,e)}return f.join(sf)}function tf(a){return a.replace(uf,function(a,c,d){-1<d.indexOf("+")?d=d.replace(/\+/g,"___"):-1<d.indexOf("___")&&(d=d.replace(/___/g,"+"));return":"+c+"("+d+")"})}
|
||||
hf.prototype.b=function(a,b,c){var d=!1;a=a.trim();var e=uf.test(a);e&&(a=a.replace(uf,function(a,b,c){return":"+b+"("+c.replace(/\s/g,"")+")"}),a=tf(a));a=a.replace(vf,wf+" $1");a=a.replace(xf,function(a,e,g){d||(a=yf(g,e,b,c),d=d||a.stop,e=a.Ka,g=a.value);return e+g});e&&(a=tf(a));return a};
|
||||
function yf(a,b,c,d){var e=a.indexOf(zf);0<=a.indexOf(wf)?a=Af(a,d):0!==e&&(a=c?Bf(a,c):a);c=!1;0<=e&&(b="",c=!0);if(c){var f=!0;c&&(a=a.replace(Cf,function(a,b){return" > "+b}))}a=a.replace(Df,function(a,b,c){return'[dir="'+c+'"] '+b+", "+b+'[dir="'+c+'"]'});return{value:a,Ka:b,stop:f}}function Bf(a,b){a=a.split(Ef);a[0]+=b;return a.join(Ef)}
|
||||
function Af(a,b){var c=a.match(Ff);return(c=c&&c[2].trim()||"")?c[0].match(Gf)?a.replace(Ff,function(a,c,f){return b+f}):c.split(Gf)[0]===b?c:Hf:a.replace(wf,b)}function If(a){a.selector===Jf&&(a.selector="html")}hf.prototype.c=function(a){return a.match(zf)?this.b(a,Kf):Bf(a.trim(),Kf)};q.Object.defineProperties(hf.prototype,{a:{configurable:!0,enumerable:!0,get:function(){return"style-scope"}}});
|
||||
var uf=/:(nth[-\w]+)\(([^)]+)\)/,Kf=":not(.style-scope)",sf=",",xf=/(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=[])+)/g,Gf=/[[.:#*]/,wf=":host",Jf=":root",zf="::slotted",vf=new RegExp("^("+zf+")"),Ff=/(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/,Cf=/(?:::slotted)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/,Df=/(.*):dir\((?:(ltr|rtl))\)/,qf=".",Ef=":",mf="class",Hf="should_not_match",W=new hf;function Lf(a,b,c,d){this.w=a||null;this.b=b||null;this.ja=c||[];this.G=null;this.P=d||"";this.a=this.u=this.B=null}function X(a){return a?a.__styleInfo:null}function Mf(a,b){return a.__styleInfo=b}Lf.prototype.c=function(){return this.w};Lf.prototype._getStyleRules=Lf.prototype.c;var Nf,Of=window.Element.prototype;Nf=Of.matches||Of.matchesSelector||Of.mozMatchesSelector||Of.msMatchesSelector||Of.oMatchesSelector||Of.webkitMatchesSelector;var Pf=navigator.userAgent.match("Trident");function Qf(){}function Rf(a){var b={},c=[],d=0;af(a,function(a){Sf(a);a.index=d++;a=a.i.cssText;for(var c;c=Ve.exec(a);){var e=c[1];":"!==c[2]&&(b[e]=!0)}},function(a){c.push(a)});a.b=c;a=[];for(var e in b)a.push(e);return a}
|
||||
function Sf(a){if(!a.i){var b={},c={};Tf(a,c)&&(b.v=c,a.rules=null);b.cssText=a.parsedCssText.replace(Ye,"").replace(Te,"");a.i=b}}function Tf(a,b){var c=a.i;if(c){if(c.v)return Object.assign(b,c.v),!0}else{c=a.parsedCssText;for(var d;a=Te.exec(c);){d=(a[2]||a[3]).trim();if("inherit"!==d||"unset"!==d)b[a[1].trim()]=d;d=!0}return d}}
|
||||
function Uf(a,b,c){b&&(b=0<=b.indexOf(";")?Vf(a,b,c):ff(b,function(b,e,f,h){if(!e)return b+h;(e=Uf(a,c[e],c))&&"initial"!==e?"apply-shim-inherit"===e&&(e="inherit"):e=Uf(a,c[f]||f,c)||f;return b+(e||"")+h}));return b&&b.trim()||""}
|
||||
function Vf(a,b,c){b=b.split(";");for(var d=0,e,f;d<b.length;d++)if(e=b[d]){Ue.lastIndex=0;if(f=Ue.exec(e))e=Uf(a,c[f[1]],c);else if(f=e.indexOf(":"),-1!==f){var h=e.substring(f);h=h.trim();h=Uf(a,h,c)||h;e=e.substring(0,f)+h}b[d]=e&&e.lastIndexOf(";")===e.length-1?e.slice(0,-1):e||""}return b.join(";")}
|
||||
function Wf(a,b){var c={},d=[];af(a,function(a){a.i||Sf(a);var e=a.m||a.parsedSelector;b&&a.i.v&&e&&Nf.call(b,e)&&(Tf(a,c),a=a.index,e=parseInt(a/32,10),d[e]=(d[e]||0)|1<<a%32)},null,!0);return{v:c,key:d}}
|
||||
function Xf(a,b,c,d){b.i||Sf(b);if(b.i.v){var e=V(a);a=e.is;e=e.P;e=a?pf(a,e):"html";var f=b.parsedSelector,h=":host > *"===f||"html"===f,g=0===f.indexOf(":host")&&!h;"shady"===c&&(h=f===e+" > *."+e||-1!==f.indexOf("html"),g=!h&&0===f.indexOf(e));"shadow"===c&&(h=":host > *"===f||"html"===f,g=g&&!h);if(h||g)c=e,g&&(R&&!b.m&&(b.m=rf(W,b,W.b,a?qf+a:"",e)),c=b.m||e),d({Xa:c,Qa:g,hb:h})}}
|
||||
function Yf(a,b){var c={},d={},e=b&&b.__cssBuild;af(b,function(b){Xf(a,b,e,function(e){Nf.call(a.b||a,e.Xa)&&(e.Qa?Tf(b,c):Tf(b,d))})},null,!0);return{Wa:d,Oa:c}}
|
||||
function Zf(a,b,c,d){var e=V(b),f=pf(e.is,e.P),h=new RegExp("(?:^|[^.#[:])"+(b.extends?"\\"+f.slice(0,-1)+"\\]":f)+"($|[.:[\\s>+~])");e=X(b).w;var g=$f(e,d);return nf(b,e,function(b){var e="";b.i||Sf(b);b.i.cssText&&(e=Vf(a,b.i.cssText,c));b.cssText=e;if(!R&&!cf(b)&&b.cssText){var k=e=b.cssText;null==b.ra&&(b.ra=We.test(e));if(b.ra)if(null==b.W){b.W=[];for(var n in g)k=g[n],k=k(e),e!==k&&(e=k,b.W.push(n))}else{for(n=0;n<b.W.length;++n)k=g[b.W[n]],e=k(e);k=e}b.cssText=k;b.m=b.m||b.selector;e="."+d;
|
||||
n=b.m.split(",");k=0;for(var t=n.length,C;k<t&&(C=n[k]);k++)n[k]=C.match(h)?C.replace(f,e):e+" "+C;b.selector=n.join(",")}})}function $f(a,b){a=a.b;var c={};if(!R&&a)for(var d=0,e=a[d];d<a.length;e=a[++d]){var f=e,h=b;f.h=new RegExp("\\b"+f.keyframesName+"(?!\\B|-)","g");f.a=f.keyframesName+"-"+h;f.m=f.m||f.selector;f.selector=f.m.replace(f.keyframesName,f.a);c[e.keyframesName]=ag(e)}return c}function ag(a){return function(b){return b.replace(a.h,a.a)}}
|
||||
function bg(a,b){var c=cg,d=bf(a);a.textContent=$e(d,function(a){var d=a.cssText=a.parsedCssText;a.i&&a.i.cssText&&(d=d.replace(Ne,"").replace(Oe,""),a.cssText=Vf(c,d,b))})}q.Object.defineProperties(Qf.prototype,{a:{configurable:!0,enumerable:!0,get:function(){return"x-scope"}}});var cg=new Qf;var dg={},eg=window.customElements;if(eg&&!R){var fg=eg.define;eg.define=function(a,b,c){var d=document.createComment(" Shady DOM styles for "+a+" "),e=document.head;e.insertBefore(d,(T?T.nextSibling:null)||e.firstChild);T=d;dg[a]=d;return fg.call(eg,a,b,c)}};function gg(){this.cache={}}gg.prototype.store=function(a,b,c,d){var e=this.cache[a]||[];e.push({v:b,styleElement:c,u:d});100<e.length&&e.shift();this.cache[a]=e};gg.prototype.fetch=function(a,b,c){if(a=this.cache[a])for(var d=a.length-1;0<=d;d--){var e=a[d],f;a:{for(f=0;f<c.length;f++){var h=c[f];if(e.v[h]!==b[h]){f=!1;break a}}f=!0}if(f)return e}};function hg(){}
|
||||
function ig(a){for(var b=0;b<a.length;b++){var c=a[b];if(c.target!==document.documentElement&&c.target!==document.head)for(var d=0;d<c.addedNodes.length;d++){var e=c.addedNodes[d];if(e.nodeType===Node.ELEMENT_NODE){var f=e.getRootNode();var h=e;var g=[];h.classList?g=Array.from(h.classList):h instanceof window.SVGElement&&h.hasAttribute("class")&&(g=h.getAttribute("class").split(/\s+/));h=g;g=h.indexOf(W.a);if((h=-1<g?h[g+1]:"")&&f===e.ownerDocument)jf(e,h,!0);else if(f.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&
|
||||
(f=f.host))if(f=V(f).is,h===f)for(e=window.ShadyDOM.nativeMethods.querySelectorAll.call(e,":not(."+W.a+")"),f=0;f<e.length;f++)lf(e[f],h);else h&&jf(e,h,!0),jf(e,f)}}}}
|
||||
if(!R){var jg=new MutationObserver(ig),kg=function(a){jg.observe(a,{childList:!0,subtree:!0})};if(window.customElements&&!window.customElements.polyfillWrapFlushCallback)kg(document);else{var lg=function(){kg(document.body)};window.HTMLImports?window.HTMLImports.whenReady(lg):requestAnimationFrame(function(){if("loading"===document.readyState){var a=function(){lg();document.removeEventListener("readystatechange",a)};document.addEventListener("readystatechange",a)}else lg()})}hg=function(){ig(jg.takeRecords())}}
|
||||
var mg=hg;var ng={};var og=Promise.resolve();function pg(a){if(a=ng[a])a._applyShimCurrentVersion=a._applyShimCurrentVersion||0,a._applyShimValidatingVersion=a._applyShimValidatingVersion||0,a._applyShimNextVersion=(a._applyShimNextVersion||0)+1}function qg(a){return a._applyShimCurrentVersion===a._applyShimNextVersion}function rg(a){a._applyShimValidatingVersion=a._applyShimNextVersion;a.qa||(a.qa=!0,og.then(function(){a._applyShimCurrentVersion=a._applyShimNextVersion;a.qa=!1}))};var sg=null,tg=window.HTMLImports&&window.HTMLImports.whenReady||null,ug;function vg(a){requestAnimationFrame(function(){tg?tg(a):(sg||(sg=new Promise(function(a){ug=a}),"complete"===document.readyState?ug():document.addEventListener("readystatechange",function(){"complete"===document.readyState&&ug()})),sg.then(function(){a&&a()}))})};var wg=new gg;function Y(){var a=this;this.L={};this.c=document.documentElement;var b=new Ae;b.rules=[];this.h=Mf(this.c,new Lf(b));this.s=!1;this.b=this.a=null;vg(function(){xg(a)})}p=Y.prototype;p.wa=function(){mg()};p.Ma=function(a){return bf(a)};p.Za=function(a){return $e(a)};
|
||||
p.prepareTemplate=function(a,b,c){if(!a.Ia){a.Ia=!0;a.name=b;a.extends=c;ng[b]=a;var d=(d=a.content.querySelector("style"))?d.getAttribute("css-build")||"":"";var e=[];for(var f=a.content.querySelectorAll("style"),h=0;h<f.length;h++){var g=f[h];if(g.hasAttribute("shady-unscoped")){if(!R){var k=g.textContent;Ze.has(k)||(Ze.add(k),k=g.cloneNode(!0),document.head.appendChild(k));g.parentNode.removeChild(g)}}else e.push(g.textContent),g.parentNode.removeChild(g)}e=e.join("").trim();c={is:b,extends:c,
|
||||
eb:d};R||jf(a.content,b);xg(this);f=Ue.test(e)||Te.test(e);Ue.lastIndex=0;Te.lastIndex=0;e=Be(e);f&&S&&this.a&&this.a.transformRules(e,b);a._styleAst=e;a.a=d;d=[];S||(d=Rf(a._styleAst));if(!d.length||S)e=R?a.content:null,b=dg[b],f=nf(c,a._styleAst),b=f.length?df(f,c.is,e,b):void 0,a.pa=b;a.Ha=d}};
|
||||
function yg(a){!a.b&&window.ShadyCSS&&window.ShadyCSS.CustomStyleInterface&&(a.b=window.ShadyCSS.CustomStyleInterface,a.b.transformCallback=function(b){a.ua(b)},a.b.validateCallback=function(){requestAnimationFrame(function(){(a.b.enqueued||a.s)&&a.F()})})}function xg(a){!a.a&&window.ShadyCSS&&window.ShadyCSS.ApplyShim&&(a.a=window.ShadyCSS.ApplyShim,a.a.invalidCallback=pg);yg(a)}
|
||||
p.F=function(){xg(this);if(this.b){var a=this.b.processStyles();if(this.b.enqueued){if(S)for(var b=0;b<a.length;b++){var c=this.b.getStyleForCustomStyle(a[b]);if(c&&S&&this.a){var d=bf(c);xg(this);this.a.transformRules(d);c.textContent=$e(d)}}else for(zg(this,this.c,this.h),b=0;b<a.length;b++)(c=this.b.getStyleForCustomStyle(a[b]))&&bg(c,this.h.B);this.b.enqueued=!1;this.s&&!S&&this.styleDocument()}}};
|
||||
p.styleElement=function(a,b){var c=V(a).is,d=X(a);if(!d){var e=V(a);d=e.is;e=e.P;var f=dg[d];d=ng[d];if(d){var h=d._styleAst;var g=d.Ha}d=Mf(a,new Lf(h,f,g,e))}a!==this.c&&(this.s=!0);b&&(d.G=d.G||{},Object.assign(d.G,b));if(S){if(d.G){b=d.G;for(var k in b)null===k?a.style.removeProperty(k):a.style.setProperty(k,b[k])}if(((k=ng[c])||a===this.c)&&k&&k.pa&&!qg(k)){if(qg(k)||k._applyShimValidatingVersion!==k._applyShimNextVersion)xg(this),this.a&&this.a.transformRules(k._styleAst,c),k.pa.textContent=
|
||||
nf(a,d.w),rg(k);R&&(c=a.shadowRoot)&&(c.querySelector("style").textContent=nf(a,d.w));d.w=k._styleAst}}else if(zg(this,a,d),d.ja&&d.ja.length){c=d;k=V(a).is;d=(b=wg.fetch(k,c.B,c.ja))?b.styleElement:null;h=c.u;(g=b&&b.u)||(g=this.L[k]=(this.L[k]||0)+1,g=k+"-"+g);c.u=g;g=c.u;e=cg;e=d?d.textContent||"":Zf(e,a,c.B,g);f=X(a);var l=f.a;l&&!R&&l!==d&&(l._useCount--,0>=l._useCount&&l.parentNode&&l.parentNode.removeChild(l));R?f.a?(f.a.textContent=e,d=f.a):e&&(d=df(e,g,a.shadowRoot,f.b)):d?d.parentNode||
|
||||
(Pf&&-1<e.indexOf("@media")&&(d.textContent=e),ef(d,null,f.b)):e&&(d=df(e,g,null,f.b));d&&(d._useCount=d._useCount||0,f.a!=d&&d._useCount++,f.a=d);g=d;R||(d=c.u,f=e=a.getAttribute("class")||"",h&&(f=e.replace(new RegExp("\\s*x-scope\\s*"+h+"\\s*","g")," ")),f+=(f?" ":"")+"x-scope "+d,e!==f&&gf(a,f));b||wg.store(k,c.B,g,c.u)}};function Ag(a,b){return(b=b.getRootNode().host)?X(b)?b:Ag(a,b):a.c}
|
||||
function zg(a,b,c){a=Ag(a,b);var d=X(a);a=Object.create(d.B||null);var e=Yf(b,c.w);b=Wf(d.w,b).v;Object.assign(a,e.Oa,b,e.Wa);b=c.G;for(var f in b)if((e=b[f])||0===e)a[f]=e;f=cg;b=Object.getOwnPropertyNames(a);for(e=0;e<b.length;e++)d=b[e],a[d]=Uf(f,a[d],a);c.B=a}p.styleDocument=function(a){this.styleSubtree(this.c,a)};
|
||||
p.styleSubtree=function(a,b){var c=a.shadowRoot;(c||a===this.c)&&this.styleElement(a,b);if(b=c&&(c.children||c.childNodes))for(a=0;a<b.length;a++)this.styleSubtree(b[a]);else if(a=a.children||a.childNodes)for(b=0;b<a.length;b++)this.styleSubtree(a[b])};p.ua=function(a){var b=this,c=bf(a);af(c,function(a){if(R)If(a);else{var c=W;a.selector=a.parsedSelector;If(a);a.selector=a.m=rf(c,a,c.c,void 0,void 0)}S&&(xg(b),b.a&&b.a.transformRule(a))});S?a.textContent=$e(c):this.h.w.rules.push(c)};
|
||||
p.getComputedStyleValue=function(a,b){var c;S||(c=(X(a)||X(Ag(this,a))).B[b]);return(c=c||window.getComputedStyle(a).getPropertyValue(b))?c.trim():""};p.Ya=function(a,b){var c=a.getRootNode();b=b?b.split(/\s/):[];c=c.host&&c.host.localName;if(!c){var d=a.getAttribute("class");if(d){d=d.split(/\s/);for(var e=0;e<d.length;e++)if(d[e]===W.a){c=d[e+1];break}}}c&&b.push(W.a,c);S||(c=X(a))&&c.u&&b.push(cg.a,c.u);gf(a,b.join(" "))};p.Ja=function(a){return X(a)};Y.prototype.flush=Y.prototype.wa;
|
||||
Y.prototype.prepareTemplate=Y.prototype.prepareTemplate;Y.prototype.styleElement=Y.prototype.styleElement;Y.prototype.styleDocument=Y.prototype.styleDocument;Y.prototype.styleSubtree=Y.prototype.styleSubtree;Y.prototype.getComputedStyleValue=Y.prototype.getComputedStyleValue;Y.prototype.setElementClass=Y.prototype.Ya;Y.prototype._styleInfoForNode=Y.prototype.Ja;Y.prototype.transformCustomStyleForDocument=Y.prototype.ua;Y.prototype.getStyleAst=Y.prototype.Ma;Y.prototype.styleAstToString=Y.prototype.Za;
|
||||
Y.prototype.flushCustomStyles=Y.prototype.F;Object.defineProperties(Y.prototype,{nativeShadow:{get:function(){return R}},nativeCss:{get:function(){return S}}});var Z=new Y,Bg,Cg;window.ShadyCSS&&(Bg=window.ShadyCSS.ApplyShim,Cg=window.ShadyCSS.CustomStyleInterface);window.ShadyCSS={ScopingShim:Z,prepareTemplate:function(a,b,c){Z.F();Z.prepareTemplate(a,b,c)},styleSubtree:function(a,b){Z.F();Z.styleSubtree(a,b)},styleElement:function(a){Z.F();Z.styleElement(a)},styleDocument:function(a){Z.F();Z.styleDocument(a)},getComputedStyleValue:function(a,b){return Z.getComputedStyleValue(a,b)},nativeCss:S,nativeShadow:R};Bg&&(window.ShadyCSS.ApplyShim=Bg);
|
||||
Cg&&(window.ShadyCSS.CustomStyleInterface=Cg);var Dg=window.customElements,Eg=window.HTMLImports,Fg=window.HTMLTemplateElement;window.WebComponents=window.WebComponents||{};if(Dg&&Dg.polyfillWrapFlushCallback){var Gg,Hg=function(){if(Gg){Fg.J&&Fg.J(window.document);var a=Gg;Gg=null;a();return!0}},Ig=Eg.whenReady;Dg.polyfillWrapFlushCallback(function(a){Gg=a;Ig(Hg)});Eg.whenReady=function(a){Ig(function(){Hg()?Eg.whenReady(a):a()})}}
|
||||
Eg.whenReady(function(){requestAnimationFrame(function(){window.WebComponents.ready=!0;document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})});var Jg=document.createElement("style");Jg.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";var Kg=document.querySelector("head");Kg.insertBefore(Jg,Kg.firstChild);}).call(this);
|
||||
|
||||
//# sourceMappingURL=webcomponents-lite.js.map
|